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;