*/
#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
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
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 ***************************
unixSleep, /* xSleep */ \
unixCurrentTime, /* xCurrentTime */ \
unixGetLastError, /* xGetLastError */ \
- unixShmOpen, /* xShmOpen */ \
- unixShmSize, /* xShmSize */ \
- unixShmGet, /* xShmGet */ \
- unixShmRelease, /* xShmRelease */ \
- unixShmLock, /* xShmLock */ \
- unixShmClose, /* xShmClose */ \
0, /* xRename */ \
unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
}