aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2013-10-15 18:38:49 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2013-10-15 18:56:22 +0300
commitef3f928cc712f6774e19f8cb8f880cbeac15e8ff (patch)
tree88f59a4c8d1867bfadb924ee547b4b74a97c5ce0 /src
parentf035194d7d1b6cc0846ad7a5d86e0d6fa9463c67 (diff)
downloadvmod-binlog-ef3f928cc712f6774e19f8cb8f880cbeac15e8ff.tar.gz
vmod-binlog-ef3f928cc712f6774e19f8cb8f880cbeac15e8ff.tar.bz2
Change default log naming.
* configure.ac: Call AM_PROG_CC_C_O * src/binlog.c (BLF_TRUNCATE): New flag. (vmod_init): Change pattern initialization. New parameter "reuselog". (createfile): Remove O_TRUNC. (checkheader): New function. (newfile): Reuse existing file, if it is the first file to be opened after varnish startup and its header matches exactly our data. * src/binlogsel.c: Use indexed directory structure to speed up searches. * src/vmod-binlog.h (BINLOG_PATTERN): Change pattern. (BINLOG_GLOB_PATTERN,BINLOG_INDEX): New defines.
Diffstat (limited to 'src')
-rw-r--r--src/binlog.c181
-rw-r--r--src/binlogsel.c245
-rw-r--r--src/vmod-binlog.h18
3 files changed, 409 insertions, 35 deletions
diff --git a/src/binlog.c b/src/binlog.c
index 765b945..e7ac7e5 100644
--- a/src/binlog.c
+++ b/src/binlog.c
@@ -39,3 +39,4 @@
-#define BLF_ROUNDTS 0x01
+#define BLF_ROUNDTS 0x01
+#define BLF_TRUNCATE 0x02
@@ -185,2 +186,25 @@ 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
@@ -193,3 +217,4 @@ vmod_init(struct sess *sp, struct vmod_priv *priv,
unsigned long n;
-
+ int user_pattern = 0;
+
p = findparam(param, "debug");
@@ -240,4 +265,28 @@ vmod_init(struct sess *sp, struct vmod_priv *priv,
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;
+ }
@@ -307,2 +356,11 @@ vmod_init(struct sess *sp, struct vmod_priv *priv,
}
+
+ p = findparam(param, "reuselog");
+ if (p) {
+ if (atoi(p))
+ conf->flags &= ~BLF_TRUNCATE;
+ else
+ conf->flags |= BLF_TRUNCATE;
+ free(p);
+ }
@@ -386,3 +444,3 @@ createfile(struct sess *sp, struct binlog_config *conf)
- fd = openat(conf->dd, fname, O_CREAT|O_RDWR|O_TRUNC,
+ fd = openat(conf->dd, fname, O_CREAT|O_RDWR,
0666 & ~conf->umask);
@@ -422,2 +480,60 @@ setstoptime(struct binlog_config *conf)
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)
@@ -426,3 +542,5 @@ newfile(struct sess *sp, struct binlog_config *conf)
void *base;
- size_t n;
+ size_t hdrsize;
+ struct stat st;
+ int reuse = 0;
@@ -432,2 +550,25 @@ newfile(struct sess *sp, struct binlog_config *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) {
@@ -435,3 +576,4 @@ newfile(struct sess *sp, struct binlog_config *conf)
conf->dir, conf->fname, strerror(errno));
- unlinkat(conf->dd, conf->fname, 0);
+ if (!reuse)
+ unlinkat(conf->dd, conf->fname, 0);
close(conf->fd);
@@ -448,3 +590,4 @@ newfile(struct sess *sp, struct binlog_config *conf)
binlog_error("mmap: %s", strerror(errno));
- unlinkat(conf->dd, conf->fname, 0);
+ if (!reuse)
+ unlinkat(conf->dd, conf->fname, 0);
close(conf->fd);
@@ -456,12 +599,17 @@ 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;
@@ -469,3 +617,2 @@ newfile(struct sess *sp, struct binlog_config *conf)
- debug(conf,1,("created new log file %s",conf->fname));
return 0;
diff --git a/src/binlogsel.c b/src/binlogsel.c
index 62299e5..8f1cfce 100644
--- a/src/binlogsel.c
+++ b/src/binlogsel.c
@@ -40,3 +40,5 @@ int verbose_option;
int timediff_option;
+char *directory;
char *pattern;
+enum binlog_index_type index_type = index_year;
@@ -47,2 +49,5 @@ time_t from_time, to_time;
+static int matchnames(const char *dir, const char *pat, glob_t *gl);
+void selglob(const char *dir, const char *pattern);
+
void
@@ -52,5 +57,5 @@ help()
}
-
+
/* Convert strftime-like pattern into globbing pattern */
-void
+char *
convpattern(const char *dir)
@@ -75,3 +80,4 @@ convpattern(const char *dir)
if (*q == '%') {
- *p++ = '*';
+ if (p > newpat && p[-1] != '*')
+ *p++ = '*';
q += 2;
@@ -81,3 +87,3 @@ convpattern(const char *dir)
*p = 0;
- pattern = newpat;
+ return newpat;
}
@@ -334,3 +340,177 @@ selfilelist(char **argv)
}
+
+static char *
+mkfilename(const char *dir, const char *file)
+{
+ size_t dirlen, size;
+ char *ret;
+
+ dirlen = strlen(dir);
+ while (dirlen > 0 && dir[dirlen-1] == '/')
+ --dirlen;
+ size = dirlen + 1 + strlen(file) + 1;
+ ret = xmalloc(size);
+ memcpy(ret, dir, dirlen);
+ ret[dirlen++] = '/';
+ strcpy(ret + dirlen, file);
+ return ret;
+}
+
+int
+filename_to_int(char *name)
+{
+ char *p = strrchr(name, '/');
+ if (!p)
+ abort();
+ return atoi(p + 1);
+}
+
+void
+selidx_day(const char *dir)
+{
+ int from_day, to_day;
+ struct tm *tm;
+ glob_t gl;
+ int glinit = 0;
+ char *dirbuf;
+ size_t dirlen;
+
+ if (index_type == index_month) {
+ selglob(dir, BINLOG_GLOB_PATTERN);
+ return;
+ }
+
+ if (timemask & FROM_TIME)
+ from_day = gmtime(&from_time)->tm_mday;
+ else {
+ glinit = matchnames(dir, "[0-9][0-9]", &gl);
+ if (glinit)
+ from_day = filename_to_int(gl.gl_pathv[0]);
+ else {
+ error("no matching files");
+ exit(1);
+ }
+ }
+
+ if (timemask & TO_TIME)
+ to_day = gmtime(&to_time)->tm_mday;
+ else {
+ if (!glinit) {
+ glinit = matchnames(dir, "[0-9][0-9]", &gl);
+ if (!glinit) {
+ error("no matching files");
+ exit(1);
+ }
+ }
+ to_day = filename_to_int(gl.gl_pathv[gl.gl_pathc - 1]);
+ }
+
+ dirlen = strlen(dir) + 4;
+ dirbuf = xmalloc(dirlen);
+ for (;from_day <= to_day; from_day++) {
+ snprintf(dirbuf, dirlen, "%s/%02d", dir, from_day);
+ selglob(dirbuf, BINLOG_GLOB_PATTERN);
+ }
+ free(dirbuf);
+ if (glinit)
+ globfree(&gl);
+}
+
+void
+selidx_month(const char *dir)
+{
+ int from_month, to_month;
+ struct tm *tm;
+ glob_t gl;
+ int glinit = 0;
+ char *dirbuf;
+ size_t dirlen;
+
+ if (index_type == index_year) {
+ selglob(dir, BINLOG_GLOB_PATTERN);
+ return;
+ }
+
+ if (timemask & FROM_TIME)
+ from_month = 1 + gmtime(&from_time)->tm_mon;
+ else {
+ glinit = matchnames(dir, "[0-9][0-9]", &gl);
+ if (glinit)
+ from_month = filename_to_int(gl.gl_pathv[0]);
+ else {
+ error("no matching files");
+ exit(1);
+ }
+ }
+
+ if (timemask & TO_TIME)
+ to_month = 1 + gmtime(&to_time)->tm_mon;
+ else {
+ if (!glinit) {
+ glinit = matchnames(dir, "[0-9][0-9]", &gl);
+ if (!glinit) {
+ error("no matching files");
+ exit(1);
+ }
+ }
+ to_month = filename_to_int(gl.gl_pathv[gl.gl_pathc - 1]);
+ }
+
+ dirlen = strlen(dir) + 4;
+ dirbuf = xmalloc(dirlen);
+ for (;from_month <= to_month; from_month++) {
+ snprintf(dirbuf, dirlen, "%s/%02d", dir, from_month);
+ selidx_day(dirbuf);
+ }
+ free(dirbuf);
+ if (glinit)
+ globfree(&gl);
+}
+
+void
+selidx_year(const char *dir)
+{
+ int from_year, to_year;
+ struct tm *tm;
+ glob_t gl;
+ int glinit = 0;
+ char *dirbuf;
+ size_t dirlen;
+
+ if (timemask & FROM_TIME)
+ from_year = 1900 + gmtime(&from_time)->tm_year;
+ else {
+ glinit = matchnames(dir, "[0-9][0-9][0-9][0-9]", &gl);
+ if (glinit)
+ from_year = filename_to_int(gl.gl_pathv[0]);
+ else {
+ error("no matching files");
+ exit(1);
+ }
+ }
+ if (timemask & TO_TIME)
+ to_year = 1900 + gmtime(&to_time)->tm_year;
+ else {
+ if (!glinit) {
+ glinit = matchnames(dir, "[0-9][0-9][0-9][0-9]", &gl);
+ if (!glinit) {
+ error("no matching files");
+ exit(1);
+ }
+ }
+ to_year = filename_to_int(gl.gl_pathv[gl.gl_pathc - 1]);
+ }
+
+ dirlen = strlen(dir) + 6;
+ dirbuf = xmalloc(dirlen);
+ for (;from_year <= to_year; from_year++) {
+ snprintf(dirbuf, dirlen, "%s/%04d", dir, from_year);
+ selidx_month(dirbuf);
+ }
+ free(dirbuf);
+ if (glinit)
+ globfree(&gl);
+}
+
int
@@ -338,3 +518,3 @@ globerrfunc (const char *epath, int eerrno)
{
- error("%s: %s", strerror(eerrno));
+ error("%s: %s", epath, strerror(eerrno));
return 0;
@@ -342,2 +522,26 @@ globerrfunc (const char *epath, int eerrno)
+static int
+matchnames(const char *dir, const char *pat, glob_t *gl)
+{
+ char *p = mkfilename(dir, pat);
+ int rc = glob(p, GLOB_ERR, globerrfunc, gl);
+ free(p);
+ switch (rc) {
+ case 0:
+ break;
+ case GLOB_NOSPACE:
+ error("out of memory");
+ exit(1);
+
+ case GLOB_ABORTED:
+ error("read error");
+ exit(1);
+
+ case GLOB_NOMATCH:
+ return 0;
+ }
+ return 1;
+}
+
+
struct logfile {
@@ -360,3 +564,3 @@ tsort(const void *a, const void *b)
void
-selpattern(void)
+selglob(const char *dir, const char *pattern)
{
@@ -365,4 +569,5 @@ selpattern(void)
struct logfile *logfiles;
-
- switch (glob(pattern, GLOB_ERR|GLOB_NOSORT, globerrfunc, &gl)) {
+ char *p = mkfilename(dir, pattern);
+
+ switch (glob(p, GLOB_ERR|GLOB_NOSORT, globerrfunc, &gl)) {
case 0:
@@ -381,3 +586,4 @@ selpattern(void)
}
-
+ free(p);
+
logfiles = xcalloc(gl.gl_pathc, sizeof(*logfiles));
@@ -402,3 +608,3 @@ selpattern(void)
}
-
+
int
@@ -408,6 +614,5 @@ main(int argc, char **argv)
struct timespec ts;
- char *directory;
setprogname(argv[0]);
- while ((c = getopt(argc, argv, "D:dF:hp:T:t:nv")) != EOF)
+ while ((c = getopt(argc, argv, "D:dF:hi:p:T:t:nv")) != EOF)
switch (c) {
@@ -431,2 +636,9 @@ main(int argc, char **argv)
return 0;
+ case 'i':
+ index_type = atoi(optarg);
+ if (index_type < 0 || index_type > index_last) {
+ error("invalid index type: %s", optarg);
+ exit(1);
+ }
+ break;
case 'p':
@@ -459,3 +671,3 @@ main(int argc, char **argv)
if (argc) {
- if (pattern) {
+ if (pattern || directory) {
error("either files or pattern (-p) must be given, "
@@ -465,7 +677,6 @@ main(int argc, char **argv)
selfilelist(argv);
+ } else if (pattern) {
+ selglob(directory, convpattern(pattern));
} else {
- if (!pattern)
- pattern = BINLOG_PATTERN;
- convpattern(directory);
- selpattern();
+ selidx_year(directory);
}
diff --git a/src/vmod-binlog.h b/src/vmod-binlog.h
index 06d517d..e39ccea 100644
--- a/src/vmod-binlog.h
+++ b/src/vmod-binlog.h
@@ -26,3 +26,11 @@
#ifndef BINLOG_PATTERN
-# define BINLOG_PATTERN "%Y/%m/%d.log"
+# define BINLOG_PATTERN "%Y%m%dT%H%M%S.log"
+#endif
+
+#ifndef BINLOG_GLOB_PATTERN
+# define BINLOG_GLOB_PATTERN "[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9].log"
+#endif
+
+#ifndef BINLOG_INDEX
+# define BINLOG_INDEX "year"
#endif
@@ -37,2 +45,10 @@
+enum binlog_index_type {
+ index_year,
+ index_month,
+ index_day,
+
+};
+#define index_last index_day
+
struct binlog_record {

Return to:

Send suggestions and report system problems to the System administrator.