X-Git-Url: https://git.distorted.org.uk/~mdw/disorder/blobdiff_plain/6c81eef9ce2587d03f6e180963adff14b96b0337..c0bcd1348031932ed3db2286b4cf5d555f393877:/server/trackdb.c diff --git a/server/trackdb.c b/server/trackdb.c index 2d369fe..432d212 100644 --- a/server/trackdb.c +++ b/server/trackdb.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "event.h" #include "mem.h" @@ -154,39 +155,36 @@ static int reap_db_deadlock(ev_source attribute((unused)) *ev, return 0; } -static pid_t subprogram(ev_source *ev, const char *prog) { +static pid_t subprogram(ev_source *ev, const char *prog, + int outputfd) { pid_t pid; - int lfd; /* If we're in the background then trap subprocess stdout/stderr */ - if(!isatty(2)) - lfd = logfd(ev, prog); - else - lfd = -1; if(!(pid = xfork())) { exitfn = _exit; - ev_signal_atfork(ev); + if(ev) + ev_signal_atfork(ev); signal(SIGPIPE, SIG_DFL); - if(lfd != -1) { - xdup2(lfd, 1); - xdup2(lfd, 2); + if(outputfd != -1) { + xdup2(outputfd, 1); + xclose(outputfd); } /* If we were negatively niced, undo it. We don't bother checking for * error, it's not that important. */ setpriority(PRIO_PROCESS, 0, 0); execlp(prog, prog, "--config", configfile, debugging ? "--debug" : "--no-debug", + log_default == &log_syslog ? "--syslog" : "--no-syslog", (char *)0); fatal(errno, "error invoking %s", prog); } - if(lfd != -1) xclose(lfd); return pid; } /* start deadlock manager */ void trackdb_master(ev_source *ev) { assert(db_deadlock_pid == -1); - db_deadlock_pid = subprogram(ev, DEADLOCK); + db_deadlock_pid = subprogram(ev, DEADLOCK, -1); ev_child(ev, db_deadlock_pid, 0, reap_db_deadlock, 0); D(("started deadlock manager")); } @@ -952,7 +950,6 @@ static int search_league(struct vector *v, int count, DB_TXN *tid) { char **trackdb_stats(int *nstatsp) { DB_TXN *tid; struct vector v; - char *s; vector_init(&v); for(;;) { @@ -968,12 +965,6 @@ char **trackdb_stats(int *nstatsp) { if(get_stats(&v, trackdb_prefsdb, SI(hash), tid)) goto fail; vector_append(&v, (char *)""); if(search_league(&v, 10, tid)) goto fail; - vector_append(&v, (char *)""); - vector_append(&v, (char *)"Server stats:"); - byte_xasprintf(&s, "track lookup cache hits: %lu", cache_files_hits); - vector_append(&v, (char *)s); - byte_xasprintf(&s, "track lookup cache misses: %lu", cache_files_misses); - vector_append(&v, (char *)s); vector_terminate(&v); break; fail: @@ -984,6 +975,89 @@ fail: return v.vec; } +struct stats_details { + void (*done)(char *data, void *u); + void *u; + int exited; /* subprocess exited */ + int closed; /* pipe close */ + int wstat; /* wait status from subprocess */ + struct dynstr data[1]; /* data read from pipe */ +}; + +static void stats_complete(struct stats_details *d) { + char *s; + + if(!(d->exited && d->closed)) + return; + byte_xasprintf(&s, "\n" + "Server stats:\n" + "track lookup cache hits: %lu\n" + "track lookup cache misses: %lu\n", + cache_files_hits, + cache_files_misses); + dynstr_append_string(d->data, s); + dynstr_terminate(d->data); + d->done(d->data->vec, d->u); +} + +static int stats_finished(ev_source attribute((unused)) *ev, + pid_t attribute((unused)) pid, + int status, + const struct rusage attribute((unused)) *rusage, + void *u) { + struct stats_details *const d = u; + + d->exited = 1; + if(status) + error(0, "disorder-stats %s", wstat(status)); + stats_complete(d); + return 0; +} + +static int stats_read(ev_source attribute((unused)) *ev, + ev_reader *reader, + void *ptr, + size_t bytes, + int eof, + void *u) { + struct stats_details *const d = u; + + dynstr_append_bytes(d->data, ptr, bytes); + ev_reader_consume(reader, bytes); + if(eof) + d->closed = 1; + stats_complete(d); + return 0; +} + +static int stats_error(ev_source attribute((unused)) *ev, + int errno_value, + void *u) { + struct stats_details *const d = u; + + error(errno_value, "error reading from pipe to disorder-stats"); + d->closed = 1; + stats_complete(d); + return 0; +} + +void trackdb_stats_subprocess(ev_source *ev, + void (*done)(char *data, void *u), + void *u) { + int p[2]; + pid_t pid; + struct stats_details *d = xmalloc(sizeof *d); + + dynstr_init(d->data); + d->done = done; + d->u = u; + xpipe(p); + pid = subprogram(ev, "disorder-stats", p[1]); + xclose(p[1]); + ev_child(ev, pid, 0, stats_finished, d); + ev_reader_new(ev, p[0], stats_read, stats_error, d, "disorder-stats reader"); +} + /* set a pref (remove if value=0) */ int trackdb_set(const char *track, const char *name, @@ -1744,9 +1818,9 @@ static int reap_rescan(ev_source attribute((unused)) *ev, void attribute((unused)) *u) { if(pid == rescan_pid) rescan_pid = -1; if(status) - error(0, "disorderd-rescan: %s", wstat(status)); + error(0, RESCAN": %s", wstat(status)); else - D(("disorderd-rescan terminate: %s", wstat(status))); + D((RESCAN" terminated: %s", wstat(status))); /* Our cache of file lookups is out of date now */ cache_clean(&cache_files_type); eventlog("rescanned", (char *)0); @@ -1754,14 +1828,22 @@ static int reap_rescan(ev_source attribute((unused)) *ev, } void trackdb_rescan(ev_source *ev) { + int w; + if(rescan_pid != -1) { error(0, "rescan already underway"); return; } - rescan_pid = subprogram(ev, RESCAN); - ev_child(ev, rescan_pid, 0, reap_rescan, 0); - D(("started rescanner")); - + rescan_pid = subprogram(ev, RESCAN, -1); + if(ev) { + ev_child(ev, rescan_pid, 0, reap_rescan, 0); + D(("started rescanner")); + } else { + /* This is the first rescan, we block until it is complete */ + while(waitpid(rescan_pid, &w, 0) < 0 && errno == EINTR) + ; + reap_rescan(0, rescan_pid, w, 0, 0); + } } int trackdb_rescan_cancel(void) {