]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Refactoring the VFS-SHM methods used by WAL. This version compiles and
authordrh <drh@noemail.net>
Wed, 12 May 2010 18:01:39 +0000 (18:01 +0000)
committerdrh <drh@noemail.net>
Wed, 12 May 2010 18:01:39 +0000 (18:01 +0000)
runs non-WAL test cases but crashes and burns on wal.test.

FossilOrigin-Name: 2b00152c1ac0b3735aa6cfab61259ff04d81c701

16 files changed:
doc/vfs-shm.txt
manifest
manifest.uuid
src/os.c
src/os.h
src/os_unix.c
src/pager.c
src/pager.h
src/sqlite.h.in
src/test6.c
src/test_devsym.c
src/test_onefile.c
src/test_vfs.c
src/vdbe.c
src/wal.c
src/wal.h

index 93ab457cd3a430976d0048a52dee2a08b7e6bea5..c1f125a12036448001be73772ac7eefcff82095f 100644 (file)
@@ -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,
index fae36ae92ad477a5d744b432a7172d881b29f279..e8b35b9920f003ba56f147cd323eacc98ad38d35 100644 (file)
--- 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-----
index fc05016e0930cbb5a07ec2c432d65aa42e263519..9b7eec0bebc1be0eda887649feb246cd5c45d5c9 100644 (file)
@@ -1 +1 @@
-7838163d087780a6fb403a17641b96f71baec088
\ No newline at end of file
+2b00152c1ac0b3735aa6cfab61259ff04d81c701
\ No newline at end of file
index b3e870034f1b71b2fdecf02ad4350ec03e380fe1..9ad13690ce877efdf5bf1e7f5dffe193482b208c 100644 (file)
--- 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
index 7b2bff0dc6e439ab3fa923bdde33c289b7fd5c28..cf7f2b7d7a447cba04082784cbeae6499e9ae869 100644 (file)
--- 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 
index 50bacfbf734b066e6ceca657b474a393f692002b..ff967ca8b96aa0b14fc1a971e9a1e89020200ff1 100644 (file)
 */
 #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,1987 +3405,1999 @@ static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
   return 0;
 }
 
-/*
-** Here ends the implementation of all sqlite3_file methods.
-**
-********************** End sqlite3_file Methods *******************************
-******************************************************************************/
+#ifndef SQLITE_OMIT_WAL
+
 
 /*
-** This division contains definitions of sqlite3_io_methods objects that
-** implement various file locking strategies.  It also contains definitions
-** of "finder" functions.  A finder-function is used to locate the appropriate
-** sqlite3_io_methods object for a particular database file.  The pAppData
-** field of the sqlite3_vfs VFS objects are initialized to be pointers to
-** the correct finder-function for that VFS.
-**
-** Most finder functions return a pointer to a fixed sqlite3_io_methods
-** object.  The only interesting finder-function is autolockIoFinder, which
-** looks at the filesystem type and tries to guess the best locking
-** strategy from that.
-**
-** For finder-funtion F, two objects are created:
-**
-**    (1) The real finder-function named "FImpt()".
-**
-**    (2) A constant pointer to this function named just "F".
-**
+** 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.
 **
-** A pointer to the F pointer is used as the pAppData value for VFS
-** objects.  We have to do this instead of letting pAppData point
-** directly at the finder-function since C90 rules prevent a void*
-** from be cast into a function pointer.
+** unixMutexHeld() must be true when creating or destroying
+** this object or while reading or writing the following fields:
 **
+**      nRef
+**      pNext 
 **
-** Each instance of this macro generates two objects:
+** The following fields are read-only after the object is created:
+** 
+**      fid
+**      zFilename
 **
-**   *  A constant sqlite3_io_methods object call METHOD that has locking
-**      methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
+** Either unixShmFile.mutex must be held or unixShmFile.nRef==0 and
+** unixMutexHeld() is true when reading or writing any other field
+** in this structure.
 **
-**   *  An I/O method finder function called FINDER that returns a pointer
-**      to the METHOD object in the previous bullet.
+** 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.
 */
-#define IOMETHODS(FINDER, METHOD, CLOSE, LOCK, UNLOCK, CKLOCK)               \
-static const sqlite3_io_methods METHOD = {                                   \
-   1,                          /* iVersion */                                \
-   CLOSE,                      /* xClose */                                  \
-   unixRead,                   /* xRead */                                   \
-   unixWrite,                  /* xWrite */                                  \
-   unixTruncate,               /* xTruncate */                               \
-   unixSync,                   /* xSync */                                   \
-   unixFileSize,               /* xFileSize */                               \
-   LOCK,                       /* xLock */                                   \
-   UNLOCK,                     /* xUnlock */                                 \
-   CKLOCK,                     /* xCheckReservedLock */                      \
-   unixFileControl,            /* xFileControl */                            \
-   unixSectorSize,             /* xSectorSize */                             \
-   unixDeviceCharacteristics   /* xDeviceCapabilities */                     \
-};                                                                           \
-static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){   \
-  UNUSED_PARAMETER(z); UNUSED_PARAMETER(p);                                  \
-  return &METHOD;                                                            \
-}                                                                            \
-static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p)    \
-    = FINDER##Impl;
+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
+};
 
 /*
-** Here are all of the sqlite3_io_methods objects for each of the
-** locking strategies.  Functions that return pointers to these methods
-** are also created.
+** A global array of all unixShmFile objects.
+**
+** The unixMutexHeld() must be true while reading or writing this list.
 */
-IOMETHODS(
-  posixIoFinder,            /* Finder function name */
-  posixIoMethods,           /* sqlite3_io_methods object name */
-  unixClose,                /* xClose method */
-  unixLock,                 /* xLock method */
-  unixUnlock,               /* xUnlock method */
-  unixCheckReservedLock     /* xCheckReservedLock method */
-)
-IOMETHODS(
-  nolockIoFinder,           /* Finder function name */
-  nolockIoMethods,          /* sqlite3_io_methods object name */
-  nolockClose,              /* xClose method */
-  nolockLock,               /* xLock method */
-  nolockUnlock,             /* xUnlock method */
-  nolockCheckReservedLock   /* xCheckReservedLock method */
-)
-IOMETHODS(
-  dotlockIoFinder,          /* Finder function name */
-  dotlockIoMethods,         /* sqlite3_io_methods object name */
-  dotlockClose,             /* xClose method */
-  dotlockLock,              /* xLock method */
-  dotlockUnlock,            /* xUnlock method */
-  dotlockCheckReservedLock  /* xCheckReservedLock method */
-)
+static unixShmFile *unixShmFileList = 0;
 
-#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
-IOMETHODS(
-  flockIoFinder,            /* Finder function name */
-  flockIoMethods,           /* sqlite3_io_methods object name */
-  flockClose,               /* xClose method */
-  flockLock,                /* xLock method */
-  flockUnlock,              /* xUnlock method */
-  flockCheckReservedLock    /* xCheckReservedLock method */
-)
+/*
+** 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
+};
 
-#if OS_VXWORKS
-IOMETHODS(
-  semIoFinder,              /* Finder function name */
-  semIoMethods,             /* sqlite3_io_methods object name */
-  semClose,                 /* xClose method */
-  semLock,                  /* xLock method */
-  semUnlock,                /* xUnlock method */
-  semCheckReservedLock      /* xCheckReservedLock method */
-)
-#endif
+/*
+** Size increment by which shared memory grows
+*/
+#define SQLITE_UNIX_SHM_INCR  4096
 
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-IOMETHODS(
-  afpIoFinder,              /* Finder function name */
-  afpIoMethods,             /* sqlite3_io_methods object name */
-  afpClose,                 /* xClose method */
-  afpLock,                  /* xLock method */
-  afpUnlock,                /* xUnlock method */
-  afpCheckReservedLock      /* xCheckReservedLock method */
-)
-#endif
+/*
+** 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
 /*
-** The proxy locking method is a "super-method" in the sense that it
-** opens secondary file descriptors for the conch and lock files and
-** it uses proxy, dot-file, AFP, and flock() locking methods on those
-** secondary files.  For this reason, the division that implements
-** proxy locking is located much further down in the file.  But we need
-** to go ahead and define the sqlite3_io_methods and finder function
-** for proxy locking here.  So we forward declare the I/O methods.
+** 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.
 */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-static int proxyClose(sqlite3_file*);
-static int proxyLock(sqlite3_file*, int);
-static int proxyUnlock(sqlite3_file*, int);
-static int proxyCheckReservedLock(sqlite3_file*, int*);
-IOMETHODS(
-  proxyIoFinder,            /* Finder function name */
-  proxyIoMethods,           /* sqlite3_io_methods object name */
-  proxyClose,               /* xClose method */
-  proxyLock,                /* xLock method */
-  proxyUnlock,              /* xUnlock method */
-  proxyCheckReservedLock    /* xCheckReservedLock method */
-)
-#endif
+static const char *unixShmLockString(u8 mask){
+  static char zBuf[48];
+  static int iBuf = 0;
+  char *z;
 
-/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-IOMETHODS(
-  nfsIoFinder,               /* Finder function name */
-  nfsIoMethods,              /* sqlite3_io_methods object name */
-  unixClose,                 /* xClose method */
-  unixLock,                  /* xLock method */
-  nfsUnlock,                 /* xUnlock method */
-  unixCheckReservedLock      /* xCheckReservedLock method */
-)
-#endif
+  z = &zBuf[iBuf];
+  iBuf += 8;
+  if( iBuf>=sizeof(zBuf) ) iBuf = 0;
 
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-/* 
-** This "finder" function attempts to determine the best locking strategy 
-** for the database file "filePath".  It then returns the sqlite3_io_methods
-** object that implements that strategy.
+  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.
 **
-** This is for MacOSX only.
-*/
-static const sqlite3_io_methods *autolockIoFinderImpl(
-  const char *filePath,    /* name of the database file */
-  unixFile *pNew           /* open file object for the database file */
+** 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 */
 ){
-  static const struct Mapping {
-    const char *zFilesystem;              /* Filesystem type name */
-    const sqlite3_io_methods *pMethods;   /* Appropriate locking method */
-  } aMap[] = {
-    { "hfs",    &posixIoMethods },
-    { "ufs",    &posixIoMethods },
-    { "afpfs",  &afpIoMethods },
-    { "smbfs",  &afpIoMethods },
-    { "webdav", &nolockIoMethods },
-    { 0, 0 }
-  };
-  int i;
-  struct statfs fsInfo;
-  struct flock lockInfo;
+  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 */
 
-  if( !filePath ){
-    /* If filePath==NULL that means we are dealing with a transient file
-    ** that does not need to be locked. */
-    return &nolockIoMethods;
+  /* 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;
   }
-  if( statfs(filePath, &fsInfo) != -1 ){
-    if( fsInfo.f_flags & MNT_RDONLY ){
-      return &nolockIoMethods;
-    }
-    for(i=0; aMap[i].zFilesystem; i++){
-      if( strcmp(fsInfo.f_fstypename, aMap[i].zFilesystem)==0 ){
-        return aMap[i].pMethods;
-      }
-    }
+
+  /* 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;
   }
 
-  /* Default case. Handles, amongst others, "nfs".
-  ** Test byte-range lock using fcntl(). If the call succeeds, 
-  ** assume that the file-system supports POSIX style locks. 
-  */
-  lockInfo.l_len = 1;
-  lockInfo.l_start = 0;
-  lockInfo.l_whence = SEEK_SET;
-  lockInfo.l_type = F_RDLCK;
-  if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
-    if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
-      return &nfsIoMethods;
-    } else {
-      return &posixIoMethods;
+  /* 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{
-    return &dotlockIoMethods;
+    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"));
+    }
   }
-}
-static const sqlite3_io_methods 
-  *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
+  OSTRACE((" - change requested %s - afterwards %s:%s\n",
+           unixShmLockString(lockMask),
+           unixShmLockString(pFile->sharedMask),
+           unixShmLockString(pFile->exclMask)));
+#endif
 
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+  return rc;        
+}
 
-#if OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE
-/* 
-** This "finder" function attempts to determine the best locking strategy 
-** for the database file "filePath".  It then returns the sqlite3_io_methods
-** object that implements that strategy.
-**
-** This is for VXWorks only.
+/*
+** For connection p, unlock all of the locks identified by the unlockMask
+** parameter.
 */
-static const sqlite3_io_methods *autolockIoFinderImpl(
-  const char *filePath,    /* name of the database file */
-  unixFile *pNew           /* the open file object */
+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 */
 ){
-  struct flock lockInfo;
+  int rc;      /* Result code */
+  unixShm *pX; /* For looping over all sibling connections */
+  u8 allMask;  /* Union of locks held by connections other than "p" */
 
-  if( !filePath ){
-    /* If filePath==NULL that means we are dealing with a transient file
-    ** that does not need to be locked. */
-    return &nolockIoMethods;
+  /* 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;
   }
 
-  /* Test if fcntl() is supported and use POSIX style locks.
-  ** Otherwise fall back to the named semaphore method.
-  */
-  lockInfo.l_len = 1;
-  lockInfo.l_start = 0;
-  lockInfo.l_whence = SEEK_SET;
-  lockInfo.l_type = F_RDLCK;
-  if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
-    return &posixIoMethods;
+  /* Unlock the system-level locks */
+  if( (unlockMask & allMask)!=unlockMask ){
+    rc = unixShmSystemLock(pFile, F_UNLCK, unlockMask & ~allMask);
   }else{
-    return &semIoMethods;
+    rc = SQLITE_OK;
   }
-}
-static const sqlite3_io_methods 
-  *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
 
-#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */
+  /* Undo the local locks */
+  if( rc==SQLITE_OK ){
+    p->exclMask &= ~unlockMask;
+    p->sharedMask &= ~unlockMask;
+  } 
+  return rc;
+}
 
 /*
-** An abstract type for a pointer to a IO method finder function:
+** Get reader locks for connection p on all locks in the readMask parameter.
 */
-typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*);
+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) );
 
-/****************************************************************************
-**************************** sqlite3_vfs methods ****************************
-**
-** This division contains the implementation of methods on the
-** sqlite3_vfs object.
-*/
+  /* 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;
+}
 
 /*
-** Initialize the contents of the unixFile structure pointed to by pId.
+** For connection p, get an exclusive lock on all locks identified in
+** the writeMask parameter.
 */
-static int fillInUnixFile(
-  sqlite3_vfs *pVfs,      /* Pointer to vfs object */
-  int h,                  /* Open file descriptor of file being opened */
-  int dirfd,              /* Directory file descriptor */
-  sqlite3_file *pId,      /* Write to the unixFile structure here */
-  const char *zFilename,  /* Name of the file being opened */
-  int noLock,             /* Omit locking if true */
-  int isDelete            /* Delete on close if true */
+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 */
 ){
-  const sqlite3_io_methods *pLockingStyle;
-  unixFile *pNew = (unixFile *)pId;
-  int rc = SQLITE_OK;
+  int rc;        /* Result code */
+  unixShm *pX;   /* For looping over all sibling connections */
 
-  assert( pNew->pLock==NULL );
-  assert( pNew->pOpen==NULL );
+  /* Access to the unixShmFile object is serialized by the caller */
+  assert( sqlite3_mutex_held(pFile->mutex) );
 
-  /* Parameter isDelete is only used on vxworks. Express this explicitly 
-  ** here to prevent compiler warnings about unused parameters.
+  /* Make sure no sibling connections hold locks that will block this
+  ** lock.  If any do, return SQLITE_BUSY right away.
   */
-  UNUSED_PARAMETER(isDelete);
+  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;
+  }
 
-  OSTRACE3("OPEN    %-3d %s\n", h, zFilename);    
-  pNew->h = h;
-  pNew->dirfd = dirfd;
-  SET_THREADID(pNew);
-  pNew->fileFlags = 0;
+  /* 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;
+}
 
-#if OS_VXWORKS
-  pNew->pId = vxworksFindFileId(zFilename);
-  if( pNew->pId==0 ){
-    noLock = 1;
-    rc = SQLITE_NOMEM;
+/*
+** 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;
+    }
   }
-#endif
+}
 
-  if( noLock ){
-    pLockingStyle = &nolockIoMethods;
-  }else{
-    pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew);
-#if SQLITE_ENABLE_LOCKING_STYLE
-    /* Cache zFilename in the locking context (AFP and dotlock override) for
-    ** proxyLock activation is possible (remote proxy is based on db name)
-    ** zFilename remains valid until file is closed, to support */
-    pNew->lockingContext = (void*)zFilename;
-#endif
+/*
+** 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);
 
-  if( pLockingStyle == &posixIoMethods
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-    || pLockingStyle == &nfsIoMethods
-#endif
-  ){
-    unixEnterMutex();
-    rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
-    if( rc!=SQLITE_OK ){
-      /* If an error occured in findLockInfo(), close the file descriptor
-      ** immediately, before releasing the mutex. findLockInfo() may fail
-      ** in two scenarios:
-      **
-      **   (a) A call to fstat() failed.
-      **   (b) A malloc failed.
-      **
-      ** Scenario (b) may only occur if the process is holding no other
-      ** file descriptors open on the same file. If there were other file
-      ** descriptors on this file, then no malloc would be required by
-      ** findLockInfo(). If this is the case, it is quite safe to close
-      ** handle h - as it is guaranteed that no posix locks will be released
-      ** by doing so.
-      **
-      ** If scenario (a) caused the error then things are not so safe. The
-      ** implicit assumption here is that if fstat() fails, things are in
-      ** such bad shape that dropping a lock or two doesn't matter much.
-      */
-      close(h);
-      h = -1;
+  /* 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;
     }
-    unixLeaveMutex();
   }
+  if( pFile ){
+    sqlite3_free(pNew);
+  }else{
+    pFile = pNew;
+    pNew = 0;
+    pFile->h = -1;
+    pFile->pNext = unixShmFileList;
+    unixShmFileList = pFile;
 
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
-  else if( pLockingStyle == &afpIoMethods ){
-    /* AFP locking uses the file path so it needs to be included in
-    ** the afpLockingContext.
-    */
-    afpLockingContext *pCtx;
-    pNew->lockingContext = pCtx = sqlite3_malloc( sizeof(*pCtx) );
-    if( pCtx==0 ){
+    pFile->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+    if( pFile->mutex==0 ){
       rc = SQLITE_NOMEM;
-    }else{
-      /* NB: zFilename exists and remains valid until the file is closed
-      ** according to requirement F11141.  So we do not need to make a
-      ** copy of the filename. */
-      pCtx->dbPath = zFilename;
-      pCtx->reserved = 0;
-      srandomdev();
-      unixEnterMutex();
-      rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
-      if( rc!=SQLITE_OK ){
-        sqlite3_free(pNew->lockingContext);
-        close(h);
-        h = -1;
-      }
-      unixLeaveMutex();        
+      goto shm_open_err;
     }
-  }
-#endif
-
-  else if( pLockingStyle == &dotlockIoMethods ){
-    /* Dotfile locking uses the file path so it needs to be included in
-    ** the dotlockLockingContext 
-    */
-    char *zLockFile;
-    int nFilename;
-    nFilename = (int)strlen(zFilename) + 6;
-    zLockFile = (char *)sqlite3_malloc(nFilename);
-    if( zLockFile==0 ){
+    pFile->mutexBuf = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+    if( pFile->mutexBuf==0 ){
       rc = SQLITE_NOMEM;
-    }else{
-      sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
+      goto shm_open_err;
     }
-    pNew->lockingContext = zLockFile;
-  }
 
-#if OS_VXWORKS
-  else if( pLockingStyle == &semIoMethods ){
-    /* Named semaphore locking uses the file path so it needs to be
-    ** included in the semLockingContext
+    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. 
     */
-    unixEnterMutex();
-    rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
-    if( (rc==SQLITE_OK) && (pNew->pOpen->pSem==NULL) ){
-      char *zSemName = pNew->pOpen->aSemName;
-      int n;
-      sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem",
-                       pNew->pId->zCanonicalName);
-      for( n=1; zSemName[n]; n++ )
-        if( zSemName[n]=='/' ) zSemName[n] = '_';
-      pNew->pOpen->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
-      if( pNew->pOpen->pSem == SEM_FAILED ){
-        rc = SQLITE_NOMEM;
-        pNew->pOpen->aSemName[0] = '\0';
+    if( unixShmSystemLock(pFile, F_WRLCK, UNIX_SHM_DMS)==SQLITE_OK ){
+      if( ftruncate(pFile->h, 0) ){
+        rc = SQLITE_IOERR;
       }
     }
-    unixLeaveMutex();
-  }
-#endif
-  
-  pNew->lastErrno = 0;
-#if OS_VXWORKS
-  if( rc!=SQLITE_OK ){
-    if( h>=0 ) close(h);
-    h = -1;
-    unlink(zFilename);
-    isDelete = 0;
-  }
-  pNew->isDelete = isDelete;
-#endif
-  if( rc!=SQLITE_OK ){
-    if( dirfd>=0 ) close(dirfd); /* silent leak if fail, already in error */
-    if( h>=0 ) close(h);
-  }else{
-    pNew->pMethod = pLockingStyle;
-    OpenCounter(+1);
+    if( rc==SQLITE_OK ){
+      rc = unixShmSystemLock(pFile, F_RDLCK, UNIX_SHM_DMS);
+    }
+    if( rc ) goto shm_open_err;
   }
-  return rc;
-}
 
-/*
-** Open a file descriptor to the directory containing file zFilename.
-** If successful, *pFd is set to the opened file descriptor and
-** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM
-** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined
-** value.
-**
-** If SQLITE_OK is returned, the caller is responsible for closing
-** the file descriptor *pFd using close().
-*/
-static int openDirectory(const char *zFilename, int *pFd){
-  int ii;
-  int fd = -1;
-  char zDirname[MAX_PATHNAME+1];
-
-  sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
-  for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
-  if( ii>0 ){
-    zDirname[ii] = '\0';
-    fd = open(zDirname, O_RDONLY|O_BINARY, 0);
-    if( fd>=0 ){
-#ifdef FD_CLOEXEC
-      fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+  /* Make the new connection a child of the unixShmFile */
+  p->pFile = pFile;
+  p->pNext = pFile->pFirst;
+#ifdef SQLITE_DEBUG
+  p->id = pFile->nextShmId++;
 #endif
-      OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname);
-    }
-  }
-  *pFd = fd;
-  return (fd>=0?SQLITE_OK:SQLITE_CANTOPEN_BKPT);
+  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;
 }
 
 /*
-** Create a temporary file name in zBuf.  zBuf must be allocated
-** by the calling process and must be big enough to hold at least
-** pVfs->mxPathname bytes.
+** Close a connection to shared-memory.  Delete the underlying 
+** storage if deleteFlag is true.
 */
-static int getTempname(int nBuf, char *zBuf){
-  static const char *azDirs[] = {
-     0,
-     0,
-     "/var/tmp",
-     "/usr/tmp",
-     "/tmp",
-     ".",
-  };
-  static const unsigned char zChars[] =
-    "abcdefghijklmnopqrstuvwxyz"
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-    "0123456789";
-  unsigned int i, j;
-  struct stat buf;
-  const char *zDir = ".";
+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 */
 
-  /* It's odd to simulate an io-error here, but really this is just
-  ** using the io-error infrastructure to test that SQLite handles this
-  ** function failing. 
-  */
-  SimulateIOError( return SQLITE_IOERR );
+  pDbFd = (unixFile*)fd;
+  p = pDbFd->pShm;
+  if( p==0 ) return SQLITE_OK;
+  pFile = p->pFile;
 
-  azDirs[0] = sqlite3_temp_directory;
-  if (NULL == azDirs[1]) {
-    azDirs[1] = getenv("TMPDIR");
-  }
-  
-  for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
-    if( azDirs[i]==0 ) continue;
-    if( stat(azDirs[i], &buf) ) continue;
-    if( !S_ISDIR(buf.st_mode) ) continue;
-    if( access(azDirs[i], 07) ) continue;
-    zDir = azDirs[i];
-    break;
-  }
+  /* Verify that the connection being closed holds no locks */
+  assert( p->exclMask==0 );
+  assert( p->sharedMask==0 );
 
-  /* Check that the output buffer is large enough for the temporary file 
-  ** name. If it is not, return SQLITE_ERROR.
-  */
-  if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 17) >= (size_t)nBuf ){
-    return SQLITE_ERROR;
+  /* 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();
 
-  do{
-    sqlite3_snprintf(nBuf-17, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
-    j = (int)strlen(zBuf);
-    sqlite3_randomness(15, &zBuf[j]);
-    for(i=0; i<15; i++, j++){
-      zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
-    }
-    zBuf[j] = 0;
-  }while( access(zBuf,0)==0 );
   return SQLITE_OK;
 }
 
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
-/*
-** Routine to transform a unixFile into a proxy-locking unixFile.
-** Implementation in the proxy-lock division, but used by unixOpen()
-** if SQLITE_PREFER_PROXY_LOCKING is defined.
-*/
-static int proxyTransformUnixFile(unixFile*, const char*);
-#endif
-
 /*
-** Search for an unused file descriptor that was opened on the database 
-** file (not a journal or master-journal file) identified by pathname
-** zPath with SQLITE_OPEN_XXX flags matching those passed as the second
-** argument to this function.
+** 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.
 **
-** Such a file descriptor may exist if a database connection was closed
-** but the associated file descriptor could not be closed because some
-** other file descriptor open on the same file is holding a file-lock.
-** Refer to comments in the unixClose() function and the lengthy comment
-** describing "Posix Advisory Locking" at the start of this file for 
-** further details. Also, ticket #4018.
+** This routine does not (necessarily) change the size of the mapping 
+** of the underlying storage into memory.  Use xShmGet() to change
+** the mapping size.
 **
-** If a suitable file descriptor is found, then it is returned. If no
-** such file descriptor is located, -1 is returned.
+** The reqSize parameter is the minimum size requested.  The implementation
+** is free to expand the storage to some larger amount if it chooses.
 */
-static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
-  UnixUnusedFd *pUnused = 0;
-
-  /* Do not search for an unused file descriptor on vxworks. Not because
-  ** vxworks would not benefit from the change (it might, we're not sure),
-  ** but because no way to test it is currently available. It is better 
-  ** not to risk breaking vxworks support for the sake of such an obscure 
-  ** feature.  */
-#if !OS_VXWORKS
-  struct stat sStat;                   /* Results of stat() call */
-
-  /* A stat() call may fail for various reasons. If this happens, it is
-  ** almost certain that an open() call on the same path will also fail.
-  ** For this reason, if an error occurs in the stat() call here, it is
-  ** ignored and -1 is returned. The caller will try to open a new file
-  ** descriptor on the same path, fail, and return an error to SQLite.
-  **
-  ** Even if a subsequent open() call does succeed, the consequences of
-  ** not searching for a resusable file descriptor are not dire.  */
-  if( 0==stat(zPath, &sStat) ){
-    struct unixOpenCnt *pOpen;
+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;
 
-    unixEnterMutex();
-    pOpen = openList;
-    while( pOpen && (pOpen->fileId.dev!=sStat.st_dev
-                     || pOpen->fileId.ino!=sStat.st_ino) ){
-       pOpen = pOpen->pNext;
-    }
-    if( pOpen ){
-      UnixUnusedFd **pp;
-      for(pp=&pOpen->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
-      pUnused = *pp;
-      if( pUnused ){
-        *pp = pUnused->pNext;
-      }
-    }
-    unixLeaveMutex();
+  if( reqSize>=0 ){
+    reqSize = (reqSize + SQLITE_UNIX_SHM_INCR - 1)/SQLITE_UNIX_SHM_INCR;
+    reqSize *= SQLITE_UNIX_SHM_INCR;
+    rc = ftruncate(pFile->h, reqSize);
   }
-#endif    /* if !OS_VXWORKS */
-  return pUnused;
+  if( fstat(pFile->h, &sStat)==0 ){
+    *pNewSize = (int)sStat.st_size;
+  }else{
+    *pNewSize = 0;
+    rc = SQLITE_IOERR;
+  }
+  return rc;
 }
 
+
 /*
-** Open the file zPath.
-** 
-** Previously, the SQLite OS layer used three functions in place of this
-** one:
+** 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.
 **
-**     sqlite3OsOpenReadWrite();
-**     sqlite3OsOpenReadOnly();
-**     sqlite3OsOpenExclusive();
+** *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.
 **
-** These calls correspond to the following combinations of flags:
+** 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.
 **
-**     ReadWrite() ->     (READWRITE | CREATE)
-**     ReadOnly()  ->     (READONLY) 
-**     OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE)
+** *pNewMapSize is set to the size of the mapping.
 **
-** The old OpenExclusive() accepted a boolean argument - "delFlag". If
-** true, the file was configured to be automatically deleted when the
-** file handle closed. To achieve the same effect using this new 
-** interface, add the DELETEONCLOSE flag to those specified above for 
-** OpenExclusive().
+** *ppBuf and *pNewMapSize might be NULL and zero if no space has
+** yet been allocated to the underlying storage.
 */
-static int unixOpen(
-  sqlite3_vfs *pVfs,           /* The VFS for which this is the xOpen method */
-  const char *zPath,           /* Pathname of file to be opened */
-  sqlite3_file *pFile,         /* The file descriptor to be filled in */
-  int flags,                   /* Input flags to control the opening */
-  int *pOutFlags               /* Output flags returned to SQLite core */
+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 *p = (unixFile *)pFile;
-  int fd = -1;                   /* File descriptor returned by open() */
-  int dirfd = -1;                /* Directory file descriptor */
-  int openFlags = 0;             /* Flags to pass to open() */
-  int eType = flags&0xFFFFFF00;  /* Type of file to open */
-  int noLock;                    /* True to omit locking primitives */
-  int rc = SQLITE_OK;            /* Function Return Code */
-
-  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
-  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
-  int isCreate     = (flags & SQLITE_OPEN_CREATE);
-  int isReadonly   = (flags & SQLITE_OPEN_READONLY);
-  int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);
-#if SQLITE_ENABLE_LOCKING_STYLE
-  int isAutoProxy  = (flags & SQLITE_OPEN_AUTOPROXY);
-#endif
-
-  /* If creating a master or main-file journal, this function will open
-  ** a file-descriptor on the directory too. The first time unixSync()
-  ** is called the directory file descriptor will be fsync()ed and close()d.
-  */
-  int isOpenDirectory = (isCreate && 
-      (eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL)
-  );
-
-  /* If argument zPath is a NULL pointer, this function is required to open
-  ** a temporary file. Use this buffer to store the file name in.
-  */
-  char zTmpname[MAX_PATHNAME+1];
-  const char *zName = zPath;
-
-  /* Check the following statements are true: 
-  **
-  **   (a) Exactly one of the READWRITE and READONLY flags must be set, and 
-  **   (b) if CREATE is set, then READWRITE must also be set, and
-  **   (c) if EXCLUSIVE is set, then CREATE must also be set.
-  **   (d) if DELETEONCLOSE is set, then CREATE must also be set.
-  */
-  assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
-  assert(isCreate==0 || isReadWrite);
-  assert(isExclusive==0 || isCreate);
-  assert(isDelete==0 || isCreate);
-
-  /* The main DB, main journal, and master journal are never automatically
-  ** deleted. Nor are they ever temporary files.  */
-  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
-  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
-  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
-
-  /* Assert that the upper layer has set one of the "file-type" flags. */
-  assert( eType==SQLITE_OPEN_MAIN_DB      || eType==SQLITE_OPEN_TEMP_DB 
-       || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL 
-       || eType==SQLITE_OPEN_SUBJOURNAL   || eType==SQLITE_OPEN_MASTER_JOURNAL 
-       || eType==SQLITE_OPEN_TRANSIENT_DB
-  );
-
-  memset(p, 0, sizeof(unixFile));
-
-  if( eType==SQLITE_OPEN_MAIN_DB ){
-    UnixUnusedFd *pUnused;
-    pUnused = findReusableFd(zName, flags);
-    if( pUnused ){
-      fd = pUnused->fd;
-    }else{
-      pUnused = sqlite3_malloc(sizeof(*pUnused));
-      if( !pUnused ){
-        return SQLITE_NOMEM;
-      }
-    }
-    p->pUnused = pUnused;
-  }else if( !zName ){
-    /* If zName is NULL, the upper layer is requesting a temp file. */
-    assert(isDelete && !isOpenDirectory);
-    rc = getTempname(MAX_PATHNAME+1, zTmpname);
-    if( rc!=SQLITE_OK ){
-      return rc;
-    }
-    zName = zTmpname;
-  }
-
-  /* Determine the value of the flags parameter passed to POSIX function
-  ** open(). These must be calculated even if open() is not called, as
-  ** they may be stored as part of the file handle and used by the 
-  ** 'conch file' locking functions later on.  */
-  if( isReadonly )  openFlags |= O_RDONLY;
-  if( isReadWrite ) openFlags |= O_RDWR;
-  if( isCreate )    openFlags |= O_CREAT;
-  if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
-  openFlags |= (O_LARGEFILE|O_BINARY);
-
-  if( fd<0 ){
-    mode_t openMode = (isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS);
-    fd = open(zName, openFlags, openMode);
-    OSTRACE4("OPENX   %-3d %s 0%o\n", fd, zName, openFlags);
-    if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
-      /* Failed to open the file for read/write access. Try read-only. */
-      flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
-      openFlags &= ~(O_RDWR|O_CREAT);
-      flags |= SQLITE_OPEN_READONLY;
-      openFlags |= O_RDONLY;
-      fd = open(zName, openFlags, openMode);
-    }
-    if( fd<0 ){
-      rc = SQLITE_CANTOPEN_BKPT;
-      goto open_finished;
-    }
-  }
-  assert( fd>=0 );
-  if( pOutFlags ){
-    *pOutFlags = flags;
-  }
-
-  if( p->pUnused ){
-    p->pUnused->fd = fd;
-    p->pUnused->flags = flags;
-  }
-
-  if( isDelete ){
-#if OS_VXWORKS
-    zPath = zName;
-#else
-    unlink(zName);
-#endif
-  }
-#if SQLITE_ENABLE_LOCKING_STYLE
-  else{
-    p->openFlags = openFlags;
-  }
-#endif
-
-  if( isOpenDirectory ){
-    rc = openDirectory(zPath, &dirfd);
-    if( rc!=SQLITE_OK ){
-      /* It is safe to close fd at this point, because it is guaranteed not
-      ** to be open on a database file. If it were open on a database file,
-      ** it would not be safe to close as this would release any locks held
-      ** on the file by this process.  */
-      assert( eType!=SQLITE_OPEN_MAIN_DB );
-      close(fd);             /* silently leak if fail, already in error */
-      goto open_finished;
-    }
-  }
-
-#ifdef FD_CLOEXEC
-  fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
-#endif
-
-  noLock = eType!=SQLITE_OPEN_MAIN_DB;
-
-  
-#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
-  struct statfs fsInfo;
-  if( fstatfs(fd, &fsInfo) == -1 ){
-    ((unixFile*)pFile)->lastErrno = errno;
-    if( dirfd>=0 ) close(dirfd); /* silently leak if fail, in error */
-    close(fd); /* silently leak if fail, in error */
-    return SQLITE_IOERR_ACCESS;
-  }
-  if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
-    ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
-  }
-#endif
-  
-#if SQLITE_ENABLE_LOCKING_STYLE
-#if SQLITE_PREFER_PROXY_LOCKING
-  isAutoProxy = 1;
-#endif
-  if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
-    char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
-    int useProxy = 0;
+  unixFile *pDbFd = (unixFile*)fd;
+  unixShm *p = pDbFd->pShm;
+  unixShmFile *pFile = p->pFile;
+  int rc = SQLITE_OK;
 
-    /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means 
-    ** never use proxy, NULL means use proxy for non-local files only.  */
-    if( envforce!=NULL ){
-      useProxy = atoi(envforce)>0;
-    }else{
-      struct statfs fsInfo;
-      if( statfs(zPath, &fsInfo) == -1 ){
-        /* In theory, the close(fd) call is sub-optimal. If the file opened
-        ** with fd is a database file, and there are other connections open
-        ** on that file that are currently holding advisory locks on it,
-        ** then the call to close() will cancel those locks. In practice,
-        ** we're assuming that statfs() doesn't fail very often. At least
-        ** not while other file descriptors opened by the same process on
-        ** the same file are working.  */
-        p->lastErrno = errno;
-        if( dirfd>=0 ){
-          close(dirfd); /* silently leak if fail, in error */
-        }
-        close(fd); /* silently leak if fail, in error */
-        rc = SQLITE_IOERR_ACCESS;
-        goto open_finished;
-      }
-      useProxy = !(fsInfo.f_flags&MNT_LOCAL);
-    }
-    if( useProxy ){
-      rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
-      if( rc==SQLITE_OK ){
-        rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
-        if( rc!=SQLITE_OK ){
-          /* Use unixClose to clean up the resources added in fillInUnixFile 
-          ** and clear all the structure's references.  Specifically, 
-          ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op 
-          */
-          unixClose(pFile);
-          return rc;
-        }
-      }
-      goto open_finished;
-    }
-  }
-#endif
-  
-  rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
-open_finished:
-  if( rc!=SQLITE_OK ){
-    sqlite3_free(p->pUnused);
+  if( p->lockState!=SQLITE_SHM_CHECKPOINT && p->hasMutexBuf==0 ){
+    assert( sqlite3_mutex_notheld(pFile->mutex) );
+    sqlite3_mutex_enter(pFile->mutexBuf);
+    p->hasMutexBuf = 1;
   }
-  return rc;
-}
-
-
-/*
-** Delete the file at zPath. If the dirSync argument is true, fsync()
-** the directory after deleting the file.
-*/
-static int unixDelete(
-  sqlite3_vfs *NotUsed,     /* VFS containing this as the xDelete method */
-  const char *zPath,        /* Name of file to be deleted */
-  int dirSync               /* If true, fsync() directory after deleting file */
-){
-  int rc = SQLITE_OK;
-  UNUSED_PARAMETER(NotUsed);
-  SimulateIOError(return SQLITE_IOERR_DELETE);
-  unlink(zPath);
-#ifndef SQLITE_DISABLE_DIRSYNC
-  if( dirSync ){
-    int fd;
-    rc = openDirectory(zPath, &fd);
-    if( rc==SQLITE_OK ){
-#if OS_VXWORKS
-      if( fsync(fd)==-1 )
-#else
-      if( fsync(fd) )
-#endif
-      {
-        rc = SQLITE_IOERR_DIR_FSYNC;
-      }
-      if( close(fd)&&!rc ){
-        rc = SQLITE_IOERR_DIR_CLOSE;
-      }
+  sqlite3_mutex_enter(pFile->mutex);
+  if( pFile->szMap==0 || reqMapSize>pFile->szMap ){
+    int actualSize;
+    if( unixShmSize(fd, -1, &actualSize)==SQLITE_OK
+     && reqMapSize<actualSize
+    ){
+      reqMapSize = actualSize;
     }
+    if( pFile->pMMapBuf ){
+      munmap(pFile->pMMapBuf, pFile->szMap);
+    }
+    pFile->pMMapBuf = mmap(0, reqMapSize, PROT_READ|PROT_WRITE, MAP_SHARED,
+                           pFile->h, 0);
+    pFile->szMap = pFile->pMMapBuf ? reqMapSize : 0;
   }
-#endif
-  return rc;
-}
-
-/*
-** Test the existance of or access permissions of file zPath. The
-** test performed depends on the value of flags:
-**
-**     SQLITE_ACCESS_EXISTS: Return 1 if the file exists
-**     SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable.
-**     SQLITE_ACCESS_READONLY: Return 1 if the file is readable.
-**
-** Otherwise return 0.
-*/
-static int unixAccess(
-  sqlite3_vfs *NotUsed,   /* The VFS containing this xAccess method */
-  const char *zPath,      /* Path of the file to examine */
-  int flags,              /* What do we want to learn about the zPath file? */
-  int *pResOut            /* Write result boolean here */
-){
-  int amode = 0;
-  UNUSED_PARAMETER(NotUsed);
-  SimulateIOError( return SQLITE_IOERR_ACCESS; );
-  switch( flags ){
-    case SQLITE_ACCESS_EXISTS:
-      amode = F_OK;
-      break;
-    case SQLITE_ACCESS_READWRITE:
-      amode = W_OK|R_OK;
-      break;
-    case SQLITE_ACCESS_READ:
-      amode = R_OK;
-      break;
-
-    default:
-      assert(!"Invalid flags argument");
-  }
-  *pResOut = (access(zPath, amode)==0);
-  return SQLITE_OK;
+  *pNewMapSize = pFile->szMap;
+  *ppBuf = pFile->pMMapBuf;
+  sqlite3_mutex_leave(pFile->mutex);
+  return rc;
 }
 
-
 /*
-** Turn a relative pathname into a full pathname. The relative path
-** is stored as a nul-terminated string in the buffer pointed to by
-** zPath. 
+** Release the lock held on the shared memory segment to that other
+** threads are free to resize it if necessary.
 **
-** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes 
-** (in this case, MAX_PATHNAME bytes). The full-path is written to
-** this buffer before returning.
+** 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 unixFullPathname(
-  sqlite3_vfs *pVfs,            /* Pointer to vfs object */
-  const char *zPath,            /* Possibly relative input path */
-  int nOut,                     /* Size of output buffer in bytes */
-  char *zOut                    /* Output buffer */
-){
-
-  /* It's odd to simulate an io-error here, but really this is just
-  ** using the io-error infrastructure to test that SQLite handles this
-  ** function failing. This function could fail if, for example, the
-  ** current working directory has been unlinked.
-  */
-  SimulateIOError( return SQLITE_ERROR );
-
-  assert( pVfs->mxPathname==MAX_PATHNAME );
-  UNUSED_PARAMETER(pVfs);
+static int unixShmRelease(sqlite3_file *fd){
+  unixFile *pDbFd = (unixFile*)fd;
+  unixShm *p = pDbFd->pShm;
 
-  zOut[nOut-1] = '\0';
-  if( zPath[0]=='/' ){
-    sqlite3_snprintf(nOut, zOut, "%s", zPath);
-  }else{
-    int nCwd;
-    if( getcwd(zOut, nOut-1)==0 ){
-      return SQLITE_CANTOPEN_BKPT;
-    }
-    nCwd = (int)strlen(zOut);
-    sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
+  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;
 }
 
-
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-/*
-** Interfaces for opening a shared library, finding entry points
-** within the shared library, and closing the shared library.
-*/
-#include <dlfcn.h>
-static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){
-  UNUSED_PARAMETER(NotUsed);
-  return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL);
-}
-
 /*
-** SQLite calls this function immediately after a call to unixDlSym() or
-** unixDlOpen() fails (returns a null pointer). If a more detailed error
-** message is available, it is written to zBufOut. If no error message
-** is available, zBufOut is left unmodified and SQLite uses a default
-** error message.
+** Symbolic names for LOCK states used for debugging.
 */
-static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
-  char *zErr;
-  UNUSED_PARAMETER(NotUsed);
-  unixEnterMutex();
-  zErr = dlerror();
-  if( zErr ){
-    sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
-  }
-  unixLeaveMutex();
-}
-static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){
-  /* 
-  ** GCC with -pedantic-errors says that C90 does not allow a void* to be
-  ** cast into a pointer to a function.  And yet the library dlsym() routine
-  ** returns a void* which is really a pointer to a function.  So how do we
-  ** use dlsym() with -pedantic-errors?
-  **
-  ** Variable x below is defined to be a pointer to a function taking
-  ** parameters void* and const char* and returning a pointer to a function.
-  ** We initialize x by assigning it a pointer to the dlsym() function.
-  ** (That assignment requires a cast.)  Then we call the function that
-  ** x points to.  
-  **
-  ** This work-around is unlikely to work correctly on any system where
-  ** you really cannot cast a function pointer into void*.  But then, on the
-  ** other hand, dlsym() will not work on such a system either, so we have
-  ** not really lost anything.
-  */
-  void (*(*x)(void*,const char*))(void);
-  UNUSED_PARAMETER(NotUsed);
-  x = (void(*(*)(void*,const char*))(void))dlsym;
-  return (*x)(p, zSym);
-}
-static void unixDlClose(sqlite3_vfs *NotUsed, void *pHandle){
-  UNUSED_PARAMETER(NotUsed);
-  dlclose(pHandle);
-}
-#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
-  #define unixDlOpen  0
-  #define unixDlError 0
-  #define unixDlSym   0
-  #define unixDlClose 0
+#ifdef SQLITE_DEBUG
+static const char *azLkName[] = {
+  "UNLOCK",
+  "READ",
+  "READ_FULL",
+  "WRITE",
+  "PENDING",
+  "CHECKPOINT",
+  "RECOVER"
+};
 #endif
 
+
 /*
-** Write nBuf bytes of random data to the supplied buffer zBuf.
+** Change the lock state for a shared-memory segment.
 */
-static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
-  UNUSED_PARAMETER(NotUsed);
-  assert((size_t)nBuf>=(sizeof(time_t)+sizeof(int)));
+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;
 
-  /* We have to initialize zBuf to prevent valgrind from reporting
-  ** errors.  The reports issued by valgrind are incorrect - we would
-  ** prefer that the randomness be increased by making use of the
-  ** uninitialized space in zBuf - but valgrind errors tend to worry
-  ** some users.  Rather than argue, it seems easier just to initialize
-  ** the whole array and silence valgrind, even if that means less randomness
-  ** in the random seed.
-  **
-  ** When testing, initializing zBuf[] to zero is all we do.  That means
-  ** that we always use the same random number sequence.  This makes the
-  ** tests repeatable.
+  /* 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.
   */
-  memset(zBuf, 0, nBuf);
-#if !defined(SQLITE_TEST)
-  {
-    int pid, fd;
-    fd = open("/dev/urandom", O_RDONLY);
-    if( fd<0 ){
-      time_t t;
-      time(&t);
-      memcpy(zBuf, &t, sizeof(t));
-      pid = getpid();
-      memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
-      assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
-      nBuf = sizeof(t) + sizeof(pid);
-    }else{
-      nBuf = read(fd, zBuf, nBuf);
-      close(fd);
+  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;
     }
   }
-#endif
-  return nBuf;
+  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;
 }
 
-
-/*
-** Sleep for a little while.  Return the amount of time slept.
-** The argument is the number of microseconds we want to sleep.
-** The return value is the number of microseconds of sleep actually
-** requested from the underlying operating system, a number which
-** might be greater than or equal to the argument, but not less
-** than the argument.
-*/
-static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
-#if OS_VXWORKS
-  struct timespec sp;
-
-  sp.tv_sec = microseconds / 1000000;
-  sp.tv_nsec = (microseconds % 1000000) * 1000;
-  nanosleep(&sp, NULL);
-  UNUSED_PARAMETER(NotUsed);
-  return microseconds;
-#elif defined(HAVE_USLEEP) && HAVE_USLEEP
-  usleep(microseconds);
-  UNUSED_PARAMETER(NotUsed);
-  return microseconds;
 #else
-  int seconds = (microseconds+999999)/1000000;
-  sleep(seconds);
-  UNUSED_PARAMETER(NotUsed);
-  return seconds*1000000;
-#endif
-}
-
-/*
-** The following variable, if set to a non-zero value, is interpreted as
-** the number of seconds since 1970 and is used to set the result of
-** sqlite3OsCurrentTime() during testing.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_current_time = 0;  /* Fake system time in seconds since 1970. */
-#endif
+# define unixShmOpen    0
+# define unixShmSize    0
+# define unixShmGet     0
+# define unixShmRelease 0
+# define unixShmLock    0
+# define unixShmClose   0
+#endif /* #ifndef SQLITE_OMIT_WAL */
 
 /*
-** Find the current time (in Universal Coordinated Time).  Write into *piNow
-** the current time and date as a Julian Day number times 86_400_000.  In
-** other words, write into *piNow the number of milliseconds since the Julian
-** epoch of noon in Greenwich on November 24, 4714 B.C according to the
-** proleptic Gregorian calendar.
+** Here ends the implementation of all sqlite3_file methods.
 **
-** On success, return 0.  Return 1 if the time and date cannot be found.
-*/
-static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
-  static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
-#if defined(NO_GETTOD)
-  time_t t;
-  time(&t);
-  *piNow = ((sqlite3_int64)i)*1000 + unixEpoch;
-#elif OS_VXWORKS
-  struct timespec sNow;
-  clock_gettime(CLOCK_REALTIME, &sNow);
-  *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
-#else
-  struct timeval sNow;
-  gettimeofday(&sNow, 0);
-  *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
-#endif
-
-#ifdef SQLITE_TEST
-  if( sqlite3_current_time ){
-    *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
-  }
-#endif
-  UNUSED_PARAMETER(NotUsed);
-  return 0;
-}
-
-/*
-** Find the current time (in Universal Coordinated Time).  Write the
-** current time and date as a Julian Day number into *prNow and
-** return 0.  Return 1 if the time and date cannot be found.
-*/
-static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
-  sqlite3_int64 i;
-  unixCurrentTimeInt64(0, &i);
-  *prNow = i/86400000.0;
-  return 0;
-}
-
-/*
-** We added the xGetLastError() method with the intention of providing
-** better low-level error messages when operating-system problems come up
-** during SQLite operation.  But so far, none of that has been implemented
-** in the core.  So this routine is never called.  For now, it is merely
-** a place-holder.
-*/
-static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
-  UNUSED_PARAMETER(NotUsed);
-  UNUSED_PARAMETER(NotUsed2);
-  UNUSED_PARAMETER(NotUsed3);
-  return 0;
-}
-
-#ifndef SQLITE_OMIT_WAL
-
-/* Forward reference */
-typedef struct unixShm unixShm;
-typedef struct unixShmFile unixShmFile;
+********************** End sqlite3_file Methods *******************************
+******************************************************************************/
 
 /*
-** 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.
+** This division contains definitions of sqlite3_io_methods objects that
+** implement various file locking strategies.  It also contains definitions
+** of "finder" functions.  A finder-function is used to locate the appropriate
+** sqlite3_io_methods object for a particular database file.  The pAppData
+** field of the sqlite3_vfs VFS objects are initialized to be pointers to
+** the correct finder-function for that VFS.
 **
-** unixMutexHeld() must be true when creating or destroying
-** this object or while reading or writing the following fields:
+** Most finder functions return a pointer to a fixed sqlite3_io_methods
+** object.  The only interesting finder-function is autolockIoFinder, which
+** looks at the filesystem type and tries to guess the best locking
+** strategy from that.
 **
-**      nRef
-**      pNext 
+** For finder-funtion F, two objects are created:
 **
-** The following fields are read-only after the object is created:
-** 
-**      fid
-**      zFilename
+**    (1) The real finder-function named "FImpt()".
 **
-** Either unixShmFile.mutex must be held or unixShmFile.nRef==0 and
-** unixMutexHeld() is true when reading or writing any other field
-** in this structure.
+**    (2) A constant pointer to this function named just "F".
 **
-** 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.
+**
+** A pointer to the F pointer is used as the pAppData value for VFS
+** objects.  We have to do this instead of letting pAppData point
+** directly at the finder-function since C90 rules prevent a void*
+** from be cast into a function pointer.
+**
+**
+** Each instance of this macro generates two objects:
+**
+**   *  A constant sqlite3_io_methods object call METHOD that has locking
+**      methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
+**
+**   *  An I/O method finder function called FINDER that returns a pointer
+**      to the METHOD object in the previous bullet.
 */
-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 */
+#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK)      \
+static const sqlite3_io_methods METHOD = {                                   \
+   VERSION,                    /* iVersion */                                \
+   CLOSE,                      /* xClose */                                  \
+   unixRead,                   /* xRead */                                   \
+   unixWrite,                  /* xWrite */                                  \
+   unixTruncate,               /* xTruncate */                               \
+   unixSync,                   /* xSync */                                   \
+   unixFileSize,               /* xFileSize */                               \
+   LOCK,                       /* xLock */                                   \
+   UNLOCK,                     /* xUnlock */                                 \
+   CKLOCK,                     /* xCheckReservedLock */                      \
+   unixFileControl,            /* xFileControl */                            \
+   unixSectorSize,             /* xSectorSize */                             \
+   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);                                  \
+  return &METHOD;                                                            \
+}                                                                            \
+static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p)    \
+    = FINDER##Impl;
+
+/*
+** Here are all of the sqlite3_io_methods objects for each of the
+** locking strategies.  Functions that return pointers to these methods
+** are also created.
+*/
+IOMETHODS(
+  posixIoFinder,            /* Finder function name */
+  posixIoMethods,           /* sqlite3_io_methods object name */
+  2,                        /* ShmOpen is enabled */
+  unixClose,                /* xClose method */
+  unixLock,                 /* xLock method */
+  unixUnlock,               /* xUnlock method */
+  unixCheckReservedLock     /* xCheckReservedLock method */
+)
+IOMETHODS(
+  nolockIoFinder,           /* Finder function name */
+  nolockIoMethods,          /* sqlite3_io_methods object name */
+  1,                        /* ShmOpen is disabled */
+  nolockClose,              /* xClose method */
+  nolockLock,               /* xLock method */
+  nolockUnlock,             /* xUnlock method */
+  nolockCheckReservedLock   /* xCheckReservedLock method */
+)
+IOMETHODS(
+  dotlockIoFinder,          /* Finder function name */
+  dotlockIoMethods,         /* sqlite3_io_methods object name */
+  1,                        /* ShmOpen is disabled */
+  dotlockClose,             /* xClose method */
+  dotlockLock,              /* xLock method */
+  dotlockUnlock,            /* xUnlock method */
+  dotlockCheckReservedLock  /* xCheckReservedLock method */
+)
+
+#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
+IOMETHODS(
+  flockIoFinder,            /* Finder function name */
+  flockIoMethods,           /* sqlite3_io_methods object name */
+  1,                        /* ShmOpen is disabled */
+  flockClose,               /* xClose method */
+  flockLock,                /* xLock method */
+  flockUnlock,              /* xUnlock method */
+  flockCheckReservedLock    /* xCheckReservedLock method */
+)
+#endif
+
+#if OS_VXWORKS
+IOMETHODS(
+  semIoFinder,              /* Finder function name */
+  semIoMethods,             /* sqlite3_io_methods object name */
+  1,                        /* ShmOpen is disabled */
+  semClose,                 /* xClose method */
+  semLock,                  /* xLock method */
+  semUnlock,                /* xUnlock method */
+  semCheckReservedLock      /* xCheckReservedLock method */
+)
 #endif
-};
 
-/*
-** A global array of all unixShmFile objects.
-**
-** The unixMutexHeld() must be true while reading or writing this list.
-*/
-static unixShmFile *unixShmFileList = 0;
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+IOMETHODS(
+  afpIoFinder,              /* Finder function name */
+  afpIoMethods,             /* sqlite3_io_methods object name */
+  1,                        /* ShmOpen is disabled */
+  afpClose,                 /* xClose method */
+  afpLock,                  /* xLock method */
+  afpUnlock,                /* xUnlock method */
+  afpCheckReservedLock      /* xCheckReservedLock method */
+)
+#endif
 
 /*
-** 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.
+** The proxy locking method is a "super-method" in the sense that it
+** opens secondary file descriptors for the conch and lock files and
+** it uses proxy, dot-file, AFP, and flock() locking methods on those
+** secondary files.  For this reason, the division that implements
+** proxy locking is located much further down in the file.  But we need
+** to go ahead and define the sqlite3_io_methods and finder function
+** for proxy locking here.  So we forward declare the I/O methods.
 */
-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 */
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+static int proxyClose(sqlite3_file*);
+static int proxyLock(sqlite3_file*, int);
+static int proxyUnlock(sqlite3_file*, int);
+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 */
+  proxyCheckReservedLock    /* xCheckReservedLock method */
+)
 #endif
-};
 
-/*
-** Size increment by which shared memory grows
-*/
-#define SQLITE_UNIX_SHM_INCR  4096
+/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+IOMETHODS(
+  nfsIoFinder,               /* Finder function name */
+  nfsIoMethods,              /* sqlite3_io_methods object name */
+  1,                         /* ShmOpen is disabled */
+  unixClose,                 /* xClose method */
+  unixLock,                  /* xLock method */
+  nfsUnlock,                 /* xUnlock method */
+  unixCheckReservedLock      /* xCheckReservedLock method */
+)
+#endif
 
-/*
-** Constants used for locking
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+/* 
+** This "finder" function attempts to determine the best locking strategy 
+** for the database file "filePath".  It then returns the sqlite3_io_methods
+** object that implements that strategy.
+**
+** This is for MacOSX only.
 */
-#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
+static const sqlite3_io_methods *autolockIoFinderImpl(
+  const char *filePath,    /* name of the database file */
+  unixFile *pNew           /* open file object for the database file */
+){
+  static const struct Mapping {
+    const char *zFilesystem;              /* Filesystem type name */
+    const sqlite3_io_methods *pMethods;   /* Appropriate locking method */
+  } aMap[] = {
+    { "hfs",    &posixIoMethods },
+    { "ufs",    &posixIoMethods },
+    { "afpfs",  &afpIoMethods },
+    { "smbfs",  &afpIoMethods },
+    { "webdav", &nolockIoMethods },
+    { 0, 0 }
+  };
+  int i;
+  struct statfs fsInfo;
+  struct flock lockInfo;
 
-#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 ".".
+  if( !filePath ){
+    /* If filePath==NULL that means we are dealing with a transient file
+    ** that does not need to be locked. */
+    return &nolockIoMethods;
+  }
+  if( statfs(filePath, &fsInfo) != -1 ){
+    if( fsInfo.f_flags & MNT_RDONLY ){
+      return &nolockIoMethods;
+    }
+    for(i=0; aMap[i].zFilesystem; i++){
+      if( strcmp(fsInfo.f_fstypename, aMap[i].zFilesystem)==0 ){
+        return aMap[i].pMethods;
+      }
+    }
+  }
+
+  /* Default case. Handles, amongst others, "nfs".
+  ** Test byte-range lock using fcntl(). If the call succeeds, 
+  ** assume that the file-system supports POSIX style locks. 
+  */
+  lockInfo.l_len = 1;
+  lockInfo.l_start = 0;
+  lockInfo.l_whence = SEEK_SET;
+  lockInfo.l_type = F_RDLCK;
+  if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
+    if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
+      return &nfsIoMethods;
+    } else {
+      return &posixIoMethods;
+    }
+  }else{
+    return &dotlockIoMethods;
+  }
+}
+static const sqlite3_io_methods 
+  *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
+
+#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+
+#if OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE
+/* 
+** This "finder" function attempts to determine the best locking strategy 
+** for the database file "filePath".  It then returns the sqlite3_io_methods
+** object that implements that strategy.
 **
-** This routine is for debugging purposes only and does not appear
-** in a production build.
+** This is for VXWorks only.
 */
-static const char *unixShmLockString(u8 mask){
-  static char zBuf[48];
-  static int iBuf = 0;
-  char *z;
+static const sqlite3_io_methods *autolockIoFinderImpl(
+  const char *filePath,    /* name of the database file */
+  unixFile *pNew           /* the open file object */
+){
+  struct flock lockInfo;
 
-  z = &zBuf[iBuf];
-  iBuf += 8;
-  if( iBuf>=sizeof(zBuf) ) iBuf = 0;
+  if( !filePath ){
+    /* If filePath==NULL that means we are dealing with a transient file
+    ** that does not need to be locked. */
+    return &nolockIoMethods;
+  }
 
-  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;
+  /* Test if fcntl() is supported and use POSIX style locks.
+  ** Otherwise fall back to the named semaphore method.
+  */
+  lockInfo.l_len = 1;
+  lockInfo.l_start = 0;
+  lockInfo.l_whence = SEEK_SET;
+  lockInfo.l_type = F_RDLCK;
+  if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
+    return &posixIoMethods;
+  }else{
+    return &semIoMethods;
+  }
 }
-#endif /* SQLITE_DEBUG */
+static const sqlite3_io_methods 
+  *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
+
+#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */
 
 /*
-** Apply posix advisory locks for all bytes identified in lockMask.
-**
-** lockMask might contain multiple bits but all bits are guaranteed
-** to be contiguous.
+** An abstract type for a pointer to a IO method finder function:
+*/
+typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*);
+
+
+/****************************************************************************
+**************************** sqlite3_vfs methods ****************************
 **
-** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking
-** otherwise.
+** This division contains the implementation of methods on the
+** sqlite3_vfs object.
 */
-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 */
+
+/*
+** Initialize the contents of the unixFile structure pointed to by pId.
+*/
+static int fillInUnixFile(
+  sqlite3_vfs *pVfs,      /* Pointer to vfs object */
+  int h,                  /* Open file descriptor of file being opened */
+  int dirfd,              /* Directory file descriptor */
+  sqlite3_file *pId,      /* Write to the unixFile structure here */
+  const char *zFilename,  /* Name of the file being opened */
+  int noLock,             /* Omit locking if true */
+  int isDelete            /* Delete on close if true */
 ){
-  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 */
+  const sqlite3_io_methods *pLockingStyle;
+  unixFile *pNew = (unixFile *)pId;
+  int rc = SQLITE_OK;
 
-  /* Access to the unixShmFile object is serialized by the caller */
-  assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
+  assert( pNew->pLock==NULL );
+  assert( pNew->pOpen==NULL );
 
-  /* 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;
-  }
+  /* Parameter isDelete is only used on vxworks. Express this explicitly 
+  ** here to prevent compiler warnings about unused parameters.
+  */
+  UNUSED_PARAMETER(isDelete);
 
-  /* 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;
+  OSTRACE3("OPEN    %-3d %s\n", h, zFilename);    
+  pNew->h = h;
+  pNew->dirfd = dirfd;
+  SET_THREADID(pNew);
+  pNew->fileFlags = 0;
+  assert( zFilename==0 || zFilename[0]=='/' );  /* Never a relative pathname */
+  pNew->zPath = zFilename;
 
-  /* Extend the locking range for each additional bit that is set */
-  mask <<= 1;
-  while( mask!=0 && (lockMask & mask)!=0 ){
-    f.l_len++;
-    mask <<= 1;
+#if OS_VXWORKS
+  pNew->pId = vxworksFindFileId(zFilename);
+  if( pNew->pId==0 ){
+    noLock = 1;
+    rc = SQLITE_NOMEM;
   }
+#endif
 
-  /* Verify that all bits set in lockMask are contiguous */
-  assert( mask==0 || (lockMask & ~(mask | (mask-1)))==0 );
+  if( noLock ){
+    pLockingStyle = &nolockIoMethods;
+  }else{
+    pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew);
+#if SQLITE_ENABLE_LOCKING_STYLE
+    /* Cache zFilename in the locking context (AFP and dotlock override) for
+    ** proxyLock activation is possible (remote proxy is based on db name)
+    ** zFilename remains valid until file is closed, to support */
+    pNew->lockingContext = (void*)zFilename;
+#endif
+  }
 
-  /* Acquire the system-level lock */
-  rc = fcntl(pFile->h, lockOp, &f);
-  rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+  if( pLockingStyle == &posixIoMethods
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+    || pLockingStyle == &nfsIoMethods
+#endif
+  ){
+    unixEnterMutex();
+    rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
+    if( rc!=SQLITE_OK ){
+      /* If an error occured in findLockInfo(), close the file descriptor
+      ** immediately, before releasing the mutex. findLockInfo() may fail
+      ** in two scenarios:
+      **
+      **   (a) A call to fstat() failed.
+      **   (b) A malloc failed.
+      **
+      ** Scenario (b) may only occur if the process is holding no other
+      ** file descriptors open on the same file. If there were other file
+      ** descriptors on this file, then no malloc would be required by
+      ** findLockInfo(). If this is the case, it is quite safe to close
+      ** handle h - as it is guaranteed that no posix locks will be released
+      ** by doing so.
+      **
+      ** If scenario (a) caused the error then things are not so safe. The
+      ** implicit assumption here is that if fstat() fails, things are in
+      ** such bad shape that dropping a lock or two doesn't matter much.
+      */
+      close(h);
+      h = -1;
+    }
+    unixLeaveMutex();
+  }
 
-  /* 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;
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
+  else if( pLockingStyle == &afpIoMethods ){
+    /* AFP locking uses the file path so it needs to be included in
+    ** the afpLockingContext.
+    */
+    afpLockingContext *pCtx;
+    pNew->lockingContext = pCtx = sqlite3_malloc( sizeof(*pCtx) );
+    if( pCtx==0 ){
+      rc = SQLITE_NOMEM;
     }else{
-      assert( lockType==F_WRLCK );
-      OSTRACE(("write-lock ok"));
-      pFile->exclMask |= lockMask;
-      pFile->sharedMask &= ~lockMask;
+      /* NB: zFilename exists and remains valid until the file is closed
+      ** according to requirement F11141.  So we do not need to make a
+      ** copy of the filename. */
+      pCtx->dbPath = zFilename;
+      pCtx->reserved = 0;
+      srandomdev();
+      unixEnterMutex();
+      rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
+      if( rc!=SQLITE_OK ){
+        sqlite3_free(pNew->lockingContext);
+        close(h);
+        h = -1;
+      }
+      unixLeaveMutex();        
     }
-  }else{
-    if( lockType==F_UNLCK ){
-      OSTRACE(("unlock failed"));
-    }else if( lockType==F_RDLCK ){
-      OSTRACE(("read-lock failed"));
+  }
+#endif
+
+  else if( pLockingStyle == &dotlockIoMethods ){
+    /* Dotfile locking uses the file path so it needs to be included in
+    ** the dotlockLockingContext 
+    */
+    char *zLockFile;
+    int nFilename;
+    nFilename = (int)strlen(zFilename) + 6;
+    zLockFile = (char *)sqlite3_malloc(nFilename);
+    if( zLockFile==0 ){
+      rc = SQLITE_NOMEM;
     }else{
-      assert( lockType==F_WRLCK );
-      OSTRACE(("write-lock failed"));
+      sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
     }
+    pNew->lockingContext = zLockFile;
+  }
+
+#if OS_VXWORKS
+  else if( pLockingStyle == &semIoMethods ){
+    /* Named semaphore locking uses the file path so it needs to be
+    ** included in the semLockingContext
+    */
+    unixEnterMutex();
+    rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
+    if( (rc==SQLITE_OK) && (pNew->pOpen->pSem==NULL) ){
+      char *zSemName = pNew->pOpen->aSemName;
+      int n;
+      sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem",
+                       pNew->pId->zCanonicalName);
+      for( n=1; zSemName[n]; n++ )
+        if( zSemName[n]=='/' ) zSemName[n] = '_';
+      pNew->pOpen->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
+      if( pNew->pOpen->pSem == SEM_FAILED ){
+        rc = SQLITE_NOMEM;
+        pNew->pOpen->aSemName[0] = '\0';
+      }
+    }
+    unixLeaveMutex();
   }
-  OSTRACE((" - change requested %s - afterwards %s:%s\n",
-           unixShmLockString(lockMask),
-           unixShmLockString(pFile->sharedMask),
-           unixShmLockString(pFile->exclMask)));
 #endif
+  
+  pNew->lastErrno = 0;
+#if OS_VXWORKS
+  if( rc!=SQLITE_OK ){
+    if( h>=0 ) close(h);
+    h = -1;
+    unlink(zFilename);
+    isDelete = 0;
+  }
+  pNew->isDelete = isDelete;
+#endif
+  if( rc!=SQLITE_OK ){
+    if( dirfd>=0 ) close(dirfd); /* silent leak if fail, already in error */
+    if( h>=0 ) close(h);
+  }else{
+    pNew->pMethod = pLockingStyle;
+    OpenCounter(+1);
+  }
+  return rc;
+}
 
-  return rc;        
+/*
+** Open a file descriptor to the directory containing file zFilename.
+** If successful, *pFd is set to the opened file descriptor and
+** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM
+** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined
+** value.
+**
+** If SQLITE_OK is returned, the caller is responsible for closing
+** the file descriptor *pFd using close().
+*/
+static int openDirectory(const char *zFilename, int *pFd){
+  int ii;
+  int fd = -1;
+  char zDirname[MAX_PATHNAME+1];
+
+  sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
+  for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
+  if( ii>0 ){
+    zDirname[ii] = '\0';
+    fd = open(zDirname, O_RDONLY|O_BINARY, 0);
+    if( fd>=0 ){
+#ifdef FD_CLOEXEC
+      fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+#endif
+      OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname);
+    }
+  }
+  *pFd = fd;
+  return (fd>=0?SQLITE_OK:SQLITE_CANTOPEN_BKPT);
 }
 
 /*
-** For connection p, unlock all of the locks identified by the unlockMask
-** parameter.
+** Create a temporary file name in zBuf.  zBuf must be allocated
+** by the calling process and must be big enough to hold at least
+** pVfs->mxPathname bytes.
 */
-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" */
+static int getTempname(int nBuf, char *zBuf){
+  static const char *azDirs[] = {
+     0,
+     0,
+     "/var/tmp",
+     "/usr/tmp",
+     "/tmp",
+     ".",
+  };
+  static const unsigned char zChars[] =
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "0123456789";
+  unsigned int i, j;
+  struct stat buf;
+  const char *zDir = ".";
 
-  /* Access to the unixShmFile object is serialized by the caller */
-  assert( sqlite3_mutex_held(pFile->mutex) );
+  /* It's odd to simulate an io-error here, but really this is just
+  ** using the io-error infrastructure to test that SQLite handles this
+  ** function failing. 
+  */
+  SimulateIOError( return SQLITE_IOERR );
 
-  /* 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;
+  azDirs[0] = sqlite3_temp_directory;
+  if (NULL == azDirs[1]) {
+    azDirs[1] = getenv("TMPDIR");
+  }
+  
+  for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
+    if( azDirs[i]==0 ) continue;
+    if( stat(azDirs[i], &buf) ) continue;
+    if( !S_ISDIR(buf.st_mode) ) continue;
+    if( access(azDirs[i], 07) ) continue;
+    zDir = azDirs[i];
+    break;
   }
 
-  /* Unlock the system-level locks */
-  if( (unlockMask & allMask)!=unlockMask ){
-    rc = unixShmSystemLock(pFile, F_UNLCK, unlockMask & ~allMask);
-  }else{
-    rc = SQLITE_OK;
+  /* Check that the output buffer is large enough for the temporary file 
+  ** name. If it is not, return SQLITE_ERROR.
+  */
+  if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 17) >= (size_t)nBuf ){
+    return SQLITE_ERROR;
   }
 
-  /* Undo the local locks */
-  if( rc==SQLITE_OK ){
-    p->exclMask &= ~unlockMask;
-    p->sharedMask &= ~unlockMask;
-  } 
-  return rc;
+  do{
+    sqlite3_snprintf(nBuf-17, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
+    j = (int)strlen(zBuf);
+    sqlite3_randomness(15, &zBuf[j]);
+    for(i=0; i<15; i++, j++){
+      zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
+    }
+    zBuf[j] = 0;
+  }while( access(zBuf,0)==0 );
+  return SQLITE_OK;
 }
 
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
 /*
-** Get reader locks for connection p on all locks in the readMask parameter.
+** Routine to transform a unixFile into a proxy-locking unixFile.
+** Implementation in the proxy-lock division, but used by unixOpen()
+** if SQLITE_PREFER_PROXY_LOCKING is defined.
 */
-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" */
+static int proxyTransformUnixFile(unixFile*, const char*);
+#endif
 
-  /* Access to the unixShmFile object is serialized by the caller */
-  assert( sqlite3_mutex_held(pFile->mutex) );
+/*
+** Search for an unused file descriptor that was opened on the database 
+** file (not a journal or master-journal file) identified by pathname
+** zPath with SQLITE_OPEN_XXX flags matching those passed as the second
+** argument to this function.
+**
+** Such a file descriptor may exist if a database connection was closed
+** but the associated file descriptor could not be closed because some
+** other file descriptor open on the same file is holding a file-lock.
+** Refer to comments in the unixClose() function and the lengthy comment
+** describing "Posix Advisory Locking" at the start of this file for 
+** further details. Also, ticket #4018.
+**
+** If a suitable file descriptor is found, then it is returned. If no
+** such file descriptor is located, -1 is returned.
+*/
+static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
+  UnixUnusedFd *pUnused = 0;
 
-  /* 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;
-  }
+  /* Do not search for an unused file descriptor on vxworks. Not because
+  ** vxworks would not benefit from the change (it might, we're not sure),
+  ** but because no way to test it is currently available. It is better 
+  ** not to risk breaking vxworks support for the sake of such an obscure 
+  ** feature.  */
+#if !OS_VXWORKS
+  struct stat sStat;                   /* Results of stat() call */
 
-  /* Get shared locks at the system level, if necessary */
-  if( (~allShared) & readMask ){
-    rc = unixShmSystemLock(pFile, F_RDLCK, readMask);
-  }else{
-    rc = SQLITE_OK;
-  }
+  /* A stat() call may fail for various reasons. If this happens, it is
+  ** almost certain that an open() call on the same path will also fail.
+  ** For this reason, if an error occurs in the stat() call here, it is
+  ** ignored and -1 is returned. The caller will try to open a new file
+  ** descriptor on the same path, fail, and return an error to SQLite.
+  **
+  ** Even if a subsequent open() call does succeed, the consequences of
+  ** not searching for a resusable file descriptor are not dire.  */
+  if( 0==stat(zPath, &sStat) ){
+    struct unixOpenCnt *pOpen;
 
-  /* Get the local shared locks */
-  if( rc==SQLITE_OK ){
-    p->sharedMask |= readMask;
+    unixEnterMutex();
+    pOpen = openList;
+    while( pOpen && (pOpen->fileId.dev!=sStat.st_dev
+                     || pOpen->fileId.ino!=sStat.st_ino) ){
+       pOpen = pOpen->pNext;
+    }
+    if( pOpen ){
+      UnixUnusedFd **pp;
+      for(pp=&pOpen->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
+      pUnused = *pp;
+      if( pUnused ){
+        *pp = pUnused->pNext;
+      }
+    }
+    unixLeaveMutex();
   }
-  return rc;
+#endif    /* if !OS_VXWORKS */
+  return pUnused;
 }
 
 /*
-** For connection p, get an exclusive lock on all locks identified in
-** the writeMask parameter.
+** Open the file zPath.
+** 
+** Previously, the SQLite OS layer used three functions in place of this
+** one:
+**
+**     sqlite3OsOpenReadWrite();
+**     sqlite3OsOpenReadOnly();
+**     sqlite3OsOpenExclusive();
+**
+** These calls correspond to the following combinations of flags:
+**
+**     ReadWrite() ->     (READWRITE | CREATE)
+**     ReadOnly()  ->     (READONLY) 
+**     OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE)
+**
+** The old OpenExclusive() accepted a boolean argument - "delFlag". If
+** true, the file was configured to be automatically deleted when the
+** file handle closed. To achieve the same effect using this new 
+** interface, add the DELETEONCLOSE flag to those specified above for 
+** OpenExclusive().
 */
-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 */
+static int unixOpen(
+  sqlite3_vfs *pVfs,           /* The VFS for which this is the xOpen method */
+  const char *zPath,           /* Pathname of file to be opened */
+  sqlite3_file *pFile,         /* The file descriptor to be filled in */
+  int flags,                   /* Input flags to control the opening */
+  int *pOutFlags               /* Output flags returned to SQLite core */
 ){
-  int rc;        /* Result code */
-  unixShm *pX;   /* For looping over all sibling connections */
+  unixFile *p = (unixFile *)pFile;
+  int fd = -1;                   /* File descriptor returned by open() */
+  int dirfd = -1;                /* Directory file descriptor */
+  int openFlags = 0;             /* Flags to pass to open() */
+  int eType = flags&0xFFFFFF00;  /* Type of file to open */
+  int noLock;                    /* True to omit locking primitives */
+  int rc = SQLITE_OK;            /* Function Return Code */
 
-  /* Access to the unixShmFile object is serialized by the caller */
-  assert( sqlite3_mutex_held(pFile->mutex) );
+  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
+  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
+  int isCreate     = (flags & SQLITE_OPEN_CREATE);
+  int isReadonly   = (flags & SQLITE_OPEN_READONLY);
+  int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);
+#if SQLITE_ENABLE_LOCKING_STYLE
+  int isAutoProxy  = (flags & SQLITE_OPEN_AUTOPROXY);
+#endif
 
-  /* Make sure no sibling connections hold locks that will block this
-  ** lock.  If any do, return SQLITE_BUSY right away.
+  /* If creating a master or main-file journal, this function will open
+  ** a file-descriptor on the directory too. The first time unixSync()
+  ** is called the directory file descriptor will be fsync()ed and close()d.
   */
-  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;
-  }
+  int isOpenDirectory = (isCreate && 
+      (eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL)
+  );
 
-  /* Get the exclusive locks at the system level.  Then if successful
-  ** also mark the local connection as being locked.
+  /* If argument zPath is a NULL pointer, this function is required to open
+  ** a temporary file. Use this buffer to store the file name in.
   */
-  rc = unixShmSystemLock(pFile, F_WRLCK, writeMask);
-  if( rc==SQLITE_OK ){
-    p->sharedMask &= ~writeMask;
-    p->exclMask |= writeMask;
+  char zTmpname[MAX_PATHNAME+1];
+  const char *zName = zPath;
+
+  /* Check the following statements are true: 
+  **
+  **   (a) Exactly one of the READWRITE and READONLY flags must be set, and 
+  **   (b) if CREATE is set, then READWRITE must also be set, and
+  **   (c) if EXCLUSIVE is set, then CREATE must also be set.
+  **   (d) if DELETEONCLOSE is set, then CREATE must also be set.
+  */
+  assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
+  assert(isCreate==0 || isReadWrite);
+  assert(isExclusive==0 || isCreate);
+  assert(isDelete==0 || isCreate);
+
+  /* The main DB, main journal, and master journal are never automatically
+  ** deleted. Nor are they ever temporary files.  */
+  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
+  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
+  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+
+  /* Assert that the upper layer has set one of the "file-type" flags. */
+  assert( eType==SQLITE_OPEN_MAIN_DB      || eType==SQLITE_OPEN_TEMP_DB 
+       || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL 
+       || eType==SQLITE_OPEN_SUBJOURNAL   || eType==SQLITE_OPEN_MASTER_JOURNAL 
+       || eType==SQLITE_OPEN_TRANSIENT_DB
+  );
+
+  memset(p, 0, sizeof(unixFile));
+
+  if( eType==SQLITE_OPEN_MAIN_DB ){
+    UnixUnusedFd *pUnused;
+    pUnused = findReusableFd(zName, flags);
+    if( pUnused ){
+      fd = pUnused->fd;
+    }else{
+      pUnused = sqlite3_malloc(sizeof(*pUnused));
+      if( !pUnused ){
+        return SQLITE_NOMEM;
+      }
+    }
+    p->pUnused = pUnused;
+  }else if( !zName ){
+    /* If zName is NULL, the upper layer is requesting a temp file. */
+    assert(isDelete && !isOpenDirectory);
+    rc = getTempname(MAX_PATHNAME+1, zTmpname);
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+    zName = zTmpname;
   }
-  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;
+  /* Determine the value of the flags parameter passed to POSIX function
+  ** open(). These must be calculated even if open() is not called, as
+  ** they may be stored as part of the file handle and used by the 
+  ** 'conch file' locking functions later on.  */
+  if( isReadonly )  openFlags |= O_RDONLY;
+  if( isReadWrite ) openFlags |= O_RDWR;
+  if( isCreate )    openFlags |= O_CREAT;
+  if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
+  openFlags |= (O_LARGEFILE|O_BINARY);
+
+  if( fd<0 ){
+    mode_t openMode = (isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS);
+    fd = open(zName, openFlags, openMode);
+    OSTRACE4("OPENX   %-3d %s 0%o\n", fd, zName, openFlags);
+    if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
+      /* Failed to open the file for read/write access. Try read-only. */
+      flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
+      openFlags &= ~(O_RDWR|O_CREAT);
+      flags |= SQLITE_OPEN_READONLY;
+      openFlags |= O_RDONLY;
+      fd = open(zName, openFlags, openMode);
+    }
+    if( fd<0 ){
+      rc = SQLITE_CANTOPEN_BKPT;
+      goto open_finished;
     }
   }
-}
+  assert( fd>=0 );
+  if( pOutFlags ){
+    *pOutFlags = flags;
+  }
 
-/*
-** 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 */
+  if( p->pUnused ){
+    p->pUnused->fd = fd;
+    p->pUnused->flags = flags;
+  }
 
-  /* 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;
+  if( isDelete ){
+#if OS_VXWORKS
+    zPath = zName;
+#else
+    unlink(zName);
+#endif
   }
-  memset(pNew, 0, sizeof(*pNew));
-  pNew->zFilename = (char*)&pNew[1];
-  sqlite3_snprintf(nName+12, pNew->zFilename, "%s-wal-index", zName);
+#if SQLITE_ENABLE_LOCKING_STYLE
+  else{
+    p->openFlags = openFlags;
+  }
+#endif
 
-  /* 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( isOpenDirectory ){
+    rc = openDirectory(zPath, &dirfd);
+    if( rc!=SQLITE_OK ){
+      /* It is safe to close fd at this point, because it is guaranteed not
+      ** to be open on a database file. If it were open on a database file,
+      ** it would not be safe to close as this would release any locks held
+      ** on the file by this process.  */
+      assert( eType!=SQLITE_OPEN_MAIN_DB );
+      close(fd);             /* silently leak if fail, already in error */
+      goto open_finished;
     }
   }
-  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;
-    }
+#ifdef FD_CLOEXEC
+  fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+#endif
 
-    pFile->h = open(pFile->zFilename, O_RDWR|O_CREAT, 0664);
-    if( pFile->h<0 ){
-      rc = SQLITE_CANTOPEN_BKPT;
-      goto shm_open_err;
-    }
+  noLock = eType!=SQLITE_OPEN_MAIN_DB;
 
-    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;
+  
+#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
+  struct statfs fsInfo;
+  if( fstatfs(fd, &fsInfo) == -1 ){
+    ((unixFile*)pFile)->lastErrno = errno;
+    if( dirfd>=0 ) close(dirfd); /* silently leak if fail, in error */
+    close(fd); /* silently leak if fail, in error */
+    return SQLITE_IOERR_ACCESS;
+  }
+  if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
+    ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
+  }
+#endif
+  
+#if SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_PREFER_PROXY_LOCKING
+  isAutoProxy = 1;
+#endif
+  if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
+    char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
+    int useProxy = 0;
 
-    /* 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;
+    /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means 
+    ** never use proxy, NULL means use proxy for non-local files only.  */
+    if( envforce!=NULL ){
+      useProxy = atoi(envforce)>0;
+    }else{
+      struct statfs fsInfo;
+      if( statfs(zPath, &fsInfo) == -1 ){
+        /* In theory, the close(fd) call is sub-optimal. If the file opened
+        ** with fd is a database file, and there are other connections open
+        ** on that file that are currently holding advisory locks on it,
+        ** then the call to close() will cancel those locks. In practice,
+        ** we're assuming that statfs() doesn't fail very often. At least
+        ** not while other file descriptors opened by the same process on
+        ** the same file are working.  */
+        p->lastErrno = errno;
+        if( dirfd>=0 ){
+          close(dirfd); /* silently leak if fail, in error */
+        }
+        close(fd); /* silently leak if fail, in error */
+        rc = SQLITE_IOERR_ACCESS;
+        goto open_finished;
       }
+      useProxy = !(fsInfo.f_flags&MNT_LOCAL);
     }
-    if( rc==SQLITE_OK ){
-      rc = unixShmSystemLock(pFile, F_RDLCK, UNIX_SHM_DMS);
+    if( useProxy ){
+      rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
+      if( rc==SQLITE_OK ){
+        rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
+        if( rc!=SQLITE_OK ){
+          /* Use unixClose to clean up the resources added in fillInUnixFile 
+          ** and clear all the structure's references.  Specifically, 
+          ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op 
+          */
+          unixClose(pFile);
+          return rc;
+        }
+      }
+      goto open_finished;
     }
-    if( rc ) goto shm_open_err;
   }
+#endif
+  
+  rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
+open_finished:
+  if( rc!=SQLITE_OK ){
+    sqlite3_free(p->pUnused);
+  }
+  return rc;
+}
 
-  /* Make the new connection a child of the unixShmFile */
-  p->pFile = pFile;
-  p->pNext = pFile->pFirst;
-#ifdef SQLITE_DEBUG
-  p->id = pFile->nextShmId++;
+
+/*
+** Delete the file at zPath. If the dirSync argument is true, fsync()
+** the directory after deleting the file.
+*/
+static int unixDelete(
+  sqlite3_vfs *NotUsed,     /* VFS containing this as the xDelete method */
+  const char *zPath,        /* Name of file to be deleted */
+  int dirSync               /* If true, fsync() directory after deleting file */
+){
+  int rc = SQLITE_OK;
+  UNUSED_PARAMETER(NotUsed);
+  SimulateIOError(return SQLITE_IOERR_DELETE);
+  unlink(zPath);
+#ifndef SQLITE_DISABLE_DIRSYNC
+  if( dirSync ){
+    int fd;
+    rc = openDirectory(zPath, &fd);
+    if( rc==SQLITE_OK ){
+#if OS_VXWORKS
+      if( fsync(fd)==-1 )
+#else
+      if( fsync(fd) )
+#endif
+      {
+        rc = SQLITE_IOERR_DIR_FSYNC;
+      }
+      if( close(fd)&&!rc ){
+        rc = SQLITE_IOERR_DIR_CLOSE;
+      }
+    }
+  }
 #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.
+** Test the existance of or access permissions of file zPath. The
+** test performed depends on the value of flags:
+**
+**     SQLITE_ACCESS_EXISTS: Return 1 if the file exists
+**     SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable.
+**     SQLITE_ACCESS_READONLY: Return 1 if the file is readable.
+**
+** Otherwise return 0.
 */
-static int unixShmClose(
-  sqlite3_vfs *pVfs,         /* The VFS */
-  sqlite3_shm *pSharedMem,   /* The shared-memory to be closed */
-  int deleteFlag             /* Delete after closing if true */
+static int unixAccess(
+  sqlite3_vfs *NotUsed,   /* The VFS containing this xAccess method */
+  const char *zPath,      /* Path of the file to examine */
+  int flags,              /* What do we want to learn about the zPath file? */
+  int *pResOut            /* Write result boolean here */
 ){
-  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);
+  int amode = 0;
+  UNUSED_PARAMETER(NotUsed);
+  SimulateIOError( return SQLITE_IOERR_ACCESS; );
+  switch( flags ){
+    case SQLITE_ACCESS_EXISTS:
+      amode = F_OK;
+      break;
+    case SQLITE_ACCESS_READWRITE:
+      amode = W_OK|R_OK;
+      break;
+    case SQLITE_ACCESS_READ:
+      amode = R_OK;
+      break;
 
-  /* 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();
+    default:
+      assert(!"Invalid flags argument");
   }
-  unixLeaveMutex();
-
+  *pResOut = (access(zPath, amode)==0);
   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.
+** Turn a relative pathname into a full pathname. The relative path
+** is stored as a nul-terminated string in the buffer pointed to by
+** zPath. 
 **
-** The reqSize parameter is the minimum size requested.  The implementation
-** is free to expand the storage to some larger amount if it chooses.
+** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes 
+** (in this case, MAX_PATHNAME bytes). The full-path is written to
+** this buffer before returning.
 */
-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 */
+static int unixFullPathname(
+  sqlite3_vfs *pVfs,            /* Pointer to vfs object */
+  const char *zPath,            /* Possibly relative input path */
+  int nOut,                     /* Size of output buffer in bytes */
+  char *zOut                    /* Output buffer */
 ){
-  unixShm *p = (unixShm*)pSharedMem;
-  unixShmFile *pFile = p->pFile;
-  int rc = SQLITE_OK;
-  struct stat sStat;
 
+  /* It's odd to simulate an io-error here, but really this is just
+  ** using the io-error infrastructure to test that SQLite handles this
+  ** function failing. This function could fail if, for example, the
+  ** current working directory has been unlinked.
+  */
+  SimulateIOError( return SQLITE_ERROR );
+
+  assert( pVfs->mxPathname==MAX_PATHNAME );
   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;
+  zOut[nOut-1] = '\0';
+  if( zPath[0]=='/' ){
+    sqlite3_snprintf(nOut, zOut, "%s", zPath);
   }else{
-    *pNewSize = 0;
-    rc = SQLITE_IOERR;
+    int nCwd;
+    if( getcwd(zOut, nOut-1)==0 ){
+      return SQLITE_CANTOPEN_BKPT;
+    }
+    nCwd = (int)strlen(zOut);
+    sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
   }
-  return rc;
+  return SQLITE_OK;
 }
 
 
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
 /*
-** 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.
+** Interfaces for opening a shared library, finding entry points
+** within the shared library, and closing the shared library.
 */
-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;
+#include <dlfcn.h>
+static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){
+  UNUSED_PARAMETER(NotUsed);
+  return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL);
+}
 
-  if( p->lockState!=SQLITE_SHM_CHECKPOINT && p->hasMutexBuf==0 ){
-    assert( sqlite3_mutex_notheld(pFile->mutex) );
-    sqlite3_mutex_enter(pFile->mutexBuf);
-    p->hasMutexBuf = 1;
+/*
+** SQLite calls this function immediately after a call to unixDlSym() or
+** unixDlOpen() fails (returns a null pointer). If a more detailed error
+** message is available, it is written to zBufOut. If no error message
+** is available, zBufOut is left unmodified and SQLite uses a default
+** error message.
+*/
+static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
+  char *zErr;
+  UNUSED_PARAMETER(NotUsed);
+  unixEnterMutex();
+  zErr = dlerror();
+  if( zErr ){
+    sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
   }
-  sqlite3_mutex_enter(pFile->mutex);
-  if( pFile->szMap==0 || reqMapSize>pFile->szMap ){
-    int actualSize;
-    if( unixShmSize(pVfs, pSharedMem, -1, &actualSize)==SQLITE_OK
-     && reqMapSize<actualSize
-    ){
-      reqMapSize = actualSize;
-    }
-    if( pFile->pMMapBuf ){
-      munmap(pFile->pMMapBuf, pFile->szMap);
+  unixLeaveMutex();
+}
+static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){
+  /* 
+  ** GCC with -pedantic-errors says that C90 does not allow a void* to be
+  ** cast into a pointer to a function.  And yet the library dlsym() routine
+  ** returns a void* which is really a pointer to a function.  So how do we
+  ** use dlsym() with -pedantic-errors?
+  **
+  ** Variable x below is defined to be a pointer to a function taking
+  ** parameters void* and const char* and returning a pointer to a function.
+  ** We initialize x by assigning it a pointer to the dlsym() function.
+  ** (That assignment requires a cast.)  Then we call the function that
+  ** x points to.  
+  **
+  ** This work-around is unlikely to work correctly on any system where
+  ** you really cannot cast a function pointer into void*.  But then, on the
+  ** other hand, dlsym() will not work on such a system either, so we have
+  ** not really lost anything.
+  */
+  void (*(*x)(void*,const char*))(void);
+  UNUSED_PARAMETER(NotUsed);
+  x = (void(*(*)(void*,const char*))(void))dlsym;
+  return (*x)(p, zSym);
+}
+static void unixDlClose(sqlite3_vfs *NotUsed, void *pHandle){
+  UNUSED_PARAMETER(NotUsed);
+  dlclose(pHandle);
+}
+#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
+  #define unixDlOpen  0
+  #define unixDlError 0
+  #define unixDlSym   0
+  #define unixDlClose 0
+#endif
+
+/*
+** Write nBuf bytes of random data to the supplied buffer zBuf.
+*/
+static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
+  UNUSED_PARAMETER(NotUsed);
+  assert((size_t)nBuf>=(sizeof(time_t)+sizeof(int)));
+
+  /* We have to initialize zBuf to prevent valgrind from reporting
+  ** errors.  The reports issued by valgrind are incorrect - we would
+  ** prefer that the randomness be increased by making use of the
+  ** uninitialized space in zBuf - but valgrind errors tend to worry
+  ** some users.  Rather than argue, it seems easier just to initialize
+  ** the whole array and silence valgrind, even if that means less randomness
+  ** in the random seed.
+  **
+  ** When testing, initializing zBuf[] to zero is all we do.  That means
+  ** that we always use the same random number sequence.  This makes the
+  ** tests repeatable.
+  */
+  memset(zBuf, 0, nBuf);
+#if !defined(SQLITE_TEST)
+  {
+    int pid, fd;
+    fd = open("/dev/urandom", O_RDONLY);
+    if( fd<0 ){
+      time_t t;
+      time(&t);
+      memcpy(zBuf, &t, sizeof(t));
+      pid = getpid();
+      memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
+      assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
+      nBuf = sizeof(t) + sizeof(pid);
+    }else{
+      nBuf = read(fd, zBuf, nBuf);
+      close(fd);
     }
-    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;
+#endif
+  return nBuf;
 }
 
+
 /*
-** 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.
+** Sleep for a little while.  Return the amount of time slept.
+** The argument is the number of microseconds we want to sleep.
+** The return value is the number of microseconds of sleep actually
+** requested from the underlying operating system, a number which
+** might be greater than or equal to the argument, but not less
+** than the argument.
 */
-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;
+static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
+#if OS_VXWORKS
+  struct timespec sp;
+
+  sp.tv_sec = microseconds / 1000000;
+  sp.tv_nsec = (microseconds % 1000000) * 1000;
+  nanosleep(&sp, NULL);
+  UNUSED_PARAMETER(NotUsed);
+  return microseconds;
+#elif defined(HAVE_USLEEP) && HAVE_USLEEP
+  usleep(microseconds);
+  UNUSED_PARAMETER(NotUsed);
+  return microseconds;
+#else
+  int seconds = (microseconds+999999)/1000000;
+  sleep(seconds);
+  UNUSED_PARAMETER(NotUsed);
+  return seconds*1000000;
+#endif
 }
 
 /*
-** Symbolic names for LOCK states used for debugging.
+** The following variable, if set to a non-zero value, is interpreted as
+** the number of seconds since 1970 and is used to set the result of
+** sqlite3OsCurrentTime() during testing.
 */
-#ifdef SQLITE_DEBUG
-static const char *azLkName[] = {
-  "UNLOCK",
-  "READ",
-  "READ_FULL",
-  "WRITE",
-  "PENDING",
-  "CHECKPOINT",
-  "RECOVER"
-};
+#ifdef SQLITE_TEST
+int sqlite3_current_time = 0;  /* Fake system time in seconds since 1970. */
 #endif
 
-
 /*
-** Change the lock state for a shared-memory segment.
+** Find the current time (in Universal Coordinated Time).  Write into *piNow
+** the current time and date as a Julian Day number times 86_400_000.  In
+** other words, write into *piNow the number of milliseconds since the Julian
+** epoch of noon in Greenwich on November 24, 4714 B.C according to the
+** proleptic Gregorian calendar.
+**
+** On success, return 0.  Return 1 if the time and date cannot be found.
 */
-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 );
+static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
+  static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+#if defined(NO_GETTOD)
+  time_t t;
+  time(&t);
+  *piNow = ((sqlite3_int64)i)*1000 + unixEpoch;
+#elif OS_VXWORKS
+  struct timespec sNow;
+  clock_gettime(CLOCK_REALTIME, &sNow);
+  *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
+#else
+  struct timeval sNow;
+  gettimeofday(&sNow, 0);
+  *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+#endif
 
-  /* 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;
+#ifdef SQLITE_TEST
+  if( sqlite3_current_time ){
+    *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
   }
+#endif
+  UNUSED_PARAMETER(NotUsed);
+  return 0;
+}
 
-  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;
+/*
+** Find the current time (in Universal Coordinated Time).  Write the
+** current time and date as a Julian Day number into *prNow and
+** return 0.  Return 1 if the time and date cannot be found.
+*/
+static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
+  sqlite3_int64 i;
+  unixCurrentTimeInt64(0, &i);
+  *prNow = i/86400000.0;
+  return 0;
+}
+
+/*
+** We added the xGetLastError() method with the intention of providing
+** better low-level error messages when operating-system problems come up
+** during SQLite operation.  But so far, none of that has been implemented
+** in the core.  So this routine is never called.  For now, it is merely
+** a place-holder.
+*/
+static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
+  UNUSED_PARAMETER(NotUsed);
+  UNUSED_PARAMETER(NotUsed2);
+  UNUSED_PARAMETER(NotUsed3);
+  return 0;
 }
 
-#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 */           \
   }
index 672789c947cccece39c409098df221ed3c6b3427..42403c997f1ba907b4de50880c756fde7c03f3af 100644 (file)
@@ -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;
index 91b2cb32f98c846662a4e3ad1543d1d6b33888bb..57ceb046311133412c37070fa9529896eb8ca4fa 100644 (file)
@@ -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);
index 15daf971f874839ede560f760d1e5c6b0531811b..af36382edcc75fb440b3ee2e31e18f32c6414db8 100644 (file)
@@ -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*);
   /*
index 1ebde80e1eb4052d545111a0421f01cb2be3c5d5..9b5c3f615e5adf9371770f943279f4ef54c78005 100644 (file)
@@ -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;
index 082d101d4e78268c130adcd040e5e055a3ef189d..ed7078d7a1bfc35196875b943ccb4b07df9deaa4 100644 (file)
@@ -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 ){
index 6b39a39ad70b867e8516806aa8a90d9dd2f18ab6..520dffcb7178b99a7ce76249d73d961c40cfd2b9 100644 (file)
@@ -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 */
index 1b5b4b09d28c8ef12c1c0ec3aae237d9a6297f12..af0c24b49af7169be277868378e17732e710b7de 100644 (file)
 #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;
 }
 
index 88f880ea942fff2cabfa3005ab4d3d51bf2a86df..3fee165da700b0c4e063963e75edc68eaab7102c 100644 (file)
@@ -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;
   }
index bdae2e9dfc2fd39310a09f9cb957b4d0ec674db0..0b2c3ceb660d036dca10d9504c601e41e186f8c6 100644 (file)
--- 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, &notUsed);
-    pVfs->xShmClose(pVfs, pWIndex, isDelete);
+    sqlite3OsShmLock(pWal->pDbFd, SQLITE_SHM_UNLOCK, &notUsed);
+    sqlite3OsShmClose(pWal->pDbFd, isDelete);
+    pWal->isWindexOpen = 0;
   }
 }
 
@@ -675,41 +675,44 @@ static void walIndexClose(Wal *pWal, int isDelete){
 */
 int sqlite3WalOpen(
   sqlite3_vfs *pVfs,              /* vfs module to open wal and wal-index */
-  const char *zDb,                /* Name of database file */
+  sqlite3_file *pDbFd,            /* The open database file */
+  const char *zDbName,            /* Name of the database file */
   Wal **ppWal                     /* OUT: Allocated Wal handle */
 ){
   int rc;                         /* Return Code */
   Wal *pRet;                      /* Object to allocate and return */
   int flags;                      /* Flags passed to OsOpen() */
-  char *zWal;                     /* Path to WAL file */
+  char *zWal;                     /* Name of write-ahead log file */
   int nWal;                       /* Length of zWal in bytes */
 
-  assert( zDb );
-  if( pVfs->xShmOpen==0 ) return SQLITE_CANTOPEN_BKPT;
+  assert( zDbName && zDbName[0] );
+  assert( pDbFd );
 
   /* Allocate an instance of struct Wal to return. */
   *ppWal = 0;
-  nWal = strlen(zDb);
-  pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile + nWal+5);
+  nWal = sqlite3Strlen30(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( iOffset<iSegment ){
       walEncodeFrame(aCksum,pLast->pgno,nTruncate,nPgsz,pLast->pData,aFrame);
-      rc = sqlite3OsWrite(pWal->pFd, aFrame, sizeof(aFrame), iOffset);
+      rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
       if( rc!=SQLITE_OK ){
         return rc;
       }
 
       iOffset += WAL_FRAME_HDRSIZE;
-      rc = sqlite3OsWrite(pWal->pFd, pLast->pData, nPgsz, iOffset); 
+      rc = sqlite3OsWrite(pWal->pWalFd, pLast->pData, nPgsz, iOffset); 
       if( rc!=SQLITE_OK ){
         return rc;
       }
@@ -1393,7 +1394,7 @@ int sqlite3WalFrames(
       iOffset += nPgsz;
     }
 
-    rc = sqlite3OsSync(pWal->pFd, sync_flags);
+    rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
   }
   assert( pWal->pWiData==0 );
 
@@ -1445,7 +1446,6 @@ int sqlite3WalFrames(
 */
 int sqlite3WalCheckpoint(
   Wal *pWal,                      /* Wal connection */
-  sqlite3_file *pFd,              /* File descriptor open on db file */
   int sync_flags,                 /* Flags to sync db file with (or 0) */
   int nBuf,                       /* Size of temporary buffer */
   u8 *zBuf,                       /* Temporary buffer to use */
@@ -1479,7 +1479,7 @@ int sqlite3WalCheckpoint(
   /* Copy data from the log to the database file. */
   rc = walIndexReadHdr(pWal, &isChanged);
   if( rc==SQLITE_OK ){
-    rc = walCheckpoint(pWal, pFd, sync_flags, nBuf, zBuf);
+    rc = walCheckpoint(pWal, sync_flags, nBuf, zBuf);
   }
   if( isChanged ){
     /* If a new wal-index header was loaded before the checkpoint was 
index 89e94869c1cd48426fbddd816c8a56f26d5b94a4..1e25fc811663536801d0df48b1414b600071f04f 100644 (file)
--- 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 */