Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a9876e50c | |||
| 658c53409f | |||
| dec013d187 | |||
| 8ecc6076af | |||
| 79898ddd76 | |||
| 9513fc97a8 | |||
| 740fe883b4 | |||
| 07444ecf8c | |||
| 6d373c89e0 |
@@ -1,5 +1,5 @@
|
||||
C Updates\sso\sthat\s"threadtest3[.exe]"\scan\sbe\sbuilt\sfor\swindows\swith\sMSVC.
|
||||
D 2021-07-19T16:49:13.643
|
||||
C Fix\sa\sproblem\sin\sthe\snew\sos_unix.c\scode.\sRefine\sthe\sthreadtest3\stest\scase\ssome.
|
||||
D 2021-07-22T10:44:31.628
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -528,8 +528,8 @@ F src/os.c 59ed1f503347e8b5434c0ce7d7d0f02a3f24a72fea8b26d0bba2de8dfaef778b
|
||||
F src/os.h 26890f540b475598cd9881dcc68931377b8d429d3ea3e2eeb64470cde64199f8
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c b11e4610769922253dec27d7af4a07ff84f65169d19bda5e9b12a152a706f7f5
|
||||
F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
|
||||
F src/os_unix.c b28ab4bc1320fde00495f5dce41544fc7de9f5b801f82afe3b1429614f487ed8
|
||||
F src/os_win.c 03017ffbfa230d833421667a02edca8baab76ff8446533e796206a04c618b2d6
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 95c255256b13827caf038c8f963d334784073f38ab6ef9d70371d9d04f3c43e0
|
||||
F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f
|
||||
@@ -1465,7 +1465,7 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46
|
||||
F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd
|
||||
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c a70a8e94bef23339d34226eb9521015ef99f4df8
|
||||
F test/threadtest3.c fee869dba633f8403a7eef03bb038a3fc45f0814b9f829ea79a914fcc11f0218
|
||||
F test/threadtest3.c 9cada9dfdc405310f8f3802e54a45e1d85449f0a15ac081e05f175c1386c82f1
|
||||
F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925
|
||||
F test/threadtest5.c 9b4d782c58d8915d7e955ff8051f3d03628bda0d33b82971ea8c0f2f2808c421
|
||||
F test/time-wordcount.sh 8e0b0f8109367827ad5d58f5cc849705731e4b90
|
||||
@@ -1920,7 +1920,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P c8601d83fbecf84ca7991d339449b380deb5a7620dc84756a91c2880f030b423
|
||||
R e7c3798c4e8afbc59f637b8a384b4003
|
||||
P b67c157fd89f73078e3bf4e3d6e8d77fa59ef1ec5c3a9d0e3af955362d751960
|
||||
R 969567a5ddcecbed0f31287f4ee2f6dc
|
||||
U dan
|
||||
Z 4507211c89102df26f9a64f266826b29
|
||||
Z 94f6a6af08448cd4cddc3bdd1340b73f
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
4ce585fb07274284e3add6adcb66ed06e4b109584704d1ec7152bf43ca8d5d85
|
||||
2039d447b717abf6b536eb2e5e41abacb6bedbccf738a929d1ee3ee6f565c5d4
|
||||
+153
-74
@@ -4271,7 +4271,12 @@ static int unixGetpagesize(void){
|
||||
*/
|
||||
struct unixShmNode {
|
||||
unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
pthread_cond_t shmcond;
|
||||
pthread_mutex_t shmmutex;
|
||||
#else
|
||||
sqlite3_mutex *pShmMutex; /* Mutex to access this object */
|
||||
#endif
|
||||
char *zFilename; /* Name of the mmapped file */
|
||||
int hShm; /* Open file descriptor */
|
||||
int szRegion; /* Size of shared-memory regions */
|
||||
@@ -4289,6 +4294,15 @@ struct unixShmNode {
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
# define ENTER_SHMNODE_MUTEX(p) pthread_mutex_lock(&p->shmmutex)
|
||||
# define LEAVE_SHMNODE_MUTEX(p) pthread_mutex_unlock(&p->shmmutex)
|
||||
#else
|
||||
# define ENTER_SHMNODE_MUTEX(p) sqlite3_mutex_enter(p->pShmMutex)
|
||||
# define LEAVE_SHMNODE_MUTEX(p) sqlite3_mutex_leave(p->pShmMutex)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Structure used internally by this VFS to record the state of an
|
||||
** open shared memory connection.
|
||||
@@ -4338,13 +4352,13 @@ static int unixFcntlExternalReader(unixFile *pFile, int *piOut){
|
||||
f.l_start = UNIX_SHM_BASE + 3;
|
||||
f.l_len = SQLITE_SHM_NLOCK - 3;
|
||||
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
ENTER_SHMNODE_MUTEX(pShmNode);
|
||||
if( osFcntl(pShmNode->hShm, F_GETLK, &f)<0 ){
|
||||
rc = SQLITE_IOERR_LOCK;
|
||||
}else{
|
||||
*piOut = (f.l_type!=F_UNLCK);
|
||||
}
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
LEAVE_SHMNODE_MUTEX(pShmNode);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -4358,7 +4372,7 @@ static int unixFcntlExternalReader(unixFile *pFile, int *piOut){
|
||||
** otherwise.
|
||||
*/
|
||||
static int unixShmSystemLock(
|
||||
unixFile *pFile, /* Open connection to the WAL file */
|
||||
unixFile *pFile, /* Open connection to the database file */
|
||||
int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */
|
||||
int ofst, /* First byte of the locking range */
|
||||
int n /* Number of bytes to lock */
|
||||
@@ -4369,7 +4383,9 @@ static int unixShmSystemLock(
|
||||
|
||||
/* Access to the unixShmNode object is serialized by the caller */
|
||||
pShmNode = pFile->pInode->pShmNode;
|
||||
#ifndef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
|
||||
#endif
|
||||
assert( pShmNode->nRef>0 || unixMutexHeld() );
|
||||
|
||||
/* Shared locks never span more than one byte */
|
||||
@@ -4463,7 +4479,12 @@ static void unixShmPurge(unixFile *pFd){
|
||||
int nShmPerMap = unixShmRegionPerMap();
|
||||
int i;
|
||||
assert( p->pInode==pFd->pInode );
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
pthread_cond_destroy(&p->shmcond);
|
||||
pthread_mutex_destroy(&p->shmmutex);
|
||||
#else
|
||||
sqlite3_mutex_free(p->pShmMutex);
|
||||
#endif
|
||||
for(i=0; i<p->nRegion; i+=nShmPerMap){
|
||||
if( p->hShm>=0 ){
|
||||
osMunmap(p->apRegion[i], p->szRegion);
|
||||
@@ -4639,11 +4660,16 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
pDbFd->pInode->pShmNode = pShmNode;
|
||||
pShmNode->pInode = pDbFd->pInode;
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
pthread_cond_init(&pShmNode->shmcond, 0);
|
||||
pthread_mutex_init(&pShmNode->shmmutex, 0);
|
||||
#else
|
||||
pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||
if( pShmNode->pShmMutex==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto shm_open_err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if( pInode->bProcessLock==0 ){
|
||||
@@ -4688,10 +4714,10 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
** at pShmNode->pFirst. This must be done while holding the
|
||||
** pShmNode->pShmMutex.
|
||||
*/
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
ENTER_SHMNODE_MUTEX(pShmNode);
|
||||
p->pNext = pShmNode->pFirst;
|
||||
pShmNode->pFirst = p;
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
LEAVE_SHMNODE_MUTEX(pShmNode);
|
||||
return rc;
|
||||
|
||||
/* Jump here on any error */
|
||||
@@ -4743,7 +4769,7 @@ static int unixShmMap(
|
||||
|
||||
p = pDbFd->pShm;
|
||||
pShmNode = p->pShmNode;
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
ENTER_SHMNODE_MUTEX(pShmNode);
|
||||
if( pShmNode->isUnlocked ){
|
||||
rc = unixLockSharedMemory(pDbFd, pShmNode);
|
||||
if( rc!=SQLITE_OK ) goto shmpage_out;
|
||||
@@ -4852,7 +4878,7 @@ shmpage_out:
|
||||
*pp = 0;
|
||||
}
|
||||
if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
LEAVE_SHMNODE_MUTEX(pShmNode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4867,7 +4893,9 @@ shmpage_out:
|
||||
static int assertLockingArrayOk(unixShmNode *pShmNode){
|
||||
unixShm *pX;
|
||||
int aLock[SQLITE_SHM_NLOCK];
|
||||
#ifndef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
|
||||
#endif
|
||||
|
||||
memset(aLock, 0, sizeof(aLock));
|
||||
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
||||
@@ -4909,6 +4937,12 @@ static int unixShmLock(
|
||||
u16 mask; /* Mask of locks to take or release */
|
||||
int *aLock = pShmNode->aLock;
|
||||
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
int bRetry;
|
||||
struct timespec sTimespec;
|
||||
memset(&sTimespec, 0, sizeof(sTimespec));
|
||||
#endif
|
||||
|
||||
assert( pShmNode==pDbFd->pInode->pShmNode );
|
||||
assert( pShmNode->pInode==pDbFd->pInode );
|
||||
assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
|
||||
@@ -4945,78 +4979,123 @@ static int unixShmLock(
|
||||
|
||||
mask = (1<<(ofst+n)) - (1<<ofst);
|
||||
assert( n>1 || mask==(1<<ofst) );
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
assert( assertLockingArrayOk(pShmNode) );
|
||||
if( flags & SQLITE_SHM_UNLOCK ){
|
||||
if( (p->exclMask|p->sharedMask) & mask ){
|
||||
int ii;
|
||||
int bUnlock = 1;
|
||||
ENTER_SHMNODE_MUTEX(pShmNode);
|
||||
|
||||
for(ii=ofst; ii<ofst+n; ii++){
|
||||
if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
|
||||
bUnlock = 0;
|
||||
}
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
do{
|
||||
bRetry = 0;
|
||||
#endif
|
||||
|
||||
if( bUnlock ){
|
||||
rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(&aLock[ofst], 0, sizeof(int)*n);
|
||||
}
|
||||
}else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
|
||||
assert( n==1 && aLock[ofst]>1 );
|
||||
aLock[ofst]--;
|
||||
}
|
||||
|
||||
/* Undo the local locks */
|
||||
if( rc==SQLITE_OK ){
|
||||
p->exclMask &= ~mask;
|
||||
p->sharedMask &= ~mask;
|
||||
}
|
||||
}
|
||||
}else if( flags & SQLITE_SHM_SHARED ){
|
||||
assert( n==1 );
|
||||
assert( (p->exclMask & (1<<ofst))==0 );
|
||||
if( (p->sharedMask & mask)==0 ){
|
||||
if( aLock[ofst]<0 ){
|
||||
rc = SQLITE_BUSY;
|
||||
}else if( aLock[ofst]==0 ){
|
||||
rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
|
||||
}
|
||||
|
||||
/* Get the local shared locks */
|
||||
if( rc==SQLITE_OK ){
|
||||
p->sharedMask |= mask;
|
||||
aLock[ofst]++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Make sure no sibling connections hold locks that will block this
|
||||
** lock. If any do, return SQLITE_BUSY right away. */
|
||||
int ii;
|
||||
for(ii=ofst; ii<ofst+n; ii++){
|
||||
assert( (p->sharedMask & mask)==0 );
|
||||
if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
|
||||
rc = SQLITE_BUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the exclusive locks at the system level. Then if successful
|
||||
** also update the in-memory values. */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( (p->sharedMask & mask)==0 );
|
||||
p->exclMask |= mask;
|
||||
assert( assertLockingArrayOk(pShmNode) );
|
||||
if( flags & SQLITE_SHM_UNLOCK ){
|
||||
if( (p->exclMask|p->sharedMask) & mask ){
|
||||
int ii;
|
||||
int bUnlock = 1;
|
||||
|
||||
for(ii=ofst; ii<ofst+n; ii++){
|
||||
aLock[ii] = -1;
|
||||
if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
|
||||
bUnlock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( bUnlock ){
|
||||
rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(&aLock[ofst], 0, sizeof(int)*n);
|
||||
}
|
||||
}else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
|
||||
assert( n==1 && aLock[ofst]>1 );
|
||||
aLock[ofst]--;
|
||||
}
|
||||
|
||||
/* Undo the local locks */
|
||||
if( rc==SQLITE_OK ){
|
||||
p->exclMask &= ~mask;
|
||||
p->sharedMask &= ~mask;
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
pthread_cond_broadcast(&pShmNode->shmcond);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}else if( flags & SQLITE_SHM_SHARED ){
|
||||
assert( n==1 );
|
||||
assert( (p->exclMask & (1<<ofst))==0 );
|
||||
if( (p->sharedMask & mask)==0 ){
|
||||
if( aLock[ofst]<0 ){
|
||||
rc = SQLITE_BUSY;
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
bRetry = (pDbFd->iBusyTimeout!=0);
|
||||
#endif
|
||||
}else if( aLock[ofst]==0 ){
|
||||
rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
|
||||
}
|
||||
|
||||
/* Get the local shared locks */
|
||||
if( rc==SQLITE_OK ){
|
||||
p->sharedMask |= mask;
|
||||
aLock[ofst]++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Make sure no sibling connections hold locks that will block this
|
||||
** lock. If any do, return SQLITE_BUSY right away. */
|
||||
int ii;
|
||||
for(ii=ofst; ii<ofst+n; ii++){
|
||||
assert( (p->sharedMask & mask)==0 );
|
||||
if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
|
||||
rc = SQLITE_BUSY;
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
bRetry = (pDbFd->iBusyTimeout!=0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the exclusive locks at the system level. Then if successful
|
||||
** also update the in-memory values. */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( (p->sharedMask & mask)==0 );
|
||||
p->exclMask |= mask;
|
||||
for(ii=ofst; ii<ofst+n; ii++){
|
||||
aLock[ii] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
if( bRetry ){
|
||||
int prc;
|
||||
assert( rc==SQLITE_BUSY );
|
||||
|
||||
/* If the timeout is still zero, calculate it now. */
|
||||
if( sTimespec.tv_sec==0 ){
|
||||
static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
|
||||
i64 iAbs;
|
||||
pDbFd->pVfs->xCurrentTimeInt64(pDbFd->pVfs, &iAbs);
|
||||
iAbs -= unixEpoch;
|
||||
iAbs += pDbFd->iBusyTimeout;
|
||||
memset(&sTimespec, 0, sizeof(sTimespec));
|
||||
sTimespec.tv_sec = iAbs / 1000;
|
||||
sTimespec.tv_nsec = (iAbs % 1000) * 1000000;
|
||||
}
|
||||
|
||||
prc = pthread_cond_timedwait(
|
||||
&pShmNode->shmcond, &pShmNode->shmmutex, &sTimespec
|
||||
);
|
||||
if( prc==0 ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
bRetry = 0;
|
||||
}
|
||||
}
|
||||
}while( bRetry );
|
||||
#endif
|
||||
|
||||
assert( assertLockingArrayOk(pShmNode) );
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
LEAVE_SHMNODE_MUTEX(pShmNode);
|
||||
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
|
||||
p->id, osGetpid(0), p->sharedMask, p->exclMask));
|
||||
return rc;
|
||||
@@ -5066,14 +5145,14 @@ static int unixShmUnmap(
|
||||
|
||||
/* Remove connection p from the set of connections associated
|
||||
** with pShmNode */
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
ENTER_SHMNODE_MUTEX(pShmNode);
|
||||
for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
|
||||
*pp = p->pNext;
|
||||
|
||||
/* Free the connection p */
|
||||
sqlite3_free(p);
|
||||
pDbFd->pShm = 0;
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
LEAVE_SHMNODE_MUTEX(pShmNode);
|
||||
|
||||
/* If pShmNode->nRef has reached 0, then close the underlying
|
||||
** shared-memory file, too */
|
||||
|
||||
+284
-36
@@ -64,6 +64,12 @@
|
||||
must be defined."
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Define this symbol to enable blocking in-process locks if the
|
||||
** core is built with SQLITE_ENABLE_SETLK_TIMEOUT.
|
||||
*/
|
||||
#define SQLITE_WIN32_LOCKTMOUT 1
|
||||
|
||||
/*
|
||||
** Define the required Windows SDK version constants if they are not
|
||||
** already available.
|
||||
@@ -272,6 +278,7 @@ struct winFile {
|
||||
winShm *pShm; /* Instance of shared memory on this file */
|
||||
#endif
|
||||
const char *zPath; /* Full pathname of this file */
|
||||
unsigned iBusyTimeout; /* Wait this many millisec on locks */
|
||||
int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
|
||||
#if SQLITE_OS_WINCE
|
||||
LPWSTR zDeleteOnClose; /* Name of file to delete when closing */
|
||||
@@ -1126,7 +1133,7 @@ static struct win_syscall {
|
||||
{ "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
|
||||
|
||||
#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \
|
||||
SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
|
||||
SQLITE_WIN32_VOLATILE*,LONG,LONG))aSyscall[76].pCurrent)
|
||||
#endif /* defined(InterlockedCompareExchange) */
|
||||
|
||||
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
|
||||
@@ -1155,6 +1162,23 @@ static struct win_syscall {
|
||||
#define osFlushViewOfFile \
|
||||
((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
|
||||
|
||||
#if !SQLITE_OS_WINRT
|
||||
{ "GetFileInformationByHandle", (SYSCALL)GetFileInformationByHandle, 0 },
|
||||
#else
|
||||
{ "GetFileInformationByHandle", (SYSCALL)0, 0 },
|
||||
#endif
|
||||
|
||||
#define osGetFileInformationByHandle ((BOOL(WINAPI*)(HANDLE, \
|
||||
LPBY_HANDLE_FILE_INFORMATION))aSyscall[80].pCurrent)
|
||||
|
||||
#if !SQLITE_OS_WINRT
|
||||
{ "SleepEx", (SYSCALL)SleepEx, 0 },
|
||||
#else
|
||||
{ "SleepEx", (SYSCALL)0, 0 },
|
||||
#endif
|
||||
|
||||
#define osSleepEx ((VOID(WINAPI*)(DWORD,BOOL))aSyscall[81].pCurrent)
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
/*
|
||||
@@ -1379,18 +1403,25 @@ void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
|
||||
static HANDLE sleepObj = NULL;
|
||||
#endif
|
||||
|
||||
void sqlite3_win32_sleep(DWORD milliseconds){
|
||||
void sqlite3Win32Sleep(DWORD milliseconds, BOOL alertable){
|
||||
#if SQLITE_OS_WINRT
|
||||
if ( sleepObj==NULL ){
|
||||
sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
|
||||
SYNCHRONIZE);
|
||||
}
|
||||
assert( sleepObj!=NULL );
|
||||
osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE);
|
||||
osWaitForSingleObjectEx(sleepObj, milliseconds, alertable);
|
||||
#else
|
||||
osSleep(milliseconds);
|
||||
if( alertable ){
|
||||
osSleepEx(milliseconds, alertable);
|
||||
}else{
|
||||
osSleep(milliseconds);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void sqlite3_win32_sleep(DWORD milliseconds){
|
||||
sqlite3Win32Sleep(milliseconds, FALSE);
|
||||
}
|
||||
|
||||
#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
|
||||
SQLITE_THREADSAFE>0
|
||||
@@ -2154,13 +2185,13 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){
|
||||
return 0;
|
||||
}
|
||||
if( winIoerrCanRetry1(e) ){
|
||||
sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
|
||||
sqlite3Win32Sleep(winIoerrRetryDelay*(1+*pnRetry), TRUE);
|
||||
++*pnRetry;
|
||||
return 1;
|
||||
}
|
||||
#if defined(winIoerrCanRetry2)
|
||||
else if( winIoerrCanRetry2(e) ){
|
||||
sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
|
||||
sqlite3Win32Sleep(winIoerrRetryDelay*(1+*pnRetry), TRUE);
|
||||
++*pnRetry;
|
||||
return 1;
|
||||
}
|
||||
@@ -2503,9 +2534,13 @@ static BOOL winceUnlockFile(
|
||||
|
||||
/*
|
||||
** Lock a file region.
|
||||
**
|
||||
** If the pFile->iBusyTimeout value is non-zero and the lock cannot be
|
||||
** acquired immediately, then try to block for up to iBusyTimeout milliseconds
|
||||
** waiting on the conflicting lock to appear.
|
||||
*/
|
||||
static BOOL winLockFile(
|
||||
LPHANDLE phFile,
|
||||
winFile *pFile,
|
||||
DWORD flags,
|
||||
DWORD offsetLow,
|
||||
DWORD offsetHigh,
|
||||
@@ -2517,17 +2552,31 @@ static BOOL winLockFile(
|
||||
** NOTE: Windows CE is handled differently here due its lack of the Win32
|
||||
** API LockFile.
|
||||
*/
|
||||
return winceLockFile(phFile, offsetLow, offsetHigh,
|
||||
return winceLockFile(&pFile->h, offsetLow, offsetHigh,
|
||||
numBytesLow, numBytesHigh);
|
||||
#else
|
||||
if( osIsNT() ){
|
||||
BOOL bResult;
|
||||
OVERLAPPED ovlp;
|
||||
memset(&ovlp, 0, sizeof(OVERLAPPED));
|
||||
ovlp.Offset = offsetLow;
|
||||
ovlp.OffsetHigh = offsetHigh;
|
||||
return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
|
||||
bResult = osLockFileEx(pFile->h, flags, 0, numBytesLow,
|
||||
numBytesHigh, &ovlp);
|
||||
if( !bResult && pFile->iBusyTimeout>0 ){
|
||||
unsigned iDelay = (unsigned)winIoerrRetryDelay;
|
||||
if( iDelay>0 ){
|
||||
u64 iTotalDelay = 0;
|
||||
do{
|
||||
sqlite3Win32Sleep(iDelay, TRUE); iTotalDelay += iDelay;
|
||||
bResult = osLockFileEx(pFile->h, flags, 0, numBytesLow,
|
||||
numBytesHigh, &ovlp);
|
||||
}while( !bResult && iTotalDelay<pFile->iBusyTimeout );
|
||||
}
|
||||
}
|
||||
return bResult;
|
||||
}else{
|
||||
return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
|
||||
return osLockFile(pFile->h, offsetLow, offsetHigh, numBytesLow,
|
||||
numBytesHigh);
|
||||
}
|
||||
#endif
|
||||
@@ -2673,7 +2722,7 @@ static int winClose(sqlite3_file *id){
|
||||
do{
|
||||
rc = osCloseHandle(pFile->h);
|
||||
/* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
|
||||
}while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
|
||||
}while( rc==0 && ++cnt<MX_CLOSE_ATTEMPT && (sqlite3Win32Sleep(100,TRUE), 1) );
|
||||
#if SQLITE_OS_WINCE
|
||||
#define WINCE_DELETION_ATTEMPTS 3
|
||||
{
|
||||
@@ -2689,7 +2738,7 @@ static int winClose(sqlite3_file *id){
|
||||
&& osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
|
||||
&& cnt++ < WINCE_DELETION_ATTEMPTS
|
||||
){
|
||||
sqlite3_win32_sleep(100); /* Wait a little before trying again */
|
||||
sqlite3Win32Sleep(100, TRUE); /* Wait a little before trying again */
|
||||
}
|
||||
sqlite3_free(pFile->zDeleteOnClose);
|
||||
}
|
||||
@@ -3162,7 +3211,7 @@ static int winGetReadLock(winFile *pFile){
|
||||
*/
|
||||
res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0);
|
||||
#else
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0,
|
||||
res = winLockFile(pFile, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0,
|
||||
SHARED_SIZE, 0);
|
||||
#endif
|
||||
}
|
||||
@@ -3171,7 +3220,7 @@ static int winGetReadLock(winFile *pFile){
|
||||
int lk;
|
||||
sqlite3_randomness(sizeof(lk), &lk);
|
||||
pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
|
||||
res = winLockFile(pFile, SQLITE_LOCKFILE_FLAGS,
|
||||
SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
|
||||
}
|
||||
#endif
|
||||
@@ -3275,7 +3324,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
|| (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK)
|
||||
){
|
||||
int cnt = 3;
|
||||
while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
|
||||
while( cnt-->0 && (res = winLockFile(pFile, SQLITE_LOCKFILE_FLAGS,
|
||||
PENDING_BYTE, 0, 1, 0))==0 ){
|
||||
/* Try 3 times to get the pending lock. This is needed to work
|
||||
** around problems caused by indexing and/or anti-virus software on
|
||||
@@ -3293,7 +3342,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
pFile->h, cnt, sqlite3ErrName(rc)));
|
||||
return rc;
|
||||
}
|
||||
if( cnt ) sqlite3_win32_sleep(1);
|
||||
if( cnt ) sqlite3Win32Sleep(1, TRUE);
|
||||
}
|
||||
gotPendingLock = res;
|
||||
if( !res ){
|
||||
@@ -3317,7 +3366,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
*/
|
||||
if( locktype==RESERVED_LOCK && res ){
|
||||
assert( pFile->locktype==SHARED_LOCK );
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
|
||||
res = winLockFile(pFile, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
|
||||
if( res ){
|
||||
newLocktype = RESERVED_LOCK;
|
||||
}else{
|
||||
@@ -3337,7 +3386,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
if( locktype==EXCLUSIVE_LOCK && res ){
|
||||
assert( pFile->locktype>=SHARED_LOCK );
|
||||
res = winUnlockReadLock(pFile);
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
|
||||
res = winLockFile(pFile, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
|
||||
SHARED_SIZE, 0);
|
||||
if( res ){
|
||||
newLocktype = EXCLUSIVE_LOCK;
|
||||
@@ -3388,7 +3437,7 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
|
||||
res = 1;
|
||||
OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res));
|
||||
}else{
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE,0,1,0);
|
||||
res = winLockFile(pFile, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE,0,1,0);
|
||||
if( res ){
|
||||
winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
|
||||
}
|
||||
@@ -3527,6 +3576,12 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_LOCK_TIMEOUT: {
|
||||
int iOld = pFile->iBusyTimeout;
|
||||
pFile->iBusyTimeout = *(int*)pArg;
|
||||
*(int*)pArg = iOld;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_SIZE_HINT: {
|
||||
if( pFile->szChunk>0 ){
|
||||
sqlite3_int64 oldSz;
|
||||
@@ -3717,7 +3772,12 @@ static int winShmMutexHeld(void) {
|
||||
**
|
||||
*/
|
||||
struct winShmNode {
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
CRITICAL_SECTION winMutex;
|
||||
CONDITION_VARIABLE winCond;
|
||||
#else
|
||||
sqlite3_mutex *mutex; /* Mutex to access this object */
|
||||
#endif
|
||||
char *zFilename; /* Name of the file */
|
||||
winFile hFile; /* File handle from winOpen */
|
||||
|
||||
@@ -3740,6 +3800,14 @@ struct winShmNode {
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
# define ENTER_SHMNODE_MUTEX(p) EnterCriticalSection(&(p)->winMutex)
|
||||
# define LEAVE_SHMNODE_MUTEX(p) LeaveCriticalSection(&(p)->winMutex)
|
||||
#else
|
||||
# define ENTER_SHMNODE_MUTEX(p) sqlite3_mutex_enter(pShmNode->mutex)
|
||||
# define LEAVE_SHMNODE_MUTEX(p) sqlite3_mutex_leave(pShmNode->mutex)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A global array of all winShmNode objects.
|
||||
**
|
||||
@@ -3804,7 +3872,7 @@ static int winShmSystemLock(
|
||||
/* Initialize the locking parameters */
|
||||
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
|
||||
if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
|
||||
rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
|
||||
rc = winLockFile(&pFile->hFile, dwFlags, ofst, 0, nByte, 0);
|
||||
}
|
||||
|
||||
if( rc!= 0 ){
|
||||
@@ -3824,6 +3892,135 @@ static int winShmSystemLock(
|
||||
/* Forward references to VFS methods */
|
||||
static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
|
||||
static int winDelete(sqlite3_vfs *,const char*,int);
|
||||
static int winFullPathname(sqlite3_vfs *,const char *,int,char *);
|
||||
static void *winConvertFromUtf8Filename(const char *);
|
||||
|
||||
#if !SQLITE_OS_WINRT
|
||||
/*
|
||||
** This function attempts to query the metadata information for the
|
||||
** specified file. Upon success, SQLITE_OK is returned; otherwise,
|
||||
** an appropriate error code is returned.
|
||||
*/
|
||||
|
||||
static int winGetFileInfo(
|
||||
const char *zFilename,
|
||||
winFile *pFile,
|
||||
LPBY_HANDLE_FILE_INFORMATION pFileInfo
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
HANDLE hFile = NULL;
|
||||
int lastError = 0;
|
||||
void *zConverted = winConvertFromUtf8Filename(zFilename);
|
||||
if( zConverted==0 ){
|
||||
lastError = osGetLastError();
|
||||
if( pFile ) pFile->lastErrno = lastError;
|
||||
return winLogError(SQLITE_IOERR_NOMEM, lastError,
|
||||
"winGetFileInfo1", zFilename);
|
||||
}
|
||||
if( osIsNT() ){
|
||||
hFile = osCreateFileW(
|
||||
(LPCWSTR)zConverted, GENERIC_READ,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
|
||||
);
|
||||
#ifdef SQLITE_WIN32_HAS_ANSI
|
||||
}else{
|
||||
hFile = osCreateFileA(
|
||||
(LPCSTR)zConverted, GENERIC_READ,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
|
||||
);
|
||||
#endif
|
||||
}
|
||||
sqlite3_free(zConverted);
|
||||
if( hFile==INVALID_HANDLE_VALUE ){
|
||||
lastError = osGetLastError();
|
||||
if( pFile ) pFile->lastErrno = lastError;
|
||||
return winLogError(SQLITE_CANTOPEN, lastError,
|
||||
"winGetFileInfo2", zFilename);
|
||||
}
|
||||
if( !osGetFileInformationByHandle(hFile, pFileInfo) ){
|
||||
lastError = osGetLastError();
|
||||
if( pFile ) pFile->lastErrno = lastError;
|
||||
rc = winLogError(SQLITE_IOERR_FSTAT, lastError,
|
||||
"winGetFileInfo3", zFilename);
|
||||
}
|
||||
osCloseHandle(hFile);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Returns non-zero if both of the specified file names refer to the same
|
||||
** underlying file. On some sub-platforms, this function may return zero
|
||||
** even when both file names refer to the same underlying file; however,
|
||||
** it will never return non-zero unless both file names refer to the same
|
||||
** underlying file.
|
||||
*/
|
||||
|
||||
static int winIsSameFile(
|
||||
sqlite3_vfs *pVfs,
|
||||
winFile *pFile,
|
||||
const char *zFilename1,
|
||||
const char *zFilename2,
|
||||
BOOL *pbSame
|
||||
){
|
||||
*pbSame = 0; /* initially, assume not the same file */
|
||||
|
||||
#if !SQLITE_OS_WINRT
|
||||
{
|
||||
BY_HANDLE_FILE_INFORMATION info1;
|
||||
BY_HANDLE_FILE_INFORMATION info2;
|
||||
|
||||
if( !winGetFileInfo(zFilename1, pFile, &info1)
|
||||
|| !winGetFileInfo(zFilename2, pFile, &info2) ){
|
||||
/* wrong file system type? ok, use fallback. */
|
||||
goto fallback;
|
||||
}
|
||||
if( info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
|
||||
&& info1.nFileIndexHigh == info2.nFileIndexHigh
|
||||
&& info1.nFileIndexLow == info2.nFileIndexLow ){
|
||||
OSTRACE(("SAME pid=%lu, pFile=%p, name1=%s, name2=%s, "
|
||||
"YES (ID), rc=SQLITE_OK\n", osGetCurrentProcessId(),
|
||||
pFile, zFilename1, zFilename2));
|
||||
*pbSame = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fallback:
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
int nFull = pVfs->mxPathname+1;
|
||||
char *zFull1 = NULL;
|
||||
char *zFull2 = NULL;
|
||||
|
||||
zFull1 = sqlite3MallocZero( nFull );
|
||||
if( zFull1==0 ){
|
||||
rc = SQLITE_IOERR_NOMEM_BKPT;
|
||||
goto done;
|
||||
}
|
||||
zFull2 = sqlite3MallocZero( nFull );
|
||||
if( zFull2==0 ){
|
||||
rc = SQLITE_IOERR_NOMEM_BKPT;
|
||||
goto done;
|
||||
}
|
||||
rc = winFullPathname(pVfs, zFilename1, nFull, zFull1);
|
||||
if( rc!=SQLITE_OK ) goto done;
|
||||
rc = winFullPathname(pVfs, zFilename2, nFull, zFull2);
|
||||
if( rc!=SQLITE_OK ) goto done;
|
||||
*pbSame = sqlite3StrICmp(zFull1, zFull2)==0;
|
||||
done:
|
||||
if( zFull2 ) sqlite3_free(zFull2);
|
||||
if( zFull1 ) sqlite3_free(zFull1);
|
||||
OSTRACE(("SAME pid=%lu, pFile=%p, name1=%s, name2=%s, "
|
||||
"%s (NAME), rc=%s\n", osGetCurrentProcessId(),
|
||||
pFile, zFilename1, zFilename2, *pbSame?"YES":"NO",
|
||||
sqlite3ErrName(rc)));
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
|
||||
@@ -3841,7 +4038,11 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
|
||||
while( (p = *pp)!=0 ){
|
||||
if( p->nRef==0 ){
|
||||
int i;
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
DeleteCriticalSection(&p->winMutex);
|
||||
#else
|
||||
if( p->mutex ){ sqlite3_mutex_free(p->mutex); }
|
||||
#endif
|
||||
for(i=0; i<p->nRegion; i++){
|
||||
BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
|
||||
OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
|
||||
@@ -3940,10 +4141,13 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
*/
|
||||
winShmEnterMutex();
|
||||
for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
|
||||
/* TBD need to come up with better match here. Perhaps
|
||||
** use FILE_ID_BOTH_DIR_INFO Structure.
|
||||
*/
|
||||
if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
|
||||
BOOL bSame;
|
||||
rc = winIsSameFile(
|
||||
pDbFd->pVfs, pDbFd, pShmNode->zFilename, pNew->zFilename,
|
||||
&bSame
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto shm_open_err;
|
||||
if( bSame ) break;
|
||||
}
|
||||
if( pShmNode ){
|
||||
sqlite3_free(pNew);
|
||||
@@ -3958,11 +4162,16 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
winShmNodeList = pShmNode;
|
||||
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
InitializeCriticalSection(&pShmNode->winMutex);
|
||||
InitializeConditionVariable(&pShmNode->winCond);
|
||||
#else
|
||||
pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||
if( pShmNode->mutex==0 ){
|
||||
rc = SQLITE_IOERR_NOMEM_BKPT;
|
||||
goto shm_open_err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
|
||||
@@ -4000,10 +4209,10 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
|
||||
** mutex.
|
||||
*/
|
||||
sqlite3_mutex_enter(pShmNode->mutex);
|
||||
ENTER_SHMNODE_MUTEX(pShmNode);
|
||||
p->pNext = pShmNode->pFirst;
|
||||
pShmNode->pFirst = p;
|
||||
sqlite3_mutex_leave(pShmNode->mutex);
|
||||
LEAVE_SHMNODE_MUTEX(pShmNode);
|
||||
return rc;
|
||||
|
||||
/* Jump here on any error */
|
||||
@@ -4036,14 +4245,14 @@ static int winShmUnmap(
|
||||
|
||||
/* Remove connection p from the set of connections associated
|
||||
** with pShmNode */
|
||||
sqlite3_mutex_enter(pShmNode->mutex);
|
||||
ENTER_SHMNODE_MUTEX(pShmNode);
|
||||
for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
|
||||
*pp = p->pNext;
|
||||
|
||||
/* Free the connection p */
|
||||
sqlite3_free(p);
|
||||
pDbFd->pShm = 0;
|
||||
sqlite3_mutex_leave(pShmNode->mutex);
|
||||
LEAVE_SHMNODE_MUTEX(pShmNode);
|
||||
|
||||
/* If pShmNode->nRef has reached 0, then close the underlying
|
||||
** shared-memory file, too */
|
||||
@@ -4073,6 +4282,10 @@ static int winShmLock(
|
||||
winShmNode *pShmNode = p->pShmNode;
|
||||
int rc = SQLITE_OK; /* Result code */
|
||||
u16 mask; /* Mask of locks to take or release */
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
i64 iTimeout = 0;
|
||||
int bRetry;
|
||||
#endif
|
||||
|
||||
assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
|
||||
assert( n>=1 );
|
||||
@@ -4084,7 +4297,14 @@ static int winShmLock(
|
||||
|
||||
mask = (u16)((1U<<(ofst+n)) - (1U<<ofst));
|
||||
assert( n>1 || mask==(1<<ofst) );
|
||||
sqlite3_mutex_enter(pShmNode->mutex);
|
||||
ENTER_SHMNODE_MUTEX(pShmNode);
|
||||
pShmNode->hFile.iBusyTimeout = pDbFd->iBusyTimeout;
|
||||
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
do{
|
||||
bRetry = 0;
|
||||
#endif
|
||||
|
||||
if( flags & SQLITE_SHM_UNLOCK ){
|
||||
u16 allMask = 0; /* Mask of locks held by siblings */
|
||||
|
||||
@@ -4106,6 +4326,9 @@ static int winShmLock(
|
||||
if( rc==SQLITE_OK ){
|
||||
p->exclMask &= ~mask;
|
||||
p->sharedMask &= ~mask;
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
WakeAllConditionVariable(&pShmNode->winCond);
|
||||
#endif
|
||||
}
|
||||
}else if( flags & SQLITE_SHM_SHARED ){
|
||||
u16 allShared = 0; /* Union of locks held by connections other than "p" */
|
||||
@@ -4117,6 +4340,9 @@ static int winShmLock(
|
||||
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
||||
if( (pX->exclMask & mask)!=0 ){
|
||||
rc = SQLITE_BUSY;
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
bRetry = (pDbFd->iBusyTimeout!=0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
allShared |= pX->sharedMask;
|
||||
@@ -4142,6 +4368,9 @@ static int winShmLock(
|
||||
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
||||
if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
|
||||
rc = SQLITE_BUSY;
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
bRetry = (pDbFd->iBusyTimeout!=0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4157,7 +4386,26 @@ static int winShmLock(
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(pShmNode->mutex);
|
||||
|
||||
#ifdef SQLITE_WIN32_LOCKTMOUT
|
||||
if( bRetry ){
|
||||
i64 iMs;
|
||||
if( iTimeout==0 ){
|
||||
pDbFd->pVfs->xCurrentTimeInt64(pDbFd->pVfs, &iTimeout);
|
||||
iTimeout += pDbFd->iBusyTimeout;
|
||||
iMs = pDbFd->iBusyTimeout;
|
||||
}else{
|
||||
pDbFd->pVfs->xCurrentTimeInt64(pDbFd->pVfs, &iMs);
|
||||
iMs -= iTimeout;
|
||||
}
|
||||
bRetry = (int)SleepConditionVariableCS(
|
||||
&pShmNode->winCond, &pShmNode->winMutex, iMs
|
||||
);
|
||||
}
|
||||
}while( bRetry );
|
||||
#endif
|
||||
|
||||
LEAVE_SHMNODE_MUTEX(pShmNode);
|
||||
OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
|
||||
osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
|
||||
sqlite3ErrName(rc)));
|
||||
@@ -4220,7 +4468,7 @@ static int winShmMap(
|
||||
}
|
||||
pShmNode = pShm->pShmNode;
|
||||
|
||||
sqlite3_mutex_enter(pShmNode->mutex);
|
||||
ENTER_SHMNODE_MUTEX(pShmNode);
|
||||
if( pShmNode->isUnlocked ){
|
||||
rc = winLockSharedMemory(pShmNode);
|
||||
if( rc!=SQLITE_OK ) goto shmpage_out;
|
||||
@@ -4337,7 +4585,7 @@ shmpage_out:
|
||||
*pp = 0;
|
||||
}
|
||||
if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
|
||||
sqlite3_mutex_leave(pShmNode->mutex);
|
||||
LEAVE_SHMNODE_MUTEX(pShmNode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4990,7 +5238,7 @@ static int winOpen(
|
||||
int flags, /* Open mode flags */
|
||||
int *pOutFlags /* Status return flags */
|
||||
){
|
||||
HANDLE h;
|
||||
HANDLE h = INVALID_HANDLE_VALUE;
|
||||
DWORD lastErrno = 0;
|
||||
DWORD dwDesiredAccess;
|
||||
DWORD dwShareMode;
|
||||
@@ -5277,7 +5525,7 @@ static int winOpen(
|
||||
pFile->ctrlFlags |= WINFILE_RDONLY;
|
||||
}
|
||||
if( (flags & SQLITE_OPEN_MAIN_DB)
|
||||
&& sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE)
|
||||
&& sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE)
|
||||
){
|
||||
pFile->ctrlFlags |= WINFILE_PSOW;
|
||||
}
|
||||
@@ -5884,7 +6132,7 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
|
||||
** Sleep for a little while. Return the amount of time slept.
|
||||
*/
|
||||
static int winSleep(sqlite3_vfs *pVfs, int microsec){
|
||||
sqlite3_win32_sleep((microsec+999)/1000);
|
||||
sqlite3Win32Sleep((microsec+999)/1000, FALSE);
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
return ((microsec+999)/1000)*1000;
|
||||
}
|
||||
@@ -6105,7 +6353,7 @@ int sqlite3_os_init(void){
|
||||
|
||||
/* Double-check that the aSyscall[] array has been constructed
|
||||
** correctly. See ticket [bb3a86e890c8e96ab] */
|
||||
assert( ArraySize(aSyscall)==80 );
|
||||
assert( ArraySize(aSyscall)==82 );
|
||||
|
||||
/* get memory map allocation granularity */
|
||||
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
|
||||
|
||||
@@ -1483,6 +1483,124 @@ static void dynamic_triggers(int nMs){
|
||||
print_and_free_err(&err);
|
||||
}
|
||||
|
||||
typedef struct Walthread6 Walthread6;
|
||||
struct Walthread6 {
|
||||
int nInsert;
|
||||
int nBusy;
|
||||
int nMaxFrame;
|
||||
};
|
||||
|
||||
static int walthread6_walhook(
|
||||
void *pArg, /* Pointer to Walthread6 structure */
|
||||
sqlite3 *db, /* Database handle */
|
||||
const char *zDb, /* "main" */
|
||||
int nFrame /* Frames current in wal file */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
Walthread6 *p = (Walthread6*)pArg;
|
||||
|
||||
if( nFrame>p->nMaxFrame ) p->nMaxFrame = nFrame;
|
||||
if( nFrame>1000 ){
|
||||
sqlite3_wal_checkpoint_v2(db, zDb, SQLITE_CHECKPOINT_RESTART, 0, 0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static char *contention1_thread(int iTid, void *pArg){
|
||||
Error err = {0};
|
||||
Sqlite db = {0};
|
||||
int nBlk = 0;
|
||||
int nInsertPerTransaction = 1;
|
||||
i64 iPrev = -1000000;
|
||||
|
||||
Walthread6 res;
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
sqlite3_busy_timeout(db.db, 1000);
|
||||
sqlite3_wal_hook(db.db, walthread6_walhook, (void*)&res);
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
int i;
|
||||
execsql(&err, &db, "BEGIN IMMEDIATE");
|
||||
if( err.rc==SQLITE_BUSY ){
|
||||
res.nBusy++;
|
||||
clear_error(&err, SQLITE_BUSY);
|
||||
}else{
|
||||
i64 iRowid;
|
||||
res.nInsert++;
|
||||
for(i=0; i<nInsertPerTransaction; i++){
|
||||
execsql(&err, &db, "INSERT INTO t1(b) VALUES(random())");
|
||||
}
|
||||
|
||||
iRowid = sqlite3_last_insert_rowid(db.db);
|
||||
if( iRowid!=(iPrev+nInsertPerTransaction) ) nBlk++;
|
||||
iPrev = iRowid;
|
||||
|
||||
sqlite3_sleep(10);
|
||||
execsql(&err, &db, "COMMIT");
|
||||
sqlite3_sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
closedb(&err, &db);
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf(
|
||||
"%d transactions in %d runs (%d busy), max-wal-size=%d frames",
|
||||
res.nInsert, nBlk, res.nBusy, res.nMaxFrame
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
** Test case "contention1".
|
||||
**
|
||||
** Start with a database in wal mode containing a single table. Then run
|
||||
** two threads in a loop as follows:
|
||||
**
|
||||
** while( not-finished ){
|
||||
** BEGIN IMMEDIATE;
|
||||
** INSERT INTO tbl ...
|
||||
** sleep( 10ms );
|
||||
** COMMIT;
|
||||
** sleep( 1ms );
|
||||
** }
|
||||
**
|
||||
** Each thread is configured with sqlite3_busy_timeout(1000ms). Each
|
||||
** thread reports:
|
||||
**
|
||||
** * the number of successful inserts,
|
||||
** * the number of runs the inserts are separated into (a run is a
|
||||
** series of contiguous inserts not interrupted by an insert from
|
||||
** the other thread), and
|
||||
** * the number of SQLITE_BUSY errors.
|
||||
*/
|
||||
static void contention1(int nMs){
|
||||
Error err = {0};
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
int i;
|
||||
int nThread = 2;
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA page_size = 1024;"
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
"CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);"
|
||||
);
|
||||
closedb(&err, &db);
|
||||
|
||||
setstoptime(&err, nMs);
|
||||
for(i=0; i<nThread; i++){
|
||||
launch_thread(&err, &threads, contention1_thread, 0);
|
||||
}
|
||||
join_all_threads(&err, &threads);
|
||||
|
||||
print_and_free_err(&err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "tt3_checkpoint.c"
|
||||
@@ -1503,6 +1621,8 @@ int main(int argc, char **argv){
|
||||
{ walthread3, "walthread3", 20000 },
|
||||
{ walthread4, "walthread4", 20000 },
|
||||
{ walthread5, "walthread5", 1000 },
|
||||
|
||||
{ contention1, "contention1", 10000 },
|
||||
|
||||
{ cgt_pager_1, "cgt_pager_1", 0 },
|
||||
{ dynamic_triggers, "dynamic_triggers", 20000 },
|
||||
|
||||
Reference in New Issue
Block a user