X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/d25c461540eadff2230653059ea2f692ee8dfc63..ad9bae0b85165ad96e35c202c96e4adb67786a90:/server/dbupgrade.c diff --git a/server/dbupgrade.c b/server/dbupgrade.c index 93c99ea..0d8600d 100644 --- a/server/dbupgrade.c +++ b/server/dbupgrade.c @@ -28,11 +28,13 @@ #include #include #include +#include #include "syscalls.h" #include "log.h" #include "defs.h" #include "kvp.h" +#include "rights.h" #include "trackdb.h" #include "trackdb-int.h" #include "mem.h" @@ -41,12 +43,24 @@ static DB_TXN *global_tid; +#define BADKEY_WARN 0 +#define BADKEY_FAIL 1 +#define BADKEY_DELETE 2 + +/** @brief Bad key behavior */ +static int badkey = BADKEY_WARN; + +static long aliases_removed, keys_normalized, values_normalized, renoticed; +static long keys_already_ok, values_already_ok; + static const struct option options[] = { { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, { "config", required_argument, 0, 'c' }, { "debug", no_argument, 0, 'd' }, { "no-debug", no_argument, 0, 'D' }, + { "delete-bad-keys", no_argument, 0, 'x' }, + { "fail-bad-keys", no_argument, 0, 'X' }, { "syslog", no_argument, 0, 's' }, { "no-syslog", no_argument, 0, 'S' }, { 0, 0, 0, 0 } @@ -62,6 +76,8 @@ static void help(void) { " --config PATH, -c PATH Set configuration file\n" " --debug, -d Turn on debugging\n" " --[no-]syslog Force logging\n" + " --delete-bad-keys, -x Delete unconvertible keys\n" + " --fail-bad-keys, -X Fail if bad keys are found\n" "\n" "Database upgrader for DisOrder. Not intended to be run\n" "directly.\n"); @@ -71,7 +87,7 @@ static void help(void) { /* display version number and terminate */ static void version(void) { - xprintf("disorder-dbupgrade version %s\n", disorder_version_string); + xprintf("%s", disorder_version_string); xfclose(stdout); exit(0); } @@ -89,6 +105,12 @@ static int scan_core(const char *name, DB *db, int err, r = 0; DBT k[1], d[1]; + values_normalized = 0; + keys_normalized = 0; + aliases_removed = 0; + renoticed = 0; + keys_already_ok = 0; + values_already_ok = 0; memset(k, 0, sizeof k); memset(d, 0, sizeof d); while((err = c->c_get(c, k, d, DB_NEXT)) == 0) { @@ -103,6 +125,17 @@ static int scan_core(const char *name, DB *db, r = (err == DB_LOCK_DEADLOCK ? err : 0); if((err = c->c_close(c))) fatal(0, "%s: error closing cursor: %s", name, db_strerror(err)); + info("%s: %ld entries scanned", name, count); + if(values_normalized || values_already_ok) + info("%s: %ld values converted, %ld already ok", name, + values_normalized, values_already_ok); + if(keys_normalized || keys_already_ok) + info("%s: %ld keys converted, %ld already OK", name, + keys_normalized, keys_already_ok); + if(aliases_removed) + info("%s: %ld aliases removed", name, aliases_removed); + if(renoticed) + info("%s: %ld tracks re-noticed", name, renoticed); return r; } @@ -152,12 +185,33 @@ static int normalize_keys(const char *name, DB *db, DBC *c, /* Find the normalized form of the key */ knfc = utf8_compose_canon(k->data, k->size, &nknfc); - if(!knfc) - fatal(0, "%s: cannot convert key to NFC: %.*s", name, - (int)k->size, (const char *)k->data); + if(!knfc) { + switch(badkey) { + case BADKEY_WARN: + error(0, "%s: invalid key: %.*s", name, + (int)k->size, (const char *)k->data); + break; + case BADKEY_DELETE: + error(0, "%s: deleting invalid key: %.*s", name, + (int)k->size, (const char *)k->data); + if((err = c->c_del(c, 0))) { + if(err != DB_LOCK_DEADLOCK) + fatal(0, "%s: error removing denormalized key: %s", + name, db_strerror(err)); + return err; + } + break; + case BADKEY_FAIL: + fatal(0, "%s: invalid key: %.*s", name, + (int)k->size, (const char *)k->data); + } + return 0; + } /* If the key is already in NFC then do nothing */ - if(nknfc == k->size && !memcmp(k->data, knfc, nknfc)) + if(nknfc == k->size && !memcmp(k->data, knfc, nknfc)) { + ++keys_already_ok; return 0; + } /* To rename the key we must delete the old one and insert a new one */ if((err = c->c_del(c, 0))) { if(err != DB_LOCK_DEADLOCK) @@ -172,6 +226,7 @@ static int normalize_keys(const char *name, DB *db, DBC *c, fatal(0, "%s: error storing normalized key: %s", name, db_strerror(err)); return err; } + ++keys_normalized; return 0; } @@ -188,8 +243,10 @@ static int normalize_values(const char *name, DB *db, fatal(0, "%s: cannot convert data to NFC: %.*s", name, (int)d->size, (const char *)d->data); /* If the key is already in NFC then do nothing */ - if(ndnfc == d->size && !memcmp(d->data, dnfc, ndnfc)) + if(ndnfc == d->size && !memcmp(d->data, dnfc, ndnfc)) { + ++values_already_ok; return 0; + } d->size = ndnfc; d->data = dnfc; if((err = db->put(db, global_tid, k, d, 0))) { @@ -197,6 +254,7 @@ static int normalize_values(const char *name, DB *db, fatal(0, "%s: error storing normalized data: %s", name, db_strerror(err)); return err; } + ++values_normalized; return 0; } @@ -208,11 +266,17 @@ static int renotice(const char *name, DB attribute((unused)) *db, const char *const path = kvp_get(t, "_path"); int err; - if(!path) + if(!path) { + /* If an alias sorts later than the actual filename then it'll appear + * in the scan. */ + if(kvp_get(t, "_alias_for")) + return 0; fatal(0, "%s: no '_path' for %.*s", name, (int)k->size, (const char *)k->data); + } switch(err = trackdb_notice_tid(track, path, global_tid)) { case 0: + ++renoticed; return 0; case DB_LOCK_DEADLOCK: return err; @@ -234,8 +298,11 @@ static int remove_aliases_normalize_keys(const char *name, DB *db, DBC *c, fatal(0, "%s: error removing alias: %s", name, db_strerror(err)); return err; } + ++aliases_removed; return 0; - } + } else if(!kvp_get(t, "_path")) + error(0, "%s: %.*s has neither _alias_for nor _path", name, + (int)k->size, (const char *)k->data); return normalize_keys(name, db, c, k, d); } @@ -273,7 +340,7 @@ int main(int argc, char **argv) { set_progname(argv); mem_init(); if(!setlocale(LC_CTYPE, "")) fatal(errno, "error calling setlocale"); - while((n = getopt_long(argc, argv, "hVc:dDSs", options, 0)) >= 0) { + while((n = getopt_long(argc, argv, "hVc:dDSsxX", options, 0)) >= 0) { switch(n) { case 'h': help(); case 'V': version(); @@ -282,6 +349,8 @@ int main(int argc, char **argv) { case 'D': debugging = 0; break; case 'S': logsyslog = 0; break; case 's': logsyslog = 1; break; + case 'x': badkey = BADKEY_DELETE; break; + case 'X': badkey = BADKEY_FAIL; break; default: fatal(0, "invalid option"); } }