In the "unix-excl" VFS, use the heap for shared memory, since only a single

process is able to read or write the database.

FossilOrigin-Name: a05a6d40875df674f9c2b46e33128c6878d4edaa
This commit is contained in:
drh 2011-03-12 18:10:44 +00:00
parent a7e61d8b24
commit 3cb9339a6c
3 changed files with 104 additions and 70 deletions

View File

@ -1,8 +1,8 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C Add\sthe\snew\soptional\s"unix-excl"\sVFS.\s\sThis\sVFS\sgrabs\san\sexclusive\slock\son\nthe\sdatabase\spreventing\sother\sprocesses\sfrom\saccessing\sit,\sbut\scontinues\sto\nallow\sother\sdatabase\sconnections\sfrom\sthe\ssame\sprocess.
D 2011-03-12T17:02:57.101
C In\sthe\s"unix-excl"\sVFS,\suse\sthe\sheap\sfor\sshared\smemory,\ssince\sonly\sa\ssingle\nprocess\sis\sable\sto\sread\sor\swrite\sthe\sdatabase.
D 2011-03-12T18:10:44.973
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -165,7 +165,7 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 2596fd2d5d0976c6c0c628d0c3c7c4e7a724f4cf
F src/os_unix.c 557837beff775c448bb072ae21edeff912d1f0df
F src/os_unix.c 1debf5ea6efd0f35335a2a615198a7a1017ffd4b
F src/os_win.c 24d72407a90551969744cf9bcbb1b4c72c5fa845
F src/pager.c 6aa906b60a59664ba58d3f746164bb010d407ce1
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
@ -916,18 +916,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P b86999436ec2414c990ba720441fe316f647eef6
R b4018b4a3ca8304164ff6618b813c5a9
T *bgcolor * #aaa8d3
T *branch * unix-excl
T *sym-unix-excl *
T -sym-trunk *
P 00051c3296e11211b2bb5ae28f016b17dca857d7
R ae21c3eefa2912bdd40576825c99670e
U drh
Z ca346ade739e93ef182345e803581a80
Z 0353c9261ee94db4155a765014c19a0b
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFNe6dEoxKgR168RlERAkgMAJ47rTo3YzDvLp8S+pIflXBmm5FOSwCggCkn
s82X2XcH9cqBqUU6lQenClw=
=LUbU
iD8DBQFNe7cnoxKgR168RlERAsDBAJ486IVhWF+3w87MQdsa9IV6+Kk3UQCfVQ5D
gOLo9IyLtbi3pQ3LQfZd9Y8=
=wzQK
-----END PGP SIGNATURE-----

View File

@ -1 +1 @@
00051c3296e11211b2bb5ae28f016b17dca857d7
a05a6d40875df674f9c2b46e33128c6878d4edaa

View File

@ -1202,17 +1202,21 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
*/
static int unixFileLock(unixFile *pFile, struct flock *pLock){
int rc;
unixInodeInfo *pInode = pFile->pInode;
assert( unixMutexHeld() );
if( (pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pFile->pInode->bProcessLock ){
if( pFile->pInode->bProcessLock==0 ){
assert( pInode!=0 );
if( (pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock ){
if( pInode->bProcessLock==0 ){
struct flock lock;
assert( pInode->nLock==0 );
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
lock.l_type = F_WRLCK;
rc = osFcntl(pFile->h, F_SETLK, &lock);
if( rc<0 ) return rc;
pFile->pInode->bProcessLock = 1;
pInode->bProcessLock = 1;
pInode->nLock++;
}else{
rc = 0;
}
@ -1731,6 +1735,8 @@ static int unixClose(sqlite3_file *id){
unixFile *pFile = (unixFile *)id;
unixUnlock(id, NO_LOCK);
unixEnterMutex();
assert( pFile->pInode==0 || pFile->pInode->nLock>0
|| pFile->pInode->bProcessLock==0 );
if( pFile->pInode && pFile->pInode->nLock ){
/* If there are outstanding locks, do not actually close the file just
** yet because that would clear those locks. Instead, add the file
@ -3559,15 +3565,17 @@ static int unixShmSystemLock(
/* Locks are within range */
assert( n>=1 && n<SQLITE_SHM_NLOCK );
/* Initialize the locking parameters */
memset(&f, 0, sizeof(f));
f.l_type = lockType;
f.l_whence = SEEK_SET;
f.l_start = ofst;
f.l_len = n;
if( pShmNode->h>=0 ){
/* Initialize the locking parameters */
memset(&f, 0, sizeof(f));
f.l_type = lockType;
f.l_whence = SEEK_SET;
f.l_start = ofst;
f.l_len = n;
rc = osFcntl(pShmNode->h, F_SETLK, &f);
rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
rc = osFcntl(pShmNode->h, F_SETLK, &f);
rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
}
/* Update the global lock state and do debug tracing */
#ifdef SQLITE_DEBUG
@ -3622,7 +3630,11 @@ static void unixShmPurge(unixFile *pFd){
assert( p->pInode==pFd->pInode );
if( p->mutex ) sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){
munmap(p->apRegion[i], p->szRegion);
if( p->h>=0 ){
munmap(p->apRegion[i], p->szRegion);
}else{
sqlite3_free(p->apRegion[i]);
}
}
sqlite3_free(p->apRegion);
if( p->h>=0 ){
@ -3662,6 +3674,12 @@ static void unixShmPurge(unixFile *pFd){
** 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.
**
** If the original database file (pDbFd) is using the "unix-excl" VFS
** that means that an exclusive lock is held on the database file and
** that no other processes are able to read or write the database. In
** that case, we do not really need shared memory. No shared memory
** file is created. The shared memory will be simulated with heap memory.
*/
static int unixOpenSharedMemory(unixFile *pDbFd){
struct unixShm *p = 0; /* The connection to be opened */
@ -3691,7 +3709,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
** with the same permissions. The actual permissions the file is created
** with are subject to the current umask setting.
*/
if( osFstat(pDbFd->h, &sStat) ){
if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
rc = SQLITE_IOERR_FSTAT;
goto shm_open_err;
}
@ -3724,26 +3742,28 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
goto shm_open_err;
}
pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
(sStat.st_mode & 0777));
if( pShmNode->h<0 ){
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
goto shm_open_err;
}
/* Check to see if another process is holding the dead-man switch.
** If not, truncate the file to zero length.
*/
rc = SQLITE_OK;
if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
if( robust_ftruncate(pShmNode->h, 0) ){
rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
if( pInode->bProcessLock==0 ){
pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
(sStat.st_mode & 0777));
if( pShmNode->h<0 ){
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
goto shm_open_err;
}
/* Check to see if another process is holding the dead-man switch.
** If not, truncate the file to zero length.
*/
rc = SQLITE_OK;
if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
if( robust_ftruncate(pShmNode->h, 0) ){
rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
}
}
if( rc==SQLITE_OK ){
rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
}
if( rc ) goto shm_open_err;
}
if( rc==SQLITE_OK ){
rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
}
if( rc ) goto shm_open_err;
}
/* Make the new connection a child of the unixShmNode */
@ -3817,6 +3837,9 @@ static int unixShmMap(
pShmNode = p->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
assert( pShmNode->pInode==pDbFd->pInode );
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
if( pShmNode->nRegion<=iRegion ){
char **apNew; /* New apRegion[] array */
@ -3825,27 +3848,30 @@ static int unixShmMap(
pShmNode->szRegion = szRegion;
/* The requested region is not mapped into this processes address space.
** Check to see if it has been allocated (i.e. if the wal-index file is
** large enough to contain the requested region).
*/
if( osFstat(pShmNode->h, &sStat) ){
rc = SQLITE_IOERR_SHMSIZE;
goto shmpage_out;
}
if( sStat.st_size<nByte ){
/* The requested memory region does not exist. If bExtend is set to
** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
**
** Alternatively, if bExtend is true, use ftruncate() to allocate
** the requested memory region.
if( pShmNode->h>=0 ){
/* The requested region is not mapped into this processes address space.
** Check to see if it has been allocated (i.e. if the wal-index file is
** large enough to contain the requested region).
*/
if( !bExtend ) goto shmpage_out;
if( robust_ftruncate(pShmNode->h, nByte) ){
rc = unixLogError(SQLITE_IOERR_SHMSIZE,"ftruncate",pShmNode->zFilename);
if( osFstat(pShmNode->h, &sStat) ){
rc = SQLITE_IOERR_SHMSIZE;
goto shmpage_out;
}
if( sStat.st_size<nByte ){
/* The requested memory region does not exist. If bExtend is set to
** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
**
** Alternatively, if bExtend is true, use ftruncate() to allocate
** the requested memory region.
*/
if( !bExtend ) goto shmpage_out;
if( robust_ftruncate(pShmNode->h, nByte) ){
rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate",
pShmNode->zFilename);
goto shmpage_out;
}
}
}
/* Map the requested memory region into this processes address space. */
@ -3858,12 +3884,22 @@ static int unixShmMap(
}
pShmNode->apRegion = apNew;
while(pShmNode->nRegion<=iRegion){
void *pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
);
if( pMem==MAP_FAILED ){
rc = SQLITE_IOERR;
goto shmpage_out;
void *pMem;
if( pShmNode->h>=0 ){
pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
);
if( pMem==MAP_FAILED ){
rc = SQLITE_IOERR;
goto shmpage_out;
}
}else{
pMem = sqlite3_malloc(szRegion);
if( pMem==0 ){
rc = SQLITE_NOMEM;
goto shmpage_out;
}
memset(pMem, 0, szRegion);
}
pShmNode->apRegion[pShmNode->nRegion] = pMem;
pShmNode->nRegion++;
@ -3910,6 +3946,8 @@ static int unixShmLock(
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
mask = (1<<(ofst+n)) - (1<<ofst);
assert( n>1 || mask==(1<<ofst) );
@ -4047,7 +4085,7 @@ static int unixShmUnmap(
assert( pShmNode->nRef>0 );
pShmNode->nRef--;
if( pShmNode->nRef==0 ){
if( deleteFlag ) unlink(pShmNode->zFilename);
if( deleteFlag && pShmNode->h>=0 ) unlink(pShmNode->zFilename);
unixShmPurge(pDbFd);
}
unixLeaveMutex();