chiark / gitweb /
disorder-rescan now obsoletes tracks that belong to no collection;
authorrjk@greenend.org.uk <>
Sun, 15 Jul 2007 16:43:59 +0000 (17:43 +0100)
committerrjk@greenend.org.uk <>
Sun, 15 Jul 2007 16:43:59 +0000 (17:43 +0100)
handy when you remove some collection.  The code should be relatively
robust against such tracks but they'll annoy the random track picker.

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
lib/trackname.h
server/rescan.c
server/trackdb-int.h
server/trackdb.c

index 93c7b3e7c86e8ec5848124821e047b130d95b0de..53824d73df8b593fd8275a2583ca64e32fe60d2d 100644 (file)
@@ -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) {
index b40c626ddfbca9837bc61a513643f08cb56d8de0..3d5ba65bac01b4a8e6f1fbed1439bb7cb788797f 100644 (file)
@@ -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@ */
 
index 6f024af5fbfb99fd7b5a6befd9088a6c6f405375..a2f26781386384568d730b3eef04738254dc546c 100644 (file)
@@ -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);
   }
index a4b278e23633bfe60d52908bfb450bada67dbb6f..81cd261332fb3365bb46466095d6d6a7ae45d573 100644 (file)
@@ -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) {
index 6f89f2a8ec2329041d62a187561c0c2dcfc21172..879adb1b1ae95837aa0ea99845c405bf416d82eb 100644 (file)
@@ -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;
   }