| diff -up nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c.orig nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c |
| --- nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c.orig 2016-02-10 10:46:23.100398000 -0500 |
| +++ nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c 2016-02-10 10:46:59.540317000 -0500 |
| @@ -29,7 +29,9 @@ |
| * |
| * clients: an "id" column containing a BLOB with the long-form clientid as |
| * sent by the client, a "time" column containing a timestamp (in |
| - * epoch seconds) of when the record was last updated. |
| + * epoch seconds) of when the record was last updated, and a |
| + * "has_session" column containing a boolean value indicating |
| + * whether the client has sessions (v4.1+) or not (v4.0). |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| @@ -50,7 +52,7 @@ |
| |
| #include "xlog.h" |
| |
| -#define CLTRACK_SQLITE_LATEST_SCHEMA_VERSION 1 |
| +#define CLTRACK_SQLITE_LATEST_SCHEMA_VERSION 2 |
| |
| /* in milliseconds */ |
| #define CLTRACK_SQLITE_BUSY_TIMEOUT 10000 |
| @@ -120,6 +122,81 @@ out: |
| return ret; |
| } |
| |
| +static int |
| +sqlite_maindb_update_v1_to_v2(void) |
| +{ |
| + int ret, ret2; |
| + char *err; |
| + |
| + /* begin transaction */ |
| + ret = sqlite3_exec(dbh, "BEGIN EXCLUSIVE TRANSACTION;", NULL, NULL, |
| + &err); |
| + if (ret != SQLITE_OK) { |
| + xlog(L_ERROR, "Unable to begin transaction: %s", err); |
| + goto rollback; |
| + } |
| + |
| + /* |
| + * Check schema version again. This time, under an exclusive |
| + * transaction to guard against racing DB setup attempts |
| + */ |
| + ret = sqlite_query_schema_version(); |
| + switch (ret) { |
| + case 1: |
| + /* Still at v1 -- do conversion */ |
| + break; |
| + case CLTRACK_SQLITE_LATEST_SCHEMA_VERSION: |
| + /* Someone else raced in and set it up */ |
| + ret = 0; |
| + goto rollback; |
| + default: |
| + /* Something went wrong -- fail! */ |
| + ret = -EINVAL; |
| + goto rollback; |
| + } |
| + |
| + /* create v2 clients table */ |
| + ret = sqlite3_exec(dbh, "ALTER TABLE clients ADD COLUMN " |
| + "has_session INTEGER;", |
| + NULL, NULL, &err); |
| + if (ret != SQLITE_OK) { |
| + xlog(L_ERROR, "Unable to update clients table: %s", err); |
| + goto rollback; |
| + } |
| + |
| + ret = snprintf(buf, sizeof(buf), "UPDATE parameters SET value = %d " |
| + "WHERE key = \"version\";", |
| + CLTRACK_SQLITE_LATEST_SCHEMA_VERSION); |
| + if (ret < 0) { |
| + xlog(L_ERROR, "sprintf failed!"); |
| + goto rollback; |
| + } else if ((size_t)ret >= sizeof(buf)) { |
| + xlog(L_ERROR, "sprintf output too long! (%d chars)", ret); |
| + ret = -EINVAL; |
| + goto rollback; |
| + } |
| + |
| + ret = sqlite3_exec(dbh, (const char *)buf, NULL, NULL, &err); |
| + if (ret != SQLITE_OK) { |
| + xlog(L_ERROR, "Unable to update schema version: %s", err); |
| + goto rollback; |
| + } |
| + |
| + ret = sqlite3_exec(dbh, "COMMIT TRANSACTION;", NULL, NULL, &err); |
| + if (ret != SQLITE_OK) { |
| + xlog(L_ERROR, "Unable to commit transaction: %s", err); |
| + goto rollback; |
| + } |
| +out: |
| + sqlite3_free(err); |
| + return ret; |
| +rollback: |
| + ret2 = sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err); |
| + if (ret2 != SQLITE_OK) |
| + xlog(L_ERROR, "Unable to rollback transaction: %s", err); |
| + goto out; |
| +} |
| + |
| /* |
| * Start an exclusive transaction and recheck the DB schema version. If it's |
| * still zero (indicating a new database) then set it up. If that all works, |
| @@ -127,9 +204,9 @@ out: |
| * transaction. On any error, rollback the transaction. |
| */ |
| int |
| -sqlite_maindb_init_v1(void) |
| +sqlite_maindb_init_v2(void) |
| { |
| - int ret; |
| + int ret, ret2; |
| char *err = NULL; |
| |
| /* Start a transaction */ |
| @@ -169,7 +246,7 @@ sqlite_maindb_init_v1(void) |
| |
| /* create the "clients" table */ |
| ret = sqlite3_exec(dbh, "CREATE TABLE clients (id BLOB PRIMARY KEY, " |
| - "time INTEGER);", |
| + "time INTEGER, has_session INTEGER);", |
| NULL, NULL, &err); |
| if (ret != SQLITE_OK) { |
| xlog(L_ERROR, "Unable to create clients table: %s", err); |
| @@ -207,7 +284,9 @@ out: |
| |
| rollback: |
| /* Attempt to rollback the transaction */ |
| - sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err); |
| + ret2 = sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err); |
| + if (ret2 != SQLITE_OK) |
| + xlog(L_ERROR, "Unable to rollback transaction: %s", err); |
| goto out; |
| } |
| |
| @@ -255,9 +334,15 @@ sqlite_prepare_dbh(const char *topdir) |
| /* DB is already set up. Do nothing */ |
| ret = 0; |
| break; |
| + case 1: |
| + /* Old DB -- update to new schema */ |
| + ret = sqlite_maindb_update_v1_to_v2(); |
| + if (ret) |
| + goto out_close; |
| + break; |
| case 0: |
| /* Query failed -- try to set up new DB */ |
| - ret = sqlite_maindb_init_v1(); |
| + ret = sqlite_maindb_init_v2(); |
| if (ret) |
| goto out_close; |
| break; |