]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Begin adding mutexes. Compiles without SQLITE_OMIT_SHARED_CACHE but we
authordrh <drh@noemail.net>
Fri, 17 Aug 2007 01:14:38 +0000 (01:14 +0000)
committerdrh <drh@noemail.net>
Fri, 17 Aug 2007 01:14:38 +0000 (01:14 +0000)
get an assertion fault on the shared cache testing. (CVS 4239)

FossilOrigin-Name: 4c1e9ffebe7c611a8b6a89153ae97ab9bca19ea3

13 files changed:
manifest
manifest.uuid
src/btree.c
src/btree.h
src/btreeInt.h
src/build.c
src/main.c
src/mutex.c
src/sqlite.h.in
src/sqliteInt.h
src/test1.c
src/test_btree.c
src/vtab.c

index b1b531801dd4524b48c47c2658bff6e9e5413d3d..a031cf3eb026d89e1bcd27979f361471bf67663b 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Change\sthe\sdesign\sof\sthe\s\smutex\sinterface\sto\sallow\sfor\nboth\s"fast"\sand\s"recursive"\smutexes.\s(CVS\s4238)
-D 2007-08-16T19:40:17
+C Begin\sadding\smutexes.\s\sCompiles\swithout\sSQLITE_OMIT_SHARED_CACHE\sbut\swe\nget\san\sassertion\sfault\son\sthe\sshared\scache\stesting.\s(CVS\s4239)
+D 2007-08-17T01:14:38
 F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe
 F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -68,10 +68,10 @@ F src/alter.c f0aac0060ae8102e58f210b44d35b53438d53173
 F src/analyze.c a14237d869c6bea0846493b59317e4097e81a0b6
 F src/attach.c a52225c75b107be8c5bc144a2b6d20201be3f8f8
 F src/auth.c 5ea90bc93dfea46e9fe4bf531e14c7cd98219ecb
-F src/btree.c f371e9d7a24ba330c108bf1bb795280051f696ac
-F src/btree.h 1d527bf61ed176f980c34999d5793a0fd45dcf8c
-F src/btreeInt.h ac1ab1fb624ffbe571786cd2bd9559f9ae336355
-F src/build.c 923d6643c8f59fbcd10cd9e2f2690e82f48db69e
+F src/btree.c 409e7362338d3cf1f72961a01e75e9fbb577cc9f
+F src/btree.h 91ee529d581c1473d8e6e15299acc3b8de1d0674
+F src/btreeInt.h 6329e955a7dadd8628d5866e2465721b5fd25ef2
+F src/build.c add67be992307b4b11849a6611bfd3352aacde92
 F src/callback.c 143436453bb93e831c9574fea0b9b9eb90e40ff3
 F src/complete.c ea63834e798a0ab14159bdc6e6cabc3df21aa346
 F src/date.c c44aa498ee9a289ba2b2c62e8269b74b1b81351f
@@ -85,12 +85,12 @@ F src/insert.c 633322aef1799f6604fa805e12488bc628570b0c
 F src/legacy.c 6013a7cb7da1b72550b3d35d4fc598b3c3e5b8c1
 F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
 F src/loadext.c aa1c6e584d39cc241226ec9390387bc2d4a23e8f
-F src/main.c 996df547489d4826f70629b16623d7408f55ecd7
+F src/main.c 6e12fdab03efb8fb17aee8cfcd3bc32329cf1cda
 F src/malloc.c 613c65f12ff0ee4edd017aa458209ab7a23cd7b1
 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
 F src/mem1.c 2c6a6e3b2c9c7cb8d398a8468095032407c3e0b7
 F src/mem2.c 661ca7ebf6e4b964fecc95d24e8c89dbcfc9dfea
-F src/mutex.c 679d5d9c99bd302c0c43ee3eba61348c44aea366
+F src/mutex.c 67b2efd36a1e67a7dc7b7fa852fd69953462c943
 F src/os.c e2faefbe0f5a8ca5e3b1c49ee1b5c6cfa0f0e279
 F src/os.h 8eff07babf74e5bc3f895f8a6c7c294dad5ff997
 F src/os_common.h a5c446d3b93f09f369d13bf217de4bed3437dd1c
@@ -112,13 +112,13 @@ F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
 F src/select.c 98c367bce3f38c5adfcc97de9ab5c79b0e5dc2b2
 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb
-F src/sqlite.h.in 8efd7d5aca057a793d221973da1f22a22e69f4db
+F src/sqlite.h.in 07eea55853b739b372d4744ceefd08795d013be9
 F src/sqlite3ext.h 647a6b8a8f76ff6c9611e4a071531d8e63ff2d6b
-F src/sqliteInt.h fa9baff32aef7ca1ecebcd014b3bd75c981829d0
+F src/sqliteInt.h 7298c560e00f2305e2ecc1d2cbdd66134f5049de
 F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa
 F src/table.c c725e47f6f3092b9a7b569fc58e408e2173ee008
 F src/tclsqlite.c 0606c4f31711492eb4d7480a981eebb80914f3d9
-F src/test1.c 8afb22ec54ee9f28c103c2a212e2e6970626995a
+F src/test1.c a1d6eb85149053fac75b01b71439f00908a07c68
 F src/test2.c 4db48e4a487d4d18c2926d9600875613ad286ba8
 F src/test3.c b87e8fcce45e1d3153aae9f04236076b7707a714
 F src/test4.c d22cb3ab4f9fdfd0a595b70d5328cee923b7322c
@@ -129,7 +129,7 @@ F src/test8.c 719c284607c1e91a893f5425df1e92b74c859aef
 F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e
 F src/test_async.c 871ffbe4a520be74b403aca87aa622ebdb690232
 F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436
-F src/test_btree.c 882d59acad48bab3b1fe3daf3645059b590cfc79
+F src/test_btree.c c1308ba0b88ab577fa56c9e493a09829dfcded9c
 F src/test_config.c 26389b032216e0fb2b544ff48a5e9101bd7b1fb4
 F src/test_hexio.c 82916f918687502658f02533b519c38cb180db6d
 F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8
@@ -152,7 +152,7 @@ F src/vdbeaux.c c6d50887e8f29706ae35b965298e58fa6ba0e9bf
 F src/vdbeblob.c cf9ee3c7d9977cbd896f8b118da4fb4268637f4f
 F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
 F src/vdbemem.c 019952d44066a24aef70ca8c284cfd2d1073c398
-F src/vtab.c 8d65679ab4ef3efce5d946d7f2d2dac5a33313b4
+F src/vtab.c ee29237ecc9b310dc43c0c2ac5caa6c6a20787be
 F src/where.c 2776a0caf8cbbfd6ec79cfb1cd9bc25074055e5e
 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -529,7 +529,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 3d60c14a32955b69e714a73372924d421899f83b
-R 79bf1accc56116075f09cd253592694c
+P 160593dcc5690af715b775c81137c6e09cca6454
+R 5d5493a8682338889467b44d542e4cdc
 U drh
-Z e40cc1b0395242393945aa35a1600f4d
+Z d35e1fbff49f629248bfcae9f72cc56d
index fc8a7b88057436a81530435f736d3d6c8ecb4af1..8ac8ae7697df20d836e09e7465a3c1876765635a 100644 (file)
@@ -1 +1 @@
-160593dcc5690af715b775c81137c6e09cca6454
\ No newline at end of file
+4c1e9ffebe7c611a8b6a89153ae97ab9bca19ea3
\ No newline at end of file
index ea2651a35dc0d7868641eeed8cecf0217f08c7d9..ce78a46e8d6b4f17bf2e0d28807975ceafd1a88a 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.398 2007/08/16 10:09:02 danielk1977 Exp $
+** $Id: btree.c,v 1.399 2007/08/17 01:14:38 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** See the header comment on "btreeInt.h" for additional information.
@@ -32,6 +32,36 @@ static const char zMagicHeader[] = SQLITE_FILE_HEADER;
 int sqlite3_btree_trace=0;  /* True to enable tracing */
 #endif
 
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/*
+** A flag to indicate whether or not shared cache is enabled.  Also,
+** a list of BtShared objects that are eligible for participation
+** in shared cache.
+*/
+#ifdef SQLITE_TEST
+BtShared *sqlite3SharedCacheList = 0;
+int sqlite3SharedCacheEnabled = 0;
+#else
+static BtShared *sqlite3SharedCacheList = 0;
+static int sqlite3SharedCacheEnabled = 0;
+#endif
+
+#endif /* SQLITE_OMIT_SHARED_CACHE */
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/*
+** Enable or disable the shared pager and schema features.
+**
+** This routine has no effect on existing database connections.
+** The shared cache setting effects only future calls to
+** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
+*/
+int sqlite3_enable_shared_cache(int enable){
+  sqlite3SharedCacheEnabled = enable;
+  return SQLITE_OK;
+}
+#endif
+
 /*
 ** Forward declaration
 */
@@ -50,8 +80,9 @@ static int checkReadLocks(Btree*,Pgno,BtCursor*);
   #define queryTableLock(a,b,c) SQLITE_OK
   #define lockTable(a,b,c) SQLITE_OK
   #define unlockAllTables(a)
-#else
+#endif
 
+#ifndef SQLITE_OMIT_SHARED_CACHE
 /*
 ** Query to see if btree handle p may obtain a lock of type eLock 
 ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
@@ -63,7 +94,7 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
   BtLock *pIter;
 
   /* This is a no-op if the shared-cache is not enabled */
-  if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){
+  if( !p->sharable ){
     return SQLITE_OK;
   }
 
@@ -96,7 +127,9 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
   }
   return SQLITE_OK;
 }
+#endif /* !SQLITE_OMIT_SHARED_CACHE */
 
+#ifndef SQLITE_OMIT_SHARED_CACHE
 /*
 ** Add a lock on the table with root-page iTable to the shared-btree used
 ** by Btree handle p. Parameter eLock must be either READ_LOCK or 
@@ -111,7 +144,7 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
   BtLock *pIter;
 
   /* This is a no-op if the shared-cache is not enabled */
-  if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){
+  if( !p->sharable ){
     return SQLITE_OK;
   }
 
@@ -164,7 +197,9 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
 
   return SQLITE_OK;
 }
+#endif /* !SQLITE_OMIT_SHARED_CACHE */
 
+#ifndef SQLITE_OMIT_SHARED_CACHE
 /*
 ** Release all the table locks (locks obtained via calls to the lockTable()
 ** procedure) held by Btree handle p.
@@ -172,11 +207,7 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
 static void unlockAllTables(Btree *p){
   BtLock **ppIter = &p->pBt->pLock;
 
-  /* If the shared-cache extension is not enabled, there should be no
-  ** locks in the BtShared.pLock list, making this procedure a no-op. Assert
-  ** that this is the case.
-  */
-  assert( sqlite3ThreadDataReadOnly()->useSharedData || 0==*ppIter );
+  assert( p->sharable || 0==*ppIter );
 
   while( *ppIter ){
     BtLock *pLock = *ppIter;
@@ -1023,6 +1054,8 @@ static void pageReinit(DbPage *pData, int pageSize){
 ** zFilename is the name of the database file.  If zFilename is NULL
 ** a new database with a random name is created.  This randomly named
 ** database file will be deleted when sqlite3BtreeClose() is called.
+** If zFilename is ":memory:" then an in-memory database is created
+** that is automatically destroyed when it is closed.
 */
 int sqlite3BtreeOpen(
   const char *zFilename,  /* Name of the file containing the BTree database */
@@ -1030,14 +1063,11 @@ int sqlite3BtreeOpen(
   Btree **ppBtree,        /* Pointer to new Btree object written here */
   int flags               /* Options */
 ){
-  BtShared *pBt;          /* Shared part of btree structure */
+  BtShared *pBt = 0;      /* Shared part of btree structure */
   Btree *p;               /* Handle to return */
   int rc = SQLITE_OK;
   int nReserve;
   unsigned char zDbHeader[100];
-#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
-  const ThreadData *pTsdro;
-#endif
 
   /* Set the variable isMemdb to true for an in-memory database, or 
   ** false for a file-based database. This symbol is only required if
@@ -1059,106 +1089,150 @@ int sqlite3BtreeOpen(
   p->inTrans = TRANS_NONE;
   p->pSqlite = pSqlite;
 
-  /* Try to find an existing Btree structure opened on zFilename. */
 #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
-  pTsdro = sqlite3ThreadDataReadOnly();
-  if( pTsdro->useSharedData && zFilename && !isMemdb ){
+  /*
+  ** If this Btree is a candidate for shared cache, try to find an
+  ** existing BtShared object that we can share with
+  */
+  if( (flags & BTREE_PRIVATE)==0
+   && isMemdb==0
+   && zFilename && zFilename[0]
+   && sqlite3SharedCacheEnabled
+  ){
     char *zFullPathname = sqlite3OsFullPathname(zFilename);
+    sqlite3_mutex *mutexShared;
+    p->sharable = 1;
     if( !zFullPathname ){
       sqlite3_free(p);
       return SQLITE_NOMEM;
     }
-    for(pBt=pTsdro->pBtree; pBt; pBt=pBt->pNext){
+    mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+    sqlite3_mutex_enter(mutexShared);
+    for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){
       assert( pBt->nRef>0 );
       if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) ){
         p->pBt = pBt;
-        *ppBtree = p;
         pBt->nRef++;
-        sqlite3_free(zFullPathname);
-        return SQLITE_OK;
+        break;
       }
     }
+    sqlite3_mutex_leave(mutexShared);
     sqlite3_free(zFullPathname);
   }
 #endif
-
-  /*
-  ** The following asserts make sure that structures used by the btree are
-  ** the right size.  This is to guard against size changes that result
-  ** when compiling on a different architecture.
-  */
-  assert( sizeof(i64)==8 || sizeof(i64)==4 );
-  assert( sizeof(u64)==8 || sizeof(u64)==4 );
-  assert( sizeof(u32)==4 );
-  assert( sizeof(u16)==2 );
-  assert( sizeof(Pgno)==4 );
-
-  pBt = sqlite3MallocZero( sizeof(*pBt) );
   if( pBt==0 ){
-    rc = SQLITE_NOMEM;
-    goto btree_open_out;
-  }
-  rc = sqlite3PagerOpen(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
-  if( rc==SQLITE_OK ){
-    rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
-  }
-  if( rc!=SQLITE_OK ){
-    goto btree_open_out;
-  }
-  p->pBt = pBt;
-
-  sqlite3PagerSetDestructor(pBt->pPager, pageDestructor);
-  sqlite3PagerSetReiniter(pBt->pPager, pageReinit);
-  pBt->pCursor = 0;
-  pBt->pPage1 = 0;
-  pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
-  pBt->pageSize = get2byte(&zDbHeader[16]);
-  if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
-       || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
-    pBt->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
-    pBt->maxEmbedFrac = 64;   /* 25% */
-    pBt->minEmbedFrac = 32;   /* 12.5% */
-    pBt->minLeafFrac = 32;    /* 12.5% */
-#ifndef SQLITE_OMIT_AUTOVACUUM
-    /* If the magic name ":memory:" will create an in-memory database, then
-    ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if
-    ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if
-    ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a
-    ** regular file-name. In this case the auto-vacuum applies as per normal.
+    /*
+    ** The following asserts make sure that structures used by the btree are
+    ** the right size.  This is to guard against size changes that result
+    ** when compiling on a different architecture.
     */
-    if( zFilename && !isMemdb ){
-      pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0);
-      pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0);
+    assert( sizeof(i64)==8 || sizeof(i64)==4 );
+    assert( sizeof(u64)==8 || sizeof(u64)==4 );
+    assert( sizeof(u32)==4 );
+    assert( sizeof(u16)==2 );
+    assert( sizeof(Pgno)==4 );
+  
+    pBt = sqlite3MallocZero( sizeof(*pBt) );
+    if( pBt==0 ){
+      rc = SQLITE_NOMEM;
+      goto btree_open_out;
     }
+    rc = sqlite3PagerOpen(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
+    if( rc==SQLITE_OK ){
+      rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
+    }
+    if( rc!=SQLITE_OK ){
+      goto btree_open_out;
+    }
+    p->pBt = pBt;
+  
+    sqlite3PagerSetDestructor(pBt->pPager, pageDestructor);
+    sqlite3PagerSetReiniter(pBt->pPager, pageReinit);
+    pBt->pCursor = 0;
+    pBt->pPage1 = 0;
+    pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
+    pBt->pageSize = get2byte(&zDbHeader[16]);
+    if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
+         || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
+      pBt->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
+      pBt->maxEmbedFrac = 64;   /* 25% */
+      pBt->minEmbedFrac = 32;   /* 12.5% */
+      pBt->minLeafFrac = 32;    /* 12.5% */
+#ifndef SQLITE_OMIT_AUTOVACUUM
+      /* If the magic name ":memory:" will create an in-memory database, then
+      ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if
+      ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if
+      ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a
+      ** regular file-name. In this case the auto-vacuum applies as per normal.
+      */
+      if( zFilename && !isMemdb ){
+        pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0);
+        pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0);
+      }
 #endif
-    nReserve = 0;
-  }else{
-    nReserve = zDbHeader[20];
-    pBt->maxEmbedFrac = zDbHeader[21];
-    pBt->minEmbedFrac = zDbHeader[22];
-    pBt->minLeafFrac = zDbHeader[23];
-    pBt->pageSizeFixed = 1;
+      nReserve = 0;
+    }else{
+      nReserve = zDbHeader[20];
+      pBt->maxEmbedFrac = zDbHeader[21];
+      pBt->minEmbedFrac = zDbHeader[22];
+      pBt->minLeafFrac = zDbHeader[23];
+      pBt->pageSizeFixed = 1;
 #ifndef SQLITE_OMIT_AUTOVACUUM
-    pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0);
-    pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0);
+      pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0);
+      pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0);
+#endif
+    }
+    pBt->usableSize = pBt->pageSize - nReserve;
+    assert( (pBt->pageSize & 7)==0 );  /* 8-byte alignment of pageSize */
+    sqlite3PagerSetPagesize(pBt->pPager, pBt->pageSize);
+   
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
+    /* Add the new BtShared object to the linked list sharable BtShareds.
+    */
+    if( p->sharable ){
+      sqlite3_mutex *mutexShared;
+      pBt->nRef = 1;
+      mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+      pBt->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+      sqlite3_mutex_enter(mutexShared);
+      pBt->pNext = sqlite3SharedCacheList;
+      sqlite3SharedCacheList = pBt;
+      sqlite3_mutex_leave(mutexShared);
+    }
 #endif
   }
-  pBt->usableSize = pBt->pageSize - nReserve;
-  assert( (pBt->pageSize & 7)==0 );  /* 8-byte alignment of pageSize */
-  sqlite3PagerSetPagesize(pBt->pPager, pBt->pageSize);
 
 #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
-  /* Add the new btree to the linked list starting at ThreadData.pBtree.
-  ** There is no chance that a malloc() may fail inside of the 
-  ** sqlite3ThreadData() call, as the ThreadData structure must have already
-  ** been allocated for pTsdro->useSharedData to be non-zero.
+  /* If the new Btree uses a sharable pBtShared, then link the new
+  ** Btree into the list of all sharable Btrees for the same connection.
+  ** The list is kept in ascending order by pBtShared address.
   */
-  if( pTsdro->useSharedData && zFilename && !isMemdb ){
-    pBt->pNext = pTsdro->pBtree;
-    sqlite3ThreadData()->pBtree = pBt;
+  if( p->sharable ){
+    int i;
+    Btree *pSib;
+    for(i=0; i<pSqlite->nDb; i++){
+      if( (pSib = pSqlite->aDb[i].pBt)!=0 && pSib->sharable ){
+        while( pSib->pPrev ){ pSib = pSib->pPrev; }
+        if( p->pBt<pSib->pBt ){
+          p->pNext = pSib;
+          p->pPrev = 0;
+          pSib->pPrev = p;
+        }else{
+          while( pSib->pNext && pSib->pNext->pBt>p->pBt ){
+            pSib = pSib->pNext;
+          }
+          p->pNext = pSib->pNext;
+          p->pPrev = pSib;
+          if( p->pNext ){
+            p->pNext->pPrev = p;
+          }
+          pSib->pNext = p;
+        }
+        break;
+      }
+    }
   }
 #endif
-  pBt->nRef = 1;
   *ppBtree = p;
 
 btree_open_out:
@@ -1173,6 +1247,43 @@ btree_open_out:
   return rc;
 }
 
+/*
+** Decrement the BtShared.nRef counter.  When it reaches zero,
+** remove the BtShared structure from the sharing list.  Return
+** true if the BtShared.nRef counter reaches zero and return
+** false if it is still positive.
+*/
+static int removeFromSharingList(BtShared *pBt){
+#ifndef SQLITE_OMIT_SHARED_CACHE
+  sqlite3_mutex *pMaster;
+  BtShared *pList;
+  int removed = 0;
+
+  pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+  sqlite3_mutex_enter(pMaster);
+  pBt->nRef--;
+  if( pBt->nRef<=0 ){
+    if( sqlite3SharedCacheList==pBt ){
+      sqlite3SharedCacheList = pBt->pNext;
+    }else{
+      pList = sqlite3SharedCacheList;
+      while( pList && pList->pNext!=pBt ){
+        pList=pList->pNext;
+      }
+      if( pList ){
+        pList->pNext = pBt->pNext;
+      }
+    }
+    sqlite3_mutex_free(pBt->mutex);
+    removed = 1;
+  }
+  sqlite3_mutex_leave(pMaster);
+  return removed;
+#else
+  return 1;
+#endif
+}
+
 /*
 ** Close an open database and invalidate all cursors.
 */
@@ -1180,11 +1291,8 @@ int sqlite3BtreeClose(Btree *p){
   BtShared *pBt = p->pBt;
   BtCursor *pCur;
 
-#ifndef SQLITE_OMIT_SHARED_CACHE
-  ThreadData *pTsd;
-#endif
-
   /* Close all cursors opened via this handle.  */
+  sqlite3BtreeEnter(p);
   pCur = pBt->pCursor;
   while( pCur ){
     BtCursor *pTmp = pCur;
@@ -1199,47 +1307,130 @@ int sqlite3BtreeClose(Btree *p){
   ** this handle.
   */
   sqlite3BtreeRollback(p);
-  sqlite3_free(p);
+  sqlite3BtreeLeave(p);
 
-#ifndef SQLITE_OMIT_SHARED_CACHE
   /* If there are still other outstanding references to the shared-btree
   ** structure, return now. The remainder of this procedure cleans 
   ** up the shared-btree.
   */
-  assert( pBt->nRef>0 );
-  pBt->nRef--;
-  if( pBt->nRef ){
-    return SQLITE_OK;
+  assert( p->wantToLock==0 && p->locked==0 );
+  if( !p->sharable || removeFromSharingList(pBt) ){
+    /* The pBt is no longer on the sharing list, so we can access
+    ** it without having to hold the mutex.
+    **
+    ** Clean out and delete the BtShared object.
+    */
+    assert( !pBt->pCursor );
+    assert( pBt->nRef==0 );
+    sqlite3PagerClose(pBt->pPager);
+    if( pBt->xFreeSchema && pBt->pSchema ){
+      pBt->xFreeSchema(pBt->pSchema);
+    }
+    sqlite3_free(pBt->pSchema);
+    sqlite3_free(pBt);
+  }
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+  else{
+    assert( p->wantToLock==0 );
+    assert( p->locked==0 );
+    assert( p->sharable );
+    if( p->pPrev ) p->pPrev->pNext = p->pNext;
+    if( p->pNext ) p->pNext->pPrev = p->pPrev;
+  }
+#endif
+
+  sqlite3_free(p);
+  return SQLITE_OK;
+}
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/*
+** Enter a mutex on the given BTree object.
+**
+** If the object is not sharable, then no mutex is ever required
+** and this routine is a no-op.  The underlying mutex is non-recursive.
+** But we keep a reference count in Btree.wantToLock so the behavior
+** of this interface is recursive.
+**
+** To avoid deadlocks, multiple Btrees are locked in the same order
+** by all database connections.  The p->pNext is a list of other
+** Btrees belonging to the same database connection as the p Btree
+** which need to be locked after p.  If we cannot get a lock on
+** p, then first unlock all of the others on p->pNext, then wait
+** for the lock to become available on p, then relock all of the
+** subsequent Btrees that desire a lock.
+*/
+void sqlite3BtreeEnter(Btree *p){
+  Btree *pLater;
+
+  /* Some basic sanity checking on the Btree.  The list of Btrees
+  ** connected by pNext and pPrev should be in sorted order by
+  ** Btree.pBt value. All elements of the list should belong to
+  ** the same connection. Only shared Btrees are on the list. */
+  assert( p->pNext==0 || p->pNext->pBt>p->pBt );
+  assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
+  assert( p->pNext==0 || p->pNext->pSqlite==p->pSqlite );
+  assert( p->pPrev==0 || p->pPrev->pSqlite==p->pSqlite );
+  assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
+
+  /* Check for locking consistency */
+  assert( !p->locked || p->wantToLock>0 );
+  assert( p->sharable || p->wantToLock==0 );
+
+  if( !p->sharable ) return;
+  p->wantToLock++;
+  if( p->locked ) return;
+
+  /* In most cases, we should be able to acquire the lock we
+  ** want without having to go throught the ascending lock
+  ** procedure that follows.  Just be sure not to block.
+  */
+  if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
+    p->locked = 1;
+    return;
   }
 
-  /* Remove the shared-btree from the thread wide list. Call 
-  ** ThreadDataReadOnly() and then cast away the const property of the 
-  ** pointer to avoid allocating thread data if it is not really required.
+  /* To avoid deadlock, first release all locks with a larger
+  ** BtShared address.  Then acquire our lock.  Then reacquire
+  ** the other BtShared locks that we used to hold in ascending
+  ** order.
   */
-  pTsd = (ThreadData *)sqlite3ThreadDataReadOnly();
-  if( pTsd->pBtree==pBt ){
-    assert( pTsd==sqlite3ThreadData() );
-    pTsd->pBtree = pBt->pNext;
-  }else{
-    BtShared *pPrev;
-    for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext){}
-    if( pPrev ){
-      assert( pTsd==sqlite3ThreadData() );
-      pPrev->pNext = pBt->pNext;
+  for(pLater=p->pNext; pLater; pLater=pLater->pNext){
+    assert( pLater->sharable );
+    assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
+    assert( !pLater->locked || pLater->wantToLock>0 );
+    if( pLater->locked ){
+      sqlite3_mutex_leave(pLater->pBt->mutex);
+      pLater->locked = 0;
     }
   }
-#endif
+  sqlite3_mutex_enter(p->pBt->mutex);
+  for(pLater=p->pNext; pLater; pLater=pLater->pNext){
+    if( pLater->wantToLock ){
+      sqlite3_mutex_enter(pLater->pBt->mutex);
+      pLater->locked = 1;
+    }
+  }
+}
+#endif /* !SQLITE_OMIT_SHARED_CACHE */
 
-  /* Close the pager and free the shared-btree structure */
-  assert( !pBt->pCursor );
-  sqlite3PagerClose(pBt->pPager);
-  if( pBt->xFreeSchema && pBt->pSchema ){
-    pBt->xFreeSchema(pBt->pSchema);
+/*
+** Exit the recursive mutex on a Btree.
+*/
+#ifndef SQLITE_OMIT_SHARED_CACHE
+void sqlite3BtreeLeave(Btree *p){
+  if( p->sharable ){
+    assert( p->wantToLock>0 );
+    p->wantToLock--;
+    if( p->wantToLock==0 ){
+      assert( p->locked );
+      sqlite3_mutex_leave(p->pBt->mutex);
+      p->locked = 0;
+    }
   }
-  sqlite3_free(pBt->pSchema);
-  sqlite3_free(pBt);
-  return SQLITE_OK;
 }
+#endif /* !SQLITE_OMIT_SHARED_CACHE */
 
 /*
 ** Change the busy handler callback function.
index bf8929d4f68fb434a23282393104403d6cdc8711..d67a432aee9d51ae345343794edbe0c466367997 100644 (file)
@@ -13,7 +13,7 @@
 ** subsystem.  See comments in the source code for a detailed description
 ** of what each interface routine does.
 **
-** @(#) $Id: btree.h,v 1.82 2007/05/08 21:45:27 drh Exp $
+** @(#) $Id: btree.h,v 1.83 2007/08/17 01:14:38 drh Exp $
 */
 #ifndef _BTREE_H_
 #define _BTREE_H_
@@ -59,6 +59,14 @@ int sqlite3BtreeOpen(
 #define BTREE_OMIT_JOURNAL  1  /* Do not use journal.  No argument */
 #define BTREE_NO_READLOCK   2  /* Omit readlocks on readonly files */
 #define BTREE_MEMORY        4  /* In-memory DB.  No argument */
+#define BTREE_READONLY      8  /* Open the database in read-only mode */
+#define BTREE_READWRITE    16  /* Open for both reading and writing */
+#define BTREE_CREATE       32  /* Create the database if it does not exist */
+
+/* Additional values for the 4th argument of sqlite3BtreeOpen that
+** are not associated with PAGER_ values.
+*/
+#define BTREE_PRIVATE      64  /* Never share with other connections */
 
 int sqlite3BtreeClose(Btree*);
 int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
@@ -87,6 +95,19 @@ void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
 int sqlite3BtreeSchemaLocked(Btree *);
 int sqlite3BtreeLockTable(Btree *, int, u8);
 
+/*
+** If we are not using shared cache, then there is no need to
+** use mutexes to access the BtShared structures.  So make the
+** Enter and Leave procedures no-ops.
+*/
+#ifdef SQLITE_OMIT_SHARED_CACHE
+# define sqlite3BtreeEnter(X)
+# define sqlite3BtreeLeave(X)
+#else
+  void sqlite3BtreeEnter(Btree*);
+  void sqlite3BtreeLeave(Btree*);
+#endif
+
 const char *sqlite3BtreeGetFilename(Btree *);
 const char *sqlite3BtreeGetDirname(Btree *);
 const char *sqlite3BtreeGetJournalname(Btree *);
index 2964ad3b923889dd0bacb425c42b9256f2fc1d53..179b1f219bb1b2d010ae7680d84066147fae2272 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btreeInt.h,v 1.5 2007/06/15 12:06:59 drh Exp $
+** $Id: btreeInt.h,v 1.6 2007/08/17 01:14:38 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -248,7 +248,7 @@ typedef struct BtLock BtLock;
 
 /*
 ** Page type flags.  An ORed combination of these flags appear as the
-** first byte of every BTree page.
+** first byte of on-disk image of every BTree page.
 */
 #define PTF_INTKEY    0x01
 #define PTF_ZERODATA  0x02
@@ -276,8 +276,8 @@ struct MemPage {
   u8 hasData;          /* True if this page stores data */
   u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
   u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
-  u16 maxLocal;        /* Copy of Btree.maxLocal or Btree.maxLeaf */
-  u16 minLocal;        /* Copy of Btree.minLocal or Btree.minLeaf */
+  u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
+  u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
   u16 cellOffset;      /* Index in aData of first cell pointer */
   u16 idxParent;       /* Index in parent of this node */
   u16 nFree;           /* Number of free bytes on the page */
@@ -286,8 +286,8 @@ struct MemPage {
     u8 *pCell;          /* Pointers to the body of the overflow cell */
     u16 idx;            /* Insert this cell before idx-th non-overflow cell */
   } aOvfl[5];
-  BtShared *pBt;       /* Pointer back to BTree structure */
-  u8 *aData;           /* Pointer back to the start of the page */
+  BtShared *pBt;       /* Pointer to BtShared that this page is part of */
+  u8 *aData;           /* Pointer to disk image of the page data */
   DbPage *pDbPage;     /* Pager page handle */
   Pgno pgno;           /* Page number for this page */
   MemPage *pParent;    /* The parent of this page.  NULL for root */
@@ -300,11 +300,30 @@ struct MemPage {
 */
 #define EXTRA_SIZE sizeof(MemPage)
 
-/* Btree handle */
+/* A Btree handle
+**
+** A database connection contains a pointer to an instance of
+** this object for every database file that it has open.  This structure
+** is opaque to the database connection.  The database connection cannot
+** see the internals of this structure and only deals with pointers to
+** this structure.
+**
+** For some database files, the same underlying database cache might be 
+** shared between multiple connections.  In that case, each contection
+** has it own pointer to this object.  But each instance of this object
+** points to the same BtShared object.  The database cache and the
+** schema associated with the database file are all contained within
+** the BtShared object.
+*/
 struct Btree {
-  sqlite3 *pSqlite;
-  BtShared *pBt;
-  u8 inTrans;            /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
+  sqlite3 *pSqlite;  /* The database connection holding this btree */
+  BtShared *pBt;     /* Sharable content of this btree */
+  u8 inTrans;        /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
+  u8 sharable;       /* True if we can share pBt with other pSqlite */
+  u8 locked;         /* True if pSqlite currently has pBt locked */
+  int wantToLock;    /* Number of nested calls to sqlite3BtreeEnter() */
+  Btree *pNext;      /* List of Btrees with the same pSqlite value */
+  Btree *pPrev;      /* Back pointer of the same list */
 };
 
 /*
@@ -312,15 +331,21 @@ struct Btree {
 **
 ** If the shared-data extension is enabled, there may be multiple users
 ** of the Btree structure. At most one of these may open a write transaction,
-** but any number may have active read transactions. Variable Btree.pDb 
-** points to the handle that owns any current write-transaction.
+** but any number may have active read transactions.
 */
 #define TRANS_NONE  0
 #define TRANS_READ  1
 #define TRANS_WRITE 2
 
 /*
-** Everything we need to know about an open database
+** An instance of this object represents a single database file.
+** 
+** A single database file can be in use as the same time by two
+** or more database connections.  When two or more connections are
+** sharing the same database file, each connection has it own
+** private Btree object for the file and each of those Btrees points
+** to this one BtShared object.  BtShared.nRef is the number of
+** connections currently sharing this database file.
 */
 struct BtShared {
   Pager *pPager;        /* The page cache */
@@ -350,6 +375,7 @@ struct BtShared {
   void *pSchema;        /* Pointer to space allocated by sqlite3BtreeSchema() */
   void (*xFreeSchema)(void*);  /* Destructor for BtShared.pSchema */
 #ifndef SQLITE_OMIT_SHARED_CACHE
+  sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
   BtLock *pLock;        /* List of locks held on this shared-btree struct */
   BtShared *pNext;      /* Next in ThreadData.pBtree linked list */
 #endif
@@ -373,9 +399,15 @@ struct CellInfo {
 };
 
 /*
-** A cursor is a pointer to a particular entry in the BTree.
+** A cursor is a pointer to a particular entry within a particular
+** b-tree within a database file.
+**
 ** The entry is identified by its MemPage and the index in
 ** MemPage.aCell[] of the entry.
+**
+** When a single database file can shared by two more database connections,
+** but cursors cannot be shared.  Each cursor is associated with a
+** particular database connection identified BtCursor.pBtree.pSqlite.
 */
 struct BtCursor {
   Btree *pBtree;            /* The Btree to which this cursor belongs */
@@ -530,8 +562,6 @@ struct BtLock {
 ** of handle p (type Btree*) are internally consistent.
 */
 #define btreeIntegrity(p) \
-  assert( p->inTrans!=TRANS_NONE || p->pBt->nTransaction<p->pBt->nRef ); \
-  assert( p->pBt->nTransaction<=p->pBt->nRef ); \
   assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
   assert( p->pBt->inTransaction>=p->inTrans ); 
 
index 510682f411ea7d3ba397de99c029c7ddd004d1b8..bd7b7305a24e5b976640cf19e224b57e4e740285 100644 (file)
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.435 2007/08/16 10:09:02 danielk1977 Exp $
+** $Id: build.c,v 1.436 2007/08/17 01:14:38 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -69,7 +69,7 @@ void sqlite3TableLock(
   int nBytes;
   TableLock *p;
 
-  if( 0==sqlite3ThreadDataReadOnly()->useSharedData || iDb<0 ){
+  if( iDb<0 ){
     return;
   }
 
@@ -100,7 +100,6 @@ void sqlite3TableLock(
 static void codeTableLocks(Parse *pParse){
   int i;
   Vdbe *pVdbe; 
-  assert( sqlite3ThreadDataReadOnly()->useSharedData || pParse->nTableLock==0 );
 
   if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){
     return;
index 8457d0b4d70aec15502111e2fd2d92e5574f7f44..4e8b7a8a7759c9aaf0ca434996cfda57ca8ae378 100644 (file)
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.382 2007/08/16 13:01:45 drh Exp $
+** $Id: main.c,v 1.383 2007/08/17 01:14:38 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -1235,35 +1235,6 @@ int sqlite3Corrupt(void){
 }
 #endif
 
-
-#ifndef SQLITE_OMIT_SHARED_CACHE
-/*
-** Enable or disable the shared pager and schema features for the
-** current thread.
-**
-** This routine should only be called when there are no open
-** database connections.
-*/
-int sqlite3_enable_shared_cache(int enable){
-  ThreadData *pTd = sqlite3ThreadData();
-  if( pTd ){
-    /* It is only legal to call sqlite3_enable_shared_cache() when there
-    ** are no currently open b-trees that were opened by the calling thread.
-    ** This condition is only easy to detect if the shared-cache were 
-    ** previously enabled (and is being disabled). 
-    */
-    if( pTd->pBtree && !enable ){
-      assert( pTd->useSharedData );
-      return SQLITE_MISUSE;
-    }
-
-    pTd->useSharedData = enable;
-    /* sqlite3ReleaseThreadData(); */
-  }
-  return sqlite3ApiExit(0, SQLITE_OK);
-}
-#endif
-
 /*
 ** This is a convenience routine that makes sure that all thread-specific
 ** data for this thread has been deallocated.
index 13e15b5c7b789c59bfe8186dcb42c1ef1734cc10..ffee6d78504aaf77d2f2152bc0a39e469479752e 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains the C functions that implement mutexes for
 ** use by the SQLite core.
 **
-** $Id: mutex.c,v 1.3 2007/08/16 19:40:17 drh Exp $
+** $Id: mutex.c,v 1.4 2007/08/17 01:14:38 drh Exp $
 */
 
 /*
@@ -228,17 +228,19 @@ void sqlite3_mutex_enter(sqlite3_mutex *pMutex){
     pthread_mutex_lock(&p->mutex);
   }else{
     struct RMutex *p = (struct RMutex*)pMutex;
-    pthread_mutex_lock(&p->auxMutex);
-    if( p->nRef==0 ){
-      p->nRef++;
-      p->owner = pthread_self();
-      pthread_mutex_lock(&p->mainMutex);
-      pthread_mutex_unlock(&p->auxMutex);
-    }else if( pthread_equal(p->owner, pthread_self()) ){
-      p->nRef++;
-      pthread_mutex_unlock(&p->auxMutex);
-    }else{
-      while( p->nRef ){
+    while(1){
+      pthread_mutex_lock(&p->auxMutex);
+      if( p->nRef==0 ){
+        p->nRef++;
+        p->owner = pthread_self();
+        pthread_mutex_lock(&p->mainMutex);
+        pthread_mutex_unlock(&p->auxMutex);
+        break;
+      }else if( pthread_equal(p->owner, pthread_self()) ){
+        p->nRef++;
+        pthread_mutex_unlock(&p->auxMutex);
+        break;
+      }else{
         pthread_mutex_unlock(&p->auxMutex);
         pthread_mutex_lock(&p->mainMutex);
         pthread_mutex_unlock(&p->mainMutex);
index 872a0f26e7faf969ad526938730918aec6dabe9c..8492399d2ebe3d4bffe1d2c0aa2577c824a81c8c 100644 (file)
@@ -30,7 +30,7 @@
 ** the version number) and changes its name to "sqlite3.h" as
 ** part of the build process.
 **
-** @(#) $Id: sqlite.h.in,v 1.226 2007/08/16 19:40:17 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.227 2007/08/17 01:14:38 drh Exp $
 */
 #ifndef _SQLITE3_H_
 #define _SQLITE3_H_
@@ -2175,6 +2175,9 @@ int sqlite3_global_recover(void);
 ** [sqlite3_value_text16()] can be invalidated by a subsequent call to
 ** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
 ** or [sqlite3_value_text16()].  
+**
+** These routines must be called from the same thread as
+** the SQL function that supplied the sqlite3_value* parameters.
 */
 const void *sqlite3_value_blob(sqlite3_value*);
 int sqlite3_value_bytes(sqlite3_value*);
@@ -2206,6 +2209,9 @@ int sqlite3_value_numeric_type(sqlite3_value*);
 ** [sqlite3_context | SQL function context] that is the first
 ** parameter to the callback routine that implements the aggregate
 ** function.
+**
+** This routine must be called from the same thread in which
+** the aggregate SQL function was originally invoked.
 */
 void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
 
@@ -2216,6 +2222,9 @@ void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
 ** and [sqlite3_create_function16()] routines
 ** used to register user functions is available to
 ** the implementation of the function using this call.
+**
+** This routine must be called from the same thread in which
+** the SQL function was originally invoked.
 */
 void *sqlite3_user_data(sqlite3_context*);
 
@@ -2248,6 +2257,9 @@ void *sqlite3_user_data(sqlite3_context*);
 ** In practice, meta-data is preserved between function calls for
 ** expressions that are constant at compile time. This includes literal
 ** values and SQL variables.
+**
+** These routine must be called from the same thread in which
+** the SQL function was originally invoked.
 */
 void *sqlite3_get_auxdata(sqlite3_context*, int);
 void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
@@ -2294,6 +2306,9 @@ typedef void (*sqlite3_destructor_type)(void*);
 ** The sqlite3_result_toobig() cause the function implementation
 ** to throw and error indicating that a string or BLOB is to long
 ** to represent.
+**
+** These routines must be called from within the same thread as
+** the SQL function associated with the [sqlite3_context] pointer.
 */
 void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
 void sqlite3_result_double(sqlite3_context*, double);
@@ -3234,8 +3249,9 @@ int sqlite3_unregister_vfs(sqlite3_vfs*);
 ** The sqlite3_mutex_free() routine deallocates a previously
 ** allocated dynamic mutex.  SQLite is careful to deallocate every
 ** dynamic mutex that it allocates.  The dynamic mutexes must not be in 
-** use when they are deallocated.  Static mutexes do not need to be
-** deallocated and SQLite never bothers to do so.
+** use when they are deallocated.  Attempting to deallocate a static
+** mutex results in undefined behavior.  SQLite never deallocates
+** a static mutex.
 **
 ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
 ** to enter a mutex.  If another thread is already within the mutex,
index 716df8c97cfb8e6220395cc35f7794d3f6fb2796..7a7238320d9bc456e9593a4650f1f73472eedef9 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.589 2007/08/16 13:01:45 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.590 2007/08/17 01:14:38 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -399,6 +399,7 @@ struct sqlite3 {
   int magic;                    /* Magic number for detect library misuse */
   int nChange;                  /* Value returned by sqlite3_changes() */
   int nTotalChange;             /* Value returned by sqlite3_total_changes() */
+  sqlite3_mutex *pMutex;        /* Connection mutex */
   struct sqlite3InitInfo {      /* Information used during initialization */
     int iDb;                    /* When back is being initialized */
     int newTnum;                /* Rootpage of table being initialized */
index 791fa9c02c3634bae5a6517e55f826a2f38b9e6a..599ef2fac6570f98ae658605445a76081f0944a0 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.262 2007/08/16 13:01:45 drh Exp $
+** $Id: test1.c,v 1.263 2007/08/17 01:14:38 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -1312,6 +1312,7 @@ static int test_enable_shared(
   int rc;
   int enable;
   int ret = 0;
+  extern int sqlite3SharedCacheEnabled;
 
   if( objc!=2 ){
     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
@@ -1320,7 +1321,7 @@ static int test_enable_shared(
   if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ){
     return TCL_ERROR;
   }
-  ret = sqlite3ThreadDataReadOnly()->useSharedData;
+  ret = sqlite3SharedCacheEnabled;
   rc = sqlite3_enable_shared_cache(enable);
   if( rc!=SQLITE_OK ){
     Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC);
index ef9eb35cba1f0f0eae6c5f10e7a8e5ded4e845c4..3647a5b0ba35e9351398d36cf6f2f5fd5eb5ff00 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test_btree.c,v 1.2 2007/05/08 11:27:16 drh Exp $
+** $Id: test_btree.c,v 1.3 2007/08/17 01:14:39 drh Exp $
 */
 #include "btreeInt.h"
 #include <tcl.h>
@@ -140,17 +140,15 @@ int sqlite3BtreeSharedCacheReport(
   Tcl_Obj *CONST objv[]
 ){
 #ifndef SQLITE_OMIT_SHARED_CACHE
-  const ThreadData *pTd = sqlite3ThreadDataReadOnly();
-  if( pTd->useSharedData ){
-    BtShared *pBt;
-    Tcl_Obj *pRet = Tcl_NewObj();
-    for(pBt=pTd->pBtree; pBt; pBt=pBt->pNext){
-      const char *zFile = sqlite3PagerFilename(pBt->pPager);
-      Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1));
-      Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef));
-    }
-    Tcl_SetObjResult(interp, pRet);
+  extern BtShared *sqlite3SharedCacheList;
+  BtShared *pBt;
+  Tcl_Obj *pRet = Tcl_NewObj();
+  for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){
+    const char *zFile = sqlite3PagerFilename(pBt->pPager);
+    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1));
+    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef));
   }
+  Tcl_SetObjResult(interp, pRet);
 #endif
   return TCL_OK;
 }
index 2f305acca087e394ba0b567b91d1416d127bb6ca..29dbc3aa9c7ad385851e2dab455228f25064a3c3 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to help implement virtual tables.
 **
-** $Id: vtab.c,v 1.50 2007/08/16 10:09:03 danielk1977 Exp $
+** $Id: vtab.c,v 1.51 2007/08/17 01:14:39 drh Exp $
 */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 #include "sqliteInt.h"
@@ -162,7 +162,7 @@ void sqlite3VtabBeginParse(
   Table *pTable;        /* The new virtual table */
   sqlite3 *db;          /* Database connection */
 
-#ifndef SQLITE_OMIT_SHARED_CACHE
+#if 0 /* FIX ME */
   if( sqlite3ThreadDataReadOnly()->useSharedData ){
     sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode");
     return;