From 64db53a092874ff63ad1a0c9ad70e4bac71aab47 Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Tue, 12 Nov 2013 18:14:14 +1030 Subject: [PATCH] Add random UUID to Rhizome database --- rhizome.h | 3 +++ rhizome_database.c | 59 +++++++++++++++++++++++++++++++++++++++------- uuid.c | 17 +++++++------ uuid.h | 7 +++++- 4 files changed, 69 insertions(+), 17 deletions(-) diff --git a/rhizome.h b/rhizome.h index 8f5c2055..37c75059 100644 --- a/rhizome.h +++ b/rhizome.h @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include "sha2.h" +#include "uuid.h" #include "str.h" #include "strbuf.h" #include "http_server.h" @@ -405,6 +406,7 @@ int create_rhizome_datastore_dir(); #define FORM_RHIZOME_IMPORT_PATH(buf,fmt,...) (form_rhizome_import_path((buf), sizeof(buf), (fmt), ##__VA_ARGS__)) extern sqlite3 *rhizome_db; +uuid_t rhizome_db_uuid; int rhizome_opendb(); int rhizome_close_db(); @@ -517,6 +519,7 @@ enum sqlbind_type { TOHEX, // const unsigned char *binary, unsigned bytes TEXT_TOUPPER, // const char *text, TEXT_LEN_TOUPPER, // const char *text, unsigned bytes + UUID_T, // const uuid_t *uuidp NUL = 1 << 15, // NUL (no arg) ; NUL|INT, ... INDEX = 0xfade0000, // INDEX|INT, int index, ... NAMED = 0xdead0000 // NAMED|INT, const char *label, ... diff --git a/rhizome_database.c b/rhizome_database.c index bb2b6a0a..40865f77 100644 --- a/rhizome_database.c +++ b/rhizome_database.c @@ -75,7 +75,8 @@ int create_rhizome_datastore_dir() return emkdirs(rhizome_datastore_path(), 0700); } -sqlite3 *rhizome_db=NULL; +sqlite3 *rhizome_db = NULL; +uuid_t rhizome_db_uuid; /* XXX Requires a messy join that might be slow. */ int rhizome_manifest_priority(sqlite_retry_state *retry, const rhizome_bid_t *bidp) @@ -207,7 +208,10 @@ void verify_bundles(){ int rhizome_opendb() { - if (rhizome_db) return 0; + if (rhizome_db) { + assert(uuid_is_valid(&rhizome_db_uuid)); + return 0; + } IN(); @@ -257,11 +261,9 @@ int rhizome_opendb() ) { RETURN(WHY("Failed to create schema")); } - /* Create indexes if they don't already exist */ sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS bundlesizeindex ON manifests (filesize);", END); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS IDX_MANIFESTS_HASH ON MANIFESTS(filehash);", END); - sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=1;", END); } if (version<2){ @@ -273,26 +275,52 @@ int rhizome_opendb() verify_bundles(); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=2;", END); } - if (version<3){ sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS IDX_MANIFESTS_ID_VERSION ON MANIFESTS(id, version);", END); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=3;", END); } - if (version<4){ sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN tail integer;", END); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=4;", END); } - + if (version<5){ + sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE TABLE IF NOT EXISTS IDENTITY(uuid text not null); ", END); + sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=5;", END); + } + + char buf[UUID_STRLEN + 1]; + int r = sqlite_exec_strbuf_retry(&retry, strbuf_local(buf, sizeof buf), "SELECT uuid from IDENTITY LIMIT 1;", END); + if (r == -1) + RETURN(-1); + if (r) { + if (!str_to_uuid(buf, &rhizome_db_uuid, NULL)) { + WHYF("IDENTITY table contains malformed UUID %s -- overwriting", alloca_str_toprint(buf)); + if (uuid_generate_random(&rhizome_db_uuid) == -1) + RETURN(WHY("Cannot generate new UUID for Rhizome database")); + if (sqlite_exec_void_retry(&retry, "UPDATE IDENTITY SET uuid = ? LIMIT 1;", UUID_T, &rhizome_db_uuid, END) == -1) + RETURN(WHY("Failed to update new UUID in Rhizome database")); + if (config.debug.rhizome) + DEBUGF("Updated Rhizome database UUID to %s", alloca_uuid_str(rhizome_db_uuid)); + } + } else if (r == 0) { + if (uuid_generate_random(&rhizome_db_uuid) == -1) + RETURN(WHY("Cannot generate UUID for Rhizome database")); + if (sqlite_exec_void_retry(&retry, "INSERT INTO IDENTITY (uuid) VALUES (?);", UUID_T, &rhizome_db_uuid, END) == -1) + RETURN(WHY("Failed to insert UUID into Rhizome database")); + if (config.debug.rhizome) + DEBUGF("Set Rhizome database UUID to %s", alloca_uuid_str(rhizome_db_uuid)); + } + // TODO recreate tables with collate nocase on hex columns - + /* Future schema updates should be performed here. The above schema can be assumed to exist. All changes should attempt to preserve any existing data */ - + // We can't delete a file that is being transferred in another process at this very moment... if (config.rhizome.clean_on_open) rhizome_cleanup(NULL); + INFOF("Opened Rhizome database %s, UUID=%s", dbpath, alloca_uuid_str(rhizome_db_uuid)); RETURN(0); OUT(); } @@ -740,6 +768,19 @@ int _sqlite_vbind(struct __sourceloc __whence, int log_level, sqlite_retry_state } } break; + case UUID_T: { + const uuid_t *uuidp = va_arg(ap, const uuid_t *); + ++argnum; + if (uuidp == NULL) { + BIND_NULL(UUID_T); + } else { + char uuid_str[UUID_STRLEN + 1]; + uuid_to_str(uuidp, uuid_str); + BIND_DEBUG(UUID_T, sqlite3_bind_text, "%s,%u,SQLITE_TRANSIENT", uuid_str, UUID_STRLEN); + BIND_RETRY(sqlite3_bind_text, uuid_str, UUID_STRLEN, SQLITE_TRANSIENT); + } + } + break; #undef BIND_RETRY default: FATALF("at bind arg %u, unsupported bind code typ=0x%08x: %s", argnum, typ, sqlite3_sql(statement)); diff --git a/uuid.c b/uuid.c index 3cf4cf3d..8666fbbe 100644 --- a/uuid.c +++ b/uuid.c @@ -66,23 +66,26 @@ int uuid_generate_random(uuid_t *uuid) return 0; } -void uuid_to_str(const uuid_t *uuid, char *dst) +char *uuid_to_str(const uuid_t *uuid, char *const dst) { + char *p = dst; assert(uuid_is_valid(uuid)); unsigned i; for (i = 0; i != sizeof uuid->u.binary; ++i) { switch (i) { case 4: case 6: case 8: case 10: - *dst++ = '-'; + *p++ = '-'; default: - *dst++ = hexdigit[uuid->u.binary[i] >> 4]; - *dst++ = hexdigit[uuid->u.binary[i] & 0xf]; + *p++ = hexdigit[uuid->u.binary[i] >> 4]; + *p++ = hexdigit[uuid->u.binary[i] & 0xf]; } } - *dst = '\0'; + *p = '\0'; + assert(p == dst + UUID_STRLEN); + return dst; } -int str_to_uuid(const char *str, uuid_t *uuid, const char **afterp) +int str_to_uuid(const char *const str, uuid_t *uuid, const char **afterp) { const char *end = str; int ret = 0; @@ -96,7 +99,7 @@ int str_to_uuid(const char *str, uuid_t *uuid, const char **afterp) && *end == '-' && strn_fromhex(uuid->u.binary + 10, 6, end + 1, &end) == 6 ) { - assert(end == str + 36); + assert(end == str + UUID_STRLEN); ret = uuid_is_valid(uuid); } if (afterp) diff --git a/uuid.h b/uuid.h index daa77d38..7a55bfc2 100644 --- a/uuid.h +++ b/uuid.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define __SERVALDNA_UUID_H #include +#include #ifndef __SERVALDNA_UUID_H_INLINE # if __GNUC__ && !__GNUC_STDC_INLINE__ @@ -93,9 +94,13 @@ int uuid_generate_random(uuid_t *dest_uuid); * are filled with the representation shown above, and the 37th byte dst[36] is * set to NUL '\0'. * + * Returns the 'dst' argument. + * * @author Andrew Bettison */ -void uuid_to_str(const uuid_t *valid_uuid, char *dst); +char *uuid_to_str(const uuid_t *valid_uuid, char *dst); +#define UUID_STRLEN 36 +#define alloca_uuid_str(uuid) uuid_to_str(&(uuid), alloca(UUID_STRLEN + 1)) /* Parse a canonical UUID string (as generated by uuid_to_str()) into a valid * UUID, which may or not be supported.