From d1694464b875e336ac335741596b15361929f630 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Sun, 15 Jul 2007 17:43:59 +0100 Subject: [PATCH] disorder-rescan now obsoletes tracks that belong to no collection; handy when you remove some collection. The code should be relatively robust against such tracks but they'll annoy the random track picker. Organization: Straylight/Edgeware From: rjk@greenend.org.uk <> trackdb_rescan() is thus modified to be able to return all tracks. find_track_collection() maps a track to its collection, or 0 if it doesn't have one. --- lib/trackname.c | 17 ++++++++++++----- lib/trackname.h | 3 +++ server/rescan.c | 39 ++++++++++++++++++++++++++++++++------- server/trackdb-int.h | 6 +++--- server/trackdb.c | 35 +++++++++++++++++++++++++---------- 5 files changed, 75 insertions(+), 25 deletions(-) diff --git a/lib/trackname.c b/lib/trackname.c index 93c7b3e..53824d7 100644 --- a/lib/trackname.c +++ b/lib/trackname.c @@ -33,7 +33,7 @@ #include "filepart.h" #include "words.h" -const char *find_track_root(const char *track) { +const struct collection *find_track_collection(const char *track) { int n; size_t l, tl = strlen(track); @@ -44,11 +44,18 @@ const char *find_track_root(const char *track) { && track[l] == '/') break; } - if(n >= config->collection.n) { - error(0, "found track in no collection '%s'", track); + if(n < config->collection.n) + return &config->collection.s[n]; + else return 0; - } - return config->collection.s[n].root; +} + +const char *find_track_root(const char *track) { + const struct collection *c = find_track_collection(track); + if(c) + return c->root; + error(0, "found track in no collection '%s'", track); + return 0; } const char *track_rootless(const char *track) { diff --git a/lib/trackname.h b/lib/trackname.h index b40c626..3d5ba65 100644 --- a/lib/trackname.h +++ b/lib/trackname.h @@ -21,6 +21,9 @@ #ifndef TRACKNAME_H #define TRACKNAME_H +const struct collection *find_track_collection(const char *track); +/* find the collection for @track@ */ + const char *find_track_root(const char *track); /* find the collection root for @track@ */ diff --git a/server/rescan.c b/server/rescan.c index 6f024af..a2f2678 100644 --- a/server/rescan.c +++ b/server/rescan.c @@ -48,6 +48,7 @@ #include "printf.h" #include "trackdb.h" #include "trackdb-int.h" +#include "trackname.h" static DB_TXN *global_tid; @@ -182,7 +183,7 @@ done: struct recheck_state { const struct collection *c; - long nobsolete, nlength; + long nobsolete, nnocollection, nlength; }; /* called for each non-alias track */ @@ -199,6 +200,15 @@ static int recheck_callback(const char *track, if(aborted()) return EINTR; D(("rechecking %s", track)); + /* if we're not checking a specific collection, find the right collection */ + if(!c) { + if(!(c = find_track_collection(track))) { + D(("obsoleting %s", track)); + if((err = trackdb_obsolete(track, tid))) return err; + ++cs->nnocollection; + return 0; + } + } /* see if the track has evaporated */ if(check(c->module, c->root, path) == 0) { D(("obsoleting %s", track)); @@ -225,13 +235,17 @@ static int recheck_callback(const char *track, static void recheck_collection(const struct collection *c) { struct recheck_state cs; - info("rechecking %s", c->root); + if(c) + info("rechecking %s", c->root); + else + info("rechecking all tracks"); for(;;) { checkabort(); global_tid = trackdb_begin_transaction(); memset(&cs, 0, sizeof cs); cs.c = c; - if(trackdb_scan(c->root, recheck_callback, &cs, global_tid)) goto fail; + if(trackdb_scan(c ? c->root : 0, recheck_callback, &cs, global_tid)) + goto fail; break; fail: /* Maybe we need to shut down */ @@ -242,12 +256,19 @@ static void recheck_collection(const struct collection *c) { /* Let anything else that is going on get out of the way. */ sleep(10); checkabort(); - info("resuming recheck of %s", c->root); + if(c) + info("resuming recheck of %s", c->root); + else + info("resuming global recheck"); } trackdb_commit_transaction(global_tid); global_tid = 0; - info("rechecked %s, %ld obsoleted, %ld lengths calculated", - c->root, cs.nobsolete, cs.nlength); + if(c) + info("rechecked %s, %ld obsoleted, %ld lengths calculated", + c->root, cs.nobsolete, cs.nlength); + else + info("rechecked all tracks, %ld no collection, %ld obsoleted, %ld lengths calculated", + cs.nnocollection, cs.nobsolete, cs.nlength); } /* rescan/recheck a collection by name */ @@ -313,12 +334,16 @@ int main(int argc, char **argv) { trackdb_init(0); trackdb_open(); if(optind == argc) { + /* Rescan all collections */ do_all(rescan_collection); - do_all(recheck_collection); + /* Check that every track still exists */ + recheck_collection(0); } else { + /* Rescan specified collections */ for(n = optind; n < argc; ++n) do_directory(argv[n], rescan_collection); + /* Check specified collections for tracks that have gone */ for(n = optind; n < argc; ++n) do_directory(argv[n], recheck_collection); } diff --git a/server/trackdb-int.h b/server/trackdb-int.h index a4b278e..81cd261 100644 --- a/server/trackdb-int.h +++ b/server/trackdb-int.h @@ -82,9 +82,9 @@ int trackdb_scan(const char *root, DB_TXN *tid), void *u, DB_TXN *tid); -/* Call CALLBACK for each non-alias track below ROOT. Return 0 or - * DB_LOCK_DEADLOCK. CALLBACK should return 0 on success or EINTR to cancel - * the scan. */ +/* Call CALLBACK for each non-alias track below ROOT (or all tracks if ROOT is + * 0). Return 0 or DB_LOCK_DEADLOCK. CALLBACK should return 0 on success or + * EINTR to cancel the scan. */ /* fill KEY in with S, returns KEY */ static inline DBT *make_key(DBT *key, const char *s) { diff --git a/server/trackdb.c b/server/trackdb.c index 6f89f2a..879adb1 100644 --- a/server/trackdb.c +++ b/server/trackdb.c @@ -1649,22 +1649,37 @@ int trackdb_scan(const char *root, DB_TXN *tid) { DBC *cursor; DBT k, d; - size_t root_len = strlen(root); - int err; + const size_t root_len = root ? strlen(root) : 0; + int err, cberr; struct kvp *data; + const char *track; cursor = trackdb_opencursor(trackdb_tracksdb, tid); - err = cursor->c_get(cursor, make_key(&k, root), prepare_data(&d), - DB_SET_RANGE); + if(root) + err = cursor->c_get(cursor, make_key(&k, root), prepare_data(&d), + DB_SET_RANGE); + else { + memset(&k, 0, sizeof k); + err = cursor->c_get(cursor, &k, prepare_data(&d), + DB_FIRST); + } while(!err) { - if(k.size > root_len - && !strncmp(k.data, root, root_len) - && ((char *)k.data)[root_len] == '/') { + if(!root + || (k.size > root_len + && !strncmp(k.data, root, root_len) + && ((char *)k.data)[root_len] == '/')) { data = kvp_urldecode(d.data, d.size); - if(kvp_get(data, "_path")) - if((err = callback(xstrndup(k.data, k.size), data, u, tid))) + if(kvp_get(data, "_path")) { + track = xstrndup(k.data, k.size); + /* Advance to the next track before the callback so that the callback + * may safely delete the track */ + err = cursor->c_get(cursor, &k, &d, DB_NEXT); + if((cberr = callback(track, data, u, tid))) { + err = cberr; break; - err = cursor->c_get(cursor, &k, &d, DB_NEXT); + } + } else + err = cursor->c_get(cursor, &k, &d, DB_NEXT); } else break; } -- [mdw]