aboutsummaryrefslogtreecommitdiff
path: root/src/binlog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/binlog.c')
-rw-r--r--src/binlog.c181
1 files changed, 164 insertions, 17 deletions
diff --git a/src/binlog.c b/src/binlog.c
index 765b945..e7ac7e5 100644
--- a/src/binlog.c
+++ b/src/binlog.c
@@ -37,7 +37,8 @@
# define O_SEARCH 0
#endif
-#define BLF_ROUNDTS 0x01
+#define BLF_ROUNDTS 0x01
+#define BLF_TRUNCATE 0x02
enum binlog_state {
state_init,
@@ -183,6 +184,29 @@ getinterval(char *p, char **endp)
}
}
+static struct indexdef {
+ char *name;
+ char *pat;
+} indextab[] = {
+ { "year", "%Y" },
+ { "0", "%Y" },
+ { "month", "%Y/%m" },
+ { "1", "%Y/%m" },
+ { "day", "%Y/%m/%d" },
+ { "2", "%Y/%m/%d" },
+ { NULL }
+};
+
+static char *
+getindexpat(const char *name)
+{
+ struct indexdef *p;
+ for (p = indextab; p->name; p++)
+ if (strcmp(p->name, name) == 0)
+ return p->pat;
+ return NULL;
+}
+
void
vmod_init(struct sess *sp, struct vmod_priv *priv,
const char *dir, const char *dataspec, const char *param)
@@ -191,7 +215,8 @@ vmod_init(struct sess *sp, struct vmod_priv *priv,
struct stat st;
char *p, *q;
unsigned long n;
-
+ int user_pattern = 0;
+
p = findparam(param, "debug");
if (p) {
conf->debug = atoi(p);
@@ -238,8 +263,32 @@ vmod_init(struct sess *sp, struct vmod_priv *priv,
if (!p) {
p = strdup(BINLOG_PATTERN);
AN(p);
- }
+ } else
+ user_pattern = 1;
conf->pattern = p;
+
+ p = findparam(param, "index");
+ if (p) {
+ q = getindexpat(p);
+ if (!q) {
+ binlog_error("invalid index type");
+ abort();
+ }
+ } else if (!user_pattern) {
+ q = getindexpat(BINLOG_INDEX);
+ AN(q);
+ } else
+ q = NULL;
+
+ if (q) {
+ p = malloc(strlen(q) + strlen(conf->pattern) + 2);
+ AN(p);
+ strcpy(p, q);
+ strcat(p, "/");
+ strcat(p, conf->pattern);
+ free(conf->pattern);
+ conf->pattern = p;
+ }
p = findparam(param, "size");
if (p) {
@@ -305,6 +354,15 @@ vmod_init(struct sess *sp, struct vmod_priv *priv,
conf->flags &= ~BLF_ROUNDTS;
free(p);
}
+
+ p = findparam(param, "reuselog");
+ if (p) {
+ if (atoi(p))
+ conf->flags &= ~BLF_TRUNCATE;
+ else
+ conf->flags |= BLF_TRUNCATE;
+ free(p);
+ }
conf->fd = -1;
conf->base = NULL;
@@ -384,7 +442,7 @@ createfile(struct sess *sp, struct binlog_config *conf)
return -1;
}
- fd = openat(conf->dd, fname, O_CREAT|O_RDWR|O_TRUNC,
+ fd = openat(conf->dd, fname, O_CREAT|O_RDWR,
0666 & ~conf->umask);
if (fd == -1) {
binlog_error("cannot create log file %s/%s: %s",
@@ -420,20 +478,104 @@ setstoptime(struct binlog_config *conf)
(((conf)->size - (conf)->base->hdrsize) / (conf)->base->recsize)
static int
+checkheader(struct binlog_config *conf, size_t hdrsize)
+{
+ struct binlog_file_header header;
+ int c;
+ ssize_t rc;
+ char *p;
+
+ rc = read(conf->fd, &header, sizeof(header));
+ if (rc == -1) {
+ binlog_error("error reading header of %s/%s: %s",
+ conf->dir, conf->fname, strerror(errno));
+ return -1;
+ } else if (rc != sizeof(header)) {
+ binlog_error("error reading header of %s/%s: %s",
+ conf->dir, conf->fname, "hit eof");
+ return -1;
+ }
+
+ if (memcmp(header.magic, BINLOG_MAGIC_STR, BINLOG_MAGIC_LEN)) {
+ binlog_error("%s/%s is not a binlog file",
+ conf->dir, conf->fname);
+ return -1;
+ }
+
+ if (header.version != BINLOG_VERSION) {
+ binlog_error("%s/%s: unknown version", conf->dir, conf->fname);
+ return -1;
+ }
+
+ if (header.hdrsize != hdrsize) {
+ debug(conf,1,("%s/%s: header size mismatch",
+ conf->dir, conf->fname));
+ return 1;
+ }
+ if (header.recsize != conf->recsize) {
+ debug(conf,1,("%s/%s: record size mismatch",
+ conf->dir, conf->fname));
+ return 1;
+ }
+
+ p = conf->dataspec;
+ while (*p) {
+ if (read(conf->fd, &c, 1) != 1 || c != *p) {
+ debug(conf,1,("%s/%s: dataspec mismatch near %s: %c",
+ conf->dir, conf->fname, p, c));
+ return 1;
+ }
+ ++p;
+ }
+ if (read(conf->fd, &c, 1) != 1 || c != 0) {
+ debug(conf,1,("%s/%s: dataspec mismatch at the end: %c",
+ conf->dir, conf->fname, c));
+ return 1;
+ }
+ return 0;
+}
+
+static int
newfile(struct sess *sp, struct binlog_config *conf)
{
int c;
void *base;
- size_t n;
+ size_t hdrsize;
+ struct stat st;
+ int reuse = 0;
setstoptime(conf);
if (createfile(sp, conf))
return -1;
+
+ hdrsize = ((sizeof(struct binlog_file_header) +
+ strlen(conf->dataspec) +
+ conf->recsize - 1) / conf->recsize) * conf->recsize;
+
+ if (fstat(conf->fd, &st) == 0) {
+ /* File already exists */
+ if (st.st_size > 0 &&
+ !(conf->flags & BLF_TRUNCATE) &&
+ checkheader(conf, hdrsize) == 0) {
+ reuse = 1;
+ } else {
+ binlog_error("truncating existing file %s/%s",
+ conf->dir, conf->fname);
+ ftruncate(conf->fd, 0);
+ }
+ } else {
+ binlog_error("can't stat %s/%s: %s",
+ conf->dir, conf->fname, strerror(errno));
+ /* try to continue anyway */
+ }
+ conf->flags |= BLF_TRUNCATE;
+
if (lseek(conf->fd, conf->size, SEEK_SET) == -1) {
binlog_error("seek in log file %s/%s failed: %s",
conf->dir, conf->fname, strerror(errno));
- unlinkat(conf->dd, conf->fname, 0);
+ if (!reuse)
+ unlinkat(conf->dd, conf->fname, 0);
close(conf->fd);
free(conf->fname);
reset(conf);
@@ -446,7 +588,8 @@ newfile(struct sess *sp, struct binlog_config *conf)
conf->fd, 0);
if (base == MAP_FAILED) {
binlog_error("mmap: %s", strerror(errno));
- unlinkat(conf->dd, conf->fname, 0);
+ if (!reuse)
+ unlinkat(conf->dd, conf->fname, 0);
close(conf->fd);
free(conf->fname);
reset(conf);
@@ -454,20 +597,24 @@ newfile(struct sess *sp, struct binlog_config *conf)
}
conf->base = base;
- 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);
-
- n = (sizeof(struct binlog_file_header) + strlen(conf->dataspec) +
- conf->recsize - 1) / conf->recsize;
- conf->base->hdrsize = n * conf->recsize;
+ if (reuse) {
+ debug(conf,1,("reusing log file %s, recnum=%lu",
+ conf->fname, (unsigned long)conf->base->recnum));
+ } else {
+ debug(conf,1,("created new log file %s",conf->fname));
+ 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->base->hdrsize = hdrsize;
+ }
+
conf->recbase = (char *) conf->base + conf->base->hdrsize;
conf->recnum = binlog_recnum(conf);
- debug(conf,1,("created new log file %s",conf->fname));
return 0;
}

Return to:

Send suggestions and report system problems to the System administrator.