[svn] commit: r2875 - in /branches/trac324/src/lib: datasrc/sqlite3_datasrc.cc python/isc/datasrc/sqlite3_ds.py
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Sep 8 22:06:23 UTC 2010
Author: each
Date: Wed Sep 8 22:06:23 2010
New Revision: 2875
Log:
Fixed a race condition where multiple processes could simultaneously try to
update the database schema from version 1 to 2. (This should also
address a similar race condition that can occur when starting bind10 for
the first time and initializing the data source, see trac #326.)
Modified:
branches/trac324/src/lib/datasrc/sqlite3_datasrc.cc
branches/trac324/src/lib/python/isc/datasrc/sqlite3_ds.py
Modified: branches/trac324/src/lib/datasrc/sqlite3_datasrc.cc
==============================================================================
--- branches/trac324/src/lib/datasrc/sqlite3_datasrc.cc (original)
+++ branches/trac324/src/lib/datasrc/sqlite3_datasrc.cc Wed Sep 8 22:06:23 2010
@@ -56,6 +56,7 @@
namespace {
// SQL statements to create a database file. schema version 2.
const char* const SCHEMA_LIST[] = {
+ "BEGIN EXCLUSIVE TRANSACTION",
"CREATE TABLE schema_version (version INTEGER NOT NULL)",
"INSERT INTO schema_version VALUES (2)",
"CREATE TABLE zones (id INTEGER PRIMARY KEY, "
@@ -78,6 +79,7 @@
"rdata STRING NOT NULL)",
"CREATE INDEX nsec3_byhash ON nsec3 (zone_id, hash, rdtype, "
"id, ttl, rdata)",
+ "COMMIT",
NULL
};
@@ -92,6 +94,7 @@
"CREATE INDEX nsec3_byhash ON nsec3 (zone_id, hash, rdtype, "
"id, ttl, rdata)",
"UPDATE schema_version SET version = 2",
+ "COMMIT",
NULL
};
@@ -647,11 +650,33 @@
checkVersion(Sqlite3Initializer* initializer) {
sqlite3* const db = initializer->params_.db_;
int version = initializer->params_.version_;
+ sqlite3_stmt* prepared = NULL;
+
switch (version) {
case 1:
+ // First we must confirm, within an exclusive transaction, that
+ // the database schema has not been changed under us by another
+ // process
+ sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL);
+ if (sqlite3_prepare_v2(db, "SELECT version FROM schema_version", -1,
+ &prepared, NULL) == SQLITE_OK &&
+ sqlite3_step(prepared) == SQLITE_ROW)
+ {
+ int current = sqlite3_column_int(prepared, 0);
+ sqlite3_finalize(prepared);
+ if (current != version) {
+ sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
+ return;
+ }
+ } else {
+ sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
+ return;
+ }
+
// XXX: replace this with a logging call
cerr << "[sqlite3] Old database version detected, "
<< "updating to schema version 2" << endl;
+
for (int i = 0; V1_TO_V2[i] != NULL; ++i) {
if (sqlite3_exec(db, V1_TO_V2[i],
NULL, NULL, NULL) != SQLITE_OK)
@@ -662,6 +687,7 @@
}
initializer->params_.version_ = 2;
break;
+
case 2:
// Current version, no action necessary
break;
Modified: branches/trac324/src/lib/python/isc/datasrc/sqlite3_ds.py
==============================================================================
--- branches/trac324/src/lib/python/isc/datasrc/sqlite3_ds.py (original)
+++ branches/trac324/src/lib/python/isc/datasrc/sqlite3_ds.py Wed Sep 8 22:06:23 2010
@@ -15,7 +15,7 @@
# $Id$
-import sqlite3, re, random
+import sqlite3, re, random, sys
import isc
@@ -36,6 +36,7 @@
#########################################################################
def create(cur):
"""Create new zone database"""
+ cur.execute("BEGIN EXCLUSIVE TRANSACTION")
cur.execute("CREATE TABLE schema_version (version INTEGER NOT NULL)")
cur.execute("INSERT INTO schema_version VALUES (2)")
cur.execute("""CREATE TABLE zones (id INTEGER PRIMARY KEY,
@@ -70,13 +71,21 @@
# to the current one
# input: cur - database cursor
# version - the current version number
-# returns: the new version
-#########################################################################
-def check_version(cur, version):
+#########################################################################
+def check_version(conn, cur, version):
if version == 1:
+ # Double-check that the version hasn't been changed under us
+ cur.execute("BEGIN EXCLUSIVE TRANSACTION")
+ cur.execute("SELECT version FROM schema_version")
+ row = cur.fetchone()
+ if not row or row[0] != version:
+ conn.commit()
+ return
+
# XXX: replace this with a logging call
print ("[sqlite3] Old database version detected, " +
"updating to schema version 2", file=sys.stderr)
+
cur.execute("DROP INDEX records_byname")
cur.execute("""CREATE INDEX records_byname ON records (zone_id, name,
rdtype, sigtype, id, ttl, rdata)""")
@@ -87,6 +96,7 @@
cur.execute("""CREATE INDEX nsec3_byhash ON nsec3 (zone_id, hash,
rdtype, id, ttl, rdata)""")
cur.execute("UPDATE schema_version SET version = 2")
+ conn.commit()
elif version != 2:
raise Sqlite3DSError("Unknown database schema version " + version)
@@ -116,12 +126,13 @@
create(cur)
conn.commit()
row = [1]
+ return conn, cur
if row == None:
raise Sqlite3DSError("Database schema version not found")
- else:
- check_version(cur, row[0]);
-
+
+ check_version(conn, cur, row[0]);
+ conn.commit()
return conn, cur
#########################################################################
More information about the bind10-changes
mailing list