mirror of https://github.com/sqlite/sqlite
Progress towards a VFS that will support WAL. Locking code is in place
but is untested. Still no support for the DMS. FossilOrigin-Name: 1bde41cf081570ad257f927b641e752dff4ed014
This commit is contained in:
parent
185cca609b
commit
7b6944047e
28
manifest
28
manifest
|
@ -1,5 +1,8 @@
|
|||
C Close\sall\sopen\sdatabase\sconnections\sat\sthe\send\sof\swal.test.
|
||||
D 2010-04-29T14:58:53
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Progress\stowards\sa\sVFS\sthat\swill\ssupport\sWAL.\s\sLocking\scode\sis\sin\splace\nbut\sis\suntested.\s\sStill\sno\ssupport\sfor\sthe\sDMS.
|
||||
D 2010-04-29T15:17:48
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in d83a0ffef3dcbfb08b410a6c6dd6c009ec9167fb
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
|
@ -148,9 +151,9 @@ F src/mutex_w32.c 4cc201c1bfd11d1562810554ff5500e735559d7e
|
|||
F src/notify.c cbfa66a836da3a51567209636e6a94059c137930
|
||||
F src/os.c 8bc63cf91e9802e2b807198e54e50227fa889306
|
||||
F src/os.h 534b082c3cb349ad05fa6fa0b06087e022af282c
|
||||
F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
|
||||
F src/os_common.h 0d6ee583b6ee3185eb9d951f890c6dd03021a08d
|
||||
F src/os_os2.c 8ad77a418630d7dee91d1bb04f79c2096301d3a0
|
||||
F src/os_unix.c c8b7d1e0f4315e08cf54324ca706e1a1a80f5fc2
|
||||
F src/os_unix.c 340c503705cdb447753a55771911a92aa41d27c8
|
||||
F src/os_win.c a8fc01d8483be472e495793c01064fd87e56a5c1
|
||||
F src/pager.c b4a41030860229e80295fa1f37addab24d21799c
|
||||
F src/pager.h cee4487ab4f0911dd9f22a40e3cd55afdb7ef444
|
||||
|
@ -166,7 +169,7 @@ F src/resolve.c ac5f1a713cd1ae77f08b83cc69581e11bf5ae6f9
|
|||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b
|
||||
F src/shell.c c40427c7245535a04a9cb4a417b6cc05c022e6a4
|
||||
F src/sqlite.h.in caf60df0991a14e22cce8243b9caa1c1dbd09d42
|
||||
F src/sqlite.h.in 0cc43a0fa5d26cd26d2609b84ecf094a159e9cb9
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h 700a2df7b8dfe57c3b8d83c52ff40928e026220c
|
||||
F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6
|
||||
|
@ -808,7 +811,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
|||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P d1cadeed4eea20d8892726cc8c69f4f3f57d0cd4
|
||||
R 606ec50aa0ca99ee2a7fabcf3364b376
|
||||
U dan
|
||||
Z c947c540d09aca713bd3451e1bec9253
|
||||
P 3cc55a7568daa3796483f632e33478969e381cf5
|
||||
R 1f2ad602233779dda1e35a2877201d1f
|
||||
U drh
|
||||
Z 5bb08c68390b552fdeb1ef93301ae98c
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFL2aMhoxKgR168RlERAntLAKCNwNXdF9LrZZqkEN8f3gsvrSxoXACaA2Ku
|
||||
SvIawhrGV2wraxrir5MNan8=
|
||||
=Vfpz
|
||||
-----END PGP SIGNATURE-----
|
||||
|
|
|
@ -1 +1 @@
|
|||
3cc55a7568daa3796483f632e33478969e381cf5
|
||||
1bde41cf081570ad257f927b641e752dff4ed014
|
|
@ -40,6 +40,7 @@ int sqlite3OSTrace = 0;
|
|||
if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
|
||||
#define OSTRACE7(X,Y,Z,A,B,C,D) \
|
||||
if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
|
||||
#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
|
||||
#else
|
||||
#define OSTRACE1(X)
|
||||
#define OSTRACE2(X,Y)
|
||||
|
@ -48,6 +49,7 @@ int sqlite3OSTrace = 0;
|
|||
#define OSTRACE5(X,Y,Z,A,B)
|
||||
#define OSTRACE6(X,Y,Z,A,B,C)
|
||||
#define OSTRACE7(X,Y,Z,A,B,C,D)
|
||||
#define OSTRACE(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
647
src/os_unix.c
647
src/os_unix.c
|
@ -4562,42 +4562,355 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Forward reference */
|
||||
typedef struct unixShm unixShm;
|
||||
typedef struct unixShmFile unixShmFile;
|
||||
|
||||
/*
|
||||
** Structure used internally by this VFS to record the state of an
|
||||
** open shared memory segment.
|
||||
** Object used to represent a single file opened and mmapped to provide
|
||||
** shared memory. When multiple threads all reference the same
|
||||
** log-summary, each thread has its own unixFile object, but they all
|
||||
** point to a single instance of this object. In other words, each
|
||||
** log-summary is opened only once per process.
|
||||
**
|
||||
** unixMutexHeld() must be true when creating or destroying
|
||||
** this object or while reading or writing the following fields:
|
||||
**
|
||||
** nRef
|
||||
** pNext
|
||||
**
|
||||
** The following fields are read-only after the object is created:
|
||||
**
|
||||
** fid
|
||||
** zFilename
|
||||
**
|
||||
** Either unixShmFile.mutex must be held or unixShmFile.nRef==0 and
|
||||
** unixMutexHeld() is true when reading or writing any other field
|
||||
** in this structure.
|
||||
*/
|
||||
struct unixShm {
|
||||
sqlite3_vfs *pVfs; /* VFS that opened this shared-memory segment */
|
||||
int size; /* Size of the shared memory area */
|
||||
char *pBuf; /* Pointer to the beginning */
|
||||
unixFile fd; /* The open file descriptor */
|
||||
struct unixShmFile {
|
||||
struct unixFileId fid; /* Unique file identifier */
|
||||
sqlite3_mutex *mutex; /* Mutex to access this object */
|
||||
sqlite3_mutex *mutexBuf; /* Mutex to access zBuf[] */
|
||||
sqlite3_mutex *mutexRecov; /* The RECOVER mutex */
|
||||
char *zFilename; /* Name of the file */
|
||||
int size; /* Size of the file */
|
||||
int h; /* Open file descriptor */
|
||||
char *pMMapBuf; /* Where currently mmapped() */
|
||||
int nReadPrefix; /* Number of SQLITE_SHM_READ_PREFIX locks */
|
||||
int nReadFull; /* Number of SQLITE_SHM_READ_FULL locks */
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
** Close a shared-memory segment
|
||||
** A global array of all unixShmFile objects.
|
||||
**
|
||||
** The unixMutexHeld() must be true while reading or writing this list.
|
||||
*/
|
||||
static int unixShmClose(sqlite3_shm *pSharedMem){
|
||||
struct unixShm *p = (struct unixShm*)pSharedMem;
|
||||
if( p && p->pVfs ){
|
||||
if( p->pBuf ){
|
||||
munmap(p->pBuf, p->size);
|
||||
}
|
||||
if( p->fd.pMethod ){
|
||||
p->fd.pMethod->xClose((sqlite3_file*)&p->fd);
|
||||
}
|
||||
memset(p, 0, sizeof(*p));
|
||||
sqlite3_free(p);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
static unixShmFile *unixShmFileList = 0;
|
||||
|
||||
/*
|
||||
** Structure used internally by this VFS to record the state of an
|
||||
** open shared memory connection.
|
||||
**
|
||||
** unixShm.pFile->mutex must be held while reading or writing the
|
||||
** unixShm.pNext and unixShm.locks[] elements.
|
||||
**
|
||||
** The unixShm.pFile element is initialized when the object is created
|
||||
** and is read-only thereafter.
|
||||
*/
|
||||
struct unixShm {
|
||||
unixShmFile *pFile; /* The underlying unixShmFile object */
|
||||
unixShm *pNext; /* Next unixShm with the same unixShmFile */
|
||||
u8 lockState; /* Current lock state */
|
||||
u8 readLock; /* Which of the two read-lock states to use */
|
||||
u8 hasMutex; /* True if holding the unixShmFile mutex */
|
||||
u8 hasMutexBuf; /* True if holding pFile->mutexBuf */
|
||||
u8 hasMutexRecov; /* True if holding pFile->mutexRecov */
|
||||
u8 sharedMask; /* Mask of shared locks held */
|
||||
u8 exclMask; /* Mask of exclusive locks held */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 id; /* Id of this connection with its unixShmFile */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** Size increment by which shared memory grows
|
||||
*/
|
||||
#define SQLITE_UNIX_SHM_INCR 4096
|
||||
|
||||
/*
|
||||
** Constants used for locking
|
||||
*/
|
||||
#define UNIX_SHM_BASE 32 /* Byte offset of the first lock byte */
|
||||
#define UNIX_SHM_MUTEX 0x01 /* Mask for MUTEX lock */
|
||||
#define UNIX_SHM_DMS 0x04 /* Mask for Dead-Man-Switch lock */
|
||||
#define UNIX_SHM_A 0x10 /* Mask for region locks... */
|
||||
#define UNIX_SHM_B 0x20
|
||||
#define UNIX_SHM_C 0x40
|
||||
#define UNIX_SHM_D 0x80
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Return a pointer to a nul-terminated string in static memory that
|
||||
** describes a locking mask. The string is of the form "MSABCD" with
|
||||
** each character representing a lock. "M" for MUTEX, "S" for DMS,
|
||||
** and "A" through "D" for the region locks. If a lock is held, the
|
||||
** letter is shown. If the lock is not held, the letter is converted
|
||||
** to ".".
|
||||
**
|
||||
** This routine is for debugging purposes only and does not appear
|
||||
** in a production build.
|
||||
*/
|
||||
static const char *unixShmLockString(u8 mask){
|
||||
static char zBuf[48];
|
||||
static int iBuf = 0;
|
||||
char *z;
|
||||
|
||||
z = &zBuf[iBuf];
|
||||
iBuf += 8;
|
||||
if( iBuf>=sizeof(zBuf) ) iBuf = 0;
|
||||
|
||||
z[0] = (mask & UNIX_SHM_MUTEX) ? 'M' : '.';
|
||||
z[1] = (mask & UNIX_SHM_DMS) ? 'S' : '.';
|
||||
z[2] = (mask & UNIX_SHM_A) ? 'A' : '.';
|
||||
z[3] = (mask & UNIX_SHM_B) ? 'B' : '.';
|
||||
z[4] = (mask & UNIX_SHM_C) ? 'C' : '.';
|
||||
z[5] = (mask & UNIX_SHM_D) ? 'D' : '.';
|
||||
z[6] = 0;
|
||||
return z;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Apply posix advisory locks for all bytes identified in lockMask.
|
||||
**
|
||||
** lockMask might contain multiple bits but all bits are guaranteed
|
||||
** to be contiguous.
|
||||
**
|
||||
** Locks block if the UNIX_SHM_MUTEX bit is set and are non-blocking
|
||||
** otherwise.
|
||||
*/
|
||||
static int unixShmSystemLocks(
|
||||
unixShmFile *pFile, /* Apply locks to this open shared-memory segment */
|
||||
int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */
|
||||
u8 lockMask /* Which bytes to lock or unlock */
|
||||
){
|
||||
struct flock f; /* The posix advisory locking structure */
|
||||
int lockOp; /* The opcode for fcntl() */
|
||||
int i; /* Offset into the locking byte range */
|
||||
int rc; /* Result code form fcntl() */
|
||||
u8 mask; /* Mask of bits in lockMask */
|
||||
|
||||
/* Initialize the locking parameters */
|
||||
memset(&f, 0, sizeof(f));
|
||||
f.l_type = lockType;
|
||||
f.l_whence = SEEK_SET;
|
||||
if( (lockMask & UNIX_SHM_MUTEX)!=0 && lockType!=F_UNLCK ){
|
||||
lockOp = F_SETLKW;
|
||||
}else{
|
||||
lockOp = F_SETLK;
|
||||
}
|
||||
|
||||
/* Find the first bit in lockMask that is set */
|
||||
for(i=0, mask=0x01; mask!=0 && (lockMask&mask)==0; mask <<= 1, i++){}
|
||||
assert( mask!=0 );
|
||||
f.l_start = i+UNIX_SHM_BASE;
|
||||
f.l_len = 1;
|
||||
|
||||
/* Extend the locking range for each additional bit that is set */
|
||||
mask <<= 1;
|
||||
while( mask!=0 && (lockMask & mask)!=0 ){
|
||||
f.l_len++;
|
||||
}
|
||||
|
||||
/* 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)==0) ? SQLITE_OK : SQLITE_BUSY;
|
||||
|
||||
/* Update the global lock state and do debug tracing */
|
||||
#ifdef SQLITE_DEBUG
|
||||
OSTRACE(("SHM-LOCK "));
|
||||
if( rc==SQLITE_OK ){
|
||||
if( lockType==F_UNLCK ){
|
||||
OSTRACE(("unlock ok"));
|
||||
pFile->exclMask &= ~lockMask;
|
||||
pFile->sharedMask &= ~lockMask;
|
||||
}else if( lockType==F_RDLCK ){
|
||||
OSTRACE(("read-lock ok"));
|
||||
pFile->exclMask &= ~lockMask;
|
||||
pFile->sharedMask |= lockMask;
|
||||
}else{
|
||||
assert( lockType==F_WRLCK );
|
||||
OSTRACE(("write-lock ok"));
|
||||
pFile->exclMask |= lockMask;
|
||||
pFile->sharedMask &= ~lockMask;
|
||||
}
|
||||
}else{
|
||||
if( lockType==F_UNLCK ){
|
||||
OSTRACE(("unlock failed"));
|
||||
}else if( lockType==F_RDLCK ){
|
||||
OSTRACE(("read-lock failed"));
|
||||
}else{
|
||||
assert( lockType==F_WRLCK );
|
||||
OSTRACE(("write-lock failed"));
|
||||
}
|
||||
}
|
||||
OSTRACE((" - change requested %s - afterwards %s,%s\n",
|
||||
unixShmLockString(lockMask),
|
||||
unixShmLockString(pFile->sharedMask),
|
||||
unixShmLockString(pFile->exclMask)));
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** For connection p, unlock all of the locks identified by the unlockMask
|
||||
** parameter.
|
||||
*/
|
||||
static int unixShmUnlock(
|
||||
unixShmFile *pFile, /* The underlying shared-memory file */
|
||||
unixShm *p, /* The connection to be unlocked */
|
||||
u8 unlockMask /* Mask of locks to be unlocked */
|
||||
){
|
||||
int rc; /* Result code */
|
||||
unixShm *pX; /* For looping over all sibling connections */
|
||||
u8 allMask; /* Union of locks held by connections other than "p" */
|
||||
|
||||
/* We never try to unlock locks that we do not hold */
|
||||
assert( ((p->exclMask|p->sharedMask) & unlockMask)==unlockMask );
|
||||
|
||||
/* Compute locks held by sibling connections */
|
||||
for(pX=pFile->pFirst; pX; pX=pX->pNext){
|
||||
if( pX==p ) continue;
|
||||
assert( (pX->exclMask & unlockMask)==0 );
|
||||
allMask |= pX->sharedMask;
|
||||
}
|
||||
|
||||
/* Unlock the system-level locks */
|
||||
if( (unlockMask & allMask)!=unlockMask ){
|
||||
rc = unixShmSystemLocks(pFile, F_UNLCK, unlockMask & ~allMask);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Undo the local locks */
|
||||
if( rc==SQLITE_OK ){
|
||||
p->exclMask &= ~unlockMask;
|
||||
p->sharedMask &= ~unlockMask;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Get reader locks for connection p on all locks in the readMask parameter.
|
||||
*/
|
||||
static int unixShmSharedLock(
|
||||
unixShmFile *pFile, /* The underlying shared-memory file */
|
||||
unixShm *p, /* The connection to get the shared locks */
|
||||
u8 readMask /* Mask of shared locks to be acquired */
|
||||
){
|
||||
int rc; /* Result code */
|
||||
unixShm *pX; /* For looping over all sibling connections */
|
||||
u8 allShared; /* Union of locks held by connections other than "p" */
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
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 = unixShmSystemLocks(pFile, F_RDLCK, readMask);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Get the local shared locks */
|
||||
if( rc==SQLITE_OK ){
|
||||
p->sharedMask |= readMask;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** For connection p, get an exclusive lock on all locks identified in
|
||||
** the writeMask parameter.
|
||||
*/
|
||||
static int unixShmExclusiveLock(
|
||||
unixShmFile *pFile, /* The underlying shared-memory file */
|
||||
unixShm *p, /* The connection to get the exclusive locks */
|
||||
u8 writeMask /* Mask of exclusive locks to be acquired */
|
||||
){
|
||||
int rc; /* Result code */
|
||||
unixShm *pX; /* For looping over all sibling connections */
|
||||
|
||||
/* Make sure no sibling connections hold locks that will block this
|
||||
** lock. If any do, return SQLITE_BUSY right away.
|
||||
*/
|
||||
for(pX=pFile->pFirst; pX; pX=pX->pNext){
|
||||
if( pX==p ) continue;
|
||||
if( (pX->exclMask & writeMask)!=0 ) return SQLITE_BUSY;
|
||||
if( (pX->sharedMask & writeMask)!=0 ) return SQLITE_BUSY;
|
||||
}
|
||||
|
||||
/* Get the exclusive locks at the system level. Then if successful
|
||||
** also mark the local connection as being locked.
|
||||
*/
|
||||
rc = unixShmSystemLocks(pFile, F_WRLCK, writeMask);
|
||||
if( rc==SQLITE_OK ){
|
||||
p->sharedMask &= ~writeMask;
|
||||
p->exclMask |= writeMask;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Purge the unixShmFileList list of all entries with unixShmFile.nRef==0.
|
||||
**
|
||||
** This is not a VFS shared-memory method; it is a utility function called
|
||||
** by VFS shared-memory methods.
|
||||
*/
|
||||
static void unixShmPurge(void){
|
||||
unixShmFile **pp;
|
||||
unixShmFile *p;
|
||||
assert( unixMutexHeld() );
|
||||
pp = &unixShmFileList;
|
||||
while( (p = *pp)!=0 ){
|
||||
if( p->nRef==0 ){
|
||||
if( p->mutex ) sqlite3_mutex_free(p->mutex);
|
||||
if( p->mutexBuf ) sqlite3_mutex_free(p->mutexBuf);
|
||||
if( p->mutexRecov ) sqlite3_mutex_free(p->mutexRecov);
|
||||
if( p->h>=0 ) close(p->h);
|
||||
*pp = p->pNext;
|
||||
sqlite3_free(p);
|
||||
}else{
|
||||
pp = &p->pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a shared-memory area. This implementation uses mmapped files.
|
||||
**
|
||||
** 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 */
|
||||
|
@ -4605,44 +4918,136 @@ static int unixShmOpen(
|
|||
sqlite3_shm **pShm /* Write the unixShm object created here */
|
||||
){
|
||||
struct unixShm *p = 0;
|
||||
struct unixShmFile *pFile = 0;
|
||||
int rc;
|
||||
int outFlags;
|
||||
struct unixFileId fid;
|
||||
struct stat sStat;
|
||||
|
||||
p = sqlite3_malloc( sizeof(*p) );
|
||||
*pShm = (sqlite3_shm*)p;
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->pVfs = pVfs;
|
||||
rc = pVfs->xOpen(pVfs, zName, (sqlite3_file*)&p->fd,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_MAIN_JOURNAL,
|
||||
&outFlags);
|
||||
if( rc!=SQLITE_OK ) goto shm_open_err;
|
||||
|
||||
rc = fstat(p->fd.h, &sStat);
|
||||
if( rc!=0 ) goto shm_open_err;
|
||||
if( sStat.st_size<SQLITE_UNIX_SHM_INCR ){
|
||||
rc = ftruncate(p->fd.h, SQLITE_UNIX_SHM_INCR);
|
||||
if( rc!=0 ) goto shm_open_err;
|
||||
p->size = SQLITE_UNIX_SHM_INCR;
|
||||
}else{
|
||||
p->size = sStat.st_size;
|
||||
unixEnterMutex();
|
||||
rc = stat(zName, &sStat);
|
||||
if( rc==0 ){
|
||||
memset(&fid, 0, sizeof(fid));
|
||||
fid.dev = sStat.st_dev;
|
||||
fid.ino = sStat.st_ino;
|
||||
for(pFile = unixShmFileList; pFile; pFile=pFile->pNext){
|
||||
if( memcmp(&pFile->fid, &fid, sizeof(fid))==0 ) break;
|
||||
}
|
||||
}
|
||||
if( pFile==0 ){
|
||||
int nName = strlen(zName);
|
||||
pFile = sqlite3_malloc( sizeof(*pFile) + nName + 1 );
|
||||
if( pFile==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto shm_open_err;
|
||||
}
|
||||
memset(pFile, 0, sizeof(pFile));
|
||||
pFile->zFilename = (char*)&pFile[1];
|
||||
memcpy(pFile->zFilename, zName, nName+1);
|
||||
pFile->h = -1;
|
||||
pFile->pNext = unixShmFileList;
|
||||
unixShmFileList = pFile;
|
||||
|
||||
pFile->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||
if( pFile->mutex==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto shm_open_err;
|
||||
}
|
||||
pFile->mutexBuf = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||
if( pFile->mutexBuf==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto shm_open_err;
|
||||
}
|
||||
pFile->mutexRecov = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||
if( pFile->mutexRecov==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto shm_open_err;
|
||||
}
|
||||
|
||||
pFile->h = open(zName, O_CREAT, 0664);
|
||||
if( pFile->h<0 ){
|
||||
rc = SQLITE_CANTOPEN;
|
||||
goto shm_open_err;
|
||||
}
|
||||
|
||||
rc = fstat(pFile->h, &sStat);
|
||||
if( rc ){
|
||||
rc = SQLITE_CANTOPEN;
|
||||
goto shm_open_err;
|
||||
}
|
||||
pFile->fid.dev = sStat.st_dev;
|
||||
pFile->fid.ino = sStat.st_ino;
|
||||
pFile->size = (int)sStat.st_size;
|
||||
pFile->size = (pFile->size/SQLITE_UNIX_SHM_INCR)*SQLITE_UNIX_SHM_INCR;
|
||||
if( pFile->size==0 ){
|
||||
pFile->size = SQLITE_UNIX_SHM_INCR;
|
||||
rc = ftruncate(pFile->h, pFile->size);
|
||||
if( rc ){
|
||||
rc = SQLITE_FULL;
|
||||
goto shm_open_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Map the file. */
|
||||
p->pBuf = mmap(0, p->size, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd.h, 0);
|
||||
if( p->pBuf==MAP_FAILED ){
|
||||
rc = SQLITE_IOERR;
|
||||
goto shm_open_err;
|
||||
}
|
||||
p->pFile = pFile;
|
||||
p->pNext = pFile->pFirst;
|
||||
#ifdef SQLITE_DEBUG
|
||||
p->id = pFile->nextShmId++;
|
||||
#endif
|
||||
pFile->pFirst = p;
|
||||
pFile->nRef++;
|
||||
*pShm = (sqlite3_shm*)p;
|
||||
unixLeaveMutex();
|
||||
return SQLITE_OK;
|
||||
|
||||
shm_open_err:
|
||||
unixShmClose((sqlite3_shm*)p);
|
||||
unixShmPurge();
|
||||
sqlite3_free(p);
|
||||
sqlite3_free(pFile);
|
||||
*pShm = 0;
|
||||
unixLeaveMutex();
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a connectioon to shared-memory.
|
||||
*/
|
||||
static int unixShmClose(sqlite3_shm *pSharedMem){
|
||||
unixShm *p; /* The connection to be closed */
|
||||
unixShmFile *pFile; /* The underlying shared-memory file */
|
||||
unixShm **pp; /* For looping over sibling connections */
|
||||
int nRef; /* Number of connections to pFile */
|
||||
|
||||
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;
|
||||
pFile->nRef--;
|
||||
nRef = pFile->nRef;
|
||||
|
||||
/* Free the connection p */
|
||||
sqlite3_free(p);
|
||||
sqlite3_mutex_leave(pFile->mutex);
|
||||
|
||||
/* If pFile->nRef has reached 0, then close the underlying
|
||||
** shared-memory file, too */
|
||||
if( nRef==0 ){
|
||||
unixShmPurge();
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query and/or changes the size of a shared-memory segment.
|
||||
** The reqSize parameter is the new size of the segment, or -1 to
|
||||
|
@ -4661,26 +5066,31 @@ static int unixShmSize(
|
|||
int *pNewSize, /* Write new size here */
|
||||
char **ppBuf /* Write new buffer origin here */
|
||||
){
|
||||
struct unixShm *p = (struct unixShm*)pSharedMem;
|
||||
unixShm *p = (unixShm*)pSharedMem;
|
||||
unixShmFile *pFile = p->pFile;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
sqlite3_mutex_enter(pFile->mutexBuf);
|
||||
sqlite3_mutex_enter(pFile->mutex);
|
||||
if( reqSize>=0 ){
|
||||
reqSize = (reqSize + SQLITE_UNIX_SHM_INCR - 1)/SQLITE_UNIX_SHM_INCR;
|
||||
reqSize *= SQLITE_UNIX_SHM_INCR;
|
||||
if( reqSize!=p->size ){
|
||||
munmap(p->pBuf, p->size);
|
||||
rc = ftruncate(p->fd.h, reqSize);
|
||||
if( reqSize!=pFile->size ){
|
||||
if( pFile->pMMapBuf ) munmap(pFile->pMMapBuf, pFile->size);
|
||||
rc = ftruncate(pFile->h, reqSize);
|
||||
if( rc ){
|
||||
p->pBuf = 0;
|
||||
p->size = 0;
|
||||
pFile->pMMapBuf = 0;
|
||||
pFile->size = 0;
|
||||
}else{
|
||||
p->pBuf = mmap(0, reqSize, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd.h,0);
|
||||
p->size = p->pBuf ? reqSize : 0;
|
||||
pFile->pMMapBuf = mmap(0, reqSize, PROT_READ|PROT_WRITE, MAP_SHARED,
|
||||
pFile->h, 0);
|
||||
pFile->size = pFile->pMMapBuf ? reqSize : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*pNewSize = p->size;
|
||||
*ppBuf = p->pBuf;
|
||||
*pNewSize = pFile->size;
|
||||
*ppBuf = pFile->pMMapBuf;
|
||||
sqlite3_mutex_leave(pFile->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -4689,19 +5099,138 @@ static int unixShmSize(
|
|||
** threads are free to resize it if necessary.
|
||||
*/
|
||||
static int unixShmRelease(sqlite3_shm *pSharedMem){
|
||||
unixShm *p = (unixShm*)pSharedMem;
|
||||
unixShmFile *pFile = p->pFile;
|
||||
sqlite3_mutex_leave(pFile->mutexBuf);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Create or release a lock on shared memory.
|
||||
** Change the lock state for a shared-memory segment.
|
||||
*/
|
||||
static int unixShmLock(
|
||||
sqlite3_shm *pSharedMem, /* Pointer from unixShmOpen() */
|
||||
int desiredLock, /* The locking state desired */
|
||||
int *pGotLock, /* The locking state actually obtained */
|
||||
int shouldBlock /* Block for the lock if true and possible */
|
||||
int desiredLock, /* One of SQLITE_SHM_xxxxx locking states */
|
||||
int *pGotLock /* The lock you actually got */
|
||||
){
|
||||
return SQLITE_OK;
|
||||
unixShm *p = (unixShm*)pSharedMem;
|
||||
unixShmFile *pFile = p->pFile;
|
||||
int rc = SQLITE_PROTOCOL;
|
||||
|
||||
/* Note that SQLITE_SHM_READ_FULL and SQLITE_SHM_PENDING are never
|
||||
** directly requested; they are side effects from requesting
|
||||
** SQLITE_SHM_READ and SQLITE_SHM_CHECKPOINT, respectively.
|
||||
*/
|
||||
assert( desiredLock==SQLITE_SHM_QUERY
|
||||
|| 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==SQLITE_SHM_QUERY
|
||||
|| desiredLock==p->lockState
|
||||
|| (desiredLock==SQLITE_SHM_READ && p->lockState==SQLITE_SHM_READ_FULL)
|
||||
){
|
||||
*pGotLock = p->lockState;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
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 = p->readLock = SQLITE_SHM_READ_FULL;
|
||||
}
|
||||
}else{
|
||||
unixShmUnlock(pFile, p, UNIX_SHM_B);
|
||||
p->lockState = p->readLock = SQLITE_SHM_READ;
|
||||
}
|
||||
}
|
||||
}else if( p->lockState==SQLITE_SHM_WRITE ){
|
||||
unixShmUnlock(pFile, p, UNIX_SHM_C|UNIX_SHM_D);
|
||||
p->lockState = p->readLock;
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
assert( p->lockState==SQLITE_SHM_RECOVER );
|
||||
unixShmUnlock(pFile, p, UNIX_SHM_MUTEX);
|
||||
sqlite3_mutex_leave(pFile->mutexRecov);
|
||||
p->lockState = p->readLock;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
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
|
||||
|| p->lockState==SQLITE_SHM_RECOVER );
|
||||
if( p->lockState==SQLITE_SHM_RECOVER ){
|
||||
unixShmUnlock(pFile, p, UNIX_SHM_MUTEX);
|
||||
sqlite3_mutex_leave(pFile->mutexRecov);
|
||||
p->lockState = SQLITE_SHM_CHECKPOINT;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
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
|
||||
|| p->lockState==SQLITE_SHM_CHECKPOINT );
|
||||
sqlite3_mutex_leave(pFile->mutex);
|
||||
sqlite3_mutex_enter(pFile->mutexRecov);
|
||||
sqlite3_mutex_enter(pFile->mutex);
|
||||
rc = unixShmExclusiveLock(pFile, p, UNIX_SHM_MUTEX);
|
||||
if( rc==SQLITE_OK ){
|
||||
p->lockState = SQLITE_SHM_RECOVER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(pFile->mutex);
|
||||
*pGotLock = p->lockState;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -848,7 +848,7 @@ struct sqlite3_vfs {
|
|||
int (*xShmRelease)(sqlite3_shm*);
|
||||
int (*xShmPush)(sqlite3_shm*);
|
||||
int (*xShmPull)(sqlite3_shm*);
|
||||
int (*xShmLock)(sqlite3_shm*, int desiredLock, int *gotLock, int shouldBlock);
|
||||
int (*xShmLock)(sqlite3_shm*, int desiredLock, int *gotLock);
|
||||
int (*xShmClose)(sqlite3_shm*);
|
||||
int (*xShmDelete)(sqlite3_vfs*, const char *zName);
|
||||
int (*xRename)(sqlite3_vfs*, const char *zOld, const char *zNew, int dirSync);
|
||||
|
@ -887,7 +887,7 @@ struct sqlite3_vfs {
|
|||
** state.
|
||||
*/
|
||||
#define SQLITE_SHM_UNLOCK 0
|
||||
#define SQLITE_SHM_READ_PREFIX 1
|
||||
#define SQLITE_SHM_READ 1
|
||||
#define SQLITE_SHM_READ_FULL 2
|
||||
#define SQLITE_SHM_WRITE 3
|
||||
#define SQLITE_SHM_PENDING 4
|
||||
|
|
Loading…
Reference in New Issue