summaryrefslogtreecommitdiffabout
path: root/src/binlog.c
Side-by-side diff
Diffstat (limited to 'src/binlog.c') (more/less context) (ignore whitespace changes)
-rw-r--r--src/binlog.c161
1 files changed, 125 insertions, 36 deletions
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 @@
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
+#include <stddef.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
@@ -29,6 +30,7 @@
#include "vcc_if.h"
#include "bin/varnishd/cache.h"
#include "vmod-binlog.h"
+#include "pack.h"
#ifndef O_SEARCH
# define O_SEARCH 0
@@ -36,6 +38,12 @@
#define BLF_ROUNDTS 0x01
+enum binlog_state {
+ state_init,
+ state_start,
+ state_pack
+};
+
struct binlog_config {
size_t size; /* maximum file size */
unsigned interval; /* file rotation interval */
@@ -45,14 +53,21 @@ struct binlog_config {
int dd; /* directory descriptor */
char *fname; /* current file name */
int fd; /* current file descriptor */
- union binlog_header *base; /* mmap base */
- struct binlog_record *recbase; /* record base */
+ struct binlog_file_header *base; /* mmap base */
+ char *recbase; /* record base */
size_t recnum; /* number of records in recbase */
- size_t recidx; /* index of the next free entry in recbase */
+ size_t recsize; /* record size */
time_t stoptime; /* when to rotate the current file */
pthread_mutex_t mutex;
int debug;
int flags;
+
+ char *dataspec;
+ struct packinst *inst_head;
+ struct packinst *inst_cur;
+ struct packenv *env;
+ enum binlog_state state;
+ time_t timestamp;
};
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -158,11 +173,12 @@ getinterval(char *p, char **endp)
}
void
-vmod_init(struct sess *sp, struct vmod_priv *priv, const char *param)
+vmod_init(struct sess *sp, struct vmod_priv *priv,
+ const char *dir, const char *dataspec, const char *param)
{
struct binlog_config *conf = priv->priv;
struct stat st;
- char *dir, *p, *q;
+ char *p, *q;
unsigned long n;
p = findparam(param, "debug");
@@ -170,12 +186,7 @@ vmod_init(struct sess *sp, struct vmod_priv *priv, const char *param)
conf->debug = atoi(p);
free(p);
}
-
- dir = findparam(param, "dir");
- if (!dir) {
- binlog_error("parameter \"dir\" not set");
- abort();
- }
+
if (stat(dir, &st)) {
if (errno == ENOENT)
binlog_error("logging directory does not exist");
@@ -194,8 +205,20 @@ vmod_init(struct sess *sp, struct vmod_priv *priv, const char *param)
dir, strerror(errno));
abort();
}
- conf->dir = dir;
+ conf->dir = strdup(dir);
+ AN(conf->dir);
+ conf->inst_head = packcomp(dataspec, &p);
+ if (*p) {
+ binlog_error("cannot compile data format near %s", p);
+ abort();
+ }
+ conf->recsize = packsize(conf->inst_head);
+ conf->env = packenv_create(conf->recsize);
+ conf->recsize += offsetof(struct binlog_record,data);
+ conf->dataspec = strdup(dataspec);
+ AN(conf->dataspec);
+
p = findparam(param, "pattern");
if (!p) {
p = strdup(BINLOG_PATTERN);
@@ -367,7 +390,6 @@ reset(struct binlog_config *conf)
conf->base = NULL;
conf->recbase = NULL;
conf->recnum = 0;
- conf->recidx = 0;
}
static int
@@ -379,11 +401,15 @@ setstoptime(struct binlog_config *conf)
conf->stoptime = ts - ts % conf->interval + conf->interval;
}
+#define binlog_recnum(conf) \
+ (((conf)->size - (conf)->base->hdrsize) / (conf)->base->recsize)
+
static int
newfile(struct sess *sp, struct binlog_config *conf)
{
int c;
void *base;
+ size_t n;
setstoptime(conf);
@@ -413,14 +439,18 @@ newfile(struct sess *sp, struct binlog_config *conf)
}
conf->base = base;
- memcpy(conf->base->hdr.magic, BINLOG_MAGIC_STR, BINLOG_MAGIC_LEN);
- conf->base->hdr.version = BINLOG_VERSION;
- conf->base->hdr.recsize = sizeof(struct binlog_record);
- conf->base->hdr.recnum = 0;
+ memcpy(conf->base->magic, BINLOG_MAGIC_STR, BINLOG_MAGIC_LEN);
+ conf->base->version = BINLOG_VERSION;
+ conf->base->recsize = conf->recsize;
+ conf->base->recnum = 0;
+ strcpy((char*)(conf->base + 1), conf->dataspec);
- conf->recbase = (struct binlog_record *) (conf->base + 1);
+ n = (sizeof(struct binlog_file_header) + strlen(conf->dataspec) +
+ conf->recsize - 1) / conf->recsize;
+ conf->base->hdrsize = n * conf->recsize;
+
+ conf->recbase = (char *) conf->base + conf->base->hdrsize;
conf->recnum = binlog_recnum(conf);
- conf->recidx = 0;
debug(conf,1,("created new log file %s",conf->fname));
return 0;
@@ -429,21 +459,23 @@ newfile(struct sess *sp, struct binlog_config *conf)
static void
closefile(struct sess *sp, struct binlog_config *conf)
{
+ size_t size;
+
if (conf->fd == -1)
return;
debug(conf,1,("closing log file %s",conf->fname));
+ size = binlog_size(conf->base);
munmap(conf->base, conf->size);
- if (ftruncate(conf->fd, binlog_size(conf)))
+ if (ftruncate(conf->fd, size))
binlog_error("error truncating \"%s/%s\": %s",
conf->dir, conf->fname, strerror(errno));
close(conf->fd);
free(conf->fname);
reset(conf);
}
-
void
-vmod_append(struct sess *sp, struct vmod_priv *priv, int nid, int aid)
+vmod_start(struct sess *sp, struct vmod_priv *priv)
{
struct binlog_config *conf = priv->priv;
time_t ts;
@@ -459,27 +491,84 @@ vmod_append(struct sess *sp, struct vmod_priv *priv, int nid, int aid)
newfile(sp, conf);
AZ(pthread_mutex_unlock(&conf->mutex));
}
+
+ packenv_init(conf->env);
+ conf->state = state_start;
+ conf->inst_cur = conf->inst_head;
+ conf->timestamp = ts;
+}
+
+void
+vmod_pack(struct sess *sp, struct vmod_priv *priv, const char *str)
+{
+ struct binlog_config *conf = priv->priv;
+ char *argv[2];
+
+ if (!conf)
+ return;
+
+ switch (conf->state) {
+ case state_start:
+ case state_pack:
+ break;
+ default:
+ binlog_error("pack called in wrong state (%d)", conf->state);
+ return;
+ }
+
+ if (!conf->inst_cur) {
+ binlog_error("format spec exhausted");
+ return;
+ }
+
+ argv[0] = (char*) str;
+ argv[1] = NULL;
+ conf->env->argv = argv;
+ conf->env->argc = 2;
+ conf->env->argi = 0;
+
+ conf->inst_cur = packinnext(conf->inst_cur, conf->env);
+
+ conf->state = state_pack;
+}
+
+void
+vmod_commit(struct sess *sp, struct vmod_priv *priv)
+{
+ struct binlog_config *conf = priv->priv;
+
+ if (!conf)
+ return;
if (conf->fd == -1)
return;
+ switch (conf->state) {
+ case state_start:
+ binlog_error("committing empty binlog record");
+ break;
+ case state_pack:
+ if (conf->inst_cur)
+ binlog_error("committing incomplete binlog record");
+ break;
+ default:
+ binlog_error("pack called in wrong state (%d)", conf->state);
+ return;
+ }
+
AZ(pthread_mutex_lock(&conf->mutex));
- if (conf->recidx == conf->recnum) {
+ if (conf->base->recnum == conf->recnum) {
binlog_error("overflow of %s/%s", conf->dir, conf->fname);
} else {
- struct binlog_record *p = conf->recbase + conf->recidx++;
- p->nid = nid;
- p->aid = aid;
- p->ts = ts;
- conf->base->hdr.recnum++;
+ struct binlog_record *p =
+ (struct binlog_record *)(conf->recbase +
+ conf->base->recnum *
+ conf->recsize);
+ p->ts = conf->timestamp;
+ memcpy(p->data, conf->env->buf_base, conf->env->buf_size);
+ conf->base->recnum++;
}
AZ(pthread_mutex_unlock(&conf->mutex));
-}
-
-void
-vmod_sappend(struct sess *sp, struct vmod_priv *priv, const char *nid,
- const char *aid)
-{
- vmod_append(sp, priv, nid ? atoi(nid): 0, aid ? atoi(aid) : 0);
+ conf->state = state_init;
}
void
@@ -492,7 +581,7 @@ vmod_sync(struct sess *sp, struct vmod_priv *priv)
AZ(pthread_mutex_lock(&conf->mutex));
if (conf->base)
- msync(conf->base, binlog_size(conf), 0);
+ msync(conf->base, binlog_size(conf->base), 0);
AZ(pthread_mutex_unlock(&conf->mutex));
}

Return to:

Send suggestions and report system problems to the System administrator.