From d9e5c4f6ed8b28c2e926679684dec191a3a52b5f Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 May 2010 18:01:39 +0000 Subject: [PATCH 1/6] Refactoring the VFS-SHM methods used by WAL. This version compiles and runs non-WAL test cases but crashes and burns on wal.test. FossilOrigin-Name: 2b00152c1ac0b3735aa6cfab61259ff04d81c701 --- doc/vfs-shm.txt | 18 +- manifest | 48 +- manifest.uuid | 2 +- src/os.c | 18 + src/os.h | 6 + src/os_unix.c | 1641 ++++++++++++++++++++++---------------------- src/pager.c | 24 +- src/pager.h | 1 + src/sqlite.h.in | 15 +- src/test6.c | 71 +- src/test_devsym.c | 72 +- src/test_onefile.c | 19 +- src/test_vfs.c | 58 +- src/vdbe.c | 4 +- src/wal.c | 104 +-- src/wal.h | 5 +- 16 files changed, 1061 insertions(+), 1045 deletions(-) diff --git a/doc/vfs-shm.txt b/doc/vfs-shm.txt index 93ab457cd3..c1f125a120 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 fae36ae92a..e8b35b9920 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 Refactoring\sthe\sVFS-SHM\smethods\sused\sby\sWAL.\s\sThis\sversion\scompiles\sand\nruns\snon-WAL\stest\scases\sbut\scrashes\sand\sburns\son\swal.test. +D 2010-05-12T18:01:40 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 c7ff5a947fc0a09de1c9c2008e3646551a1a8137 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 c910ea795b7cd9dc1bb8e90776816ef5ed8833ea 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 6e828b42e1b50ce923f9bde890f84f78f8cc8b74 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 5f52f5ea690e1d542e094ca8c83bea43c2f7ad96 +F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -817,14 +817,18 @@ 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 +R 6b207856113b77baacd412d73fab162a +T *bgcolor * #c0ffc0 +T *branch * wal-refactor +T *sym-wal-refactor * +T -sym-trunk * U drh -Z ec71604d99e1c3eded3bf24db26ac01b +Z 917cc375618b87c5f919c29d2da7a2ff -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) -iD8DBQFL6rIioxKgR168RlERArxoAJ96khmiBmpRdJSt374I6oMPRFYeDgCeJaEi -RMst0QQ2MlMNKv1/iZMvQcE= -=vEcN +iD8DBQFL6u0HoxKgR168RlERAnOPAJ9UCbogkeIyu/LrQqmeBg4rRTUaswCdFBEg +ymzYvEeQKLujVf/zBF2BuxA= +=vRvp -----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index fc05016e09..9b7eec0beb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7838163d087780a6fb403a17641b96f71baec088 \ No newline at end of file +2b00152c1ac0b3735aa6cfab61259ff04d81c701 \ No newline at end of file diff --git a/src/os.c b/src/os.c index b3e870034f..9ad13690ce 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 7b2bff0dc6..cf7f2b7d7a 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 50bacfbf73..ff967ca8b9 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,808 @@ 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; + + 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_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 + && reqMapSizepMMapBuf ){ + 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 +4247,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 +4261,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 +4284,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 +4293,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 +4302,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 +4313,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 +4325,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 +4337,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 +4362,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 +4375,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 +4529,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 +5398,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 - && reqMapSizepMMapBuf ){ - 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 +6617,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 672789c947..42403c997f 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 @@ -5891,6 +5891,15 @@ int sqlite3PagerWalCallback(Pager *pPager){ return sqlite3WalCallback(pPager->pWal); } +/* +** 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 91b2cb32f9..57ceb04631 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 15daf971f8..af36382edc 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 1ebde80e1e..9b5c3f615e 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 082d101d4e..ed7078d7a1 100644 --- a/src/test_devsym.c +++ b/src/test_devsym.c @@ -68,13 +68,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 +94,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 +111,13 @@ static sqlite3_io_methods devsym_io_methods = { devsymCheckReservedLock, /* xCheckReservedLock */ devsymFileControl, /* xFileControl */ devsymSectorSize, /* xSectorSize */ - devsymDeviceCharacteristics /* xDeviceCharacteristics */ + devsymDeviceCharacteristics, /* xDeviceCharacteristics */ + 0, /* xShmOpen */ + 0, /* xShmSize */ + 0, /* xShmGet */ + 0, /* xShmRelease */ + 0, /* xShmLock */ + 0 /* xShmClose */ }; struct DevsymGlobal { @@ -350,45 +343,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 +352,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 6b39a39ad7..520dffcb71 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 1b5b4b09d2..af0c24b49a 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -16,15 +16,20 @@ #include "sqlite3.h" #include "sqliteInt.h" -typedef struct tvfs_file tvfs_file; -struct tvfs_file { - sqlite3_file base; - sqlite3_file *pReal; -}; +#if 0 /* FIX THIS LATER */ typedef struct Testvfs Testvfs; typedef struct TestvfsShm TestvfsShm; typedef struct TestvfsBuffer TestvfsBuffer; +typedef struct tvfs_file tvfs_file; +struct tvfs_file { + sqlite3_file base; /* Base class. Must be first */ + sqlite3_vfs *pVfs; /* the VFS */ + TestvfsShm *pShm; /* Shared memory segment */ + const char *zFilename; /* Filename */ + sqlite3_file *pReal; /* The real, underlying file descriptor */ +}; + /* ** An instance of this structure is allocated for each VFS created. The @@ -97,15 +102,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,7 +122,13 @@ 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 */ }; /* @@ -238,6 +249,9 @@ static int tvfsOpen( ){ int rc; tvfs_file *p = (tvfs_file *)pFile; + p->pShm = 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 ){ @@ -405,15 +419,16 @@ 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); 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 */ + tvfs_file *pFd; /* The file descriptor */ + + pFd = (tvfs_file*)pFileDes; /* Evaluate the Tcl script: ** @@ -424,7 +439,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); @@ -714,12 +729,6 @@ static int testvfs_cmd( tvfsSleep, /* xSleep */ tvfsCurrentTime, /* xCurrentTime */ 0, /* xGetLastError */ - tvfsShmOpen, - tvfsShmSize, - tvfsShmGet, - tvfsShmRelease, - tvfsShmLock, - tvfsShmClose, 0, 0, }; @@ -788,9 +797,10 @@ static int testvfs_cmd( Tcl_WrongNumArgs(interp, 1, objv, "?-noshm? VFSNAME SCRIPT"); return TCL_ERROR; } +#endif /* 0 */ int Sqlitetestvfs_Init(Tcl_Interp *interp){ - Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0); + /* Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0); */ return TCL_OK; } diff --git a/src/vdbe.c b/src/vdbe.c index 88f880ea94..3fee165da7 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 bdae2e9dfc..0b2c3ceb66 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->pWalFd, 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, ¬Used); - pVfs->xShmClose(pVfs, pWIndex, isDelete); + sqlite3OsShmLock(pWal->pDbFd, SQLITE_SHM_UNLOCK, ¬Used); + 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(zWal) + 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); + pRet->isWindexOpen = 1; /* Open file handle on the write-ahead log file. */ if( rc==SQLITE_OK ){ 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( iOffsetpgno,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 89e94869c1..1e25fc8116 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 */ From 686138fe8817fe6a90937e33da7319887db33141 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 May 2010 18:10:52 +0000 Subject: [PATCH 2/6] A couple simple fixes to get wal.test mostly working. FossilOrigin-Name: c74458127468f30b16715594c8d68e9d3c05d292 --- manifest | 22 +++++++++------------- manifest.uuid | 2 +- src/wal.c | 4 ++-- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index e8b35b9920..455726248b 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 -C Refactoring\sthe\sVFS-SHM\smethods\sused\sby\sWAL.\s\sThis\sversion\scompiles\sand\nruns\snon-WAL\stest\scases\sbut\scrashes\sand\sburns\son\swal.test. -D 2010-05-12T18:01:40 +C A\scouple\ssimple\sfixes\sto\sget\swal.test\smostly\sworking. +D 2010-05-12T18:10:52 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -227,7 +227,7 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda -F src/wal.c 5f52f5ea690e1d542e094ca8c83bea43c2f7ad96 +F src/wal.c c66ba0b722297df063fe84edb4193ef2b05d20d0 F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356 @@ -817,18 +817,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 7838163d087780a6fb403a17641b96f71baec088 -R 6b207856113b77baacd412d73fab162a -T *bgcolor * #c0ffc0 -T *branch * wal-refactor -T *sym-wal-refactor * -T -sym-trunk * +P 2b00152c1ac0b3735aa6cfab61259ff04d81c701 +R b7946fb277db4dbc4bc013e5e5fa093c U drh -Z 917cc375618b87c5f919c29d2da7a2ff +Z 62e42baf1876f9498d88e14692278875 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) -iD8DBQFL6u0HoxKgR168RlERAnOPAJ9UCbogkeIyu/LrQqmeBg4rRTUaswCdFBEg -ymzYvEeQKLujVf/zBF2BuxA= -=vRvp +iD8DBQFL6u8uoxKgR168RlERAoSbAJ9jNFTVpnB+tvn+mLuDe10PoEq3+ACeI55J +3VWwGaEkCHFZz1L5A8JAA68= +=qjYf -----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index 9b7eec0beb..62c6d71cbf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2b00152c1ac0b3735aa6cfab61259ff04d81c701 \ No newline at end of file +c74458127468f30b16715594c8d68e9d3c05d292 \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index 0b2c3ceb66..3c99d039ee 100644 --- a/src/wal.c +++ b/src/wal.c @@ -224,7 +224,7 @@ static int walSetLock(Wal *pWal, int desiredStatus){ pWal->lockState = desiredStatus; }else{ int got = pWal->lockState; - rc = sqlite3OsShmLock(pWal->pWalFd, desiredStatus, &got); + rc = sqlite3OsShmLock(pWal->pDbFd, desiredStatus, &got); pWal->lockState = got; if( got==SQLITE_SHM_READ_FULL || got==SQLITE_SHM_READ ){ pWal->readerType = got; @@ -690,7 +690,7 @@ int sqlite3WalOpen( /* Allocate an instance of struct Wal to return. */ *ppWal = 0; - nWal = sqlite3Strlen30(zWal) + 5; + nWal = sqlite3Strlen30(zDbName) + 5; pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile + nWal); if( !pRet ){ return SQLITE_NOMEM; From 365e2d255bf3457b29f38837a2d9466cdfe1d2a4 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 May 2010 18:30:36 +0000 Subject: [PATCH 3/6] Fix for the test_devsym.c test module for the VFS-SHM refactoring. FossilOrigin-Name: 49d62933759d4e160ee3a4dd2aa316a2f5bbb4e6 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/test_devsym.c | 48 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 455726248b..360b1740a6 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 -C A\scouple\ssimple\sfixes\sto\sget\swal.test\smostly\sworking. -D 2010-05-12T18:10:52 +C Fix\sfor\sthe\stest_devsym.c\stest\smodule\sfor\sthe\sVFS-SHM\srefactoring. +D 2010-05-12T18:30:36 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -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 c910ea795b7cd9dc1bb8e90776816ef5ed8833ea +F src/test_devsym.c 136869028132c3dc34fe920a9fda716f391227f4 F src/test_func.c 13b582345fb1185a93e46c53310fae8547dcce20 F src/test_hexio.c 1237f000ec7a491009b1233f5c626ea71bce1ea2 F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c @@ -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 2b00152c1ac0b3735aa6cfab61259ff04d81c701 -R b7946fb277db4dbc4bc013e5e5fa093c +P c74458127468f30b16715594c8d68e9d3c05d292 +R 5a9efacb9856d7f4bdde2f4883d79672 U drh -Z 62e42baf1876f9498d88e14692278875 +Z 630d17e21b3111ffa913dd47b8968c39 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) -iD8DBQFL6u8uoxKgR168RlERAoSbAJ9jNFTVpnB+tvn+mLuDe10PoEq3+ACeI55J -3VWwGaEkCHFZz1L5A8JAA68= -=qjYf +iD8DBQFL6vPPoxKgR168RlERAj53AJkBapvtr+dRsf/F1XjNxRi5BCrThQCdFxa3 +EJzQfQYaZjLG21xvWiHqkgU= +=76NU -----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index 62c6d71cbf..0fda76004a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c74458127468f30b16715594c8d68e9d3c05d292 \ No newline at end of file +49d62933759d4e160ee3a4dd2aa316a2f5bbb4e6 \ No newline at end of file diff --git a/src/test_devsym.c b/src/test_devsym.c index ed7078d7a1..0a60b3c94d 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. @@ -112,12 +118,12 @@ static sqlite3_io_methods devsym_io_methods = { devsymFileControl, /* xFileControl */ devsymSectorSize, /* xSectorSize */ devsymDeviceCharacteristics, /* xDeviceCharacteristics */ - 0, /* xShmOpen */ - 0, /* xShmSize */ - 0, /* xShmGet */ - 0, /* xShmRelease */ - 0, /* xShmLock */ - 0 /* xShmClose */ + devsymShmOpen, /* xShmOpen */ + devsymShmSize, /* xShmSize */ + devsymShmGet, /* xShmGet */ + devsymShmRelease, /* xShmRelease */ + devsymShmLock, /* xShmLock */ + devsymShmClose /* xShmClose */ }; struct DevsymGlobal { @@ -231,6 +237,36 @@ static int devsymDeviceCharacteristics(sqlite3_file *pFile){ return g.iDeviceChar; } +/* +** 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. */ From 7fd555a634bb9a609b0b3c1b1893216b44ee212a Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 13 May 2010 06:19:37 +0000 Subject: [PATCH 4/6] Modify the VFS in test_vfs.c to match the refactoring of the xShmXXX methods. FossilOrigin-Name: 25e72f81561575051c63e9bf5d2c8e76f9fcf5c6 --- manifest | 24 ++----- manifest.uuid | 2 +- src/test_vfs.c | 181 +++++++++++++++++++++++++------------------------ 3 files changed, 99 insertions(+), 108 deletions(-) diff --git a/manifest b/manifest index 360b1740a6..d14a522e36 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,5 @@ ------BEGIN PGP SIGNED MESSAGE----- -Hash: SHA1 - -C Fix\sfor\sthe\stest_devsym.c\stest\smodule\sfor\sthe\sVFS-SHM\srefactoring. -D 2010-05-12T18:30:36 +C Modify\sthe\sVFS\sin\stest_vfs.c\sto\smatch\sthe\srefactoring\sof\sthe\sxShmXXX\smethods. +D 2010-05-13T06:19:37 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -210,7 +207,7 @@ 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 6e828b42e1b50ce923f9bde890f84f78f8cc8b74 +F src/test_vfs.c 3601f9b6d46cb6daf0697d60c76bf8e18b90b123 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d @@ -817,14 +814,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P c74458127468f30b16715594c8d68e9d3c05d292 -R 5a9efacb9856d7f4bdde2f4883d79672 -U drh -Z 630d17e21b3111ffa913dd47b8968c39 ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1.4.6 (GNU/Linux) - -iD8DBQFL6vPPoxKgR168RlERAj53AJkBapvtr+dRsf/F1XjNxRi5BCrThQCdFxa3 -EJzQfQYaZjLG21xvWiHqkgU= -=76NU ------END PGP SIGNATURE----- +P 49d62933759d4e160ee3a4dd2aa316a2f5bbb4e6 +R f8fd118199dfa730f3f5ccb6ad378e59 +U dan +Z b35bfe52883b808b3d9e1494afbcf52c diff --git a/manifest.uuid b/manifest.uuid index 0fda76004a..eb9623f6b8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -49d62933759d4e160ee3a4dd2aa316a2f5bbb4e6 \ No newline at end of file +25e72f81561575051c63e9bf5d2c8e76f9fcf5c6 \ No newline at end of file diff --git a/src/test_vfs.c b/src/test_vfs.c index af0c24b49a..ce4afa7622 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -16,18 +16,21 @@ #include "sqlite3.h" #include "sqliteInt.h" -#if 0 /* FIX THIS LATER */ - typedef struct Testvfs Testvfs; typedef struct TestvfsShm TestvfsShm; typedef struct TestvfsBuffer TestvfsBuffer; -typedef struct tvfs_file tvfs_file; -struct tvfs_file { - sqlite3_file base; /* Base class. Must be first */ - sqlite3_vfs *pVfs; /* the VFS */ - TestvfsShm *pShm; /* Shared memory segment */ - const char *zFilename; /* Filename */ - sqlite3_file *pReal; /* The real, underlying file descriptor */ +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 */ }; @@ -44,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; }; /* @@ -57,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); @@ -135,7 +131,14 @@ static sqlite3_io_methods tvfs_io_methods = { ** 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); } @@ -148,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); } @@ -161,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); } @@ -169,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); } @@ -177,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); } @@ -185,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); } @@ -193,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); } @@ -201,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); } @@ -209,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); } @@ -217,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); } @@ -225,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); } @@ -233,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); } @@ -248,15 +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; } @@ -351,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); @@ -421,14 +437,15 @@ static int tvfsResultCode(Testvfs *p, int *pRc){ static int tvfsShmOpen( 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 */ - tvfs_file *pFd; /* The file descriptor */ + TestvfsFile *pFd; /* The testvfs file structure */ - pFd = (tvfs_file*)pFileDes; + pFd = (TestvfsFile*)pFileDes; + p = (Testvfs *)pFd->pVfs->pAppData; + assert( pFd->pShmId==0 && pFd->pShm==0 ); /* Evaluate the Tcl script: ** @@ -447,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); @@ -530,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 ){ @@ -549,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); @@ -561,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); @@ -587,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; } @@ -702,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 */ @@ -779,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); @@ -797,10 +799,9 @@ static int testvfs_cmd( Tcl_WrongNumArgs(interp, 1, objv, "?-noshm? VFSNAME SCRIPT"); return TCL_ERROR; } -#endif /* 0 */ int Sqlitetestvfs_Init(Tcl_Interp *interp){ - /* Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0); */ + Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0); return TCL_OK; } From bd50ddeb42ac99c98c65beca62f29f0e1c0a97e3 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 13 May 2010 07:08:53 +0000 Subject: [PATCH 5/6] Fix for a segfault that can follow a malloc failure. FossilOrigin-Name: 3cab9022457ce50f82c5822d8ba6c04a3a85cb6a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/wal.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d14a522e36..d8efdf0e53 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Modify\sthe\sVFS\sin\stest_vfs.c\sto\smatch\sthe\srefactoring\sof\sthe\sxShmXXX\smethods. -D 2010-05-13T06:19:37 +C Fix\sfor\sa\ssegfault\sthat\scan\sfollow\sa\smalloc\sfailure. +D 2010-05-13T07:08:54 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -224,7 +224,7 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda -F src/wal.c c66ba0b722297df063fe84edb4193ef2b05d20d0 +F src/wal.c 3806c5ed7047debc408665b3576f17bab05b2be6 F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356 @@ -814,7 +814,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 49d62933759d4e160ee3a4dd2aa316a2f5bbb4e6 -R f8fd118199dfa730f3f5ccb6ad378e59 +P 25e72f81561575051c63e9bf5d2c8e76f9fcf5c6 +R d6f93e9926f16286e5aafb3fc350bd84 U dan -Z b35bfe52883b808b3d9e1494afbcf52c +Z c60bce3aa77615040a5ca2d947852fe0 diff --git a/manifest.uuid b/manifest.uuid index eb9623f6b8..7b1e6c33df 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -25e72f81561575051c63e9bf5d2c8e76f9fcf5c6 \ No newline at end of file +3cab9022457ce50f82c5822d8ba6c04a3a85cb6a \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index 3c99d039ee..3c16dccc34 100644 --- a/src/wal.c +++ b/src/wal.c @@ -702,10 +702,10 @@ int sqlite3WalOpen( pRet->zWalName = zWal = pVfs->szOsFile + (char*)pRet->pWalFd; sqlite3_snprintf(nWal, zWal, "%s-wal", zDbName); rc = sqlite3OsShmOpen(pDbFd); - pRet->isWindexOpen = 1; /* 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->pWalFd, flags, &flags); } From a925fd256b74e5da9c6320849c3b7d85110ce73f Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 13 May 2010 08:33:35 +0000 Subject: [PATCH 6/6] Change the xShmSize() implementation in os_unix.c so that it will only increase and never decrease the size of a shared-memory segment. FossilOrigin-Name: 149d2ae4a6fe2f86822f286d2a7092c51bec7ebb --- manifest | 24 +++++++++++++++++------- manifest.uuid | 2 +- src/os_unix.c | 23 ++++++++++++++++------- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index d8efdf0e53..c850c8b0ce 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,8 @@ -C Fix\sfor\sa\ssegfault\sthat\scan\sfollow\sa\smalloc\sfailure. -D 2010-05-13T07:08:54 +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +C Change\sthe\sxShmSize()\simplementation\sin\sos_unix.c\sso\sthat\sit\swill\sonly\nincrease\sand\snever\sdecrease\sthe\ssize\sof\sa\sshared-memory\ssegment. +D 2010-05-13T08:33:36 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -152,7 +155,7 @@ 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 c7ff5a947fc0a09de1c9c2008e3646551a1a8137 +F src/os_unix.c a65eb0c527306fbf8d5818c068cccb4179e2c187 F src/os_win.c a8fc01d8483be472e495793c01064fd87e56a5c1 F src/pager.c 1e163a82ae8405433dca559831caa06aafbba3b0 F src/pager.h 76466c3a5af56943537f68b1f16567101a0cd1d0 @@ -814,7 +817,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 25e72f81561575051c63e9bf5d2c8e76f9fcf5c6 -R d6f93e9926f16286e5aafb3fc350bd84 -U dan -Z c60bce3aa77615040a5ca2d947852fe0 +P 3cab9022457ce50f82c5822d8ba6c04a3a85cb6a +R 8a7d44076bf0e05c11800be3998eddd6 +U drh +Z 3a36caf9fe5b6632b303e603e184218b +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.6 (GNU/Linux) + +iD8DBQFL67ljoxKgR168RlERAvKRAJ9jAZ2qvV6Q9GpsBE6wLhS3nq7pbACfcnYP +hXJABDPCTP9dztwWLTfVSAc= +=rTx0 +-----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index 7b1e6c33df..46bd746c8f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3cab9022457ce50f82c5822d8ba6c04a3a85cb6a \ No newline at end of file +149d2ae4a6fe2f86822f286d2a7092c51bec7ebb \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index ff967ca8b9..4ddff190ae 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -3957,16 +3957,25 @@ static int unixShmSize( int rc = SQLITE_OK; struct stat sStat; - if( reqSize>=0 ){ + /* 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); - } - if( fstat(pFile->h, &sStat)==0 ){ - *pNewSize = (int)sStat.st_size; - }else{ - *pNewSize = 0; - rc = SQLITE_IOERR; + reqSize = -1; } return rc; }