summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile.am6
-rw-r--r--src/binlog.c161
-rw-r--r--src/binlogcat.c71
-rw-r--r--src/pack.c588
-rw-r--r--src/pack.h47
-rw-r--r--src/vmod-binlog.h21
-rw-r--r--src/vmod.vcc7
-rw-r--r--tests/test01.at9
-rw-r--r--tests/test02.at9
10 files changed, 843 insertions, 77 deletions
diff --git a/src/.gitignore b/src/.gitignore
index 7f6e438..a75fe6d 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,2 +1,3 @@
1binlogcat
1vcc_if.c 2vcc_if.c
2vcc_if.h 3vcc_if.h
diff --git a/src/Makefile.am b/src/Makefile.am
index c9daf9a..9ce519f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,7 +17,8 @@
17AM_CPPFLAGS = -I$(VARNISHSRC)/include -I$(VARNISHSRC) 17AM_CPPFLAGS = -I$(VARNISHSRC)/include -I$(VARNISHSRC)
18 18
19bin_PROGRAMS = binlogcat 19bin_PROGRAMS = binlogcat
20binlogcat_SOURCES = binlogcat.c 20binlogcat_SOURCES = binlogcat.c pack.c
21binlogcat_CFLAGS = $(AM_CFLAGS)
21 22
22vmoddir = $(VMODDIR) 23vmoddir = $(VMODDIR)
23vmod_LTLIBRARIES = libvmod_binlog.la 24vmod_LTLIBRARIES = libvmod_binlog.la
@@ -27,9 +28,12 @@ libvmod_binlog_la_LIBADD=
27 28
28libvmod_binlog_la_SOURCES = \ 29libvmod_binlog_la_SOURCES = \
29 binlog.c\ 30 binlog.c\
31 pack.c\
30 vmod-binlog.h\ 32 vmod-binlog.h\
31 vcc_if.c vcc_if.h 33 vcc_if.c vcc_if.h
32 34
35noinst_HEADERS = pack.h
36
33BUILT_SOURCES = vcc_if.c vcc_if.h 37BUILT_SOURCES = vcc_if.c vcc_if.h
34 38
35vcc_if.c vcc_if.h: $(VARNISHSRC)/lib/libvmod_std/vmod.py $(top_srcdir)/src/vmod.vcc 39vcc_if.c vcc_if.h: $(VARNISHSRC)/lib/libvmod_std/vmod.py $(top_srcdir)/src/vmod.vcc
diff --git a/src/binlog.c b/src/binlog.c
index be32e10..6f438a8 100644
--- a/src/binlog.c
+++ b/src/binlog.c
@@ -22,6 +22,7 @@
22#include <unistd.h> 22#include <unistd.h>
23#include <errno.h> 23#include <errno.h>
24#include <syslog.h> 24#include <syslog.h>
25#include <stddef.h>
25#include <stdlib.h> 26#include <stdlib.h>
26#include <ctype.h> 27#include <ctype.h>
27#include <time.h> 28#include <time.h>
@@ -29,6 +30,7 @@
29#include "vcc_if.h" 30#include "vcc_if.h"
30#include "bin/varnishd/cache.h" 31#include "bin/varnishd/cache.h"
31#include "vmod-binlog.h" 32#include "vmod-binlog.h"
33#include "pack.h"
32 34
33#ifndef O_SEARCH 35#ifndef O_SEARCH
34# define O_SEARCH 0 36# define O_SEARCH 0
@@ -36,6 +38,12 @@
36 38
37#define BLF_ROUNDTS 0x01 39#define BLF_ROUNDTS 0x01
38 40
41enum binlog_state {
42 state_init,
43 state_start,
44 state_pack
45};
46
39struct binlog_config { 47struct binlog_config {
40 size_t size; /* maximum file size */ 48 size_t size; /* maximum file size */
41 unsigned interval; /* file rotation interval */ 49 unsigned interval; /* file rotation interval */
@@ -45,14 +53,21 @@ struct binlog_config {
45 int dd; /* directory descriptor */ 53 int dd; /* directory descriptor */
46 char *fname; /* current file name */ 54 char *fname; /* current file name */
47 int fd; /* current file descriptor */ 55 int fd; /* current file descriptor */
48 union binlog_header *base; /* mmap base */ 56 struct binlog_file_header *base; /* mmap base */
49 struct binlog_record *recbase; /* record base */ 57 char *recbase; /* record base */
50 size_t recnum; /* number of records in recbase */ 58 size_t recnum; /* number of records in recbase */
51 size_t recidx; /* index of the next free entry in recbase */ 59 size_t recsize; /* record size */
52 time_t stoptime; /* when to rotate the current file */ 60 time_t stoptime; /* when to rotate the current file */
53 pthread_mutex_t mutex; 61 pthread_mutex_t mutex;
54 int debug; 62 int debug;
55 int flags; 63 int flags;
64
65 char *dataspec;
66 struct packinst *inst_head;
67 struct packinst *inst_cur;
68 struct packenv *env;
69 enum binlog_state state;
70 time_t timestamp;
56}; 71};
57 72
58static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 73static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -158,11 +173,12 @@ getinterval(char *p, char **endp)
158} 173}
159 174
160void 175void
161vmod_init(struct sess *sp, struct vmod_priv *priv, const char *param) 176vmod_init(struct sess *sp, struct vmod_priv *priv,
177 const char *dir, const char *dataspec, const char *param)
162{ 178{
163 struct binlog_config *conf = priv->priv; 179 struct binlog_config *conf = priv->priv;
164 struct stat st; 180 struct stat st;
165 char *dir, *p, *q; 181 char *p, *q;
166 unsigned long n; 182 unsigned long n;
167 183
168 p = findparam(param, "debug"); 184 p = findparam(param, "debug");
@@ -170,12 +186,7 @@ vmod_init(struct sess *sp, struct vmod_priv *priv, const char *param)
170 conf->debug = atoi(p); 186 conf->debug = atoi(p);
171 free(p); 187 free(p);
172 } 188 }
173 189
174 dir = findparam(param, "dir");
175 if (!dir) {
176 binlog_error("parameter \"dir\" not set");
177 abort();
178 }
179 if (stat(dir, &st)) { 190 if (stat(dir, &st)) {
180 if (errno == ENOENT) 191 if (errno == ENOENT)
181 binlog_error("logging directory does not exist"); 192 binlog_error("logging directory does not exist");
@@ -194,8 +205,20 @@ vmod_init(struct sess *sp, struct vmod_priv *priv, const char *param)
194 dir, strerror(errno)); 205 dir, strerror(errno));
195 abort(); 206 abort();
196 } 207 }
197 conf->dir = dir; 208 conf->dir = strdup(dir);
209 AN(conf->dir);
198 210
211 conf->inst_head = packcomp(dataspec, &p);
212 if (*p) {
213 binlog_error("cannot compile data format near %s", p);
214 abort();
215 }
216 conf->recsize = packsize(conf->inst_head);
217 conf->env = packenv_create(conf->recsize);
218 conf->recsize += offsetof(struct binlog_record,data);
219 conf->dataspec = strdup(dataspec);
220 AN(conf->dataspec);
221
199 p = findparam(param, "pattern"); 222 p = findparam(param, "pattern");
200 if (!p) { 223 if (!p) {
201 p = strdup(BINLOG_PATTERN); 224 p = strdup(BINLOG_PATTERN);
@@ -367,7 +390,6 @@ reset(struct binlog_config *conf)
367 conf->base = NULL; 390 conf->base = NULL;
368 conf->recbase = NULL; 391 conf->recbase = NULL;
369 conf->recnum = 0; 392 conf->recnum = 0;
370 conf->recidx = 0;
371} 393}
372 394
373static int 395static int
@@ -379,11 +401,15 @@ setstoptime(struct binlog_config *conf)
379 conf->stoptime = ts - ts % conf->interval + conf->interval; 401 conf->stoptime = ts - ts % conf->interval + conf->interval;
380} 402}
381 403
404#define binlog_recnum(conf) \
405 (((conf)->size - (conf)->base->hdrsize) / (conf)->base->recsize)
406
382static int 407static int
383newfile(struct sess *sp, struct binlog_config *conf) 408newfile(struct sess *sp, struct binlog_config *conf)
384{ 409{
385 int c; 410 int c;
386 void *base; 411 void *base;
412 size_t n;
387 413
388 setstoptime(conf); 414 setstoptime(conf);
389 415
@@ -413,14 +439,18 @@ newfile(struct sess *sp, struct binlog_config *conf)
413 } 439 }
414 440
415 conf->base = base; 441 conf->base = base;
416 memcpy(conf->base->hdr.magic, BINLOG_MAGIC_STR, BINLOG_MAGIC_LEN); 442 memcpy(conf->base->magic, BINLOG_MAGIC_STR, BINLOG_MAGIC_LEN);
417 conf->base->hdr.version = BINLOG_VERSION; 443 conf->base->version = BINLOG_VERSION;
418 conf->base->hdr.recsize = sizeof(struct binlog_record); 444 conf->base->recsize = conf->recsize;
419 conf->base->hdr.recnum = 0; 445 conf->base->recnum = 0;
446 strcpy((char*)(conf->base + 1), conf->dataspec);
420 447
421 conf->recbase = (struct binlog_record *) (conf->base + 1); 448 n = (sizeof(struct binlog_file_header) + strlen(conf->dataspec) +
449 conf->recsize - 1) / conf->recsize;
450 conf->base->hdrsize = n * conf->recsize;
451
452 conf->recbase = (char *) conf->base + conf->base->hdrsize;
422 conf->recnum = binlog_recnum(conf); 453 conf->recnum = binlog_recnum(conf);
423 conf->recidx = 0;
424 454
425 debug(conf,1,("created new log file %s",conf->fname)); 455 debug(conf,1,("created new log file %s",conf->fname));
426 return 0; 456 return 0;
@@ -429,21 +459,23 @@ newfile(struct sess *sp, struct binlog_config *conf)
429static void 459static void
430closefile(struct sess *sp, struct binlog_config *conf) 460closefile(struct sess *sp, struct binlog_config *conf)
431{ 461{
462 size_t size;
463
432 if (conf->fd == -1) 464 if (conf->fd == -1)
433 return; 465 return;
434 debug(conf,1,("closing log file %s",conf->fname)); 466 debug(conf,1,("closing log file %s",conf->fname));
467 size = binlog_size(conf->base);
435 munmap(conf->base, conf->size); 468 munmap(conf->base, conf->size);
436 if (ftruncate(conf->fd, binlog_size(conf))) 469 if (ftruncate(conf->fd, size))
437 binlog_error("error truncating \"%s/%s\": %s", 470 binlog_error("error truncating \"%s/%s\": %s",
438 conf->dir, conf->fname, strerror(errno)); 471 conf->dir, conf->fname, strerror(errno));
439 close(conf->fd); 472 close(conf->fd);
440 free(conf->fname); 473 free(conf->fname);
441 reset(conf); 474 reset(conf);
442} 475}
443
444 476
445void 477void
446vmod_append(struct sess *sp, struct vmod_priv *priv, int nid, int aid) 478vmod_start(struct sess *sp, struct vmod_priv *priv)
447{ 479{
448 struct binlog_config *conf = priv->priv; 480 struct binlog_config *conf = priv->priv;
449 time_t ts; 481 time_t ts;
@@ -459,27 +491,84 @@ vmod_append(struct sess *sp, struct vmod_priv *priv, int nid, int aid)
459 newfile(sp, conf); 491 newfile(sp, conf);
460 AZ(pthread_mutex_unlock(&conf->mutex)); 492 AZ(pthread_mutex_unlock(&conf->mutex));
461 } 493 }
494
495 packenv_init(conf->env);
496 conf->state = state_start;
497 conf->inst_cur = conf->inst_head;
498 conf->timestamp = ts;
499}
500
501void
502vmod_pack(struct sess *sp, struct vmod_priv *priv, const char *str)
503{
504 struct binlog_config *conf = priv->priv;
505 char *argv[2];
506
507 if (!conf)
508 return;
509
510 switch (conf->state) {
511 case state_start:
512 case state_pack:
513 break;
514 default:
515 binlog_error("pack called in wrong state (%d)", conf->state);
516 return;
517 }
518
519 if (!conf->inst_cur) {
520 binlog_error("format spec exhausted");
521 return;
522 }
523
524 argv[0] = (char*) str;
525 argv[1] = NULL;
526 conf->env->argv = argv;
527 conf->env->argc = 2;
528 conf->env->argi = 0;
529
530 conf->inst_cur = packinnext(conf->inst_cur, conf->env);
531
532 conf->state = state_pack;
533}
534
535void
536vmod_commit(struct sess *sp, struct vmod_priv *priv)
537{
538 struct binlog_config *conf = priv->priv;
539
540 if (!conf)
541 return;
462 if (conf->fd == -1) 542 if (conf->fd == -1)
463 return; 543 return;
464 544
545 switch (conf->state) {
546 case state_start:
547 binlog_error("committing empty binlog record");
548 break;
549 case state_pack:
550 if (conf->inst_cur)
551 binlog_error("committing incomplete binlog record");
552 break;
553 default:
554 binlog_error("pack called in wrong state (%d)", conf->state);
555 return;
556 }
557
465 AZ(pthread_mutex_lock(&conf->mutex)); 558 AZ(pthread_mutex_lock(&conf->mutex));
466 if (conf->recidx == conf->recnum) { 559 if (conf->base->recnum == conf->recnum) {
467 binlog_error("overflow of %s/%s", conf->dir, conf->fname); 560 binlog_error("overflow of %s/%s", conf->dir, conf->fname);
468 } else { 561 } else {
469 struct binlog_record *p = conf->recbase + conf->recidx++; 562 struct binlog_record *p =
470 p->nid = nid; 563 (struct binlog_record *)(conf->recbase +
471 p->aid = aid; 564 conf->base->recnum *
472 p->ts = ts; 565 conf->recsize);
473 conf->base->hdr.recnum++; 566 p->ts = conf->timestamp;
567 memcpy(p->data, conf->env->buf_base, conf->env->buf_size);
568 conf->base->recnum++;
474 } 569 }
475 AZ(pthread_mutex_unlock(&conf->mutex)); 570 AZ(pthread_mutex_unlock(&conf->mutex));
476} 571 conf->state = state_init;
477
478void
479vmod_sappend(struct sess *sp, struct vmod_priv *priv, const char *nid,
480 const char *aid)
481{
482 vmod_append(sp, priv, nid ? atoi(nid): 0, aid ? atoi(aid) : 0);
483} 572}
484 573
485void 574void
@@ -492,7 +581,7 @@ vmod_sync(struct sess *sp, struct vmod_priv *priv)
492 581
493 AZ(pthread_mutex_lock(&conf->mutex)); 582 AZ(pthread_mutex_lock(&conf->mutex));
494 if (conf->base) 583 if (conf->base)
495 msync(conf->base, binlog_size(conf), 0); 584 msync(conf->base, binlog_size(conf->base), 0);
496 AZ(pthread_mutex_unlock(&conf->mutex)); 585 AZ(pthread_mutex_unlock(&conf->mutex));
497 } 586 }
498 587
diff --git a/src/binlogcat.c b/src/binlogcat.c
index 219f78c..ee8837a 100644
--- a/src/binlogcat.c
+++ b/src/binlogcat.c
@@ -17,12 +17,14 @@
17 17
18#include <config.h> 18#include <config.h>
19#include <unistd.h> 19#include <unistd.h>
20#include <stddef.h>
20#include <stdio.h> 21#include <stdio.h>
21#include <stdlib.h> 22#include <stdlib.h>
22#include <errno.h> 23#include <errno.h>
23#include <time.h> 24#include <time.h>
24#include <string.h> 25#include <string.h>
25#include "vmod-binlog.h" 26#include "vmod-binlog.h"
27#include "pack.h"
26 28
27char *progname; 29char *progname;
28char *timefmt = "%c"; 30char *timefmt = "%c";
@@ -34,11 +36,16 @@ void
34catlog(const char *fname) 36catlog(const char *fname)
35{ 37{
36 FILE *fp; 38 FILE *fp;
37 union binlog_header header; 39 struct binlog_file_header header;
38 struct binlog_record rec; 40 struct binlog_record *rec;
39 char timebuf[128]; 41 char timebuf[128];
40 size_t i; 42 size_t i;
41 time_t start_ts; 43 time_t start_ts;
44 char *dataspec;
45 size_t size;
46 struct packenv *env;
47 struct packinst *inst;
48 char *p;
42 49
43 if (strcmp(fname, "-") == 0) 50 if (strcmp(fname, "-") == 0)
44 fp = stdin; 51 fp = stdin;
@@ -57,29 +64,54 @@ catlog(const char *fname)
57 exit(1); 64 exit(1);
58 } 65 }
59 66
60 if (memcmp(header.hdr.magic, BINLOG_MAGIC_STR, BINLOG_MAGIC_LEN)) { 67 if (memcmp(header.magic, BINLOG_MAGIC_STR, BINLOG_MAGIC_LEN)) {
61 fprintf(stderr, "%s: %s is not a binlog file\n", 68 fprintf(stderr, "%s: %s is not a binlog file\n",
62 progname, fname); 69 progname, fname);
63 exit(1); 70 exit(1);
64 } 71 }
65 72
66 if (header.hdr.version != BINLOG_VERSION) { 73 if (header.version != BINLOG_VERSION) {
67 fprintf(stderr, "%s: %s: unknown version\n", 74 fprintf(stderr, "%s: %s: unknown version\n",
68 progname, fname); 75 progname, fname);
69 exit(1); 76 exit(1);
70 } 77 }
71 78
72 if (header.hdr.recsize != sizeof(struct binlog_record)) { 79 size = header.hdrsize - sizeof(header);
73 fprintf(stderr, "%s: %s: record length mismatch\n", 80 dataspec = malloc(size);
74 progname, fname); 81 if (!dataspec) {
82 fprintf(stderr, "%s: not enough memory", progname);
83 abort();
84 }
85
86 if (fread(dataspec, size, 1, fp) != 1) {
87 fprintf(stderr, "%s: error reading header of %s: %s\n",
88 progname, fname, strerror(errno));
75 exit(1); 89 exit(1);
76 } 90 }
77 91
78 if (verbose_option) 92 if (verbose_option)
79 printf("# %s; %lu records\n", fname, header.hdr.recnum); 93 printf("# %s; format=%s; recsize=%lu; recnum=%lu\n",
94 fname, dataspec, header.recsize, header.recnum);
95
96 inst = packcomp(dataspec, &p);
97 if (*p) {
98 fprintf(stderr, "%s: %s: bad dataspec near %s",
99 progname, dataspec, p);
100 exit(1);
101 }
102 free(dataspec);
103
104 rec = malloc(header.recsize);
105 if (!rec) {
106 fprintf(stderr, "%s: not enough memory", progname);
107 abort();
108 }
109 env = packenv_create(header.recsize -
110 offsetof(struct binlog_record,data));
111 env->fp = stdout;
80 112
81 for (i = 0; i < header.hdr.recnum; i++) { 113 for (i = 0; i < header.recnum; i++) {
82 if (fread(&rec, sizeof(rec), 1, fp) != 1) { 114 if (fread(rec, header.recsize, 1, fp) != 1) {
83 fprintf(stderr, "%s: %s: unexpected eof\n", 115 fprintf(stderr, "%s: %s: unexpected eof\n",
84 progname, fname); 116 progname, fname);
85 break; 117 break;
@@ -87,15 +119,26 @@ catlog(const char *fname)
87 119
88 if (timediff_option) { 120 if (timediff_option) {
89 if (i == 0) 121 if (i == 0)
90 start_ts = rec.ts; 122 start_ts = rec->ts;
91 rec.ts -= start_ts; 123 rec->ts -= start_ts;
92 } 124 }
93 125
94 strftime(timebuf, sizeof timebuf, timefmt, localtime(&rec.ts)); 126 strftime(timebuf, sizeof timebuf, timefmt,
127 localtime(&rec->ts));
95 if (number_option) 128 if (number_option)
96 printf("%lu ", (unsigned long) i); 129 printf("%lu ", (unsigned long) i);
97 printf("%s %ld %ld\n", timebuf, rec.nid, rec.aid); 130 printf("%s ", timebuf);
131
132 memcpy(env->buf_base, rec->data, env->buf_size);
133 env->buf_pos = 0;
134
135 packout(inst, env);
136 fputc('\n', stdout);
98 } 137 }
138
139 free(rec);
140 packenv_free(env);
141 packfree(inst);
99 142
100 fclose(fp); 143 fclose(fp);
101} 144}
diff --git a/src/pack.c b/src/pack.c
new file mode 100644
index 0000000..a6ee933
--- a/dev/null
+++ b/src/pack.c
@@ -0,0 +1,588 @@
1/* This file is part of vmod-binlog
2 Copyright (C) 2013 Sergey Poznyakoff
3
4 Vmod-binlog is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Vmod-binlog is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with vmod-binlog. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include <config.h>
18#include <stdint.h>
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <ctype.h>
23#include "pack.h"
24
25/* Data format specification is a simplified form of Perl pack() template.
26 It consists of a series of template letters optionally followed by
27 numeric repeat count (which may be enclosed in square brackets). The
28 valid template letters are:
29
30 Z A null-terminated (ASCIZ) string of at most N-1 characters, will be
31 null padded. This letter must be followed by repeat count.
32
33 c A signed char (8-bit) value.
34 C An unsigned char (octet) value.
35
36 s A signed short (16-bit) value.
37 S An unsigned short value.
38
39 l A signed long (32-bit) value.
40 L An unsigned long value.
41
42 q A signed quad (64-bit) value.
43 Q An unsigned quad value.
44
45 i A signed integer value.
46 I A unsigned integer value.
47
48 x A null byte (a.k.a ASCII NUL, "\000", chr(0))
49 X Back up a byte.
50 @ Null-fill or truncate to absolute position, counted from the
51 current position.
52 . Null-fill or truncate to absolute position specified by
53 the repeat count.
54*/
55
56#define F_REP 0x01
57
58struct packspec {
59 int ch;
60 size_t size;
61 int flags;
62 void (*packer)(struct packenv *, struct packspec *, int);
63 void (*unpacker)(struct packenv *, struct packspec *, int);
64};
65
66struct packinst {
67 struct packinst *next;
68 struct packspec *spec;
69 int rep;
70};
71
72static char *
73packenv_get(struct packenv *env)
74{
75 if (env->argi == env->argc)
76 return NULL;
77 return env->argv[env->argi++];
78}
79
80static void
81printunum(FILE *fp, uintmax_t num)
82{
83 char numbuf[512];
84 char *p = numbuf + sizeof(numbuf);
85 *--p = 0;
86 do
87 *--p = num % 10 + '0';
88 while (num /= 10);
89 fputs(p, fp);
90}
91
92static void
93printsnum(FILE *fp, intmax_t num)
94{
95 if (num < 0) {
96 fputc('-', fp);
97 num = - num;
98 }
99 printunum(fp, num);
100}
101
102static void
103Z_packer(struct packenv *env, struct packspec *spec, int rep)
104{
105 if (env->buf_base) {
106 char *arg = packenv_get(env);
107
108 memset(env->buf_base + env->buf_pos, 0, rep);
109 if (arg) {
110 size_t len = strlen(arg);
111 if (len > rep - 1)
112 len = rep - 1;
113 memcpy(env->buf_base + env->buf_pos, arg, len);
114 }
115 }
116 env->buf_pos += rep;
117}
118
119static void
120Z_unpacker(struct packenv *env, struct packspec *spec, int rep)
121{
122 fprintf(env->fp, "%-*.*s", rep, rep, env->buf_base + env->buf_pos);
123 env->buf_pos += rep;
124}
125
126static void
127c_packer(struct packenv *env, struct packspec *spec, int rep)
128{
129 if (env->buf_base) {
130 char *arg = packenv_get(env);
131 if (arg)
132 env->buf_base[env->buf_pos] = *arg;
133 }
134 env->buf_pos++;
135}
136
137static void
138c_unpacker(struct packenv *env, struct packspec *spec, int rep)
139{
140 fprintf(env->fp, "%c", env->buf_base[env->buf_pos++]);
141}
142
143static void
144s_packer(struct packenv *env, struct packspec *spec, int rep)
145{
146 if (env->buf_base) {
147 char *arg = packenv_get(env);
148 if (arg) {
149 int16_t v = atoi(arg);
150 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
151 }
152 }
153 env->buf_pos += spec->size;
154}
155
156static void
157s_unpacker(struct packenv *env, struct packspec *spec, int rep)
158{
159 printsnum(env->fp, *(int16_t *) (env->buf_base + env->buf_pos));
160 env->buf_pos += spec->size;
161}
162
163static void
164S_packer(struct packenv *env, struct packspec *spec, int rep)
165{
166 if (env->buf_base) {
167 char *arg = packenv_get(env);
168 if (arg) {
169 uint16_t v = atoi(arg);
170 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
171 }
172 }
173 env->buf_pos += spec->size;
174}
175
176static void
177S_unpacker(struct packenv *env, struct packspec *spec, int rep)
178{
179 printunum(env->fp, *(uint16_t *)(env->buf_base + env->buf_pos));
180 env->buf_pos += spec->size;
181}
182
183static void
184l_packer(struct packenv *env, struct packspec *spec, int rep)
185{
186 if (env->buf_base) {
187 char *arg = packenv_get(env);
188 if (arg) {
189 int32_t v = atoi(arg);
190 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
191 }
192 }
193 env->buf_pos += spec->size;
194}
195
196static void
197l_unpacker(struct packenv *env, struct packspec *spec, int rep)
198{
199 printsnum(env->fp, *(int32_t *)(env->buf_base + env->buf_pos));
200 env->buf_pos += spec->size;
201}
202
203static void
204L_packer(struct packenv *env, struct packspec *spec, int rep)
205{
206 if (env->buf_base) {
207 char *arg = packenv_get(env);
208 if (arg) {
209 uint32_t v = atoi(arg);
210 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
211 }
212 }
213 env->buf_pos += spec->size;
214}
215
216static void
217L_unpacker(struct packenv *env, struct packspec *spec, int rep)
218{
219 printunum(env->fp, *(uint32_t *)(env->buf_base + env->buf_pos));
220 env->buf_pos += spec->size;
221}
222
223static void
224q_packer(struct packenv *env, struct packspec *spec, int rep)
225{
226 if (env->buf_base) {
227 char *arg = packenv_get(env);
228 if (arg) {
229 int64_t v = atoi(arg);
230 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
231 }
232 }
233 env->buf_pos += spec->size;
234}
235
236static void
237q_unpacker(struct packenv *env, struct packspec *spec, int rep)
238{
239 printsnum(env->fp, *(int64_t *)(env->buf_base + env->buf_pos));
240 env->buf_pos += spec->size;
241}
242
243static void
244Q_packer(struct packenv *env, struct packspec *spec, int rep)
245{
246 if (env->buf_base) {
247 char *arg = packenv_get(env);
248 if (arg) {
249 uint64_t v = atoi(arg);
250 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
251 }
252 }
253 env->buf_pos += spec->size;
254}
255
256static void
257Q_unpacker(struct packenv *env, struct packspec *spec, int rep)
258{
259 printunum(env->fp, *(uint64_t *)(env->buf_base + env->buf_pos));
260 env->buf_pos += spec->size;
261}
262
263static void
264i_packer(struct packenv *env, struct packspec *spec, int rep)
265{
266 if (env->buf_base) {
267 char *arg = packenv_get(env);
268 if (arg) {
269 int v = atoi(arg);
270 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
271 }
272 }
273 env->buf_pos += spec->size;
274}
275
276static void
277i_unpacker(struct packenv *env, struct packspec *spec, int rep)
278{
279 printsnum(env->fp, *(int *)(env->buf_base + env->buf_pos));
280 env->buf_pos += spec->size;
281}
282
283static void
284I_packer(struct packenv *env, struct packspec *spec, int rep)
285{
286 if (env->buf_base) {
287 char *arg = packenv_get(env);
288 if (arg) {
289 unsigned int v = atoi(arg);
290 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
291 }
292 }
293 env->buf_pos += spec->size;
294}
295
296static void
297I_unpacker(struct packenv *env, struct packspec *spec, int rep)
298{
299 printunum(env->fp, *(unsigned *)(env->buf_base + env->buf_pos));
300 env->buf_pos += spec->size;
301}
302
303static void
304x_packer(struct packenv *env, struct packspec *spec, int rep)
305{
306 if (env->buf_base)
307 env->buf_base[env->buf_pos] = 0;
308 env->buf_pos++;
309}
310
311static void
312x_unpacker(struct packenv *env, struct packspec *spec, int rep)
313{
314 fputc(0, env->fp);
315}
316
317static void
318X_packer(struct packenv *env, struct packspec *spec, int rep)
319{
320 if (env->buf_pos)
321 --env->buf_pos;
322}
323
324static void
325at_packer(struct packenv *env, struct packspec *spec, int rep)
326{
327 if (env->buf_base)
328 memset(env->buf_base + env->buf_pos, 0, rep);
329 env->buf_pos += rep;
330}
331
332static void
333at_unpacker(struct packenv *env, struct packspec *spec, int rep)
334{
335 env->buf_pos += rep;
336}
337
338static void
339dot_packer(struct packenv *env, struct packspec *spec, int rep)
340{
341 if (env->buf_base) {
342 if (rep < env->buf_pos)
343 memset(env->buf_base + rep, 0, env->buf_pos - rep);
344 else
345 memset(env->buf_base + env->buf_pos, 0,
346 rep - env->buf_pos);
347 }
348 env->buf_pos = rep;
349}
350
351static void
352dot_unpacker(struct packenv *env, struct packspec *spec, int rep)
353{
354 env->buf_pos = rep;
355}
356
357static struct packspec packspec[] = {
358 { 'Z', 1, F_REP, Z_packer, Z_unpacker },
359 { 'c', 1, 0, c_packer, c_unpacker },
360 { 's', sizeof(int16_t), 0, s_packer, s_unpacker },
361 { 'S', sizeof(uint16_t), 0, S_packer, S_unpacker },
362 { 'l', sizeof(int32_t), 0, l_packer, l_unpacker },
363 { 'L', sizeof(uint32_t), 0, L_packer, L_unpacker },
364 { 'q', sizeof(int64_t), 0, q_packer, q_unpacker },
365 { 'Q', sizeof(uint64_t), 0, Q_packer, Q_unpacker },
366 { 'i', sizeof(int), 0, i_packer, i_unpacker },
367 { 'I', sizeof(unsigned), 0, I_packer, I_unpacker },
368 /* FIXME: n N v V f d */
369 { 'x', 1, 0, x_packer, x_unpacker },
370 { 'X', 1, 0, X_packer, X_packer },
371 { '@', 0, F_REP, at_packer, at_unpacker },
372 { '.', 0, F_REP, dot_packer, dot_unpacker },
373
374 { 0 }
375};
376
377static int
378getrep(const char *s, char const **endp, int *rep)
379{
380 int n;
381 char *p;
382
383 if (*s == '[') {
384 if (s[1]) {
385 if (isdigit(s[1])) {
386 n = strtol(s + 1, &p, 10);
387 if (n <= 0) {
388 *endp = s;
389 return -1;
390 } else if (*p != ']') {
391 *endp = p;
392 return -1;
393 }
394 *rep = n;
395 *endp = p + 1;
396 } else {
397 *endp = s;
398 return -1;
399 }
400 } else {
401 *endp = s;
402 return -1;
403 }
404 } else if (isdigit(*s)) {
405 n = strtol(s, &p, 10);
406 if (n <= 0) {
407 *endp = s;
408 return -1;
409 }
410 *rep = n;
411 *endp = p;
412 } else {
413 *rep = 1;
414 *endp = s;
415 }
416 return 0;
417}
418
419struct packinst *
420packcomp(const char *s, char **endp)
421{
422 struct packinst *head = NULL, *tail = NULL, *pi;
423 struct packspec *ps;
424 int rep;
425
426 while (s) {
427 for (ps = packspec; ps->ch; ps++)
428 if (ps->ch == *s)
429 break;
430 if (!ps->ch)
431 break;
432 if (getrep(s + 1, &s, &rep))
433 break;
434 pi = malloc(sizeof(*pi));
435 pi->next = NULL;
436 pi->spec = ps;
437 pi->rep = rep;
438 if (tail)
439 tail->next = pi;
440 else
441 head = pi;
442 tail = pi;
443 }
444 if (endp)
445 *endp = (char*) s;
446 return head;
447}
448
449void
450packfree(struct packinst *pi)
451{
452 while (pi) {
453 struct packinst *next = pi->next;
454 free(pi);
455 pi = next;
456 }
457}
458
459void
460packin(struct packinst *pi, struct packenv *env)
461{
462 int i;
463
464 for (; pi; pi = pi->next) {
465 if (pi->spec->flags & F_REP)
466 pi->spec->packer(env, pi->spec, pi->rep);
467 else
468 for (i = 0; i < pi->rep; i++)
469 pi->spec->packer(env, pi->spec, 1);
470 }
471}
472
473struct packinst *
474packinnext(struct packinst *pi, struct packenv *env)
475{
476 int i;
477
478 if (!pi)
479 return NULL;
480 if (pi->spec->flags & F_REP)
481 pi->spec->packer(env, pi->spec, pi->rep);
482 else
483 for (i = 0; i < pi->rep; i++)
484 pi->spec->packer(env, pi->spec, 1);
485 return pi->next;
486}
487
488void
489packout(struct packinst *pi, struct packenv *env)
490{
491 int i;
492
493 for (; pi; pi = pi->next) {
494 if (pi->spec->flags & F_REP)
495 pi->spec->unpacker(env, pi->spec, pi->rep);
496 else
497 for (i = 0; i < pi->rep; i++)
498 pi->spec->unpacker(env, pi->spec, 1);
499 if (pi->next)
500 fputc(' ', env->fp);
501 }
502}
503
504size_t
505packsize(struct packinst *pi)
506{
507 struct packenv env;
508
509 memset(&env, 0, sizeof env);
510 packin(pi, &env);
511 return env.buf_pos;
512}
513
514struct packenv *
515packenv_create(size_t size)
516{
517 struct packenv *env = calloc(1, sizeof(*env));
518 env->buf_base = calloc(1, size);
519 env->buf_size = size;
520 return env;
521}
522
523void
524packenv_free(struct packenv *env)
525{
526 if (!env)
527 return;
528 free(env->buf_base);
529 free(env);
530}
531
532void
533packenv_init(struct packenv *env)
534{
535 memset(env->buf_base, 0, env->buf_size);
536 env->buf_pos = 0;
537}
538
539#ifdef STANDALONE
540#include <unistd.h>
541
542int
543main(int argc, char **argv)
544{
545 void (*fn)(struct packinst *pi, struct packenv *env) = packin;
546 struct packinst *pi;
547 struct packenv *env;
548 char *end;
549 int c;
550
551 while ((c = getopt(argc, argv, "d")) != EOF) {
552 switch (c) {
553 case 'd':
554 fn = packout;
555 break;
556 default:
557 exit(1);
558 }
559 }
560
561 argc -= optind;
562 argv += optind;
563
564 if (argc == 0)
565 abort();
566
567 pi = packcomp(argv[0], &end);
568 if (*end) {
569 fprintf(stderr, "compile error near %s\n", end);
570 exit(1);
571 }
572 env = packenv_create(packsize(pi));
573 env->fp = stdout;
574 env->argv = argv + 1;
575 env->argc = argc - 1;
576
577 if (fn == packout)
578 fread(env->buf_base, env->buf_size, 1, stdin);
579
580 fn(pi, env);
581 if (fn == packin) {
582 fwrite(env->buf_base, env->buf_size, 1, stdout);
583 }
584
585 packenv_free(env);
586 packfree(pi);
587}
588#endif
diff --git a/src/pack.h b/src/pack.h
new file mode 100644
index 0000000..70a2488
--- a/dev/null
+++ b/src/pack.h
@@ -0,0 +1,47 @@
1/* This file is part of vmod-binlog
2 Copyright (C) 2013 Sergey Poznyakoff
3
4 Vmod-binlog is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Vmod-binlog is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with vmod-binlog. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include <stdio.h>
18
19struct packenv {
20 char *buf_base;
21 size_t buf_size;
22 size_t buf_pos;
23 char **argv;
24 int argc;
25 int argi;
26 FILE *fp;
27};
28
29struct packinst;
30
31struct packinst *packcomp(const char *s, char **endp);
32void packfree(struct packinst *pi);
33void packin(struct packinst *pi, struct packenv *env);
34void packout(struct packinst *pi, struct packenv *env);
35struct packinst *packinnext(struct packinst *pi, struct packenv *env);
36
37size_t packsize(struct packinst *pi);
38struct packenv *packenv_create(size_t size);
39void packenv_init(struct packenv *env);
40void packenv_free(struct packenv *env);
41
42
43
44
45
46
47
diff --git a/src/vmod-binlog.h b/src/vmod-binlog.h
index db6c7f0..06d517d 100644
--- a/src/vmod-binlog.h
+++ b/src/vmod-binlog.h
@@ -36,9 +36,8 @@
36#endif 36#endif
37 37
38struct binlog_record { 38struct binlog_record {
39 long nid; /* node ID */
40 long aid; /* article ID */
41 time_t ts; /* timestamp */ 39 time_t ts; /* timestamp */
40 char data[1]; /* payload */
42}; 41};
43 42
44#define BINLOG_MAGIC_STR "NXCBINLOG" 43#define BINLOG_MAGIC_STR "NXCBINLOG"
@@ -49,23 +48,11 @@ struct binlog_file_header {
49 char magic[BINLOG_MAGIC_LEN]; 48 char magic[BINLOG_MAGIC_LEN];
50 char pad[16 - BINLOG_MAGIC_LEN]; 49 char pad[16 - BINLOG_MAGIC_LEN];
51 uint32_t version; 50 uint32_t version;
51 size_t hdrsize;
52 size_t recsize; 52 size_t recsize;
53 size_t recnum; 53 size_t recnum;
54 /*char dataspec[X];*/
54}; 55};
55 56
56#define BINLOG_HEADER_SIZE \ 57#define binlog_size(hdr) ((hdr)->hdrsize + (hdr)->recnum * (hdr)->recsize)
57 ((sizeof(struct binlog_file_header) + sizeof(struct binlog_record) - 1) / \
58 sizeof(struct binlog_record))
59
60union binlog_header {
61 struct binlog_file_header hdr;
62 struct binlog_record pad[BINLOG_HEADER_SIZE];
63};
64
65#define binlog_size(conf) \
66 (sizeof(union binlog_header) + \
67 (conf)->recidx * sizeof(struct binlog_record))
68#define binlog_recnum(conf) \
69 (((conf)->size - sizeof(union binlog_header)) / \
70 sizeof(struct binlog_record))
71 58
diff --git a/src/vmod.vcc b/src/vmod.vcc
index def0ec3..45da354 100644
--- a/src/vmod.vcc
+++ b/src/vmod.vcc
@@ -1,7 +1,8 @@
1Module binlog 1Module binlog
2Init module_init 2Init module_init
3Function VOID init(PRIV_VCL, STRING) 3Function VOID init(PRIV_VCL, STRING, STRING, STRING)
4Function VOID append(PRIV_VCL, INT, INT) 4Function VOID start(PRIV_VCL)
5Function VOID sappend(PRIV_VCL, STRING, STRING) 5Function VOID commit(PRIV_VCL)
6Function VOID pack(PRIV_VCL, STRING)
6Function VOID sync(PRIV_VCL) 7Function VOID sync(PRIV_VCL)
7Function VOID close(PRIV_VCL) 8Function VOID close(PRIV_VCL)
diff --git a/tests/test01.at b/tests/test01.at
index 116c8f1..62eb4fb 100644
--- a/tests/test01.at
+++ b/tests/test01.at
@@ -15,7 +15,7 @@
15# along with vmod-binlog. If not, see <http://www.gnu.org/licenses/>. 15# along with vmod-binlog. If not, see <http://www.gnu.org/licenses/>.
16 16
17AT_SETUP([appends]) 17AT_SETUP([appends])
18AT_KEYWORDS([append]) 18AT_KEYWORDS([test01 append])
19 19
20AT_CHECK([ 20AT_CHECK([
21cwd=`pwd` 21cwd=`pwd`
@@ -32,13 +32,16 @@ server s1 {
32varnish v1 -vcl+backend { 32varnish v1 -vcl+backend {
33 import binlog from "$abs_top_builddir/src/.libs/libvmod_binlog.so"; 33 import binlog from "$abs_top_builddir/src/.libs/libvmod_binlog.so";
34 sub vcl_init { 34 sub vcl_init {
35 binlog.init("dir=$cwd/log;size=1M;pattern=logfile"); 35 binlog.init("$cwd/log", "LL", "size=1M;pattern=logfile");
36 } 36 }
37 sub vcl_fini { 37 sub vcl_fini {
38 binlog.close(); 38 binlog.close();
39 } 39 }
40 sub vcl_recv { 40 sub vcl_recv {
41 binlog.sappend(req.http.X-nid, req.http.X-aid); 41 binlog.start();
42 binlog.pack(req.http.X-nid);
43 binlog.pack(req.http.X-aid);
44 binlog.commit();
42 return (lookup); 45 return (lookup);
43 } 46 }
44} -start 47} -start
diff --git a/tests/test02.at b/tests/test02.at
index df639a5..459a3cc 100644
--- a/tests/test02.at
+++ b/tests/test02.at
@@ -15,7 +15,7 @@
15# along with vmod-binlog. If not, see <http://www.gnu.org/licenses/>. 15# along with vmod-binlog. If not, see <http://www.gnu.org/licenses/>.
16 16
17AT_SETUP([log rotation]) 17AT_SETUP([log rotation])
18AT_KEYWORDS([rotation]) 18AT_KEYWORDS([test02 rotation])
19 19
20AT_CHECK([ 20AT_CHECK([
21cwd=`pwd` 21cwd=`pwd`
@@ -32,13 +32,16 @@ server s1 {
32varnish v1 -vcl+backend { 32varnish v1 -vcl+backend {
33 import binlog from "$abs_top_builddir/src/.libs/libvmod_binlog.so"; 33 import binlog from "$abs_top_builddir/src/.libs/libvmod_binlog.so";
34 sub vcl_init { 34 sub vcl_init {
35 binlog.init("dir=$cwd/log;size=1M;interval=10;roundts=1;pattern=%S.log"); 35 binlog.init("$cwd/log","LL","size=1M;interval=10;roundts=1;pattern=%S.log");
36 } 36 }
37 sub vcl_fini { 37 sub vcl_fini {
38 binlog.close(); 38 binlog.close();
39 } 39 }
40 sub vcl_recv { 40 sub vcl_recv {
41 binlog.sappend(req.http.X-nid, req.http.X-aid); 41 binlog.start();
42 binlog.pack(req.http.X-nid);
43 binlog.pack(req.http.X-aid);
44 binlog.commit();
42 return (lookup); 45 return (lookup);
43 } 46 }
44} -start 47} -start

Return to:

Send suggestions and report system problems to the System administrator.