Diff
Not logged in

Differences From:

File src/db.c part of check-in [6b0196aeb8] - The FOSSIL_VFS environment variable, if it exists, determines which SQLite VFS is used. Use "export FOSSIL_VFS=unix-none" or "export FOSSIL_VFS=unix-dotfile" to work-around non-posix filesystems such as AFS on unix systems. by drh on 2009-08-09 17:29:25. [view]

To:

File src/db.c part of check-in [00ac7945a9] - Disconnect the global configuration database in ~/.fossil from the respository database in most cases. This allows multiple "sync" or "commit" operations to be running on different repositories at the same time. by drh on 2009-08-13 14:27:24. [view]

@@ -621,8 +621,31 @@
   sqlite3_close(db);
 }
 
 /*
+** Open a database file.  Return a pointer to the new database
+** connection.  An error results in process abort.
+*/
+static sqlite3 *openDatabase(const char *zDbName){
+  int rc;
+  const char *zVfs;
+  sqlite3 *db;
+
+  zVfs = getenv("FOSSIL_VFS");
+  rc = sqlite3_open_v2(
+       zDbName, &db,
+       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+       zVfs
+  );
+  if( rc!=SQLITE_OK ){
+    db_err(sqlite3_errmsg(db));
+  }
+  sqlite3_busy_timeout(db, 5000);
+  return db;
+}
+
+
+/*
 ** zDbName is the name of a database file.  If no other database
 ** file is open, then open this one.  If another database file is
 ** already open, then attach zDbName using the name zLabel.
 */
@@ -630,21 +653,9 @@
 #ifdef __MINGW32__
   zDbName = mbcsToUtf8(zDbName);
 #endif
   if( !g.db ){
-    int rc;
-    const char *zVfs;
-
-    zVfs = getenv("FOSSIL_VFS");
-    rc = sqlite3_open_v2(
-         zDbName, &g.db,
-         SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
-         zVfs
-    );
-    if( rc!=SQLITE_OK ){
-      db_err(sqlite3_errmsg(g.db));
-    }
-    sqlite3_busy_timeout(g.db, 5000);
+    g.db = openDatabase(zDbName);
     db_connection_init();
   }else{
     db_multi_exec("ATTACH DATABASE %Q AS %s", zDbName, zLabel);
   }
@@ -652,10 +663,18 @@
 
 /*
 ** Open the user database in "~/.fossil".  Create the database anew if
 ** it does not already exist.
-*/
-void db_open_config(void){
+**
+** If the useAttach flag is 0 (the usual case) then the user database is
+** opened on a separate database connection g.dbConfig.  This prevents
+** the ~/.fossil database from becoming locked on long check-in or sync
+** operations which hold an exclusive transaction.  In a few cases, though,
+** it is convenient for the ~/.fossil to be attached to the main database
+** connection so that we can join between the various databases.  In that
+** case, invoke this routine with useAttach as 1.
+*/
+void db_open_config(int useAttach){
   char *zDbName;
   const char *zHome;
   if( g.configOpen ) return;
 #ifdef __MINGW32__
@@ -685,9 +704,15 @@
 #endif
   if( file_size(zDbName)<1024*3 ){
     db_init_database(zDbName, zConfigSchema, (char*)0);
   }
-  db_open_or_attach(zDbName, "configdb");
+  g.useAttach = useAttach;
+  if( useAttach ){
+    db_open_or_attach(zDbName, "configdb");
+    g.dbConfig = 0;
+  }else{
+    g.dbConfig = openDatabase(zDbName);
+  }
   g.configOpen = 1;
 }
 
 /*
@@ -703,9 +728,9 @@
   lsize = file_size(zDbName);
   if( lsize%1024!=0 || lsize<4096 ) return 0;
   db_open_or_attach(zDbName, "localdb");
   g.localOpen = 1;
-  db_open_config();
+  db_open_config(0);
   db_open_repository(0);
 
   /* If the "mtime" column is missing from the vfile table, then
   ** add it now.   This code added on 2008-12-06.  After all users have
@@ -988,9 +1013,9 @@
     usage("REPOSITORY-NAME");
   }
   db_create_repository(g.argv[2]);
   db_open_repository(g.argv[2]);
-  db_open_config();
+  db_open_config(0);
   db_begin_transaction();
   db_initial_setup(zDate, 1);
   db_end_transaction(0);
   printf("project-id: %s\n", db_get("project-code", 0));
@@ -1148,8 +1173,25 @@
   return 0;
 }
 
 /*
+** Swap the g.db and g.dbConfig connections so that the various db_* routines
+** work on the ~/.fossil database instead of on the repository database.
+** Be sure to swap them back after doing the operation.
+**
+** If g.useAttach that means the ~/.fossil database was opened with
+** the useAttach flag set to 1.  In that case no connection swap is required
+** so this routine is a no-op.
+*/
+void db_swap_connections(void){
+  if( !g.useAttach ){
+    sqlite3 *dbTemp = g.db;
+    g.db = g.dbConfig;
+    g.dbConfig = dbTemp;
+  }
+}
+
+/*
 ** Get and set values from the CONFIG, GLOBAL_CONFIG and VVAR table in the
 ** repository and local databases.
 */
 char *db_get(const char *zName, char *zDefault){
@@ -1157,9 +1199,11 @@
   if( g.repositoryOpen ){
     z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
   }
   if( z==0 && g.configOpen ){
+    db_swap_connections();
     z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
+    db_swap_connections();
   }
   if( z==0 ){
     z = zDefault;
   }
@@ -1166,30 +1210,44 @@
   return z;
 }
 void db_set(const char *zName, const char *zValue, int globalFlag){
   db_begin_transaction();
-  db_multi_exec("REPLACE INTO %sconfig(name,value) VALUES(%Q,%Q)",
-                 globalFlag ? "global_" : "", zName, zValue);
+  if( globalFlag ){
+    db_swap_connections();
+    db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
+                   zName, zValue);
+    db_swap_connections();
+  }else{
+    db_multi_exec("REPLACE INTO config(name,value) VALUES(%Q,%Q)",
+                   zName, zValue);
+  }
   if( globalFlag && g.repositoryOpen ){
     db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
   }
   db_end_transaction(0);
 }
 void db_unset(const char *zName, int globalFlag){
   db_begin_transaction();
-  db_multi_exec("DELETE FROM %sconfig WHERE name=%Q",
-                 globalFlag ? "global_" : "", zName);
+  if( globalFlag ){
+    db_swap_connections();
+    db_multi_exec("DELETE INTO global_config WHERE name=%Q", zName);
+    db_swap_connections();
+  }else{
+    db_multi_exec("DELETE INTO config WHERE name=%Q", zName);
+  }
   if( globalFlag && g.repositoryOpen ){
     db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
   }
   db_end_transaction(0);
 }
 int db_is_global(const char *zName){
+  int rc = 0;
   if( g.configOpen ){
-    return db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
-  }else{
-    return 0;
-  }
+    db_swap_connections();
+    rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
+    db_swap_connections();
+  }
+  return rc;
 }
 int db_get_int(const char *zName, int dflt){
   int v = dflt;
   int rc;
@@ -1204,20 +1262,27 @@
   }else{
     rc = SQLITE_DONE;
   }
   if( rc==SQLITE_DONE && g.configOpen ){
+    db_swap_connections();
     v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName);
+    db_swap_connections();
   }
   return v;
 }
 void db_set_int(const char *zName, int value, int globalFlag){
-  db_begin_transaction();
-  db_multi_exec("REPLACE INTO %sconfig(name,value) VALUES(%Q,%d)",
-                globalFlag ? "global_" : "", zName, value);
+  if( globalFlag ){
+    db_swap_connections();
+    db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)",
+                  zName, value);
+    db_swap_connections();
+  }else{
+    db_multi_exec("REPLACE INTO config(name,value) VALUES(%Q,%d)",
+                  zName, value);
+  }
   if( globalFlag && g.repositoryOpen ){
     db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
   }
-  db_end_transaction(0);
 }
 int db_get_boolean(const char *zName, int dflt){
   char *zVal = db_get(zName, dflt ? "on" : "off");
   if( is_truth(zVal) ) return 1;
@@ -1253,13 +1318,15 @@
     if( !g.localOpen ) return;
     zName = db_lget("repository", 0);
   }
   file_canonical_name(zName, &full);
+  db_swap_connections();
   db_multi_exec(
      "INSERT OR IGNORE INTO global_config(name,value)"
      "VALUES('repo:%q',1)",
      blob_str(&full)
   );
+  db_swap_connections();
   blob_reset(&full);
 }
 
 /*
@@ -1413,13 +1480,13 @@
   };
   int i;
   int globalFlag = find_option("global","g",0)!=0;
   int unsetFlag = g.argv[1][0]=='u';
+  db_open_config(1);
   db_find_and_open_repository(0);
   if( !g.repositoryOpen ){
     globalFlag = 1;
   }
-  db_open_config();
   if( unsetFlag && g.argc!=3 ){
     usage("PROPERTY ?-global?");
   }
   if( g.argc==2 ){