aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2010-05-13 08:53:41 +0000
committerdrh <drh@noemail.net>2010-05-13 08:53:41 +0000
commit043c20e63e7c075e85ef554fdf7bbba5cd9c0ea7 (patch)
tree51961f4f4d2f98d34248b8c4722f7d36d7e8c37e
parenteaf52d883a9eafbe7ad60bd7590988c66d696c07 (diff)
parenta925fd256b74e5da9c6320849c3b7d85110ce73f (diff)
downloadsqlite-043c20e63e7c075e85ef554fdf7bbba5cd9c0ea7.tar.gz
sqlite-043c20e63e7c075e85ef554fdf7bbba5cd9c0ea7.zip
The refactored of VFS SHM primitives are now working so merge the
wal-refactor branch back into the trunk. FossilOrigin-Name: bce21c18380715e894eac9c173c97315e0d69d93
-rw-r--r--doc/vfs-shm.txt18
-rw-r--r--manifest44
-rw-r--r--manifest.uuid2
-rw-r--r--src/os.c18
-rw-r--r--src/os.h6
-rw-r--r--src/os_unix.c1650
-rw-r--r--src/pager.c24
-rw-r--r--src/pager.h1
-rw-r--r--src/sqlite.h.in15
-rw-r--r--src/test6.c71
-rw-r--r--src/test_devsym.c108
-rw-r--r--src/test_onefile.c19
-rw-r--r--src/test_vfs.c213
-rw-r--r--src/vdbe.c4
-rw-r--r--src/wal.c104
-rw-r--r--src/wal.h5
16 files changed, 1180 insertions, 1122 deletions
diff --git a/doc/vfs-shm.txt b/doc/vfs-shm.txt
index 93ab457cd..c1f125a12 100644
--- a/doc/vfs-shm.txt
+++ b/doc/vfs-shm.txt
@@ -78,14 +78,24 @@ during testing using an instrumented lock manager.
(5) No part of the wal-index will be read without holding either some
kind of SHM lock or an EXCLUSIVE lock on the original database.
+ The original database is the file named in the 2nd parameter to
+ the xShmOpen method.
+
(6) A holder of a READ_FULL will never read any page of the database
file that is contained anywhere in the wal-index.
+
(7) No part of the wal-index other than the header will be written nor
- will the size of the wal-index grow without holding a WRITE.
+ will the size of the wal-index grow without holding a WRITE or
+ an EXCLUSIVE on the original database file.
+
(8) The wal-index header will not be written without holding one of
- WRITE, CHECKPOINT, or RECOVER.
-(9) A CHECKPOINT or RECOVER must be held in order to reset the last valid
- frame counter in the header of the wal-index back to zero.
+ WRITE, CHECKPOINT, or RECOVER on the wal-index or an EXCLUSIVE on
+ the original database files.
+
+(9) A CHECKPOINT or RECOVER must be held on the wal-index, or an
+ EXCLUSIVE on the original database file, in order to reset the
+ last valid frame counter in the header of the wal-index back to zero.
+
(10) A WRITE can only increase the last valid frame pointer in the header.
The SQLite core will only ever send requests for UNLOCK, READ, WRITE,
diff --git a/manifest b/manifest
index fae36ae92..3e20abc84 100644
--- a/manifest
+++ b/manifest
@@ -1,8 +1,8 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
-C Remove\sthe\sOP_Variable\soptimization\sof\scheck-in\s[48b77b04935d894]\ssince\sit\ncan\slead\sto\smalfunctions\sas\sdescribed\sin\sticket\s[26ff0c82d1e90].
-D 2010-05-12T13:50:23
+C The\srefactored\sof\sVFS\sSHM\sprimitives\sare\snow\sworking\sso\smerge\sthe\s\nwal-refactor\sbranch\sback\sinto\sthe\strunk.
+D 2010-05-13T08:53:42
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -27,7 +27,7 @@ F configure.ac 14740970ddb674d92a9f5da89083dff1179014ff
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
F doc/pager-invariants.txt 870107036470d7c419e93768676fae2f8749cf9e
-F doc/vfs-shm.txt 7945d691a41ec90f358f6415095ffe70cfc9fe9e
+F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1
F ext/async/README.txt 0c541f418b14b415212264cbaaf51c924ec62e5b
F ext/async/sqlite3async.c 676066c2a111a8b3107aeb59bdbbbf335c348f4a
@@ -151,14 +151,14 @@ F src/mutex_os2.c 20477db50cf3817c2f1cd3eb61e5c177e50231db
F src/mutex_unix.c 04a25238abce7e3d06b358dcf706e26624270809
F src/mutex_w32.c 4cc201c1bfd11d1562810554ff5500e735559d7e
F src/notify.c cbfa66a836da3a51567209636e6a94059c137930
-F src/os.c aec6922553585a25d5655666defc125a7e217674
-F src/os.h b389844e5469a2918e8a45fe6ae52b4c28dfb2b2
+F src/os.c c0a5dfce2a214dacb679425632d04f8a2021f364
+F src/os.h 8a7e2456237ecf3a2e55b02f9fe6091f1ad36902
F src/os_common.h 0d6ee583b6ee3185eb9d951f890c6dd03021a08d
F src/os_os2.c 8ad77a418630d7dee91d1bb04f79c2096301d3a0
-F src/os_unix.c c306feb1be41283afc47f1da74363d2bde466aae
+F src/os_unix.c a65eb0c527306fbf8d5818c068cccb4179e2c187
F src/os_win.c a8fc01d8483be472e495793c01064fd87e56a5c1
-F src/pager.c ad9cb3bea70d8b159de1a9b235c94c7abc340956
-F src/pager.h 934b598583a9d936bb13c37d62a2fe68ac48781c
+F src/pager.c 1e163a82ae8405433dca559831caa06aafbba3b0
+F src/pager.h 76466c3a5af56943537f68b1f16567101a0cd1d0
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
@@ -171,7 +171,7 @@ F src/resolve.c ac5f1a713cd1ae77f08b83cc69581e11bf5ae6f9
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
-F src/sqlite.h.in aa54957165356be128b9c8baf3fc66592cb2da7f
+F src/sqlite.h.in a86bb87f5c9e97ed286a70d515d6c19de031f382
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
F src/sqliteInt.h 9819b45610abeca390176243a9a31758c1f0ac7a
F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
@@ -183,7 +183,7 @@ F src/test2.c 31f1b9d076b4774a22d2605d0af1f34e14a9a7bd
F src/test3.c 4c21700c73a890a47fc685c1097bfb661346ac94
F src/test4.c ad03bb987ddedce928f4258c1e7fa4109a73497d
F src/test5.c cc55900118fa4add8ec9cf69fc4225a4662f76b1
-F src/test6.c 8b9eedc2fee0850636797bcd30a9dd740b449cd7
+F src/test6.c d00c3930e2d22a9dc84415b1a2ead2ca4ab430ae
F src/test7.c 3f2d63e4ccf97f8c2cf1a7fa0a3c8e2e2a354e6e
F src/test8.c f959db9a22d882013b64c92753fa793b2ce3bdea
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
@@ -193,7 +193,7 @@ F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
F src/test_config.c 6210f501d358bde619ae761f06f123529c6ba24f
F src/test_demovfs.c da81a5f7785bb352bda7911c332a983ec4f17f27
-F src/test_devsym.c 257adf02150986902f1f15b478f8a319ecfce7f3
+F src/test_devsym.c 136869028132c3dc34fe920a9fda716f391227f4
F src/test_func.c 13b582345fb1185a93e46c53310fae8547dcce20
F src/test_hexio.c 1237f000ec7a491009b1233f5c626ea71bce1ea2
F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c
@@ -203,14 +203,14 @@ F src/test_journal.c 51da4dd6118ee843349592fde29429fab84a6243
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
F src/test_malloc.c 2842c922b8e8d992aba722214952204ca025b411
F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
-F src/test_onefile.c d9585f6e2056868f208b0c21378a05b68c9ceae2
+F src/test_onefile.c df4d7858b5cd1dffe92d36ec9dbad11f0037ffd1
F src/test_osinst.c f5d1a4ee8b80fc58d1430c56146de748584013a9
F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
-F src/test_vfs.c c1e13b5f787042130878996f31827ffb5d4d8efc
+F src/test_vfs.c 3601f9b6d46cb6daf0697d60c76bf8e18b90b123
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
@@ -218,7 +218,7 @@ F src/update.c c0dc6b75ad28b76b619042d934f337b02acee208
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
F src/vacuum.c b17355fc10cef0875626932ec2f1fa1deb0daa48
-F src/vdbe.c f41188f624dccabf9f1fd1cb6af57314857e9dd2
+F src/vdbe.c 8c6301a7dd844d2d6370ebd46f4e2d0cf449c2de
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d
@@ -227,8 +227,8 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
-F src/wal.c 2f747b6a6bfd9b75b837a1e31176235a21342e0f
-F src/wal.h 32f36b2a827b78373658dac5521291485dfa52b6
+F src/wal.c 3806c5ed7047debc408665b3576f17bab05b2be6
+F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -817,14 +817,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P c501b2ede6aad123bef0aa7ce8b356a134eb6d26
-R f34b360b99a8eca6d2a66ca5009c7cf8
+P 7838163d087780a6fb403a17641b96f71baec088 149d2ae4a6fe2f86822f286d2a7092c51bec7ebb
+R 8a7d44076bf0e05c11800be3998eddd6
U drh
-Z ec71604d99e1c3eded3bf24db26ac01b
+Z ffd3a6c6136965defa15e38ab4e7a314
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
-iD8DBQFL6rIioxKgR168RlERArxoAJ96khmiBmpRdJSt374I6oMPRFYeDgCeJaEi
-RMst0QQ2MlMNKv1/iZMvQcE=
-=vEcN
+iD8DBQFL674ZoxKgR168RlERAsK5AJ4haW8eDmlcRUUp3Yf+C8gRnJAr1gCeNdrT
+0Fo99N7uchNWHAmE6yfdaFc=
+=KgrW
-----END PGP SIGNATURE-----
diff --git a/manifest.uuid b/manifest.uuid
index fc05016e0..80b52dc31 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-7838163d087780a6fb403a17641b96f71baec088 \ No newline at end of file
+bce21c18380715e894eac9c173c97315e0d69d93 \ No newline at end of file
diff --git a/src/os.c b/src/os.c
index b3e870034..9ad13690c 100644
--- a/src/os.c
+++ b/src/os.c
@@ -98,6 +98,24 @@ int sqlite3OsSectorSize(sqlite3_file *id){
int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
return id->pMethods->xDeviceCharacteristics(id);
}
+int sqlite3OsShmOpen(sqlite3_file *id){
+ return id->pMethods->xShmOpen(id);
+}
+int sqlite3OsShmSize(sqlite3_file *id, int reqSize, int *pNewSize){
+ return id->pMethods->xShmSize(id, reqSize, pNewSize);
+}
+int sqlite3OsShmGet(sqlite3_file *id, int reqSize, int *pSize, void **pp){
+ return id->pMethods->xShmGet(id, reqSize, pSize, pp);
+}
+int sqlite3OsShmRelease(sqlite3_file *id){
+ return id->pMethods->xShmRelease(id);
+}
+int sqlite3OsShmLock(sqlite3_file *id, int desiredLock, int *pGotLock){
+ return id->pMethods->xShmLock(id, desiredLock, pGotLock);
+}
+int sqlite3OsShmClose(sqlite3_file *id, int deleteFlag){
+ return id->pMethods->xShmClose(id, deleteFlag);
+}
/*
** The next group of routines are convenience wrappers around the
diff --git a/src/os.h b/src/os.h
index 7b2bff0dc..cf7f2b7d7 100644
--- a/src/os.h
+++ b/src/os.h
@@ -243,6 +243,12 @@ int sqlite3OsFileControl(sqlite3_file*,int,void*);
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
int sqlite3OsSectorSize(sqlite3_file *id);
int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+int sqlite3OsShmOpen(sqlite3_file *id);
+int sqlite3OsShmSize(sqlite3_file *id, int, int*);
+int sqlite3OsShmGet(sqlite3_file *id, int, int*, void**);
+int sqlite3OsShmRelease(sqlite3_file *id);
+int sqlite3OsShmLock(sqlite3_file *id, int, int*);
+int sqlite3OsShmClose(sqlite3_file *id, int);
/*
** Functions for accessing sqlite3_vfs methods
diff --git a/src/os_unix.c b/src/os_unix.c
index 50bacfbf7..4ddff190a 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -175,6 +175,9 @@
*/
#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY))
+/* Forward reference */
+typedef struct unixShm unixShm;
+typedef struct unixShmFile unixShmFile;
/*
** Sometimes, after a file handle is closed by SQLite, the file descriptor
@@ -205,6 +208,8 @@ struct unixFile {
void *lockingContext; /* Locking style specific state */
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
int fileFlags; /* Miscellanous flags */
+ const char *zPath; /* Name of the file */
+ unixShm *pShm; /* Shared memory segment information */
#if SQLITE_ENABLE_LOCKING_STYLE
int openFlags; /* The flags specified at open() */
#endif
@@ -3400,6 +3405,817 @@ static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
return 0;
}
+#ifndef SQLITE_OMIT_WAL
+
+
+/*
+** Object used to represent a single file opened and mmapped to provide
+** shared memory. When multiple threads all reference the same
+** log-summary, each thread has its own unixFile object, but they all
+** point to a single instance of this object. In other words, each
+** log-summary is opened only once per process.
+**
+** unixMutexHeld() must be true when creating or destroying
+** this object or while reading or writing the following fields:
+**
+** nRef
+** pNext
+**
+** The following fields are read-only after the object is created:
+**
+** fid
+** zFilename
+**
+** Either unixShmFile.mutex must be held or unixShmFile.nRef==0 and
+** unixMutexHeld() is true when reading or writing any other field
+** in this structure.
+**
+** To avoid deadlocks, mutex and mutexBuf are always released in the
+** reverse order that they are acquired. mutexBuf is always acquired
+** first and released last. This invariant is check by asserting
+** sqlite3_mutex_notheld() on mutex whenever mutexBuf is acquired or
+** released.
+*/
+struct unixShmFile {
+ struct unixFileId fid; /* Unique file identifier */
+ sqlite3_mutex *mutex; /* Mutex to access this object */
+ sqlite3_mutex *mutexBuf; /* Mutex to access zBuf[] */
+ char *zFilename; /* Name of the mmapped file */
+ int h; /* Open file descriptor */
+ int szMap; /* Size of the mapping of file into memory */
+ char *pMMapBuf; /* Where currently mmapped(). NULL if unmapped */
+ int nRef; /* Number of unixShm objects pointing to this */
+ unixShm *pFirst; /* All unixShm objects pointing to this */
+ unixShmFile *pNext; /* Next in list of all unixShmFile objects */
+#ifdef SQLITE_DEBUG
+ u8 exclMask; /* Mask of exclusive locks held */
+ u8 sharedMask; /* Mask of shared locks held */
+ u8 nextShmId; /* Next available unixShm.id value */
+#endif
+};
+
+/*
+** A global array of all unixShmFile objects.
+**
+** The unixMutexHeld() must be true while reading or writing this list.
+*/
+static unixShmFile *unixShmFileList = 0;
+
+/*
+** Structure used internally by this VFS to record the state of an
+** open shared memory connection.
+**
+** unixShm.pFile->mutex must be held while reading or writing the
+** unixShm.pNext and unixShm.locks[] elements.
+**
+** The unixShm.pFile element is initialized when the object is created
+** and is read-only thereafter.
+*/
+struct unixShm {
+ unixShmFile *pFile; /* The underlying unixShmFile object */
+ unixShm *pNext; /* Next unixShm with the same unixShmFile */
+ u8 lockState; /* Current lock state */
+ u8 hasMutex; /* True if holding the unixShmFile mutex */
+ u8 hasMutexBuf; /* True if holding pFile->mutexBuf */
+ u8 sharedMask; /* Mask of shared locks held */
+ u8 exclMask; /* Mask of exclusive locks held */
+#ifdef SQLITE_DEBUG
+ u8 id; /* Id of this connection with its unixShmFile */
+#endif
+};
+
+/*
+** Size increment by which shared memory grows
+*/
+#define SQLITE_UNIX_SHM_INCR 4096
+
+/*
+** Constants used for locking
+*/
+#define UNIX_SHM_BASE 32 /* Byte offset of the first lock byte */
+#define UNIX_SHM_DMS 0x01 /* Mask for Dead-Man-Switch lock */
+#define UNIX_SHM_A 0x10 /* Mask for region locks... */
+#define UNIX_SHM_B 0x20
+#define UNIX_SHM_C 0x40
+#define UNIX_SHM_D 0x80
+
+#ifdef SQLITE_DEBUG
+/*
+** Return a pointer to a nul-terminated string in static memory that
+** describes a locking mask. The string is of the form "MSABCD" with
+** each character representing a lock. "M" for MUTEX, "S" for DMS,
+** and "A" through "D" for the region locks. If a lock is held, the
+** letter is shown. If the lock is not held, the letter is converted
+** to ".".
+**
+** This routine is for debugging purposes only and does not appear
+** in a production build.
+*/
+static const char *unixShmLockString(u8 mask){
+ static char zBuf[48];
+ static int iBuf = 0;
+ char *z;
+
+ z = &zBuf[iBuf];
+ iBuf += 8;
+ if( iBuf>=sizeof(zBuf) ) iBuf = 0;
+
+ z[0] = (mask & UNIX_SHM_DMS) ? 'S' : '.';
+ z[1] = (mask & UNIX_SHM_A) ? 'A' : '.';
+ z[2] = (mask & UNIX_SHM_B) ? 'B' : '.';
+ z[3] = (mask & UNIX_SHM_C) ? 'C' : '.';
+ z[4] = (mask & UNIX_SHM_D) ? 'D' : '.';
+ z[5] = 0;
+ return z;
+}
+#endif /* SQLITE_DEBUG */
+
+/*
+** Apply posix advisory locks for all bytes identified in lockMask.
+**
+** lockMask might contain multiple bits but all bits are guaranteed
+** to be contiguous.
+**
+** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking
+** otherwise.
+*/
+static int unixShmSystemLock(
+ unixShmFile *pFile, /* Apply locks to this open shared-memory segment */
+ int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */
+ u8 lockMask /* Which bytes to lock or unlock */
+){
+ struct flock f; /* The posix advisory locking structure */
+ int lockOp; /* The opcode for fcntl() */
+ int i; /* Offset into the locking byte range */
+ int rc; /* Result code form fcntl() */
+ u8 mask; /* Mask of bits in lockMask */
+
+ /* Access to the unixShmFile object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
+
+ /* Initialize the locking parameters */
+ memset(&f, 0, sizeof(f));
+ f.l_type = lockType;
+ f.l_whence = SEEK_SET;
+ if( lockMask==UNIX_SHM_C && lockType!=F_UNLCK ){
+ lockOp = F_SETLKW;
+ OSTRACE(("SHM-LOCK requesting blocking lock\n"));
+ }else{
+ lockOp = F_SETLK;
+ }
+
+ /* Find the first bit in lockMask that is set */
+ for(i=0, mask=0x01; mask!=0 && (lockMask&mask)==0; mask <<= 1, i++){}
+ assert( mask!=0 );
+ f.l_start = i+UNIX_SHM_BASE;
+ f.l_len = 1;
+
+ /* Extend the locking range for each additional bit that is set */
+ mask <<= 1;
+ while( mask!=0 && (lockMask & mask)!=0 ){
+ f.l_len++;
+ mask <<= 1;
+ }
+
+ /* Verify that all bits set in lockMask are contiguous */
+ assert( mask==0 || (lockMask & ~(mask | (mask-1)))==0 );
+
+ /* Acquire the system-level lock */
+ rc = fcntl(pFile->h, lockOp, &f);
+ rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+
+ /* Update the global lock state and do debug tracing */
+#ifdef SQLITE_DEBUG
+ OSTRACE(("SHM-LOCK "));
+ if( rc==SQLITE_OK ){
+ if( lockType==F_UNLCK ){
+ OSTRACE(("unlock ok"));
+ pFile->exclMask &= ~lockMask;
+ pFile->sharedMask &= ~lockMask;
+ }else if( lockType==F_RDLCK ){
+ OSTRACE(("read-lock ok"));
+ pFile->exclMask &= ~lockMask;
+ pFile->sharedMask |= lockMask;
+ }else{
+ assert( lockType==F_WRLCK );
+ OSTRACE(("write-lock ok"));
+ pFile->exclMask |= lockMask;
+ pFile->sharedMask &= ~lockMask;
+ }
+ }else{
+ if( lockType==F_UNLCK ){
+ OSTRACE(("unlock failed"));
+ }else if( lockType==F_RDLCK ){
+ OSTRACE(("read-lock failed"));
+ }else{
+ assert( lockType==F_WRLCK );
+ OSTRACE(("write-lock failed"));
+ }
+ }
+ OSTRACE((" - change requested %s - afterwards %s:%s\n",
+ unixShmLockString(lockMask),
+ unixShmLockString(pFile->sharedMask),
+ unixShmLockString(pFile->exclMask)));
+#endif
+
+ return rc;
+}
+
+/*
+** For connection p, unlock all of the locks identified by the unlockMask
+** parameter.
+*/
+static int unixShmUnlock(
+ unixShmFile *pFile, /* The underlying shared-memory file */
+ unixShm *p, /* The connection to be unlocked */
+ u8 unlockMask /* Mask of locks to be unlocked */
+){
+ int rc; /* Result code */
+ unixShm *pX; /* For looping over all sibling connections */
+ u8 allMask; /* Union of locks held by connections other than "p" */
+
+ /* Access to the unixShmFile object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) );
+
+ /* Compute locks held by sibling connections */
+ allMask = 0;
+ for(pX=pFile->pFirst; pX; pX=pX->pNext){
+ if( pX==p ) continue;
+ assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
+ allMask |= pX->sharedMask;
+ }
+
+ /* Unlock the system-level locks */
+ if( (unlockMask & allMask)!=unlockMask ){
+ rc = unixShmSystemLock(pFile, F_UNLCK, unlockMask & ~allMask);
+ }else{
+ rc = SQLITE_OK;
+ }
+
+ /* Undo the local locks */
+ if( rc==SQLITE_OK ){
+ p->exclMask &= ~unlockMask;
+ p->sharedMask &= ~unlockMask;
+ }
+ return rc;
+}
+
+/*
+** Get reader locks for connection p on all locks in the readMask parameter.
+*/
+static int unixShmSharedLock(
+ unixShmFile *pFile, /* The underlying shared-memory file */
+ unixShm *p, /* The connection to get the shared locks */
+ u8 readMask /* Mask of shared locks to be acquired */
+){
+ int rc; /* Result code */
+ unixShm *pX; /* For looping over all sibling connections */
+ u8 allShared; /* Union of locks held by connections other than "p" */
+
+ /* Access to the unixShmFile object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) );
+
+ /* Find out which shared locks are already held by sibling connections.
+ ** If any sibling already holds an exclusive lock, go ahead and return
+ ** SQLITE_BUSY.
+ */
+ allShared = 0;
+ for(pX=pFile->pFirst; pX; pX=pX->pNext){
+ if( pX==p ) continue;
+ if( (pX->exclMask & readMask)!=0 ) return SQLITE_BUSY;
+ allShared |= pX->sharedMask;
+ }
+
+ /* Get shared locks at the system level, if necessary */
+ if( (~allShared) & readMask ){
+ rc = unixShmSystemLock(pFile, F_RDLCK, readMask);
+ }else{
+ rc = SQLITE_OK;
+ }
+
+ /* Get the local shared locks */
+ if( rc==SQLITE_OK ){
+ p->sharedMask |= readMask;
+ }
+ return rc;
+}
+
+/*
+** For connection p, get an exclusive lock on all locks identified in
+** the writeMask parameter.
+*/
+static int unixShmExclusiveLock(
+ unixShmFile *pFile, /* The underlying shared-memory file */
+ unixShm *p, /* The connection to get the exclusive locks */
+ u8 writeMask /* Mask of exclusive locks to be acquired */
+){
+ int rc; /* Result code */
+ unixShm *pX; /* For looping over all sibling connections */
+
+ /* Access to the unixShmFile object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) );
+
+ /* Make sure no sibling connections hold locks that will block this
+ ** lock. If any do, return SQLITE_BUSY right away.
+ */
+ for(pX=pFile->pFirst; pX; pX=pX->pNext){
+ if( pX==p ) continue;
+ if( (pX->exclMask & writeMask)!=0 ) return SQLITE_BUSY;
+ if( (pX->sharedMask & writeMask)!=0 ) return SQLITE_BUSY;
+ }
+
+ /* Get the exclusive locks at the system level. Then if successful
+ ** also mark the local connection as being locked.
+ */
+ rc = unixShmSystemLock(pFile, F_WRLCK, writeMask);
+ if( rc==SQLITE_OK ){
+ p->sharedMask &= ~writeMask;
+ p->exclMask |= writeMask;
+ }
+ return rc;
+}
+
+/*
+** Purge the unixShmFileList list of all entries with unixShmFile.nRef==0.
+**
+** This is not a VFS shared-memory method; it is a utility function called
+** by VFS shared-memory methods.
+*/
+static void unixShmPurge(void){
+ unixShmFile **pp;
+ unixShmFile *p;
+ assert( unixMutexHeld() );
+ pp = &unixShmFileList;
+ while( (p = *pp)!=0 ){
+ if( p->nRef==0 ){
+ if( p->mutex ) sqlite3_mutex_free(p->mutex);
+ if( p->mutexBuf ) sqlite3_mutex_free(p->mutexBuf);
+ if( p->h>=0 ) close(p->h);
+ *pp = p->pNext;
+ sqlite3_free(p);
+ }else{
+ pp = &p->pNext;
+ }
+ }
+}
+
+/*
+** Open a shared-memory area. This particular implementation uses
+** mmapped files.
+**
+** zName is a filename used to identify the shared-memory area. The
+** implementation does not (and perhaps should not) use this name
+** directly, but rather use it as a template for finding an appropriate
+** name for the shared-memory storage. In this implementation, the
+** string "-index" is appended to zName and used as the name of the
+** mmapped file.
+**
+** When opening a new shared-memory file, if no other instances of that
+** file are currently open, in this process or in other processes, then
+** the file must be truncated to zero length or have its header cleared.
+*/
+static int unixShmOpen(
+ sqlite3_file *fd /* The file descriptor of the associated database */
+){
+ struct unixShm *p = 0; /* The connection to be opened */
+ struct unixShmFile *pFile = 0; /* The underlying mmapped file */
+ int rc; /* Result code */
+ struct unixFileId fid; /* Unix file identifier */
+ struct unixShmFile *pNew; /* Newly allocated pFile */
+ struct stat sStat; /* Result from stat() an fstat() */
+ struct unixFile *pDbFd; /* Underlying database file */
+ int nPath; /* Size of pDbFd->zPath in bytes */
+
+ /* Allocate space for the new sqlite3_shm object. Also speculatively
+ ** allocate space for a new unixShmFile and filename.
+ */
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) return SQLITE_NOMEM;
+ memset(p, 0, sizeof(*p));
+ pDbFd = (struct unixFile*)fd;
+ assert( pDbFd->pShm==0 );
+ nPath = strlen(pDbFd->zPath);
+ pNew = sqlite3_malloc( sizeof(*pFile) + nPath + 15 );
+ if( pNew==0 ){
+ sqlite3_free(p);
+ return SQLITE_NOMEM;
+ }
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->zFilename = (char*)&pNew[1];
+ sqlite3_snprintf(nPath+15, pNew->zFilename, "%s-wal-index", pDbFd->zPath);
+
+ /* Look to see if there is an existing unixShmFile that can be used.
+ ** If no matching unixShmFile currently exists, create a new one.
+ */
+ unixEnterMutex();
+ rc = stat(pNew->zFilename, &sStat);
+ if( rc==0 ){
+ memset(&fid, 0, sizeof(fid));
+ fid.dev = sStat.st_dev;
+ fid.ino = sStat.st_ino;
+ for(pFile = unixShmFileList; pFile; pFile=pFile->pNext){
+ if( memcmp(&pFile->fid, &fid, sizeof(fid))==0 ) break;
+ }
+ }
+ if( pFile ){
+ sqlite3_free(pNew);
+ }else{
+ pFile = pNew;
+ pNew = 0;
+ pFile->h = -1;
+ pFile->pNext = unixShmFileList;
+ unixShmFileList = pFile;
+
+ pFile->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pFile->mutex==0 ){
+ rc = SQLITE_NOMEM;
+ goto shm_open_err;
+ }
+ pFile->mutexBuf = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pFile->mutexBuf==0 ){
+ rc = SQLITE_NOMEM;
+ goto shm_open_err;
+ }
+
+ pFile->h = open(pFile->zFilename, O_RDWR|O_CREAT, 0664);
+ if( pFile->h<0 ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto shm_open_err;
+ }
+
+ rc = fstat(pFile->h, &sStat);
+ if( rc ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto shm_open_err;
+ }
+ pFile->fid.dev = sStat.st_dev;
+ pFile->fid.ino = sStat.st_ino;
+
+ /* Check to see if another process is holding the dead-man switch.
+ ** If not, truncate the file to zero length.
+ */
+ if( unixShmSystemLock(pFile, F_WRLCK, UNIX_SHM_DMS)==SQLITE_OK ){
+ if( ftruncate(pFile->h, 0) ){
+ rc = SQLITE_IOERR;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ rc = unixShmSystemLock(pFile, F_RDLCK, UNIX_SHM_DMS);
+ }
+ if( rc ) goto shm_open_err;
+ }
+
+ /* Make the new connection a child of the unixShmFile */
+ p->pFile = pFile;
+ p->pNext = pFile->pFirst;
+#ifdef SQLITE_DEBUG
+ p->id = pFile->nextShmId++;
+#endif
+ pFile->pFirst = p;
+ pFile->nRef++;
+ pDbFd->pShm = p;
+ unixLeaveMutex();
+ return SQLITE_OK;
+
+ /* Jump here on any error */
+shm_open_err:
+ unixShmPurge(); /* This call frees pFile if required */
+ sqlite3_free(p);
+ sqlite3_free(pNew);
+ unixLeaveMutex();
+ return rc;
+}
+
+/*
+** Close a connection to shared-memory. Delete the underlying
+** storage if deleteFlag is true.
+*/
+static int unixShmClose(
+ sqlite3_file *fd, /* The underlying database file */
+ int deleteFlag /* Delete shared-memory if true */
+){
+ unixShm *p; /* The connection to be closed */
+ unixShmFile *pFile; /* The underlying shared-memory file */
+ unixShm **pp; /* For looping over sibling connections */
+ unixFile *pDbFd; /* The underlying database file */
+
+ pDbFd = (unixFile*)fd;
+ p = pDbFd->pShm;
+ if( p==0 ) return SQLITE_OK;
+ pFile = p->pFile;
+
+ /* Verify that the connection being closed holds no locks */
+ assert( p->exclMask==0 );
+ assert( p->sharedMask==0 );
+
+ /* Remove connection p from the set of connections associated with pFile */
+ sqlite3_mutex_enter(pFile->mutex);
+ for(pp=&pFile->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
+ *pp = p->pNext;
+
+ /* Free the connection p */
+ sqlite3_free(p);
+ pDbFd->pShm = 0;
+ sqlite3_mutex_leave(pFile->mutex);
+
+ /* If pFile->nRef has reached 0, then close the underlying
+ ** shared-memory file, too */
+ unixEnterMutex();
+ assert( pFile->nRef>0 );
+ pFile->nRef--;
+ if( pFile->nRef==0 ){
+ if( deleteFlag ) unlink(pFile->zFilename);
+ unixShmPurge();
+ }
+ unixLeaveMutex();
+
+ return SQLITE_OK;
+}
+
+/*
+** Query and/or changes the size of the underlying storage for
+** a shared-memory segment. The reqSize parameter is the new size
+** of the underlying storage, or -1 to do just a query. The size
+** of the underlying storage (after resizing if resizing occurs) is
+** written into pNewSize.
+**
+** This routine does not (necessarily) change the size of the mapping
+** of the underlying storage into memory. Use xShmGet() to change
+** the mapping size.
+**
+** The reqSize parameter is the minimum size requested. The implementation
+** is free to expand the storage to some larger amount if it chooses.
+*/
+static int unixShmSize(
+ sqlite3_file *fd, /* The open database file holding SHM */
+ int reqSize, /* Requested size. -1 for query only */
+ int *pNewSize /* Write new size here */
+){
+ unixFile *pDbFd = (unixFile*)fd;
+ unixShm *p = pDbFd->pShm;
+ unixShmFile *pFile = p->pFile;
+ int rc = SQLITE_OK;
+ struct stat sStat;
+
+ /* On a query, this loop runs once. When reqSize>=0, the loop potentially
+ ** runs twice, except if the actual size is already greater than or equal
+ ** to the requested size, reqSize is set to -1 on the first iteration and
+ ** the loop only runs once.
+ */
+ while( 1 ){
+ if( fstat(pFile->h, &sStat)==0 ){
+ *pNewSize = (int)sStat.st_size;
+ if( reqSize>=0 && reqSize<=(int)sStat.st_size ) break;
+ }else{
+ *pNewSize = 0;
+ rc = SQLITE_IOERR;
+ break;
+ }
+ if( reqSize<0 ) break;
+ reqSize = (reqSize + SQLITE_UNIX_SHM_INCR - 1)/SQLITE_UNIX_SHM_INCR;
+ reqSize *= SQLITE_UNIX_SHM_INCR;
+ rc = ftruncate(pFile->h, reqSize);
+ reqSize = -1;
+ }
+ return rc;
+}
+
+
+/*
+** Map the shared storage into memory. The minimum size of the
+** mapping should be reqMapSize if reqMapSize is positive. If
+** reqMapSize is zero or negative, the implementation can choose
+** whatever mapping size is convenient.
+**
+** *ppBuf is made to point to the memory which is a mapping of the
+** underlying storage. A mutex is acquired to prevent other threads
+** from running while *ppBuf is in use in order to prevent other threads
+** remapping *ppBuf out from under this thread. The unixShmRelease()
+** call will release the mutex. However, if the lock state is CHECKPOINT,
+** the mutex is not acquired because CHECKPOINT will never remap the
+** buffer. RECOVER might remap, though, so CHECKPOINT will acquire
+** the mutex if and when it promotes to RECOVER.
+**
+** RECOVER needs to be atomic. The same mutex that prevents *ppBuf from
+** being remapped also prevents more than one thread from being in
+** RECOVER at a time. But, RECOVER sometimes wants to remap itself.
+** To prevent RECOVER from losing its lock while remapping, the
+** mutex is not released by unixShmRelease() when in RECOVER.
+**
+** *pNewMapSize is set to the size of the mapping.
+**
+** *ppBuf and *pNewMapSize might be NULL and zero if no space has
+** yet been allocated to the underlying storage.
+*/
+static int unixShmGet(
+ sqlite3_file *fd, /* Database file holding shared memory */
+ int reqMapSize, /* Requested size of mapping. -1 means don't care */
+ int *pNewMapSize, /* Write new size of mapping here */
+ void **ppBuf /* Write mapping buffer origin here */
+){
+ unixFile *pDbFd = (unixFile*)fd;
+ unixShm *p = pDbFd->pShm;
+ unixShmFile *pFile = p->pFile;
+ int rc = SQLITE_OK;
+
+ if( p->lockState!=SQLITE_SHM_CHECKPOINT && p->hasMutexBuf==0 ){
+ assert( sqlite3_mutex_notheld(pFile->mutex) );
+ sqlite3_mutex_enter(pFile->mutexBuf);
+ p->hasMutexBuf = 1;
+ }
+ sqlite3_mutex_enter(pFile->mutex);
+ if( pFile->szMap==0 || reqMapSize>pFile->szMap ){
+ int actualSize;
+ if( unixShmSize(fd, -1, &actualSize)==SQLITE_OK
+ && reqMapSize<actualSize
+ ){
+ reqMapSize = actualSize;
+ }
+ if( pFile->pMMapBuf ){
+ munmap(pFile->pMMapBuf, pFile->szMap);
+ }
+ pFile->pMMapBuf = mmap(0, reqMapSize, PROT_READ|PROT_WRITE, MAP_SHARED,
+ pFile->h, 0);
+ pFile->szMap = pFile->pMMapBuf ? reqMapSize : 0;
+ }
+ *pNewMapSize = pFile->szMap;
+ *ppBuf = pFile->pMMapBuf;
+ sqlite3_mutex_leave(pFile->mutex);
+ return rc;
+}
+
+/*
+** Release the lock held on the shared memory segment to that other
+** threads are free to resize it if necessary.
+**
+** If the lock is not currently held, this routine is a harmless no-op.
+**
+** If the shared-memory object is in lock state RECOVER, then we do not
+** really want to release the lock, so in that case too, this routine
+** is a no-op.
+*/
+static int unixShmRelease(sqlite3_file *fd){
+ unixFile *pDbFd = (unixFile*)fd;
+ unixShm *p = pDbFd->pShm;
+
+ if( p->hasMutexBuf && p->lockState!=SQLITE_SHM_RECOVER ){
+ assert( sqlite3_mutex_notheld(p->pFile->mutex) );
+ sqlite3_mutex_leave(p->pFile->mutexBuf);
+ p->hasMutexBuf = 0;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Symbolic names for LOCK states used for debugging.
+*/
+#ifdef SQLITE_DEBUG
+static const char *azLkName[] = {
+ "UNLOCK",
+ "READ",
+ "READ_FULL",
+ "WRITE",
+ "PENDING",
+ "CHECKPOINT",
+ "RECOVER"
+};
+#endif
+
+
+/*
+** Change the lock state for a shared-memory segment.
+*/
+static int unixShmLock(
+ sqlite3_file *fd, /* Database file holding the shared memory */
+ int desiredLock, /* One of SQLITE_SHM_xxxxx locking states */
+ int *pGotLock /* The lock you actually got */
+){
+ unixFile *pDbFd = (unixFile*)fd;
+ unixShm *p = pDbFd->pShm;
+ unixShmFile *pFile = p->pFile;
+ int rc = SQLITE_PROTOCOL;
+
+ /* Note that SQLITE_SHM_READ_FULL and SQLITE_SHM_PENDING are never
+ ** directly requested; they are side effects from requesting
+ ** SQLITE_SHM_READ and SQLITE_SHM_CHECKPOINT, respectively.
+ */
+ assert( desiredLock==SQLITE_SHM_UNLOCK
+ || desiredLock==SQLITE_SHM_READ
+ || desiredLock==SQLITE_SHM_WRITE
+ || desiredLock==SQLITE_SHM_CHECKPOINT
+ || desiredLock==SQLITE_SHM_RECOVER );
+
+ /* Return directly if this is just a lock state query, or if
+ ** the connection is already in the desired locking state.
+ */
+ if( desiredLock==p->lockState
+ || (desiredLock==SQLITE_SHM_READ && p->lockState==SQLITE_SHM_READ_FULL)
+ ){
+ OSTRACE(("SHM-LOCK shmid-%d, pid-%d request %s and got %s\n",
+ p->id, getpid(), azLkName[desiredLock], azLkName[p->lockState]));
+ if( pGotLock ) *pGotLock = p->lockState;
+ return SQLITE_OK;
+ }
+
+ OSTRACE(("SHM-LOCK shmid-%d, pid-%d request %s->%s\n",
+ p->id, getpid(), azLkName[p->lockState], azLkName[desiredLock]));
+
+ if( desiredLock==SQLITE_SHM_RECOVER && !p->hasMutexBuf ){
+ assert( sqlite3_mutex_notheld(pFile->mutex) );
+ sqlite3_mutex_enter(pFile->mutexBuf);
+ p->hasMutexBuf = 1;
+ }
+ sqlite3_mutex_enter(pFile->mutex);
+ switch( desiredLock ){
+ case SQLITE_SHM_UNLOCK: {
+ assert( p->lockState!=SQLITE_SHM_RECOVER );
+ unixShmUnlock(pFile, p, UNIX_SHM_A|UNIX_SHM_B|UNIX_SHM_C|UNIX_SHM_D);
+ rc = SQLITE_OK;
+ p->lockState = SQLITE_SHM_UNLOCK;
+ break;
+ }
+ case SQLITE_SHM_READ: {
+ if( p->lockState==SQLITE_SHM_UNLOCK ){
+ int nAttempt;
+ rc = SQLITE_BUSY;
+ assert( p->lockState==SQLITE_SHM_UNLOCK );
+ for(nAttempt=0; nAttempt<5 && rc==SQLITE_BUSY; nAttempt++){
+ rc = unixShmSharedLock(pFile, p, UNIX_SHM_A|UNIX_SHM_B);
+ if( rc==SQLITE_BUSY ){
+ rc = unixShmSharedLock(pFile, p, UNIX_SHM_D);
+ if( rc==SQLITE_OK ){
+ p->lockState = SQLITE_SHM_READ_FULL;
+ }
+ }else{
+ unixShmUnlock(pFile, p, UNIX_SHM_B);
+ p->lockState = SQLITE_SHM_READ;
+ }
+ }
+ }else{
+ assert( p->lockState==SQLITE_SHM_WRITE
+ || p->lockState==SQLITE_SHM_RECOVER );
+ rc = unixShmSharedLock(pFile, p, UNIX_SHM_A);
+ unixShmUnlock(pFile, p, UNIX_SHM_C|UNIX_SHM_D);
+ p->lockState = SQLITE_SHM_READ;
+ }
+ break;
+ }
+ case SQLITE_SHM_WRITE: {
+ assert( p->lockState==SQLITE_SHM_READ
+ || p->lockState==SQLITE_SHM_READ_FULL );
+ rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_C|UNIX_SHM_D);
+ if( rc==SQLITE_OK ){
+ p->lockState = SQLITE_SHM_WRITE;
+ }
+ break;
+ }
+ case SQLITE_SHM_CHECKPOINT: {
+ assert( p->lockState==SQLITE_SHM_UNLOCK
+ || p->lockState==SQLITE_SHM_PENDING
+ );
+ if( p->lockState==SQLITE_SHM_UNLOCK ){
+ rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_B|UNIX_SHM_C);
+ if( rc==SQLITE_OK ){
+ p->lockState = SQLITE_SHM_PENDING;
+ }
+ }
+ if( p->lockState==SQLITE_SHM_PENDING ){
+ rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_A);
+ if( rc==SQLITE_OK ){
+ p->lockState = SQLITE_SHM_CHECKPOINT;
+ }
+ }
+ break;
+ }
+ default: {
+ assert( desiredLock==SQLITE_SHM_RECOVER );
+ assert( p->lockState==SQLITE_SHM_READ
+ || p->lockState==SQLITE_SHM_READ_FULL
+ );
+ assert( sqlite3_mutex_held(pFile->mutexBuf) );
+ rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_C);
+ if( rc==SQLITE_OK ){
+ p->lockState = SQLITE_SHM_RECOVER;
+ }
+ break;
+ }
+ }
+ sqlite3_mutex_leave(pFile->mutex);
+ OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %s\n",
+ p->id, getpid(), azLkName[p->lockState]));
+ if( pGotLock ) *pGotLock = p->lockState;
+ return rc;
+}
+
+#else
+# define unixShmOpen 0
+# define unixShmSize 0
+# define unixShmGet 0
+# define unixShmRelease 0
+# define unixShmLock 0
+# define unixShmClose 0
+#endif /* #ifndef SQLITE_OMIT_WAL */
+
/*
** Here ends the implementation of all sqlite3_file methods.
**
@@ -3440,9 +4256,9 @@ static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
** * An I/O method finder function called FINDER that returns a pointer
** to the METHOD object in the previous bullet.
*/
-#define IOMETHODS(FINDER, METHOD, CLOSE, LOCK, UNLOCK, CKLOCK) \
+#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \
static const sqlite3_io_methods METHOD = { \
- 1, /* iVersion */ \
+ VERSION, /* iVersion */ \
CLOSE, /* xClose */ \
unixRead, /* xRead */ \
unixWrite, /* xWrite */ \
@@ -3454,7 +4270,13 @@ static const sqlite3_io_methods METHOD = { \
CKLOCK, /* xCheckReservedLock */ \
unixFileControl, /* xFileControl */ \
unixSectorSize, /* xSectorSize */ \
- unixDeviceCharacteristics /* xDeviceCapabilities */ \
+ unixDeviceCharacteristics, /* xDeviceCapabilities */ \
+ unixShmOpen, /* xShmOpen */ \
+ unixShmSize, /* xShmSize */ \
+ unixShmGet, /* xShmGet */ \
+ unixShmRelease, /* xShmRelease */ \
+ unixShmLock, /* xShmLock */ \
+ unixShmClose /* xShmClose */ \
}; \
static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
@@ -3471,6 +4293,7 @@ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
IOMETHODS(
posixIoFinder, /* Finder function name */
posixIoMethods, /* sqlite3_io_methods object name */
+ 2, /* ShmOpen is enabled */
unixClose, /* xClose method */
unixLock, /* xLock method */
unixUnlock, /* xUnlock method */
@@ -3479,6 +4302,7 @@ IOMETHODS(
IOMETHODS(
nolockIoFinder, /* Finder function name */
nolockIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
nolockClose, /* xClose method */
nolockLock, /* xLock method */
nolockUnlock, /* xUnlock method */
@@ -3487,6 +4311,7 @@ IOMETHODS(
IOMETHODS(
dotlockIoFinder, /* Finder function name */
dotlockIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
dotlockClose, /* xClose method */
dotlockLock, /* xLock method */
dotlockUnlock, /* xUnlock method */
@@ -3497,6 +4322,7 @@ IOMETHODS(
IOMETHODS(
flockIoFinder, /* Finder function name */
flockIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
flockClose, /* xClose method */
flockLock, /* xLock method */
flockUnlock, /* xUnlock method */
@@ -3508,6 +4334,7 @@ IOMETHODS(
IOMETHODS(
semIoFinder, /* Finder function name */
semIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
semClose, /* xClose method */
semLock, /* xLock method */
semUnlock, /* xUnlock method */
@@ -3519,6 +4346,7 @@ IOMETHODS(
IOMETHODS(
afpIoFinder, /* Finder function name */
afpIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
afpClose, /* xClose method */
afpLock, /* xLock method */
afpUnlock, /* xUnlock method */
@@ -3543,6 +4371,7 @@ static int proxyCheckReservedLock(sqlite3_file*, int*);
IOMETHODS(
proxyIoFinder, /* Finder function name */
proxyIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
proxyClose, /* xClose method */
proxyLock, /* xLock method */
proxyUnlock, /* xUnlock method */
@@ -3555,6 +4384,7 @@ IOMETHODS(
IOMETHODS(
nfsIoFinder, /* Finder function name */
nfsIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
unixClose, /* xClose method */
unixLock, /* xLock method */
nfsUnlock, /* xUnlock method */
@@ -3708,6 +4538,8 @@ static int fillInUnixFile(
pNew->dirfd = dirfd;
SET_THREADID(pNew);
pNew->fileFlags = 0;
+ assert( zFilename==0 || zFilename[0]=='/' ); /* Never a relative pathname */
+ pNew->zPath = zFilename;
#if OS_VXWORKS
pNew->pId = vxworksFindFileId(zFilename);
@@ -4575,812 +5407,6 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
return 0;
}
-#ifndef SQLITE_OMIT_WAL
-
-/* Forward reference */
-typedef struct unixShm unixShm;
-typedef struct unixShmFile unixShmFile;
-
-/*
-** Object used to represent a single file opened and mmapped to provide
-** shared memory. When multiple threads all reference the same
-** log-summary, each thread has its own unixFile object, but they all
-** point to a single instance of this object. In other words, each
-** log-summary is opened only once per process.
-**
-** unixMutexHeld() must be true when creating or destroying
-** this object or while reading or writing the following fields:
-**
-** nRef
-** pNext
-**
-** The following fields are read-only after the object is created:
-**
-** fid
-** zFilename
-**
-** Either unixShmFile.mutex must be held or unixShmFile.nRef==0 and
-** unixMutexHeld() is true when reading or writing any other field
-** in this structure.
-**
-** To avoid deadlocks, mutex and mutexBuf are always released in the
-** reverse order that they are acquired. mutexBuf is always acquired
-** first and released last. This invariant is check by asserting
-** sqlite3_mutex_notheld() on mutex whenever mutexBuf is acquired or
-** released.
-*/
-struct unixShmFile {
- struct unixFileId fid; /* Unique file identifier */
- sqlite3_mutex *mutex; /* Mutex to access this object */
- sqlite3_mutex *mutexBuf; /* Mutex to access zBuf[] */
- char *zFilename; /* Name of the file */
- int h; /* Open file descriptor */
- int szMap; /* Size of the mapping of file into memory */
- char *pMMapBuf; /* Where currently mmapped(). NULL if unmapped */
- int nRef; /* Number of unixShm objects pointing to this */
- unixShm *pFirst; /* All unixShm objects pointing to this */
- unixShmFile *pNext; /* Next in list of all unixShmFile objects */
-#ifdef SQLITE_DEBUG
- u8 exclMask; /* Mask of exclusive locks held */
- u8 sharedMask; /* Mask of shared locks held */
- u8 nextShmId; /* Next available unixShm.id value */
-#endif
-};
-
-/*
-** A global array of all unixShmFile objects.
-**
-** The unixMutexHeld() must be true while reading or writing this list.
-*/
-static unixShmFile *unixShmFileList = 0;
-
-/*
-** Structure used internally by this VFS to record the state of an
-** open shared memory connection.
-**
-** unixShm.pFile->mutex must be held while reading or writing the
-** unixShm.pNext and unixShm.locks[] elements.
-**
-** The unixShm.pFile element is initialized when the object is created
-** and is read-only thereafter.
-*/
-struct unixShm {
- unixShmFile *pFile; /* The underlying unixShmFile object */
- unixShm *pNext; /* Next unixShm with the same unixShmFile */
- u8 lockState; /* Current lock state */
- u8 hasMutex; /* True if holding the unixShmFile mutex */
- u8 hasMutexBuf; /* True if holding pFile->mutexBuf */
- u8 sharedMask; /* Mask of shared locks held */
- u8 exclMask; /* Mask of exclusive locks held */
-#ifdef SQLITE_DEBUG
- u8 id; /* Id of this connection with its unixShmFile */
-#endif
-};
-
-/*
-** Size increment by which shared memory grows
-*/
-#define SQLITE_UNIX_SHM_INCR 4096
-
-/*
-** Constants used for locking
-*/
-#define UNIX_SHM_BASE 32 /* Byte offset of the first lock byte */
-#define UNIX_SHM_DMS 0x01 /* Mask for Dead-Man-Switch lock */
-#define UNIX_SHM_A 0x10 /* Mask for region locks... */
-#define UNIX_SHM_B 0x20
-#define UNIX_SHM_C 0x40
-#define UNIX_SHM_D 0x80
-
-#ifdef SQLITE_DEBUG
-/*
-** Return a pointer to a nul-terminated string in static memory that
-** describes a locking mask. The string is of the form "MSABCD" with
-** each character representing a lock. "M" for MUTEX, "S" for DMS,
-** and "A" through "D" for the region locks. If a lock is held, the
-** letter is shown. If the lock is not held, the letter is converted
-** to ".".
-**
-** This routine is for debugging purposes only and does not appear
-** in a production build.
-*/
-static const char *unixShmLockString(u8 mask){
- static char zBuf[48];
- static int iBuf = 0;
- char *z;
-
- z = &zBuf[iBuf];
- iBuf += 8;
- if( iBuf>=sizeof(zBuf) ) iBuf = 0;
-
- z[0] = (mask & UNIX_SHM_DMS) ? 'S' : '.';
- z[1] = (mask & UNIX_SHM_A) ? 'A' : '.';
- z[2] = (mask & UNIX_SHM_B) ? 'B' : '.';
- z[3] = (mask & UNIX_SHM_C) ? 'C' : '.';
- z[4] = (mask & UNIX_SHM_D) ? 'D' : '.';
- z[5] = 0;
- return z;
-}
-#endif /* SQLITE_DEBUG */
-
-/*
-** Apply posix advisory locks for all bytes identified in lockMask.
-**
-** lockMask might contain multiple bits but all bits are guaranteed
-** to be contiguous.
-**
-** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking
-** otherwise.
-*/
-static int unixShmSystemLock(
- unixShmFile *pFile, /* Apply locks to this open shared-memory segment */
- int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */
- u8 lockMask /* Which bytes to lock or unlock */
-){
- struct flock f; /* The posix advisory locking structure */
- int lockOp; /* The opcode for fcntl() */
- int i; /* Offset into the locking byte range */
- int rc; /* Result code form fcntl() */
- u8 mask; /* Mask of bits in lockMask */
-
- /* Access to the unixShmFile object is serialized by the caller */
- assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
-
- /* Initialize the locking parameters */
- memset(&f, 0, sizeof(f));
- f.l_type = lockType;
- f.l_whence = SEEK_SET;
- if( lockMask==UNIX_SHM_C && lockType!=F_UNLCK ){
- lockOp = F_SETLKW;
- OSTRACE(("SHM-LOCK requesting blocking lock\n"));
- }else{
- lockOp = F_SETLK;
- }
-
- /* Find the first bit in lockMask that is set */
- for(i=0, mask=0x01; mask!=0 && (lockMask&mask)==0; mask <<= 1, i++){}
- assert( mask!=0 );
- f.l_start = i+UNIX_SHM_BASE;
- f.l_len = 1;
-
- /* Extend the locking range for each additional bit that is set */
- mask <<= 1;
- while( mask!=0 && (lockMask & mask)!=0 ){
- f.l_len++;
- mask <<= 1;
- }
-
- /* Verify that all bits set in lockMask are contiguous */
- assert( mask==0 || (lockMask & ~(mask | (mask-1)))==0 );
-
- /* Acquire the system-level lock */
- rc = fcntl(pFile->h, lockOp, &f);
- rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
-
- /* Update the global lock state and do debug tracing */
-#ifdef SQLITE_DEBUG
- OSTRACE(("SHM-LOCK "));
- if( rc==SQLITE_OK ){
- if( lockType==F_UNLCK ){
- OSTRACE(("unlock ok"));
- pFile->exclMask &= ~lockMask;
- pFile->sharedMask &= ~lockMask;
- }else if( lockType==F_RDLCK ){
- OSTRACE(("read-lock ok"));
- pFile->exclMask &= ~lockMask;
- pFile->sharedMask |= lockMask;
- }else{
- assert( lockType==F_WRLCK );
- OSTRACE(("write-lock ok"));
- pFile->exclMask |= lockMask;
- pFile->sharedMask &= ~lockMask;
- }
- }else{
- if( lockType==F_UNLCK ){
- OSTRACE(("unlock failed"));
- }else if( lockType==F_RDLCK ){
- OSTRACE(("read-lock failed"));
- }else{
- assert( lockType==F_WRLCK );
- OSTRACE(("write-lock failed"));
- }
- }
- OSTRACE((" - change requested %s - afterwards %s:%s\n",
- unixShmLockString(lockMask),
- unixShmLockString(pFile->sharedMask),
- unixShmLockString(pFile->exclMask)));
-#endif
-
- return rc;
-}
-
-/*
-** For connection p, unlock all of the locks identified by the unlockMask
-** parameter.
-*/
-static int unixShmUnlock(
- unixShmFile *pFile, /* The underlying shared-memory file */
- unixShm *p, /* The connection to be unlocked */
- u8 unlockMask /* Mask of locks to be unlocked */
-){
- int rc; /* Result code */
- unixShm *pX; /* For looping over all sibling connections */
- u8 allMask; /* Union of locks held by connections other than "p" */
-
- /* Access to the unixShmFile object is serialized by the caller */
- assert( sqlite3_mutex_held(pFile->mutex) );
-
- /* Compute locks held by sibling connections */
- allMask = 0;
- for(pX=pFile->pFirst; pX; pX=pX->pNext){
- if( pX==p ) continue;
- assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
- allMask |= pX->sharedMask;
- }
-
- /* Unlock the system-level locks */
- if( (unlockMask & allMask)!=unlockMask ){
- rc = unixShmSystemLock(pFile, F_UNLCK, unlockMask & ~allMask);
- }else{
- rc = SQLITE_OK;
- }
-
- /* Undo the local locks */
- if( rc==SQLITE_OK ){
- p->exclMask &= ~unlockMask;
- p->sharedMask &= ~unlockMask;
- }
- return rc;
-}
-
-/*
-** Get reader locks for connection p on all locks in the readMask parameter.
-*/
-static int unixShmSharedLock(
- unixShmFile *pFile, /* The underlying shared-memory file */
- unixShm *p, /* The connection to get the shared locks */
- u8 readMask /* Mask of shared locks to be acquired */
-){
- int rc; /* Result code */
- unixShm *pX; /* For looping over all sibling connections */
- u8 allShared; /* Union of locks held by connections other than "p" */
-
- /* Access to the unixShmFile object is serialized by the caller */
- assert( sqlite3_mutex_held(pFile->mutex) );
-
- /* Find out which shared locks are already held by sibling connections.
- ** If any sibling already holds an exclusive lock, go ahead and return
- ** SQLITE_BUSY.
- */
- allShared = 0;
- for(pX=pFile->pFirst; pX; pX=pX->pNext){
- if( pX==p ) continue;
- if( (pX->exclMask & readMask)!=0 ) return SQLITE_BUSY;
- allShared |= pX->sharedMask;
- }
-
- /* Get shared locks at the system level, if necessary */
- if( (~allShared) & readMask ){
- rc = unixShmSystemLock(pFile, F_RDLCK, readMask);
- }else{
- rc = SQLITE_OK;
- }
-
- /* Get the local shared locks */
- if( rc==SQLITE_OK ){
- p->sharedMask |= readMask;
- }
- return rc;
-}
-
-/*
-** For connection p, get an exclusive lock on all locks identified in
-** the writeMask parameter.
-*/
-static int unixShmExclusiveLock(
- unixShmFile *pFile, /* The underlying shared-memory file */
- unixShm *p, /* The connection to get the exclusive locks */
- u8 writeMask /* Mask of exclusive locks to be acquired */
-){
- int rc; /* Result code */
- unixShm *pX; /* For looping over all sibling connections */
-
- /* Access to the unixShmFile object is serialized by the caller */
- assert( sqlite3_mutex_held(pFile->mutex) );
-
- /* Make sure no sibling connections hold locks that will block this
- ** lock. If any do, return SQLITE_BUSY right away.
- */
- for(pX=pFile->pFirst; pX; pX=pX->pNext){
- if( pX==p ) continue;
- if( (pX->exclMask & writeMask)!=0 ) return SQLITE_BUSY;
- if( (pX->sharedMask & writeMask)!=0 ) return SQLITE_BUSY;
- }
-
- /* Get the exclusive locks at the system level. Then if successful
- ** also mark the local connection as being locked.
- */
- rc = unixShmSystemLock(pFile, F_WRLCK, writeMask);
- if( rc==SQLITE_OK ){
- p->sharedMask &= ~writeMask;
- p->exclMask |= writeMask;
- }
- return rc;
-}
-
-/*
-** Purge the unixShmFileList list of all entries with unixShmFile.nRef==0.
-**
-** This is not a VFS shared-memory method; it is a utility function called
-** by VFS shared-memory methods.
-*/
-static void unixShmPurge(void){
- unixShmFile **pp;
- unixShmFile *p;
- assert( unixMutexHeld() );
- pp = &unixShmFileList;
- while( (p = *pp)!=0 ){
- if( p->nRef==0 ){
- if( p->mutex ) sqlite3_mutex_free(p->mutex);
- if( p->mutexBuf ) sqlite3_mutex_free(p->mutexBuf);
- if( p->h>=0 ) close(p->h);
- *pp = p->pNext;
- sqlite3_free(p);
- }else{
- pp = &p->pNext;
- }
- }
-}
-
-/*
-** Open a shared-memory area. This particular implementation uses
-** mmapped files.
-**
-** zName is a filename used to identify the shared-memory area. The
-** implementation does not (and perhaps should not) use this name
-** directly, but rather use it as a template for finding an appropriate
-** name for the shared-memory storage. In this implementation, the
-** string "-index" is appended to zName and used as the name of the
-** mmapped file.
-**
-** When opening a new shared-memory file, if no other instances of that
-** file are currently open, in this process or in other processes, then
-** the file must be truncated to zero length or have its header cleared.
-*/
-static int unixShmOpen(
- sqlite3_vfs *pVfs, /* The VFS */
- const char *zName, /* Name of the corresponding database file */
- sqlite3_shm **pShm /* Write the unixShm object created here */
-){
- struct unixShm *p = 0; /* The connection to be opened */
- struct unixShmFile *pFile = 0; /* The underlying mmapped file */
- int rc; /* Result code */
- struct unixFileId fid; /* Unix file identifier */
- struct unixShmFile *pNew; /* Newly allocated pFile */
- struct stat sStat; /* Result from stat() an fstat() */
- int nName; /* Size of zName in bytes */
-
- /* Allocate space for the new sqlite3_shm object. Also speculatively
- ** allocate space for a new unixShmFile and filename.
- */
- p = sqlite3_malloc( sizeof(*p) );
- if( p==0 ) return SQLITE_NOMEM;
- memset(p, 0, sizeof(*p));
- nName = strlen(zName);
- pNew = sqlite3_malloc( sizeof(*pFile) + nName + 15 );
- if( pNew==0 ){
- sqlite3_free(p);
- return SQLITE_NOMEM;
- }
- memset(pNew, 0, sizeof(*pNew));
- pNew->zFilename = (char*)&pNew[1];
- sqlite3_snprintf(nName+12, pNew->zFilename, "%s-wal-index", zName);
-
- /* Look to see if there is an existing unixShmFile that can be used.
- ** If no matching unixShmFile currently exists, create a new one.
- */
- unixEnterMutex();
- rc = stat(pNew->zFilename, &sStat);
- if( rc==0 ){
- memset(&fid, 0, sizeof(fid));
- fid.dev = sStat.st_dev;
- fid.ino = sStat.st_ino;
- for(pFile = unixShmFileList; pFile; pFile=pFile->pNext){
- if( memcmp(&pFile->fid, &fid, sizeof(fid))==0 ) break;
- }
- }
- if( pFile ){
- sqlite3_free(pNew);
- }else{
- pFile = pNew;
- pNew = 0;
- pFile->h = -1;
- pFile->pNext = unixShmFileList;
- unixShmFileList = pFile;
-
- pFile->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
- if( pFile->mutex==0 ){
- rc = SQLITE_NOMEM;
- goto shm_open_err;
- }
- pFile->mutexBuf = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
- if( pFile->mutexBuf==0 ){
- rc = SQLITE_NOMEM;
- goto shm_open_err;
- }
-
- pFile->h = open(pFile->zFilename, O_RDWR|O_CREAT, 0664);
- if( pFile->h<0 ){
- rc = SQLITE_CANTOPEN_BKPT;
- goto shm_open_err;
- }
-
- rc = fstat(pFile->h, &sStat);
- if( rc ){
- rc = SQLITE_CANTOPEN_BKPT;
- goto shm_open_err;
- }
- pFile->fid.dev = sStat.st_dev;
- pFile->fid.ino = sStat.st_ino;
-
- /* Check to see if another process is holding the dead-man switch.
- ** If not, truncate the file to zero length.
- */
- if( unixShmSystemLock(pFile, F_WRLCK, UNIX_SHM_DMS)==SQLITE_OK ){
- if( ftruncate(pFile->h, 0) ){
- rc = SQLITE_IOERR;
- }
- }
- if( rc==SQLITE_OK ){
- rc = unixShmSystemLock(pFile, F_RDLCK, UNIX_SHM_DMS);
- }
- if( rc ) goto shm_open_err;
- }
-
- /* Make the new connection a child of the unixShmFile */
- p->pFile = pFile;
- p->pNext = pFile->pFirst;
-#ifdef SQLITE_DEBUG
- p->id = pFile->nextShmId++;
-#endif
- pFile->pFirst = p;
- pFile->nRef++;
- *pShm = (sqlite3_shm*)p;
- unixLeaveMutex();
- return SQLITE_OK;
-
- /* Jump here on any error */
-shm_open_err:
- unixShmPurge(); /* This call frees pFile if required */
- sqlite3_free(p);
- sqlite3_free(pNew);
- *pShm = 0;
- unixLeaveMutex();
- return rc;
-}
-
-/*
-** Close a connection to shared-memory. Delete the underlying
-** storage if deleteFlag is true.
-*/
-static int unixShmClose(
- sqlite3_vfs *pVfs, /* The VFS */
- sqlite3_shm *pSharedMem, /* The shared-memory to be closed */
- int deleteFlag /* Delete after closing if true */
-){
- unixShm *p; /* The connection to be closed */
- unixShmFile *pFile; /* The underlying shared-memory file */
- unixShm **pp; /* For looping over sibling connections */
-
- UNUSED_PARAMETER(pVfs);
- if( pSharedMem==0 ) return SQLITE_OK;
- p = (struct unixShm*)pSharedMem;
- pFile = p->pFile;
-
- /* Verify that the connection being closed holds no locks */
- assert( p->exclMask==0 );
- assert( p->sharedMask==0 );
-
- /* Remove connection p from the set of connections associated with pFile */
- sqlite3_mutex_enter(pFile->mutex);
- for(pp=&pFile->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
- *pp = p->pNext;
-
- /* Free the connection p */
- sqlite3_free(p);
- sqlite3_mutex_leave(pFile->mutex);
-
- /* If pFile->nRef has reached 0, then close the underlying
- ** shared-memory file, too */
- unixEnterMutex();
- assert( pFile->nRef>0 );
- pFile->nRef--;
- if( pFile->nRef==0 ){
- if( deleteFlag ) unlink(pFile->zFilename);
- unixShmPurge();
- }
- unixLeaveMutex();
-
- return SQLITE_OK;
-}
-
-/*
-** Query and/or changes the size of the underlying storage for
-** a shared-memory segment. The reqSize parameter is the new size
-** of the underlying storage, or -1 to do just a query. The size
-** of the underlying storage (after resizing if resizing occurs) is
-** written into pNewSize.
-**
-** This routine does not (necessarily) change the size of the mapping
-** of the underlying storage into memory. Use xShmGet() to change
-** the mapping size.
-**
-** The reqSize parameter is the minimum size requested. The implementation
-** is free to expand the storage to some larger amount if it chooses.
-*/
-static int unixShmSize(
- sqlite3_vfs *pVfs, /* The VFS */
- sqlite3_shm *pSharedMem, /* Pointer returned by unixShmOpen() */
- int reqSize, /* Requested size. -1 for query only */
- int *pNewSize /* Write new size here */
-){
- unixShm *p = (unixShm*)pSharedMem;
- unixShmFile *pFile = p->pFile;
- int rc = SQLITE_OK;
- struct stat sStat;
-
- UNUSED_PARAMETER(pVfs);
-
- if( reqSize>=0 ){
- reqSize = (reqSize + SQLITE_UNIX_SHM_INCR - 1)/SQLITE_UNIX_SHM_INCR;
- reqSize *= SQLITE_UNIX_SHM_INCR;
- rc = ftruncate(pFile->h, reqSize);
- }
- if( fstat(pFile->h, &sStat)==0 ){
- *pNewSize = (int)sStat.st_size;
- }else{
- *pNewSize = 0;
- rc = SQLITE_IOERR;
- }
- return rc;
-}
-
-
-/*
-** Map the shared storage into memory. The minimum size of the
-** mapping should be reqMapSize if reqMapSize is positive. If
-** reqMapSize is zero or negative, the implementation can choose
-** whatever mapping size is convenient.
-**
-** *ppBuf is made to point to the memory which is a mapping of the
-** underlying storage. A mutex is acquired to prevent other threads
-** from running while *ppBuf is in use in order to prevent other threads
-** remapping *ppBuf out from under this thread. The unixShmRelease()
-** call will release the mutex. However, if the lock state is CHECKPOINT,
-** the mutex is not acquired because CHECKPOINT will never remap the
-** buffer. RECOVER might remap, though, so CHECKPOINT will acquire
-** the mutex if and when it promotes to RECOVER.
-**
-** RECOVER needs to be atomic. The same mutex that prevents *ppBuf from
-** being remapped also prevents more than one thread from being in
-** RECOVER at a time. But, RECOVER sometimes wants to remap itself.
-** To prevent RECOVER from losing its lock while remapping, the
-** mutex is not released by unixShmRelease() when in RECOVER.
-**
-** *pNewMapSize is set to the size of the mapping.
-**
-** *ppBuf and *pNewMapSize might be NULL and zero if no space has
-** yet been allocated to the underlying storage.
-*/
-static int unixShmGet(
- sqlite3_vfs *pVfs, /* The VFS */
- sqlite3_shm *pSharedMem, /* Pointer returned by unixShmOpen() */
- int reqMapSize, /* Requested size of mapping. -1 means don't care */
- int *pNewMapSize, /* Write new size of mapping here */
- void **ppBuf /* Write mapping buffer origin here */
-){
- unixShm *p = (unixShm*)pSharedMem;
- unixShmFile *pFile = p->pFile;
- int rc = SQLITE_OK;
-
- if( p->lockState!=SQLITE_SHM_CHECKPOINT && p->hasMutexBuf==0 ){
- assert( sqlite3_mutex_notheld(pFile->mutex) );
- sqlite3_mutex_enter(pFile->mutexBuf);
- p->hasMutexBuf = 1;
- }
- sqlite3_mutex_enter(pFile->mutex);
- if( pFile->szMap==0 || reqMapSize>pFile->szMap ){
- int actualSize;
- if( unixShmSize(pVfs, pSharedMem, -1, &actualSize)==SQLITE_OK
- && reqMapSize<actualSize
- ){
- reqMapSize = actualSize;
- }
- if( pFile->pMMapBuf ){
- munmap(pFile->pMMapBuf, pFile->szMap);
- }
- pFile->pMMapBuf = mmap(0, reqMapSize, PROT_READ|PROT_WRITE, MAP_SHARED,
- pFile->h, 0);
- pFile->szMap = pFile->pMMapBuf ? reqMapSize : 0;
- }
- *pNewMapSize = pFile->szMap;
- *ppBuf = pFile->pMMapBuf;
- sqlite3_mutex_leave(pFile->mutex);
- return rc;
-}
-
-/*
-** Release the lock held on the shared memory segment to that other
-** threads are free to resize it if necessary.
-**
-** If the lock is not currently held, this routine is a harmless no-op.
-**
-** If the shared-memory object is in lock state RECOVER, then we do not
-** really want to release the lock, so in that case too, this routine
-** is a no-op.
-*/
-static int unixShmRelease(sqlite3_vfs *pVfs, sqlite3_shm *pSharedMem){
- unixShm *p = (unixShm*)pSharedMem;
- UNUSED_PARAMETER(pVfs);
- if( p->hasMutexBuf && p->lockState!=SQLITE_SHM_RECOVER ){
- assert( sqlite3_mutex_notheld(p->pFile->mutex) );
- sqlite3_mutex_leave(p->pFile->mutexBuf);
- p->hasMutexBuf = 0;
- }
- return SQLITE_OK;
-}
-
-/*
-** Symbolic names for LOCK states used for debugging.
-*/
-#ifdef SQLITE_DEBUG
-static const char *azLkName[] = {
- "UNLOCK",
- "READ",
- "READ_FULL",
- "WRITE",
- "PENDING",
- "CHECKPOINT",
- "RECOVER"
-};
-#endif
-
-
-/*
-** Change the lock state for a shared-memory segment.
-*/
-static int unixShmLock(
- sqlite3_vfs *pVfs, /* The VFS */
- sqlite3_shm *pSharedMem, /* Pointer from unixShmOpen() */
- int desiredLock, /* One of SQLITE_SHM_xxxxx locking states */
- int *pGotLock /* The lock you actually got */
-){
- unixShm *p = (unixShm*)pSharedMem;
- unixShmFile *pFile = p->pFile;
- int rc = SQLITE_PROTOCOL;
-
- UNUSED_PARAMETER(pVfs);
-
- /* Note that SQLITE_SHM_READ_FULL and SQLITE_SHM_PENDING are never
- ** directly requested; they are side effects from requesting
- ** SQLITE_SHM_READ and SQLITE_SHM_CHECKPOINT, respectively.
- */
- assert( desiredLock==SQLITE_SHM_UNLOCK
- || desiredLock==SQLITE_SHM_READ
- || desiredLock==SQLITE_SHM_WRITE
- || desiredLock==SQLITE_SHM_CHECKPOINT
- || desiredLock==SQLITE_SHM_RECOVER );
-
- /* Return directly if this is just a lock state query, or if
- ** the connection is already in the desired locking state.
- */
- if( desiredLock==p->lockState
- || (desiredLock==SQLITE_SHM_READ && p->lockState==SQLITE_SHM_READ_FULL)
- ){
- OSTRACE(("SHM-LOCK shmid-%d, pid-%d request %s and got %s\n",
- p->id, getpid(), azLkName[desiredLock], azLkName[p->lockState]));
- if( pGotLock ) *pGotLock = p->lockState;
- return SQLITE_OK;
- }
-
- OSTRACE(("SHM-LOCK shmid-%d, pid-%d request %s->%s\n",
- p->id, getpid(), azLkName[p->lockState], azLkName[desiredLock]));
-
- if( desiredLock==SQLITE_SHM_RECOVER && !p->hasMutexBuf ){
- assert( sqlite3_mutex_notheld(pFile->mutex) );
- sqlite3_mutex_enter(pFile->mutexBuf);
- p->hasMutexBuf = 1;
- }
- sqlite3_mutex_enter(pFile->mutex);
- switch( desiredLock ){
- case SQLITE_SHM_UNLOCK: {
- assert( p->lockState!=SQLITE_SHM_RECOVER );
- unixShmUnlock(pFile, p, UNIX_SHM_A|UNIX_SHM_B|UNIX_SHM_C|UNIX_SHM_D);
- rc = SQLITE_OK;
- p->lockState = SQLITE_SHM_UNLOCK;
- break;
- }
- case SQLITE_SHM_READ: {
- if( p->lockState==SQLITE_SHM_UNLOCK ){
- int nAttempt;
- rc = SQLITE_BUSY;
- assert( p->lockState==SQLITE_SHM_UNLOCK );
- for(nAttempt=0; nAttempt<5 && rc==SQLITE_BUSY; nAttempt++){
- rc = unixShmSharedLock(pFile, p, UNIX_SHM_A|UNIX_SHM_B);
- if( rc==SQLITE_BUSY ){
- rc = unixShmSharedLock(pFile, p, UNIX_SHM_D);
- if( rc==SQLITE_OK ){
- p->lockState = SQLITE_SHM_READ_FULL;
- }
- }else{
- unixShmUnlock(pFile, p, UNIX_SHM_B);
- p->lockState = SQLITE_SHM_READ;
- }
- }
- }else{
- assert( p->lockState==SQLITE_SHM_WRITE
- || p->lockState==SQLITE_SHM_RECOVER );
- rc = unixShmSharedLock(pFile, p, UNIX_SHM_A);
- unixShmUnlock(pFile, p, UNIX_SHM_C|UNIX_SHM_D);
- p->lockState = SQLITE_SHM_READ;
- }
- break;
- }
- case SQLITE_SHM_WRITE: {
- assert( p->lockState==SQLITE_SHM_READ
- || p->lockState==SQLITE_SHM_READ_FULL );
- rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_C|UNIX_SHM_D);
- if( rc==SQLITE_OK ){
- p->lockState = SQLITE_SHM_WRITE;
- }
- break;
- }
- case SQLITE_SHM_CHECKPOINT: {
- assert( p->lockState==SQLITE_SHM_UNLOCK
- || p->lockState==SQLITE_SHM_PENDING
- );
- if( p->lockState==SQLITE_SHM_UNLOCK ){
- rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_B|UNIX_SHM_C);
- if( rc==SQLITE_OK ){
- p->lockState = SQLITE_SHM_PENDING;
- }
- }
- if( p->lockState==SQLITE_SHM_PENDING ){
- rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_A);
- if( rc==SQLITE_OK ){
- p->lockState = SQLITE_SHM_CHECKPOINT;
- }
- }
- break;
- }
- default: {
- assert( desiredLock==SQLITE_SHM_RECOVER );
- assert( p->lockState==SQLITE_SHM_READ
- || p->lockState==SQLITE_SHM_READ_FULL
- );
- assert( sqlite3_mutex_held(pFile->mutexBuf) );
- rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_C);
- if( rc==SQLITE_OK ){
- p->lockState = SQLITE_SHM_RECOVER;
- }
- break;
- }
- }
- sqlite3_mutex_leave(pFile->mutex);
- OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %s\n",
- p->id, getpid(), azLkName[p->lockState]));
- if( pGotLock ) *pGotLock = p->lockState;
- return rc;
-}
-
-#else
-# define unixShmOpen 0
-# define unixShmSize 0
-# define unixShmGet 0
-# define unixShmRelease 0
-# define unixShmLock 0
-# define unixShmClose 0
-#endif /* #ifndef SQLITE_OMIT_WAL */
/*
************************ End of sqlite3_vfs methods ***************************
@@ -6600,12 +6626,6 @@ int sqlite3_os_init(void){
unixSleep, /* xSleep */ \
unixCurrentTime, /* xCurrentTime */ \
unixGetLastError, /* xGetLastError */ \
- unixShmOpen, /* xShmOpen */ \
- unixShmSize, /* xShmSize */ \
- unixShmGet, /* xShmGet */ \
- unixShmRelease, /* xShmRelease */ \
- unixShmLock, /* xShmLock */ \
- unixShmClose, /* xShmClose */ \
0, /* xRename */ \
unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
}
diff --git a/src/pager.c b/src/pager.c
index 672789c94..42403c997 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -3077,7 +3077,7 @@ int sqlite3PagerClose(Pager *pPager){
pPager->errCode = 0;
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
- sqlite3WalClose(pPager->pWal, pPager->fd,
+ sqlite3WalClose(pPager->pWal,
(pPager->noSync ? 0 : pPager->sync_flags),
pPager->pageSize, pTmp
);
@@ -5878,7 +5878,7 @@ int sqlite3PagerCheckpoint(Pager *pPager){
int rc = SQLITE_OK;
if( pPager->pWal ){
u8 *zBuf = (u8 *)pPager->pTmpSpace;
- rc = sqlite3WalCheckpoint(pPager->pWal, pPager->fd,
+ rc = sqlite3WalCheckpoint(pPager->pWal,
(pPager->noSync ? 0 : pPager->sync_flags),
pPager->pageSize, zBuf,
pPager->xBusyHandler, pPager->pBusyHandlerArg
@@ -5892,6 +5892,15 @@ int sqlite3PagerWalCallback(Pager *pPager){
}
/*
+** Return true if the underlying VFS for the given pager supports the
+** primitives necessary for write-ahead logging.
+*/
+int sqlite3PagerWalSupported(Pager *pPager){
+ const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
+ return pMethods->iVersion>=2 && pMethods->xShmOpen!=0;
+}
+
+/*
** Open a connection to the write-ahead log file for pager pPager. If
** the log connection is already open, this function is a no-op.
**
@@ -5903,12 +5912,14 @@ int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen){
assert( pPager->state>=PAGER_SHARED );
if( !pPager->pWal ){
+ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
/* Open the connection to the log file. If this operation fails,
** (e.g. due to malloc() failure), unlock the database file and
** return an error code.
*/
- rc = sqlite3WalOpen(pPager->pVfs, pPager->zFilename, &pPager->pWal);
+ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd,
+ pPager->zFilename, &pPager->pWal);
if( rc==SQLITE_OK ){
pPager->journalMode = PAGER_JOURNALMODE_WAL;
}
@@ -5944,7 +5955,8 @@ int sqlite3PagerCloseWal(Pager *pPager){
rc = pagerHasWAL(pPager, &logexists);
}
if( rc==SQLITE_OK && logexists ){
- rc = sqlite3WalOpen(pPager->pVfs, pPager->zFilename, &pPager->pWal);
+ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd,
+ pPager->zFilename, &pPager->pWal);
}
}
@@ -5954,8 +5966,8 @@ int sqlite3PagerCloseWal(Pager *pPager){
if( rc==SQLITE_OK && pPager->pWal ){
rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_EXCLUSIVE);
if( rc==SQLITE_OK ){
- rc = sqlite3WalClose(pPager->pWal, pPager->fd,
- (pPager->noSync ? 0 : pPager->sync_flags),
+ rc = sqlite3WalClose(pPager->pWal,
+ (pPager->noSync ? 0 : pPager->sync_flags),
pPager->pageSize, (u8*)pPager->pTmpSpace
);
pPager->pWal = 0;
diff --git a/src/pager.h b/src/pager.h
index 91b2cb32f..57ceb0463 100644
--- a/src/pager.h
+++ b/src/pager.h
@@ -135,6 +135,7 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
int sqlite3PagerSharedLock(Pager *pPager);
int sqlite3PagerCheckpoint(Pager *pPager);
+int sqlite3PagerWalSupported(Pager *pPager);
int sqlite3PagerWalCallback(Pager *pPager);
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
int sqlite3PagerCloseWal(Pager *pPager);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 15daf971f..af36382ed 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -653,6 +653,14 @@ struct sqlite3_io_methods {
int (*xFileControl)(sqlite3_file*, int op, void *pArg);
int (*xSectorSize)(sqlite3_file*);
int (*xDeviceCharacteristics)(sqlite3_file*);
+ /* Methods above are valid for version 1 */
+ int (*xShmOpen)(sqlite3_file*);
+ int (*xShmSize)(sqlite3_file*, int reqSize, int *pNewSize);
+ int (*xShmGet)(sqlite3_file*, int reqSize, int *pSize, void**);
+ int (*xShmRelease)(sqlite3_file*);
+ int (*xShmLock)(sqlite3_file*, int desiredLock, int *gotLock);
+ int (*xShmClose)(sqlite3_file*, int deleteFlag);
+ /* Methods above are valid for version 2 */
/* Additional methods may be added in future releases */
};
@@ -818,7 +826,6 @@ typedef struct sqlite3_mutex sqlite3_mutex;
**
*/
typedef struct sqlite3_vfs sqlite3_vfs;
-typedef struct sqlite3_shm sqlite3_shm;
struct sqlite3_vfs {
int iVersion; /* Structure version number (currently 2) */
int szOsFile; /* Size of subclassed sqlite3_file */
@@ -843,12 +850,6 @@ struct sqlite3_vfs {
** The methods above are in version 1 of the sqlite_vfs object
** definition. Those that follow are added in version 2 or later
*/
- int (*xShmOpen)(sqlite3_vfs*, const char *zName, sqlite3_shm**);
- int (*xShmSize)(sqlite3_vfs*, sqlite3_shm*, int reqSize, int *pNewSize);
- int (*xShmGet)(sqlite3_vfs*, sqlite3_shm*, int reqSize, int *pSize, void**);
- int (*xShmRelease)(sqlite3_vfs*, sqlite3_shm*);
- int (*xShmLock)(sqlite3_vfs*, sqlite3_shm*, int desiredLock, int *gotLock);
- int (*xShmClose)(sqlite3_vfs*, sqlite3_shm*, int deleteFlag);
int (*xRename)(sqlite3_vfs*, const char *zOld, const char *zNew, int dirSync);
int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
/*
diff --git a/src/test6.c b/src/test6.c
index 1ebde80e1..9b5c3f615 100644
--- a/src/test6.c
+++ b/src/test6.c
@@ -520,8 +520,31 @@ static int cfDeviceCharacteristics(sqlite3_file *pFile){
return g.iDeviceCharacteristics;
}
+/*
+** Pass-throughs for WAL support.
+*/
+static int cfShmOpen(sqlite3_file *pFile){
+ return sqlite3OsShmOpen(((CrashFile*)pFile)->pRealFile);
+}
+static int cfShmSize(sqlite3_file *pFile, int reqSize, int *pNew){
+ return sqlite3OsShmSize(((CrashFile*)pFile)->pRealFile, reqSize, pNew);
+}
+static int cfShmGet(sqlite3_file *pFile, int reqSize, int *pSize, void **pp){
+ return sqlite3OsShmGet(((CrashFile*)pFile)->pRealFile, reqSize, pSize, pp);
+}
+static int cfShmRelease(sqlite3_file *pFile){
+ return sqlite3OsShmRelease(((CrashFile*)pFile)->pRealFile);
+}
+static int cfShmLock(sqlite3_file *pFile, int desired, int *pGot){
+ return sqlite3OsShmLock(((CrashFile*)pFile)->pRealFile, desired, pGot);
+}
+static int cfShmClose(sqlite3_file *pFile, int delFlag){
+ return sqlite3OsShmClose(((CrashFile*)pFile)->pRealFile, delFlag);
+}
+
+
static const sqlite3_io_methods CrashFileVtab = {
- 1, /* iVersion */
+ 2, /* iVersion */
cfClose, /* xClose */
cfRead, /* xRead */
cfWrite, /* xWrite */
@@ -533,7 +556,13 @@ static const sqlite3_io_methods CrashFileVtab = {
cfCheckReservedLock, /* xCheckReservedLock */
cfFileControl, /* xFileControl */
cfSectorSize, /* xSectorSize */
- cfDeviceCharacteristics /* xDeviceCharacteristics */
+ cfDeviceCharacteristics, /* xDeviceCharacteristics */
+ cfShmOpen, /* xShmOpen */
+ cfShmSize, /* xShmSize */
+ cfShmGet, /* xShmGet */
+ cfShmRelease, /* xShmRelease */
+ cfShmLock, /* xShmLock */
+ cfShmClose /* xShmClose */
};
/*
@@ -657,33 +686,6 @@ static int cfCurrentTime(sqlite3_vfs *pCfVfs, double *pTimeOut){
sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
return pVfs->xCurrentTime(pVfs, pTimeOut);
}
-static int cfShmOpen(sqlite3_vfs *pCfVfs, const char *zName, sqlite3_shm **pp){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
- return pVfs->xShmOpen(pVfs, zName, pp);
-}
-static int cfShmSize(sqlite3_vfs *pCfVfs, sqlite3_shm *p,
- int reqSize, int *pNew){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
- return pVfs->xShmSize(pVfs, p, reqSize, pNew);
-}
-static int cfShmGet(sqlite3_vfs *pCfVfs, sqlite3_shm *p,
- int reqSize, int *pSize, void **pp){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
- return pVfs->xShmGet(pVfs, p, reqSize, pSize, pp);
-}
-static int cfShmRelease(sqlite3_vfs *pCfVfs, sqlite3_shm *p){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
- return pVfs->xShmRelease(pVfs, p);
-}
-static int cfShmLock(sqlite3_vfs *pCfVfs, sqlite3_shm *p,
- int desiredLock, int *gotLock){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
- return pVfs->xShmLock(pVfs, p, desiredLock, gotLock);
-}
-static int cfShmClose(sqlite3_vfs *pCfVfs, sqlite3_shm *p, int delFlag){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
- return pVfs->xShmClose(pVfs, p, delFlag);
-}
static int processDevSymArgs(
Tcl_Interp *interp,
@@ -810,12 +812,6 @@ static int crashEnableCmd(
cfSleep, /* xSleep */
cfCurrentTime, /* xCurrentTime */
0, /* xGetlastError */
- cfShmOpen, /* xShmOpen */
- cfShmSize, /* xShmSize */
- cfShmGet, /* xShmGet */
- cfShmRelease, /* xShmRelease */
- cfShmLock, /* xShmLock */
- cfShmClose, /* xShmClose */
0, /* xRename */
0, /* xCurrentTimeInt64 */
};
@@ -838,11 +834,6 @@ static int crashEnableCmd(
crashVfs.mxPathname = pOriginalVfs->mxPathname;
crashVfs.pAppData = (void *)pOriginalVfs;
crashVfs.szOsFile = sizeof(CrashFile) + pOriginalVfs->szOsFile;
- if( pOriginalVfs->iVersion<2 || pOriginalVfs->xShmOpen==0 ){
- crashVfs.xShmOpen = 0;
- }else{
- crashVfs.xShmOpen = cfShmOpen;
- }
sqlite3_vfs_register(&crashVfs, 0);
}else{
crashVfs.pAppData = 0;
diff --git a/src/test_devsym.c b/src/test_devsym.c
index 082d101d4..0a60b3c94 100644
--- a/src/test_devsym.c
+++ b/src/test_devsym.c
@@ -50,6 +50,12 @@ static int devsymCheckReservedLock(sqlite3_file*, int *);
static int devsymFileControl(sqlite3_file*, int op, void *pArg);
static int devsymSectorSize(sqlite3_file*);
static int devsymDeviceCharacteristics(sqlite3_file*);
+static int devsymShmOpen(sqlite3_file*);
+static int devsymShmSize(sqlite3_file*,int,int*);
+static int devsymShmGet(sqlite3_file*,int,int*,void**);
+static int devsymShmRelease(sqlite3_file*);
+static int devsymShmLock(sqlite3_file*,int,int*);
+static int devsymShmClose(sqlite3_file*,int);
/*
** Method declarations for devsym_vfs.
@@ -68,13 +74,6 @@ static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int devsymSleep(sqlite3_vfs*, int microseconds);
static int devsymCurrentTime(sqlite3_vfs*, double*);
-static int devsymShmOpen(sqlite3_vfs *, const char *, sqlite3_shm **);
-static int devsymShmSize(sqlite3_vfs*, sqlite3_shm *, int , int *);
-static int devsymShmGet(sqlite3_vfs*, sqlite3_shm *, int , int *, void **);
-static int devsymShmRelease(sqlite3_vfs*, sqlite3_shm *);
-static int devsymShmLock(sqlite3_vfs*, sqlite3_shm *, int , int *);
-static int devsymShmClose(sqlite3_vfs*, sqlite3_shm *, int);
-
static sqlite3_vfs devsym_vfs = {
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
@@ -101,18 +100,12 @@ static sqlite3_vfs devsym_vfs = {
devsymSleep, /* xSleep */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
- devsymShmOpen,
- devsymShmSize,
- devsymShmGet,
- devsymShmRelease,
- devsymShmLock,
- devsymShmClose,
- 0,
- 0,
+ 0, /* xRename */
+ 0 /* xCurrentTimeInt64 */
};
static sqlite3_io_methods devsym_io_methods = {
- 1, /* iVersion */
+ 2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
devsymWrite, /* xWrite */
@@ -124,7 +117,13 @@ static sqlite3_io_methods devsym_io_methods = {
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
devsymSectorSize, /* xSectorSize */
- devsymDeviceCharacteristics /* xDeviceCharacteristics */
+ devsymDeviceCharacteristics, /* xDeviceCharacteristics */
+ devsymShmOpen, /* xShmOpen */
+ devsymShmSize, /* xShmSize */
+ devsymShmGet, /* xShmGet */
+ devsymShmRelease, /* xShmRelease */
+ devsymShmLock, /* xShmLock */
+ devsymShmClose /* xShmClose */
};
struct DevsymGlobal {
@@ -239,6 +238,36 @@ static int devsymDeviceCharacteristics(sqlite3_file *pFile){
}
/*
+** Shared-memory methods are all pass-thrus.
+*/
+static int devsymShmOpen(sqlite3_file *pFile){
+ devsym_file *p = (devsym_file *)pFile;
+ return sqlite3OsShmOpen(p->pReal);
+}
+static int devsymShmSize(sqlite3_file *pFile, int reqSize, int *pSize){
+ devsym_file *p = (devsym_file *)pFile;
+ return sqlite3OsShmSize(p->pReal, reqSize, pSize);
+}
+static int devsymShmGet(sqlite3_file *pFile, int reqSz, int *pSize, void **pp){
+ devsym_file *p = (devsym_file *)pFile;
+ return sqlite3OsShmGet(p->pReal, reqSz, pSize, pp);
+}
+static int devsymShmRelease(sqlite3_file *pFile){
+ devsym_file *p = (devsym_file *)pFile;
+ return sqlite3OsShmRelease(p->pReal);
+}
+static int devsymShmLock(sqlite3_file *pFile, int desired, int *pGot){
+ devsym_file *p = (devsym_file *)pFile;
+ return sqlite3OsShmLock(p->pReal, desired, pGot);
+}
+static int devsymShmClose(sqlite3_file *pFile, int delFlag){
+ devsym_file *p = (devsym_file *)pFile;
+ return sqlite3OsShmClose(p->pReal, delFlag);
+}
+
+
+
+/*
** Open an devsym file handle.
*/
static int devsymOpen(
@@ -350,45 +379,6 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
}
-static int devsymShmOpen(
- sqlite3_vfs *pVfs,
- const char *zName,
- sqlite3_shm **pp
-){
- return g.pVfs->xShmOpen(g.pVfs, zName, pp);
-}
-static int devsymShmSize(
- sqlite3_vfs *pVfs,
- sqlite3_shm *p,
- int reqSize,
- int *pNewSize
-){
- return g.pVfs->xShmSize(g.pVfs, p, reqSize, pNewSize);
-}
-static int devsymShmGet(
- sqlite3_vfs *pVfs,
- sqlite3_shm *p,
- int reqMapSize,
- int *pMapSize,
- void **pp
-){
- return g.pVfs->xShmGet(g.pVfs, p, reqMapSize, pMapSize, pp);
-}
-static int devsymShmRelease(sqlite3_vfs *pVfs, sqlite3_shm *p){
- return g.pVfs->xShmRelease(g.pVfs, p);
-}
-static int devsymShmLock(
- sqlite3_vfs *pVfs,
- sqlite3_shm *p,
- int desiredLock,
- int *gotLock
-){
- return g.pVfs->xShmLock(g.pVfs, p, desiredLock, gotLock);
-}
-static int devsymShmClose(sqlite3_vfs *pVfs, sqlite3_shm *p, int deleteFlag){
- return g.pVfs->xShmClose(g.pVfs, p, deleteFlag);
-}
-
/*
** This procedure registers the devsym vfs with SQLite. If the argument is
** true, the devsym vfs becomes the new default vfs. It is the only publicly
@@ -398,12 +388,6 @@ void devsym_register(int iDeviceChar, int iSectorSize){
if( g.pVfs==0 ){
g.pVfs = sqlite3_vfs_find(0);
devsym_vfs.szOsFile += g.pVfs->szOsFile;
- devsym_vfs.xShmOpen = (g.pVfs->xShmOpen ? devsymShmOpen : 0);
- devsym_vfs.xShmSize = (g.pVfs->xShmSize ? devsymShmSize : 0);
- devsym_vfs.xShmGet = (g.pVfs->xShmGet ? devsymShmGet : 0);
- devsym_vfs.xShmRelease = (g.pVfs->xShmRelease ? devsymShmRelease : 0);
- devsym_vfs.xShmLock = (g.pVfs->xShmLock ? devsymShmLock : 0);
- devsym_vfs.xShmClose = (g.pVfs->xShmClose ? devsymShmClose : 0);
sqlite3_vfs_register(&devsym_vfs, 0);
}
if( iDeviceChar>=0 ){
diff --git a/src/test_onefile.c b/src/test_onefile.c
index 6b39a39ad..520dffcb7 100644
--- a/src/test_onefile.c
+++ b/src/test_onefile.c
@@ -199,11 +199,6 @@ static fs_vfs_t fs_vfs = {
fsRandomness, /* xRandomness */
fsSleep, /* xSleep */
fsCurrentTime, /* xCurrentTime */
- 0, /* xShmOpen */
- 0, /* xShmSize */
- 0, /* xShmLock */
- 0, /* xShmClose */
- 0, /* xShmDelete */
0, /* xRename */
0 /* xCurrentTimeInt64 */
},
@@ -224,7 +219,12 @@ static sqlite3_io_methods fs_io_methods = {
fsCheckReservedLock, /* xCheckReservedLock */
fsFileControl, /* xFileControl */
fsSectorSize, /* xSectorSize */
- fsDeviceCharacteristics /* xDeviceCharacteristics */
+ fsDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmOpen */
+ 0, /* xShmSize */
+ 0, /* xShmLock */
+ 0, /* xShmClose */
+ 0, /* xShmDelete */
};
@@ -241,7 +241,12 @@ static sqlite3_io_methods tmp_io_methods = {
tmpCheckReservedLock, /* xCheckReservedLock */
tmpFileControl, /* xFileControl */
tmpSectorSize, /* xSectorSize */
- tmpDeviceCharacteristics /* xDeviceCharacteristics */
+ tmpDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmOpen */
+ 0, /* xShmSize */
+ 0, /* xShmLock */
+ 0, /* xShmClose */
+ 0, /* xShmDelete */
};
/* Useful macros used in several places */
diff --git a/src/test_vfs.c b/src/test_vfs.c
index 1b5b4b09d..ce4afa762 100644
--- a/src/test_vfs.c
+++ b/src/test_vfs.c
@@ -16,15 +16,23 @@
#include "sqlite3.h"
#include "sqliteInt.h"
-typedef struct tvfs_file tvfs_file;
-struct tvfs_file {
- sqlite3_file base;
- sqlite3_file *pReal;
-};
-
typedef struct Testvfs Testvfs;
typedef struct TestvfsShm TestvfsShm;
typedef struct TestvfsBuffer TestvfsBuffer;
+typedef struct TestvfsFile TestvfsFile;
+
+/*
+** An open file handle.
+*/
+struct TestvfsFile {
+ sqlite3_file base; /* Base class. Must be first */
+ sqlite3_vfs *pVfs; /* The VFS */
+ const char *zFilename; /* Filename as passed to xOpen() */
+ sqlite3_file *pReal; /* The real, underlying file descriptor */
+ Tcl_Obj *pShmId; /* Shared memory id for Tcl callbacks */
+ TestvfsBuffer *pShm; /* Shared memory buffer */
+};
+
/*
** An instance of this structure is allocated for each VFS created. The
@@ -39,6 +47,7 @@ struct Testvfs {
int nScript; /* Number of elements in array apScript */
Tcl_Obj **apScript; /* Script to execute */
TestvfsBuffer *pBuffer; /* List of shared buffers */
+ int isNoshm;
};
/*
@@ -52,20 +61,12 @@ struct TestvfsBuffer {
TestvfsBuffer *pNext; /* Next in linked list of all buffers */
};
-/*
-** A shared-memory handle returned by tvfsShmOpen().
-*/
-struct TestvfsShm {
- Tcl_Obj *id; /* Name of this handle */
- TestvfsBuffer *pBuffer; /* Underlying buffer */
-};
-
#define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent)
/*
-** Method declarations for tvfs_file.
+** Method declarations for TestvfsFile.
*/
static int tvfsClose(sqlite3_file*);
static int tvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
@@ -97,15 +98,15 @@ static int tvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int tvfsSleep(sqlite3_vfs*, int microseconds);
static int tvfsCurrentTime(sqlite3_vfs*, double*);
-static int tvfsShmOpen(sqlite3_vfs *, const char *, sqlite3_shm **);
-static int tvfsShmSize(sqlite3_vfs*, sqlite3_shm *, int , int *);
-static int tvfsShmGet(sqlite3_vfs*, sqlite3_shm *, int , int *, void **);
-static int tvfsShmRelease(sqlite3_vfs*, sqlite3_shm *);
-static int tvfsShmLock(sqlite3_vfs*, sqlite3_shm *, int , int *);
-static int tvfsShmClose(sqlite3_vfs*, sqlite3_shm *, int);
+static int tvfsShmOpen(sqlite3_file*);
+static int tvfsShmSize(sqlite3_file*, int , int *);
+static int tvfsShmGet(sqlite3_file*, int , int *, void **);
+static int tvfsShmRelease(sqlite3_file*);
+static int tvfsShmLock(sqlite3_file*, int , int *);
+static int tvfsShmClose(sqlite3_file*, int);
static sqlite3_io_methods tvfs_io_methods = {
- 1, /* iVersion */
+ 2, /* iVersion */
tvfsClose, /* xClose */
tvfsRead, /* xRead */
tvfsWrite, /* xWrite */
@@ -117,14 +118,27 @@ static sqlite3_io_methods tvfs_io_methods = {
tvfsCheckReservedLock, /* xCheckReservedLock */
tvfsFileControl, /* xFileControl */
tvfsSectorSize, /* xSectorSize */
- tvfsDeviceCharacteristics /* xDeviceCharacteristics */
+ tvfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ tvfsShmOpen, /* xShmOpen */
+ tvfsShmSize, /* xShmSize */
+ tvfsShmGet, /* xShmGet */
+ tvfsShmRelease, /* xShmRelease */
+ tvfsShmLock, /* xShmLock */
+ tvfsShmClose /* xShmClose */
};
/*
** Close an tvfs-file.
*/
static int tvfsClose(sqlite3_file *pFile){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
+ if( p->pShmId ){
+ Tcl_DecrRefCount(p->pShmId);
+ p->pShmId = 0;
+ }
+ if( pFile->pMethods ){
+ ckfree((char *)pFile->pMethods);
+ }
return sqlite3OsClose(p->pReal);
}
@@ -137,7 +151,7 @@ static int tvfsRead(
int iAmt,
sqlite_int64 iOfst
){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
}
@@ -150,7 +164,7 @@ static int tvfsWrite(
int iAmt,
sqlite_int64 iOfst
){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}
@@ -158,7 +172,7 @@ static int tvfsWrite(
** Truncate an tvfs-file.
*/
static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsTruncate(p->pReal, size);
}
@@ -166,7 +180,7 @@ static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
** Sync an tvfs-file.
*/
static int tvfsSync(sqlite3_file *pFile, int flags){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsSync(p->pReal, flags);
}
@@ -174,7 +188,7 @@ static int tvfsSync(sqlite3_file *pFile, int flags){
** Return the current file-size of an tvfs-file.
*/
static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsFileSize(p->pReal, pSize);
}
@@ -182,7 +196,7 @@ static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
** Lock an tvfs-file.
*/
static int tvfsLock(sqlite3_file *pFile, int eLock){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsLock(p->pReal, eLock);
}
@@ -190,7 +204,7 @@ static int tvfsLock(sqlite3_file *pFile, int eLock){
** Unlock an tvfs-file.
*/
static int tvfsUnlock(sqlite3_file *pFile, int eLock){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsUnlock(p->pReal, eLock);
}
@@ -198,7 +212,7 @@ static int tvfsUnlock(sqlite3_file *pFile, int eLock){
** Check if another file-handle holds a RESERVED lock on an tvfs-file.
*/
static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsCheckReservedLock(p->pReal, pResOut);
}
@@ -206,7 +220,7 @@ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
** File control method. For custom operations on an tvfs-file.
*/
static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsFileControl(p->pReal, op, pArg);
}
@@ -214,7 +228,7 @@ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
** Return the sector-size in bytes for an tvfs-file.
*/
static int tvfsSectorSize(sqlite3_file *pFile){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsSectorSize(p->pReal);
}
@@ -222,7 +236,7 @@ static int tvfsSectorSize(sqlite3_file *pFile){
** Return the device characteristic flags supported by an tvfs-file.
*/
static int tvfsDeviceCharacteristics(sqlite3_file *pFile){
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsDeviceCharacteristics(p->pReal);
}
@@ -237,12 +251,28 @@ static int tvfsOpen(
int *pOutFlags
){
int rc;
- tvfs_file *p = (tvfs_file *)pFile;
+ TestvfsFile *p = (TestvfsFile *)pFile;
+ p->pShm = 0;
+ p->pShmId = 0;
+ p->zFilename = zName;
+ p->pVfs = pVfs;
p->pReal = (sqlite3_file *)&p[1];
rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, p->pReal, flags, pOutFlags);
if( p->pReal->pMethods ){
- pFile->pMethods = &tvfs_io_methods;
+ sqlite3_io_methods *pMethods;
+ pMethods = (sqlite3_io_methods *)ckalloc(sizeof(sqlite3_io_methods));
+ memcpy(pMethods, &tvfs_io_methods, sizeof(sqlite3_io_methods));
+ if( ((Testvfs *)pVfs->pAppData)->isNoshm ){
+ pMethods->xShmOpen = 0;
+ pMethods->xShmGet = 0;
+ pMethods->xShmSize = 0;
+ pMethods->xShmRelease = 0;
+ pMethods->xShmClose = 0;
+ pMethods->xShmLock = 0;
+ }
+ pFile->pMethods = pMethods;
}
+
return rc;
}
@@ -337,8 +367,8 @@ static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut);
}
-static void tvfsGrowBuffer(TestvfsShm *pShm, int reqSize, int *pNewSize){
- TestvfsBuffer *pBuffer = pShm->pBuffer;
+static void tvfsGrowBuffer(TestvfsFile *pFd, int reqSize, int *pNewSize){
+ TestvfsBuffer *pBuffer = pFd->pShm;
if( reqSize>pBuffer->n ){
pBuffer->a = (u8 *)ckrealloc((char *)pBuffer->a, reqSize);
memset(&pBuffer->a[pBuffer->n], 0x55, reqSize-pBuffer->n);
@@ -405,15 +435,17 @@ static int tvfsResultCode(Testvfs *p, int *pRc){
}
static int tvfsShmOpen(
- sqlite3_vfs *pVfs,
- const char *zName,
- sqlite3_shm **pp
+ sqlite3_file *pFileDes
){
- Testvfs *p = (Testvfs *)(pVfs->pAppData);
+ Testvfs *p;
int rc = SQLITE_OK; /* Return code */
Tcl_Obj *pId = 0; /* Id for this connection */
TestvfsBuffer *pBuffer; /* Buffer to open connection to */
- TestvfsShm *pShm; /* New shm handle */
+ TestvfsFile *pFd; /* The testvfs file structure */
+
+ pFd = (TestvfsFile*)pFileDes;
+ p = (Testvfs *)pFd->pVfs->pAppData;
+ assert( pFd->pShmId==0 && pFd->pShm==0 );
/* Evaluate the Tcl script:
**
@@ -424,7 +456,7 @@ static int tvfsShmOpen(
** connection is named "anon". Otherwise, the value returned by the
** script is used as the connection name.
*/
- tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(zName, -1), 0, 0);
+ tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0);
if( tvfsResultCode(p, &rc) ){
if( rc!=SQLITE_OK ) return rc;
pId = Tcl_NewStringObj("anon", -1);
@@ -432,82 +464,75 @@ static int tvfsShmOpen(
pId = Tcl_GetObjResult(p->interp);
}
Tcl_IncrRefCount(pId);
-
- /* Allocate the TestvfsShm handle. */
- pShm = (TestvfsShm *)ckalloc(sizeof(TestvfsShm));
- memset(pShm, 0, sizeof(TestvfsShm));
- pShm->id = pId;
+ pFd->pShmId = pId;
/* Search for a TestvfsBuffer. Create a new one if required. */
for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){
- if( 0==strcmp(zName, pBuffer->zFile) ) break;
+ if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break;
}
if( !pBuffer ){
- int nByte = sizeof(TestvfsBuffer) + strlen(zName) + 1;
+ int nByte = sizeof(TestvfsBuffer) + strlen(pFd->zFilename) + 1;
pBuffer = (TestvfsBuffer *)ckalloc(nByte);
memset(pBuffer, 0, nByte);
pBuffer->zFile = (char *)&pBuffer[1];
- strcpy(pBuffer->zFile, zName);
+ strcpy(pBuffer->zFile, pFd->zFilename);
pBuffer->pNext = p->pBuffer;
p->pBuffer = pBuffer;
}
/* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */
pBuffer->nRef++;
- pShm->pBuffer = pBuffer;
- *pp = (sqlite3_shm *)pShm;
+ pFd->pShm = pBuffer;
return SQLITE_OK;
}
static int tvfsShmSize(
- sqlite3_vfs *pVfs,
- sqlite3_shm *pShmHandle,
+ sqlite3_file *pFile,
int reqSize,
int *pNewSize
){
int rc = SQLITE_OK;
- Testvfs *p = (Testvfs *)(pVfs->pAppData);
- TestvfsShm *pShm = (TestvfsShm *)pShmHandle;
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
tvfsExecTcl(p, "xShmSize",
- Tcl_NewStringObj(pShm->pBuffer->zFile, -1), pShm->id, 0
+ Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
if( rc==SQLITE_OK ){
- tvfsGrowBuffer(pShm, reqSize, pNewSize);
+ tvfsGrowBuffer(pFd, reqSize, pNewSize);
}
return rc;
}
static int tvfsShmGet(
- sqlite3_vfs *pVfs,
- sqlite3_shm *pShmHandle,
+ sqlite3_file *pFile,
int reqMapSize,
int *pMapSize,
void **pp
){
int rc = SQLITE_OK;
- Testvfs *p = (Testvfs *)(pVfs->pAppData);
- TestvfsShm *pShm = (TestvfsShm *)pShmHandle;
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
tvfsExecTcl(p, "xShmGet",
- Tcl_NewStringObj(pShm->pBuffer->zFile, -1), pShm->id, 0
+ Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
if( rc==SQLITE_OK ){
- tvfsGrowBuffer(pShm, reqMapSize, pMapSize);
- *pp = pShm->pBuffer->a;
+ tvfsGrowBuffer(pFd, reqMapSize, pMapSize);
+ *pp = pFd->pShm->a;
}
return rc;
}
-static int tvfsShmRelease(sqlite3_vfs *pVfs, sqlite3_shm *pShmHandle){
+static int tvfsShmRelease(sqlite3_file *pFile){
int rc = SQLITE_OK;
- Testvfs *p = (Testvfs *)(pVfs->pAppData);
- TestvfsShm *pShm = (TestvfsShm *)pShmHandle;
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
tvfsExecTcl(p, "xShmRelease",
- Tcl_NewStringObj(pShm->pBuffer->zFile, -1), pShm->id, 0
+ Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
@@ -515,14 +540,13 @@ static int tvfsShmRelease(sqlite3_vfs *pVfs, sqlite3_shm *pShmHandle){
}
static int tvfsShmLock(
- sqlite3_vfs *pVfs,
- sqlite3_shm *pShmHandle,
+ sqlite3_file *pFile,
int desiredLock,
int *gotLock
){
int rc = SQLITE_OK;
- Testvfs *p = (Testvfs *)(pVfs->pAppData);
- TestvfsShm *pShm = (TestvfsShm *)pShmHandle;
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
char *zLock = "";
switch( desiredLock ){
@@ -534,7 +558,7 @@ static int tvfsShmLock(
case SQLITE_SHM_UNLOCK: zLock = "UNLOCK"; break;
}
tvfsExecTcl(p, "xShmLock",
- Tcl_NewStringObj(pShm->pBuffer->zFile, -1), pShm->id,
+ Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId,
Tcl_NewStringObj(zLock, -1)
);
tvfsResultCode(p, &rc);
@@ -546,21 +570,21 @@ static int tvfsShmLock(
}
static int tvfsShmClose(
- sqlite3_vfs *pVfs,
- sqlite3_shm *pShmHandle,
+ sqlite3_file *pFile,
int deleteFlag
){
int rc = SQLITE_OK;
- Testvfs *p = (Testvfs *)(pVfs->pAppData);
- TestvfsShm *pShm = (TestvfsShm *)pShmHandle;
- TestvfsBuffer *pBuffer = pShm->pBuffer;
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
+ TestvfsBuffer *pBuffer = pFd->pShm;
+ assert( pFd->pShmId && pFd->pShm );
#if 0
assert( (deleteFlag!=0)==(pBuffer->nRef==1) );
#endif
tvfsExecTcl(p, "xShmClose",
- Tcl_NewStringObj(pShm->pBuffer->zFile, -1), pShm->id, 0
+ Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
@@ -572,8 +596,9 @@ static int tvfsShmClose(
ckfree((char *)pBuffer->a);
ckfree((char *)pBuffer);
}
- Tcl_DecrRefCount(pShm->id);
- ckfree((char *)pShm);
+ Tcl_DecrRefCount(pFd->pShmId);
+ pFd->pShmId = 0;
+ pFd->pShm = 0;
return rc;
}
@@ -687,10 +712,9 @@ static int testvfs_cmd(
int objc,
Tcl_Obj *CONST objv[]
){
-
static sqlite3_vfs tvfs_vfs = {
2, /* iVersion */
- sizeof(tvfs_file), /* szOsFile */
+ sizeof(TestvfsFile), /* szOsFile */
0, /* mxPathname */
0, /* pNext */
0, /* zName */
@@ -714,12 +738,6 @@ static int testvfs_cmd(
tvfsSleep, /* xSleep */
tvfsCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
- tvfsShmOpen,
- tvfsShmSize,
- tvfsShmGet,
- tvfsShmRelease,
- tvfsShmLock,
- tvfsShmClose,
0,
0,
};
@@ -770,14 +788,7 @@ static int testvfs_cmd(
pVfs->mxPathname = p->pParent->mxPathname;
pVfs->szOsFile += p->pParent->szOsFile;
p->pVfs = pVfs;
- if( isNoshm ){
- pVfs->xShmOpen = 0;
- pVfs->xShmGet = 0;
- pVfs->xShmSize = 0;
- pVfs->xShmRelease = 0;
- pVfs->xShmClose = 0;
- pVfs->xShmLock = 0;
- }
+ p->isNoshm = isNoshm;
Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
sqlite3_vfs_register(pVfs, 0);
diff --git a/src/vdbe.c b/src/vdbe.c
index 88f880ea9..3fee165da 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -5248,8 +5248,8 @@ case OP_JournalMode: { /* out2-prerelease */
** in temporary storage or if the VFS does not support xShmOpen.
*/
if( eNew==PAGER_JOURNALMODE_WAL
- && (zFilename[0]==0 /* Temp file */
- || pVfs->iVersion<2 || pVfs->xShmOpen==0) /* No xShmOpen support */
+ && (zFilename[0]==0 /* Temp file */
+ || !sqlite3PagerWalSupported(pPager)) /* No xShmOpen support */
){
eNew = PAGER_JOURNALMODE_QUERY;
}
diff --git a/src/wal.c b/src/wal.c
index bdae2e9df..3c16dccc3 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -125,16 +125,17 @@ struct WalIndexHdr {
*/
struct Wal {
sqlite3_vfs *pVfs; /* The VFS used to create pFd */
- sqlite3_file *pFd; /* File handle for WAL file */
+ sqlite3_file *pDbFd; /* File handle for the database file */
+ sqlite3_file *pWalFd; /* File handle for WAL file */
u32 iCallback; /* Value to pass to log callback (or 0) */
- sqlite3_shm *pWIndex; /* The open wal-index file */
int szWIndex; /* Size of the wal-index that is mapped in mem */
u32 *pWiData; /* Pointer to wal-index content in memory */
u8 lockState; /* SQLITE_SHM_xxxx constant showing lock state */
u8 readerType; /* SQLITE_SHM_READ or SQLITE_SHM_READ_FULL */
u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
+ u8 isWindexOpen; /* True if ShmOpen() called on pDbFd */
WalIndexHdr hdr; /* Wal-index for current snapshot */
- char *zName; /* Name of underlying storage */
+ char *zWalName; /* Name of WAL file */
};
@@ -223,7 +224,7 @@ static int walSetLock(Wal *pWal, int desiredStatus){
pWal->lockState = desiredStatus;
}else{
int got = pWal->lockState;
- rc = pWal->pVfs->xShmLock(pWal->pVfs, pWal->pWIndex, desiredStatus, &got);
+ rc = sqlite3OsShmLock(pWal->pDbFd, desiredStatus, &got);
pWal->lockState = got;
if( got==SQLITE_SHM_READ_FULL || got==SQLITE_SHM_READ ){
pWal->readerType = got;
@@ -404,7 +405,7 @@ static int walMappingSize(u32 iFrame){
*/
static void walIndexUnmap(Wal *pWal){
if( pWal->pWiData ){
- pWal->pVfs->xShmRelease(pWal->pVfs, pWal->pWIndex);
+ sqlite3OsShmRelease(pWal->pDbFd);
pWal->pWiData = 0;
}
}
@@ -418,8 +419,8 @@ static void walIndexUnmap(Wal *pWal){
static int walIndexMap(Wal *pWal, int reqSize){
int rc = SQLITE_OK;
if( pWal->pWiData==0 || reqSize>pWal->szWIndex ){
- rc = pWal->pVfs->xShmGet(pWal->pVfs, pWal->pWIndex, reqSize,
- &pWal->szWIndex, (void**)(char*)&pWal->pWiData);
+ rc = sqlite3OsShmGet(pWal->pDbFd, reqSize, &pWal->szWIndex,
+ (void**)(char*)&pWal->pWiData);
if( rc==SQLITE_OK && pWal->pWiData==0 ){
/* Make sure pWal->pWiData is not NULL while we are holding the
** lock on the mapping. */
@@ -443,7 +444,7 @@ static int walIndexMap(Wal *pWal, int reqSize){
static int walIndexRemap(Wal *pWal, int enlargeTo){
int rc;
int sz;
- rc = pWal->pVfs->xShmSize(pWal->pVfs, pWal->pWIndex, enlargeTo, &sz);
+ rc = sqlite3OsShmSize(pWal->pDbFd, enlargeTo, &sz);
if( rc==SQLITE_OK && sz>pWal->szWIndex ){
walIndexUnmap(pWal);
rc = walIndexMap(pWal, sz);
@@ -561,7 +562,7 @@ static int walIndexRecover(Wal *pWal){
assert( pWal->lockState>SQLITE_SHM_READ );
memset(&hdr, 0, sizeof(hdr));
- rc = sqlite3OsFileSize(pWal->pFd, &nSize);
+ rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -579,7 +580,7 @@ static int walIndexRecover(Wal *pWal){
/* Read in the first frame header in the file (to determine the
** database page size).
*/
- rc = sqlite3OsRead(pWal->pFd, aBuf, WAL_HDRSIZE, 0);
+ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -610,7 +611,7 @@ static int walIndexRecover(Wal *pWal){
int isValid; /* True if this frame is valid */
/* Read and decode the next log frame. */
- rc = sqlite3OsRead(pWal->pFd, aFrame, nFrame, iOffset);
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, nFrame, iOffset);
if( rc!=SQLITE_OK ) break;
isValid = walDecodeFrame(aCksum, &pgno, &nTruncate, nPgsz, aData, aFrame);
if( !isValid ) break;
@@ -648,12 +649,11 @@ finished:
** Close an open wal-index.
*/
static void walIndexClose(Wal *pWal, int isDelete){
- sqlite3_shm *pWIndex = pWal->pWIndex;
- if( pWIndex ){
- sqlite3_vfs *pVfs = pWal->pVfs;
+ if( pWal->isWindexOpen ){
int notUsed;
- pVfs->xShmLock(pVfs, pWIndex, SQLITE_SHM_UNLOCK, &notUsed);
- pVfs->xShmClose(pVfs, pWIndex, isDelete);
+ sqlite3OsShmLock(pWal->pDbFd, SQLITE_SHM_UNLOCK, &notUsed);
+ sqlite3OsShmClose(pWal->pDbFd, isDelete);
+ pWal->isWindexOpen = 0;
}
}
@@ -675,41 +675,44 @@ static void walIndexClose(Wal *pWal, int isDelete){
*/
int sqlite3WalOpen(
sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
- const char *zDb, /* Name of database file */
+ sqlite3_file *pDbFd, /* The open database file */
+ const char *zDbName, /* Name of the database file */
Wal **ppWal /* OUT: Allocated Wal handle */
){
int rc; /* Return Code */
Wal *pRet; /* Object to allocate and return */
int flags; /* Flags passed to OsOpen() */
- char *zWal; /* Path to WAL file */
+ char *zWal; /* Name of write-ahead log file */
int nWal; /* Length of zWal in bytes */
- assert( zDb );
- if( pVfs->xShmOpen==0 ) return SQLITE_CANTOPEN_BKPT;
+ assert( zDbName && zDbName[0] );
+ assert( pDbFd );
/* Allocate an instance of struct Wal to return. */
*ppWal = 0;
- nWal = strlen(zDb);
- pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile + nWal+5);
+ nWal = sqlite3Strlen30(zDbName) + 5;
+ pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile + nWal);
if( !pRet ){
return SQLITE_NOMEM;
}
pRet->pVfs = pVfs;
- pRet->pFd = (sqlite3_file *)&pRet[1];
- pRet->zName = zWal = pVfs->szOsFile + (char*)pRet->pFd;
- sqlite3_snprintf(nWal+5, zWal, "%s-wal", zDb);
- rc = pVfs->xShmOpen(pVfs, zDb, &pRet->pWIndex);
+ pRet->pWalFd = (sqlite3_file *)&pRet[1];
+ pRet->pDbFd = pDbFd;
+ pRet->zWalName = zWal = pVfs->szOsFile + (char*)pRet->pWalFd;
+ sqlite3_snprintf(nWal, zWal, "%s-wal", zDbName);
+ rc = sqlite3OsShmOpen(pDbFd);
/* Open file handle on the write-ahead log file. */
if( rc==SQLITE_OK ){
+ pRet->isWindexOpen = 1;
flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MAIN_JOURNAL);
- rc = sqlite3OsOpen(pVfs, zWal, pRet->pFd, flags, &flags);
+ rc = sqlite3OsOpen(pVfs, zWal, pRet->pWalFd, flags, &flags);
}
if( rc!=SQLITE_OK ){
walIndexClose(pRet, 0);
- sqlite3OsClose(pRet->pFd);
+ sqlite3OsClose(pRet->pWalFd);
sqlite3_free(pRet);
}else{
*ppWal = pRet;
@@ -809,7 +812,6 @@ static void walIteratorFree(WalIterator *p){
*/
static int walCheckpoint(
Wal *pWal, /* Wal connection */
- sqlite3_file *pFd, /* File descriptor open on db file */
int sync_flags, /* Flags for OsSync() (or 0) */
int nBuf, /* Size of zBuf in bytes */
u8 *zBuf /* Temporary buffer to use */
@@ -833,27 +835,27 @@ static int walCheckpoint(
/* Sync the log file to disk */
if( sync_flags ){
- rc = sqlite3OsSync(pWal->pFd, sync_flags);
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
if( rc!=SQLITE_OK ) goto out;
}
/* Iterate through the contents of the log, copying data to the db file. */
while( 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
- rc = sqlite3OsRead(pWal->pFd, zBuf, pgsz,
+ rc = sqlite3OsRead(pWal->pWalFd, zBuf, pgsz,
walFrameOffset(iFrame, pgsz) + WAL_FRAME_HDRSIZE
);
if( rc!=SQLITE_OK ) goto out;
- rc = sqlite3OsWrite(pFd, zBuf, pgsz, (iDbpage-1)*pgsz);
+ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, pgsz, (iDbpage-1)*pgsz);
if( rc!=SQLITE_OK ) goto out;
}
/* Truncate the database file */
- rc = sqlite3OsTruncate(pFd, ((i64)pWal->hdr.nPage*(i64)pgsz));
+ rc = sqlite3OsTruncate(pWal->pDbFd, ((i64)pWal->hdr.nPage*(i64)pgsz));
if( rc!=SQLITE_OK ) goto out;
/* Sync the database file. If successful, update the wal-index. */
if( sync_flags ){
- rc = sqlite3OsSync(pFd, sync_flags);
+ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
if( rc!=SQLITE_OK ) goto out;
}
pWal->hdr.iLastPg = 0;
@@ -876,9 +878,9 @@ static int walCheckpoint(
*/
#if 0
memset(zBuf, 0, WAL_FRAME_HDRSIZE);
- rc = sqlite3OsWrite(pWal->pFd, zBuf, WAL_FRAME_HDRSIZE, 0);
+ rc = sqlite3OsWrite(pWal->pWalFd, zBuf, WAL_FRAME_HDRSIZE, 0);
if( rc!=SQLITE_OK ) goto out;
- rc = sqlite3OsSync(pWal->pFd, pWal->sync_flags);
+ rc = sqlite3OsSync(pWal->pWalFd, pWal->sync_flags);
#endif
out:
@@ -891,7 +893,6 @@ static int walCheckpoint(
*/
int sqlite3WalClose(
Wal *pWal, /* Wal to close */
- sqlite3_file *pFd, /* Database file */
int sync_flags, /* Flags to pass to OsSync() (or 0) */
int nBuf,
u8 *zBuf /* Buffer of at least nBuf bytes */
@@ -908,9 +909,9 @@ int sqlite3WalClose(
**
** The EXCLUSIVE lock is not released before returning.
*/
- rc = sqlite3OsLock(pFd, SQLITE_LOCK_EXCLUSIVE);
+ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
if( rc==SQLITE_OK ){
- rc = sqlite3WalCheckpoint(pWal, pFd, sync_flags, nBuf, zBuf, 0, 0);
+ rc = sqlite3WalCheckpoint(pWal, sync_flags, nBuf, zBuf, 0, 0);
if( rc==SQLITE_OK ){
isDelete = 1;
}
@@ -918,9 +919,9 @@ int sqlite3WalClose(
}
walIndexClose(pWal, isDelete);
- sqlite3OsClose(pWal->pFd);
+ sqlite3OsClose(pWal->pWalFd);
if( isDelete ){
- sqlite3OsDelete(pWal->pVfs, pWal->zName, 0);
+ sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
}
sqlite3_free(pWal);
}
@@ -1191,7 +1192,7 @@ int sqlite3WalRead(
if( iRead ){
i64 iOffset = walFrameOffset(iRead, pWal->hdr.pgsz) + WAL_FRAME_HDRSIZE;
*pInWal = 1;
- return sqlite3OsRead(pWal->pFd, pOut, nOut, iOffset);
+ return sqlite3OsRead(pWal->pWalFd, pOut, nOut, iOffset);
}
*pInWal = 0;
@@ -1290,7 +1291,7 @@ int sqlite3WalSavepointUndo(Wal *pWal, u32 iFrame){
pWal->hdr.iLastPg = iFrame;
if( iFrame>0 ){
i64 iOffset = walFrameOffset(iFrame, pWal->hdr.pgsz) + sizeof(u32)*2;
- rc = sqlite3OsRead(pWal->pFd, aCksum, sizeof(aCksum), iOffset);
+ rc = sqlite3OsRead(pWal->pWalFd, aCksum, sizeof(aCksum), iOffset);
pWal->hdr.iCheck1 = sqlite3Get4byte(&aCksum[0]);
pWal->hdr.iCheck2 = sqlite3Get4byte(&aCksum[4]);
}
@@ -1334,7 +1335,7 @@ int sqlite3WalFrames(
sqlite3_randomness(8, &aFrame[4]);
pWal->hdr.iCheck1 = sqlite3Get4byte(&aFrame[4]);
pWal->hdr.iCheck2 = sqlite3Get4byte(&aFrame[8]);
- rc = sqlite3OsWrite(pWal->pFd, aFrame, WAL_HDRSIZE, 0);
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, WAL_HDRSIZE, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -1353,13 +1354,13 @@ int sqlite3WalFrames(
/* Populate and write the frame header */
nDbsize = (isCommit && p->pDirty==0) ? nTruncate : 0;
walEncodeFrame(aCksum, p->pgno, nDbsize, nPgsz, p->pData, aFrame);
- rc = sqlite3OsWrite(pWal->pFd, aFrame, sizeof(aFrame), iOffset);
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
if( rc!=SQLITE_OK ){
return rc;
}
/* Write the page data */
- rc = sqlite3OsWrite(pWal->pFd, p->pData, nPgsz, iOffset + sizeof(aFrame));
+ rc = sqlite3OsWrite(pWal->pWalFd, p->pData, nPgsz, iOffset + sizeof(aFrame));
if( rc!=SQLITE_OK ){
return rc;
}
@@ -1368,7 +1369,7 @@ int sqlite3WalFrames(
/* Sync the log file if the 'isSync' flag was specified. */
if( sync_flags ){
- i64 iSegment = sqlite3OsSectorSize(pWal->pFd);
+ i64 iSegment = sqlite3OsSectorSize(pWal->pWalFd);
i64 iOffset = walFrameOffset(iFrame+1, nPgsz);
assert( isCommit );
@@ -1379,13 +1380,13 @@ int sqlite3WalFrames(
iSegment = (((iOffset+iSegment-1)/iSegment) * iSegment);
while( iOffset<iSegment ){
walEncodeFrame(aCksum,pLast->pgno,nTruncate,nPgsz,pLast->pData,aFrame);
- rc = sqlite3OsWrite(pWal->pFd, aFrame, sizeof(aFrame), iOffset);
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
if( rc!=SQLITE_OK ){
return rc;
}
iOffset += WAL_FRAME_HDRSIZE;
- rc = sqlite3OsWrite(pWal->pFd, pLast->pData, nPgsz, iOffset);
+ rc = sqlite3OsWrite(pWal->pWalFd, pLast->pData, nPgsz, iOffset);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -1393,7 +1394,7 @@ int sqlite3WalFrames(
iOffset += nPgsz;
}
- rc = sqlite3OsSync(pWal->pFd, sync_flags);
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
}
assert( pWal->pWiData==0 );
@@ -1445,7 +1446,6 @@ int sqlite3WalFrames(
*/
int sqlite3WalCheckpoint(
Wal *pWal, /* Wal connection */
- sqlite3_file *pFd, /* File descriptor open on db file */
int sync_flags, /* Flags to sync db file with (or 0) */
int nBuf, /* Size of temporary buffer */
u8 *zBuf, /* Temporary buffer to use */
@@ -1479,7 +1479,7 @@ int sqlite3WalCheckpoint(
/* Copy data from the log to the database file. */
rc = walIndexReadHdr(pWal, &isChanged);
if( rc==SQLITE_OK ){
- rc = walCheckpoint(pWal, pFd, sync_flags, nBuf, zBuf);
+ rc = walCheckpoint(pWal, sync_flags, nBuf, zBuf);
}
if( isChanged ){
/* If a new wal-index header was loaded before the checkpoint was
diff --git a/src/wal.h b/src/wal.h
index 89e94869c..1e25fc811 100644
--- a/src/wal.h
+++ b/src/wal.h
@@ -41,8 +41,8 @@
typedef struct Wal Wal;
/* Open and close a connection to a write-ahead log. */
-int sqlite3WalOpen(sqlite3_vfs*, const char *zDb, Wal **ppWal);
-int sqlite3WalClose(Wal *pWal, sqlite3_file *pFd, int sync_flags, int, u8 *);
+int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, Wal**);
+int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
/* Used by readers to open (lock) and close (unlock) a snapshot. A
** snapshot is like a read-transaction. It is the state of the database
@@ -81,7 +81,6 @@ int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
/* Copy pages from the log to the database file */
int sqlite3WalCheckpoint(
Wal *pWal, /* Write-ahead log connection */
- sqlite3_file *pFd, /* File descriptor open on db file */
int sync_flags, /* Flags to sync db file with (or 0) */
int nBuf, /* Size of buffer nBuf */
u8 *zBuf, /* Temporary buffer to use */