aboutsummaryrefslogtreecommitdiff
path: root/src/binlogsel.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2014-05-30 16:45:49 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2014-05-30 16:45:49 +0300
commitb425cc797090c46c3c9ab7b3052d322c4224bd76 (patch)
tree4a613bd71502b12851ddfb69fc1d442a09c3ecf5 /src/binlogsel.c
parent2035536f831b0ce54c28c2a0b405febb113e0fab (diff)
downloadvmod-binlog-b425cc797090c46c3c9ab7b3052d322c4224bd76.tar.gz
vmod-binlog-b425cc797090c46c3c9ab7b3052d322c4224bd76.tar.bz2
binlogsel: dry-run and incremental mode.
* src/binlogsel.c (last_ts): New variable. (module_init): Change signature (incompatible change!) (interval) <descr>: New member. (interval_count): New variable. (interval_add): Take descr as argument. Fill in interval->descr. (interval_add): Increment interval_count. (interval_add_str): Construct descr. (selmem): Update last_ts (selidx_day,selidx_month,selidx_year): Silently ignore non-existing directories. Don't bail out if no matching file was found. (selidx_year): Clear the START_TIME flag after the first iteration. (read_status_fp,read_status_file) (write_status_file): New functions. (main): New option -n. Use interval_add_str to parse intervals. Pass flags to module_init. Process status file, if requested.
Diffstat (limited to 'src/binlogsel.c')
-rw-r--r--src/binlogsel.c216
1 files changed, 182 insertions, 34 deletions
diff --git a/src/binlogsel.c b/src/binlogsel.c
index da04636..c448bd5 100644
--- a/src/binlogsel.c
+++ b/src/binlogsel.c
@@ -43,9 +43,11 @@ char *directory;
char *pattern;
enum binlog_index_type index_type = index_year;
+time_t last_ts;
+
char *module_name;
char *module_args;
-void (*module_init)(char *, void (*)(const char *, const char *, const char *));
+void (*module_init)(int, char *, void (*)(const char *, const char *, const char *));
int (*module_open)(const char *, size_t, const char *);
void (*module_close)(void);
void (*module_done)(void);
@@ -69,19 +71,23 @@ void selglob(const char *dir, const char *pattern);
struct interval {
struct interval *next;
char *name;
+ char *descr;
int timemask;
time_t start;
time_t end;
};
static struct interval *interval_head, *interval_tail;
+size_t interval_count;
void
-interval_add(const char *name, int tmask, time_t start, time_t end)
+interval_add(const char *name, const char *descr,
+ int tmask, time_t start, time_t end)
{
struct interval *p = xmalloc(sizeof(*p));
p->next = NULL;
p->name = xstrdup(name);
+ p->descr = xstrdup(descr);
p->timemask = tmask;
p->start = start;
p->end = end;
@@ -90,7 +96,8 @@ interval_add(const char *name, int tmask, time_t start, time_t end)
else
interval_head = p;
interval_tail = p;
-
+ ++interval_count;
+
if (tmask & START_TIME) {
if (!(timemask & START_TIME) || start_time > start) {
start_time = start;
@@ -133,8 +140,20 @@ interval_add_str(const char *id, const char *from, const char *to)
tmask |= STOP_TIME;
}
- if (tmask)
- interval_add(id, tmask, start, end);
+ if (tmask) {
+ char *descr = xmalloc((from ? strlen(from) : 0)
+ + (from ? strlen(from) : 0) + 1);
+ descr[0] = 0;
+ if (from)
+ strcat(descr, from);
+ strcat(descr, ":");
+ if (to)
+ strcat(descr, to);
+
+ interval_add(id, descr, tmask, start, end);
+
+ free(descr);
+ }
}
@@ -349,6 +368,9 @@ selmem(const char *name, void *base)
continue;
if ((ip->timemask & STOP_TIME) && ip->end < rec->ts)
continue;
+
+ last_ts = rec->ts;
+
if (module_record)
module_record(ip->name, rec->ts, env->buf_base);
else {
@@ -519,6 +541,13 @@ selidx_day(const char *dir)
char *dirbuf;
size_t dirlen;
+ if (access(dir, F_OK)) {
+ if (errno == ENOENT)
+ return;
+ else
+ error("can't access %s: %s", dir, strerror(errno));
+ }
+
if (index_type == index_month) {
selglob(dir, BINLOG_GLOB_PATTERN);
return;
@@ -532,7 +561,7 @@ selidx_day(const char *dir)
from_day = filename_to_int(gl.gl_pathv[0]);
else {
error("no matching files");
- exit(1);
+ return;
}
}
@@ -543,7 +572,7 @@ selidx_day(const char *dir)
glinit = matchnames(dir, "[0-9][0-9]", &gl);
if (!glinit) {
error("no matching files");
- exit(1);
+ return;
}
}
to_day = filename_to_int(gl.gl_pathv[gl.gl_pathc - 1]);
@@ -569,6 +598,13 @@ selidx_month(const char *dir)
char *dirbuf;
size_t dirlen;
+ if (access(dir, F_OK)) {
+ if (errno == ENOENT)
+ return;
+ else
+ error("can't access %s: %s", dir, strerror(errno));
+ }
+
if (index_type == index_year) {
selglob(dir, BINLOG_GLOB_PATTERN);
return;
@@ -582,7 +618,7 @@ selidx_month(const char *dir)
from_month = filename_to_int(gl.gl_pathv[0]);
else {
error("no matching files");
- exit(1);
+ return;
}
}
@@ -593,7 +629,7 @@ selidx_month(const char *dir)
glinit = matchnames(dir, "[0-9][0-9]", &gl);
if (!glinit) {
error("no matching files");
- exit(1);
+ return;
}
}
to_month = filename_to_int(gl.gl_pathv[gl.gl_pathc - 1]);
@@ -619,6 +655,13 @@ selidx_year(const char *dir)
char *dirbuf;
size_t dirlen;
+ if (access(dir, F_OK)) {
+ if (errno == ENOENT)
+ return;
+ else
+ error("can't access %s: %s", dir, strerror(errno));
+ }
+
if (timemask & START_TIME)
from_year = 1900 + gmtime(&start_time)->tm_year;
else {
@@ -627,7 +670,7 @@ selidx_year(const char *dir)
from_year = filename_to_int(gl.gl_pathv[0]);
else {
error("no matching files");
- exit(1);
+ return;
}
}
@@ -638,7 +681,7 @@ selidx_year(const char *dir)
glinit = matchnames(dir, "[0-9][0-9][0-9][0-9]", &gl);
if (!glinit) {
error("no matching files");
- exit(1);
+ return;
}
}
to_year = filename_to_int(gl.gl_pathv[gl.gl_pathc - 1]);
@@ -649,6 +692,7 @@ selidx_year(const char *dir)
for (; from_year <= to_year; from_year++) {
snprintf(dirbuf, dirlen, "%s/%04d", dir, from_year);
selidx_month(dirbuf);
+ timemask &= ~START_TIME;
}
free(dirbuf);
if (glinit)
@@ -666,7 +710,7 @@ 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);
+ int rc = glob(p, GLOB_ERR|GLOB_ONLYDIR, globerrfunc, gl);
free(p);
switch (rc) {
case 0:
@@ -821,19 +865,121 @@ loader_init(void)
module_done = lt_dlsym(handle, "done");
}
+/* Status file format:
+ timestamp LF
+ N LF
+ INT-1-DESCR LF
+ ...
+ INT-N-DESCR LF
+*/
+
+int
+read_status_fp(FILE *fp)
+{
+ struct interval *ip;
+ unsigned long i;
+ char buf[256];
+ unsigned long n;
+ time_t ts;
+
+ if (fscanf(fp, "%lu\n", &n) != 1)
+ return 1;
+ ts = (time_t) n;
+
+ if (fscanf(fp, "%lu\n", &n) != 1)
+ return 1;
+ if (n != interval_count)
+ return 1;
+
+ for (ip = interval_head; ip; ip = ip->next) {
+ char c;
+ char *p = ip->descr;
+
+ do {
+ if ((c = fgetc(fp)) == EOF)
+ return 1;
+ if (c == '\n')
+ c = 0;
+ if (c != *p++)
+ return 1;
+ } while (c);
+ }
+ if (ferror(fp))
+ return 1;
+ if (fgetc(fp) != EOF)
+ return 1;
+
+ timemask |= START_TIME;
+ start_time = ts;
+
+ return 0;
+}
+
+int
+read_status_file(char const *name)
+{
+ FILE *fp;
+ int rc;
+
+ fp = fopen(name, "r");
+ if (!fp) {
+ if (errno == ENOENT)
+ return 0;
+ error("cannot open '%s' for reading: %s",
+ name, strerror(errno));
+ return 1;
+ }
+
+ rc = read_status_fp(fp);
+
+ fclose(fp);
+
+ return rc;
+}
+
+int
+write_status_file(char const *name)
+{
+ FILE *fp;
+ struct interval *ip;
+ unsigned long i;
+
+ fp = fopen(name, "w");
+ if (!fp) {
+ error("cannot open '%s' for writing: %s",
+ name, strerror(errno));
+ return 1;
+ }
+
+ fprintf(fp, "%lu\n", (unsigned long) last_ts);
+ fprintf(fp, "%lu\n", (unsigned long) interval_count);
+
+ /* Save intervals */
+ for (ip = interval_head; ip; ip = ip->next) {
+ fprintf(fp, "%s\n", ip->descr);
+ }
+
+ fclose(fp);
+}
+
+
+#define F_DRY_RUN 0x01
+#define F_INCREMENTAL 0x02
+
int
main(int argc, char **argv)
{
int c;
struct timespec ts;
const char *id;
- int tmask = 0;
- time_t start, stop;
+ char *start = NULL, *stop = NULL;
char *p;
+ char *status_file_name = NULL;
+ int flags = 0;
setprogname(argv[0]);
add_load_path(BINLOGSEL_MODDIR, LP_APPEND);
- while ((c = getopt(argc, argv, "D:dF:hi:I:L:m:p:P:T:t:nVv")) != EOF)
+ while ((c = getopt(argc, argv, "D:dF:hi:I:L:m:Nns:p:P:T:t:Vv")) != EOF)
switch (c) {
case 'D':
directory = optarg;
@@ -843,20 +989,15 @@ main(int argc, char **argv)
timefmt = "%s";
break;
case 'F':
- if (!parse_datetime(&ts, optarg, NULL)) {
- error("invalid timespec: %s", optarg);
- exit(1);
- }
- start = ts.tv_sec;
- tmask |= START_TIME;
+ start = optarg;
break;
case 'h':
help();
return 0;
case 'I':
- if (tmask)
- interval_add(id, tmask, start, stop);
- tmask = 0;
+ if (start || stop)
+ interval_add_str(id, start, stop);
+ start = stop = NULL;
id = optarg;
break;
case 'i':
@@ -880,24 +1021,26 @@ main(int argc, char **argv)
}
module_name = optarg;
break;
+ case 'n':
+ flags |= F_DRY_RUN;
+ break;
case 'P':
add_load_path(optarg, LP_PREPEND);
break;
case 'p':
pattern = optarg;
break;
+ case 's':
+ flags |= F_INCREMENTAL;
+ status_file_name = optarg;
+ break;
case 'T':
- if (!parse_datetime(&ts, optarg, NULL)) {
- error("invalid timespec: %s", optarg);
- exit(1);
- }
- stop = ts.tv_sec;
- tmask |= STOP_TIME;
+ stop = optarg;
break;
case 't':
timefmt = optarg;
break;
- case 'n':
+ case 'N':
number_option = 1;
break;
case 'V':
@@ -910,8 +1053,8 @@ main(int argc, char **argv)
exit(1);
}
- if (tmask)
- interval_add(id, tmask, start, stop);
+ if (start || stop)
+ interval_add_str(id, start, stop);
argc -= optind;
argv += optind;
@@ -919,13 +1062,16 @@ main(int argc, char **argv)
loader_init();
if (module_init)
- module_init(module_args, interval_add_str);
+ module_init(flags, module_args, interval_add_str);
if (timemask & CLEAR_START_TIME)
timemask &= ~START_TIME;
if (timemask & CLEAR_STOP_TIME)
timemask &= ~STOP_TIME;
+ if (status_file_name)
+ read_status_file(status_file_name);
+
if (argc) {
if (pattern) {
error("either files or pattern (-p) must be given, "
@@ -940,6 +1086,8 @@ main(int argc, char **argv)
}
if (module_done)
module_done();
+ if (status_file_name && !(flags & F_DRY_RUN))
+ write_status_file(status_file_name);
exit(0);
}

Return to:

Send suggestions and report system problems to the System administrator.