[master] 61f3d9a93 vslc: New mmap cursor type for regular files
Nils Goroll
nils.goroll at uplex.de
Fri Oct 9 17:46:06 UTC 2020
commit 61f3d9a936bd75c68b54955bd8f17b5a539ffa26
Author: Dridi Boukelmoune <dridi.boukelmoune at gmail.com>
Date: Wed Oct 7 14:35:04 2020 +0200
vslc: New mmap cursor type for regular files
This cursor is the simplest of all as of now, and also the fastest way
to skim through a -r input when it's a regular file. This is essentially
a file cursor with much less memory churn.
On a 13GB log dump captured during a performance benchmark varnishlog
takes around 6m15s to print all the transactions to /dev/null but the
mmap cursor consistently reduces this time to around 1m01s.
This is particularly useful to audit logs at rest, be it error logs
after an incident or transactions captured during a benchmark-type
scenario.
diff --git a/lib/libvarnishapi/vsl_cursor.c b/lib/libvarnishapi/vsl_cursor.c
index cf5349ade..bb79dc9b3 100644
--- a/lib/libvarnishapi/vsl_cursor.c
+++ b/lib/libvarnishapi/vsl_cursor.c
@@ -33,12 +33,15 @@
#include "config.h"
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
#include <unistd.h>
#include "vdef.h"
@@ -399,9 +402,115 @@ static const struct vslc_tbl vslc_file_tbl = {
.check = NULL,
};
+struct vslc_mmap {
+ unsigned magic;
+#define VSLC_MMAP_MAGIC 0x7de15f61
+ int fd;
+ char *b;
+ char *e;
+ struct VSL_cursor cursor;
+ struct VSLC_ptr next;
+};
+
+static void
+vslc_mmap_delete(const struct VSL_cursor *cursor)
+{
+ struct vslc_mmap *c;
+
+ CAST_OBJ_NOTNULL(c, cursor->priv_data, VSLC_MMAP_MAGIC);
+ assert(&c->cursor == cursor);
+ AZ(munmap(c->b, c->e - c->b));
+ FREE_OBJ(c);
+}
+
+static enum vsl_status v_matchproto_(vslc_next_f)
+vslc_mmap_next(const struct VSL_cursor *cursor)
+{
+ struct vslc_mmap *c;
+ const char *t;
+
+ CAST_OBJ_NOTNULL(c, cursor->priv_data, VSLC_MMAP_MAGIC);
+ assert(&c->cursor == cursor);
+ c->cursor.rec = c->next;
+ t = TRUST_ME(c->cursor.rec.ptr);
+ if (t == c->e)
+ return (vsl_e_eof);
+ c->next.ptr = VSL_NEXT(c->next.ptr);
+ t = TRUST_ME(c->next.ptr);
+ if (t > c->e)
+ return (vsl_e_io);
+ return (vsl_more);
+}
+
+static enum vsl_status v_matchproto_(vslc_reset_f)
+vslc_mmap_reset(const struct VSL_cursor *cursor)
+{
+ struct vslc_mmap *c;
+
+ CAST_OBJ_NOTNULL(c, cursor->priv_data, VSLC_MMAP_MAGIC);
+ assert(&c->cursor == cursor);
+ return (vsl_e_eof);
+}
+
+static enum vsl_check v_matchproto_(vslc_check_f)
+vslc_mmap_check(const struct VSL_cursor *cursor, const struct VSLC_ptr *ptr)
+{
+ struct vslc_mmap *c;
+
+ CAST_OBJ_NOTNULL(c, cursor->priv_data, VSLC_MMAP_MAGIC);
+ assert(&c->cursor == cursor);
+ AN(ptr->ptr);
+ return (vsl_check_valid);
+}
+
+static const struct vslc_tbl vslc_mmap_tbl = {
+ .magic = VSLC_TBL_MAGIC,
+ .delete = vslc_mmap_delete,
+ .next = vslc_mmap_next,
+ .reset = vslc_mmap_reset,
+ .check = vslc_mmap_check,
+};
+
+static struct VSL_cursor *
+vsl_cursor_mmap(struct VSL_data *vsl, int fd)
+{
+ struct vslc_mmap *c;
+ struct stat st[1];
+ void *p;
+
+ AZ(fstat(fd, st));
+ if ((st->st_mode & S_IFMT) != S_IFREG)
+ return (MAP_FAILED);
+
+ assert(st->st_size >= sizeof VSL_FILE_ID);
+ p = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (p == MAP_FAILED) {
+ vsl_diag(vsl, "Cannot mmap: %s", strerror(errno));
+ return (MAP_FAILED);
+ }
+
+ ALLOC_OBJ(c, VSLC_MMAP_MAGIC);
+ if (c == NULL) {
+ (void)munmap(p, st->st_size);
+ (void)close(fd);
+ vsl_diag(vsl, "Out of memory");
+ return (NULL);
+ }
+ c->cursor.priv_tbl = &vslc_mmap_tbl;
+ c->cursor.priv_data = c;
+
+ c->fd = fd;
+ c->b = p;
+ c->e = c->b + st->st_size;
+ c->next.ptr = TRUST_ME(c->b + sizeof VSL_FILE_ID);
+
+ return (&c->cursor);
+}
+
struct VSL_cursor *
VSL_CursorFile(struct VSL_data *vsl, const char *name, unsigned options)
{
+ struct VSL_cursor *mc;
struct vslc_file *c;
int fd;
int close_fd = 0;
@@ -440,6 +549,12 @@ VSL_CursorFile(struct VSL_data *vsl, const char *name, unsigned options)
return (NULL);
}
+ mc = vsl_cursor_mmap(vsl, fd);
+ if (mc == NULL)
+ return (NULL);
+ if (mc != MAP_FAILED)
+ return (mc);
+
ALLOC_OBJ(c, VSLC_FILE_MAGIC);
if (c == NULL) {
if (close_fd)
More information about the varnish-commit
mailing list