From 0d0481713f2a145802f8afc86750b58f10174fd4 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Mon, 22 Nov 2010 14:30:12 +0100 Subject: [PATCH] database versioning --- etc/cnid_dbd/cmd_dbd.c | 2 +- etc/cnid_dbd/dbif.c | 105 +++++++++++++++++++++++++++++++++-- etc/cnid_dbd/dbif.h | 4 +- etc/cnid_dbd/main.c | 2 +- include/atalk/cnid_private.h | 31 +++++++++-- 5 files changed, 130 insertions(+), 14 deletions(-) diff --git a/etc/cnid_dbd/cmd_dbd.c b/etc/cnid_dbd/cmd_dbd.c index dc4c3923..a08b92c0 100644 --- a/etc/cnid_dbd/cmd_dbd.c +++ b/etc/cnid_dbd/cmd_dbd.c @@ -412,7 +412,7 @@ int main(int argc, char **argv) /* Prepare upgrade ? */ if (prep_upgrade) { - if (dbif_prep_upgrade(dbpath)) + if (dbif_env_remove(dbpath)) goto exit_failure; goto exit_success; } diff --git a/etc/cnid_dbd/dbif.c b/etc/cnid_dbd/dbif.c index a24f75f3..6a11d359 100644 --- a/etc/cnid_dbd/dbif.c +++ b/etc/cnid_dbd/dbif.c @@ -77,6 +77,33 @@ exit: return (ret < 0 ? ret : found); } +/*! + * Upgrade CNID database versions + * + * For now this does nothing, as upgrading from ver. 0 to 1 is done in dbif_open + */ +static int dbif_upgrade(DBD *dbd) +{ + int version; + + if ((version = dbif_getversion(dbd)) == -1) + return -1; + + /* + * Do upgrade stuff ... + */ + + /* Write current version to database */ + if (version != CNID_VERSION) { + if (dbif_setversion(dbd, CNID_VERSION) != 0) + return -1; + } + + LOG(log_debug, logtype_cnid, "Finished CNID database version upgrade check"); + + return 0; +} + /* --------------- */ static int dbif_openlog(DBD *dbd) { @@ -411,7 +438,7 @@ int dbif_open(DBD *dbd, struct db_param *dbp, int reindex) LOG(log_error, logtype_cnid, "error forcing checkpoint: %s", db_strerror(ret)); return -1; } - LOG(log_debug, logtype_cnid, "Finished CNID database upgrade check"); + LOG(log_debug, logtype_cnid, "Finished BerkeleyBD upgrade check"); } if ((fchdir(cwd)) != 0) { @@ -507,13 +534,20 @@ int dbif_open(DBD *dbd, struct db_param *dbp, int reindex) dbd->db_txn, dbd->db_table[DBIF_IDX_NAME].db, idxname, - DB_CREATE)) - != 0) { - LOG(log_error, logtype_cnid, "Failed to associate name index: %s",db_strerror(ret)); + (reindex + || + ((CNID_VERSION == CNID_VERSION_1) && (dbif_getversion(dbd) == CNID_VERSION_0))) + ? DB_CREATE : 0)) != 0) { + LOG(log_error, logtype_cnid, "Failed to associate name index: %s", db_strerror(ret)); return -1; } if (reindex) LOG(log_info, logtype_cnid, "... done."); + + if ((ret = dbif_upgrade(dbd)) != 0) { + LOG(log_error, logtype_cnid, "Error upgrading CNID database to version %d", CNID_VERSION); + return -1; + } return 0; } @@ -567,7 +601,7 @@ int dbif_close(DBD *dbd) In order to support silent database upgrades: destroy env at cnid_dbd shutdown. */ -int dbif_prep_upgrade(const char *path) +int dbif_env_remove(const char *path) { int ret; DBD *dbd; @@ -744,6 +778,67 @@ int dbif_del(DBD *dbd, const int dbi, DBT *key, u_int32_t flags) return 1; } +/*! + * Return CNID database version number + * @returns -1 on error, version number otherwise + */ +int dbif_getversion(DBD *dbd) +{ + DBT key, data; + uint32_t version; + int ret; + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = ROOTINFO_KEY; + key.size = ROOTINFO_KEYLEN; + + switch (dbif_get(dbd, DBIF_CNID, &key, &data, 0)) { + case 1: + memcpy(&version, (char *)data.data + CNID_DID_OFS, sizeof(version)); + version = ntohl(version); + LOG(log_debug, logtype_cnid, "CNID database version %u", version); + ret = version; + break; + default: + ret = -1; + break; + } + return ret; +} + +/*! + * Return CNID database version number + * @returns -1 on error, version number otherwise + */ +int dbif_setversion(DBD *dbd, int version) +{ + DBT key, data; + uint32_t v; + + v = version; + v = htonl(v); + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = ROOTINFO_KEY; + key.size = ROOTINFO_KEYLEN; + + switch (dbif_get(dbd, DBIF_CNID, &key, &data, 0)) { + case 1: + break; + default: + return -1; + } + + memcpy((char *)data.data + CNID_DID_OFS, &v, sizeof(v)); + data.size = ROOTINFO_DATALEN; + if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) < 0) + return -1; + + return 0; +} + /*! * Search the database by name * diff --git a/etc/cnid_dbd/dbif.h b/etc/cnid_dbd/dbif.h index 04eea3d9..033fc72e 100644 --- a/etc/cnid_dbd/dbif.h +++ b/etc/cnid_dbd/dbif.h @@ -89,7 +89,9 @@ extern DBD *dbif_init(const char *envhome, const char *dbname); extern int dbif_env_open(DBD *dbd, struct db_param *dbp, uint32_t dbenv_oflags); extern int dbif_open(DBD *dbd, struct db_param *dbp, int reindex); extern int dbif_close(DBD *dbd); -extern int dbif_prep_upgrade(const char *path); +extern int dbif_env_remove(const char *path); +extern int dbif_getversion(DBD *dbd); +extern int dbif_setversion(DBD *dbd, int); extern int dbif_get(DBD *, const int, DBT *, DBT *, u_int32_t); extern int dbif_pget(DBD *, const int, DBT *, DBT *, DBT *, u_int32_t); diff --git a/etc/cnid_dbd/main.c b/etc/cnid_dbd/main.c index 1b1b9887..91027157 100644 --- a/etc/cnid_dbd/main.c +++ b/etc/cnid_dbd/main.c @@ -385,7 +385,7 @@ int main(int argc, char *argv[]) if (dbif_close(dbd) < 0) err++; - if (dbif_prep_upgrade(dir) < 0) + if (dbif_env_remove(dir) < 0) err++; free_lock(lockfd); diff --git a/include/atalk/cnid_private.h b/include/atalk/cnid_private.h index 6525ce48..741077b1 100644 --- a/include/atalk/cnid_private.h +++ b/include/atalk/cnid_private.h @@ -38,13 +38,21 @@ #define ROOTINFO_KEYLEN 4 /* - Rootinfo data: - 4 unused bytes (cnid) - 8 bytes, in first 4 bytes db stamp: struct stat.st_ctime of database file (dev) - 8 unused bytes (inode) + Rootinfo data, fields as they are used by normal entries for CNIDs (for reference): + 4 bytes: CNID + 8 bytes: dev + 8 bytes: inode 4 bytes: is a file/directory (type) - 4 unused bytes (did) - 9 bytes name "RootInfo" + 4 bytes: DID + x bytes: name + + Contents in Rootinfo entry: + 4 bytes: 0 + 8 bytes: db stamp: struct stat.st_ctime of database file + 8 bytes: unused + 4 bytes: last used CNID + 4 bytes: version as htonl(uint32_t) + 9 bytes: name "RootInfo" */ #define ROOTINFO_DATA "\0\0\0\0" \ "\0\0\0\0\0\0\0\0" \ @@ -54,4 +62,15 @@ "RootInfo" #define ROOTINFO_DATALEN (3*4 + 2*8 + 9) +/* + * CNID version history: + * 0: up to Netatalk 2.1.x + * 1: starting with 2.2, additional name index, used in cnid_find + */ +#define CNID_VERSION_0 0 +#define CNID_VERSION_1 1 + +/* Current CNID version */ +#define CNID_VERSION CNID_VERSION_1 + #endif -- 2.39.2