Initial work on porting the changes on this branch to Win32.

FossilOrigin-Name: 3738bfd0c0eadb10eea58954af5052cb6ce164059f3aacfe65d7da6a400c63c7
This commit is contained in:
mistachkin 2017-11-09 16:30:55 +00:00
parent 9214c1efe8
commit 4ff8431fd1
5 changed files with 179 additions and 56 deletions

View File

@ -1,5 +1,5 @@
C Extra\scomments\son\sthe\ssqlite3OsShmMap()\scall\sin\swalBeginUnlocked().\s\sNo\nchanges\sto\scode.
D 2017-11-08T19:26:27.278
C Initial\swork\son\sporting\sthe\schanges\son\sthis\sbranch\sto\sWin32.
D 2017-11-09T16:30:55.245
F Makefile.in 5bae3f2f3d42f2ad52b141562d74872c97ac0fca6c54953c91bb150a0e6427a8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 3a5cb477ec3ce5274663b693164e349db63348667cd45bad78cc13d580b691e2
@ -448,7 +448,7 @@ F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c e87cef0bb894b94d96ee3af210be669549d111c580817d14818101b992640767
F src/os_win.c 6892c3ff23b7886577e47f13d827ca220c0831bae3ce00eea8c258352692f8c6
F src/os_win.c 47687775641c97743c228f99813fbcffe7d53602da5cdcf0fe52f6810341a46c
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 07cf850241667874fcce9d7d924c814305e499b26c804322e2261247b5921903
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
@ -1527,8 +1527,8 @@ F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03
F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6
F test/walprotocol.test 0b92feb132ccebd855494d917d3f6c2d717ace20
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
F test/walro2.test 2e499d89fa825c9d23b53ed4da8e4dcc7017ea16212d6a4f3aec56d1861eaf8e
F test/walrofault.test befa889648b2f779e2886f8434d8b44c05c49c130048305977da3e97c33dcb8d
F test/walro2.test 2c01a3c38ca731df4690cc901e3c0bee21bf9d231fa3d47d81162be10462c40b
F test/walrofault.test f1c9c361a73faab98ce1bb4588333e42f7dd330f2b4987e962aa5fe68e7982de
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
@ -1669,7 +1669,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 04974a8b5c0e6748216226006ca9125529c8bb2a7a9df4641217eb1413426a14
R eba2a72214a6da7d512bda6426cfe5de
U drh
Z 493ea33d970c37f0e10aaccf35cd6d47
P 033ee92bf4d5dc57f5cb8fd02d1154ae06f2d3261d214e7191a82c70c8ffebf7
R a3370fa9345068426fa8edd8924927fc
U mistachkin
Z fbbc6e55aa870fcd83aef8acf0e01375

View File

@ -1 +1 @@
033ee92bf4d5dc57f5cb8fd02d1154ae06f2d3261d214e7191a82c70c8ffebf7
3738bfd0c0eadb10eea58954af5052cb6ce164059f3aacfe65d7da6a400c63c7

View File

@ -2098,6 +2098,17 @@ static int winLogErrorAtLine(
static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY;
static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
/*
** The "winIsLockingError" macro is used to determine if a particular I/O
** error code is due to file locking. It must accept the error code DWORD
** as its only argument and should return non-zero if the error code is due
** to file locking.
*/
#if !defined(winIsLockingError)
#define winIsLockingError(a) (((a)==ERROR_LOCK_VIOLATION) || \
((a)==ERROR_IO_PENDING))
#endif
/*
** The "winIoerrCanRetry1" macro is used to determine if a particular I/O
** error code obtained via GetLastError() is eligible to be retried. It
@ -3673,6 +3684,9 @@ struct winShmNode {
int szRegion; /* Size of shared-memory regions */
int nRegion; /* Size of array apRegion */
u8 isReadonly; /* True if read-only */
u8 isUnlocked; /* True if no DMS lock held */
struct ShmRegion {
HANDLE hMap; /* File handle from CreateFileMapping */
void *pMap;
@ -3820,6 +3834,116 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
}
}
/*
** Query the status of the DMS lock for the specified file. Returns
** SQLITE_OK upon success. Upon success, the integer pointed to by
** the pLockType argument will be set to the lock type held by the
** other process, as follows:
**
** WINSHM_UNLCK -- No locks are held on the DMS.
** WINSHM_RDLCK -- A SHARED lock is held on the DMS.
** WINSHM_WRLCK -- An EXCLUSIVE lock is held on the DMS.
*/
static int winGetShmDmsLockType(
winFile *pFile, /* File handle object */
int *pLockType /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
){
#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
OVERLAPPED overlapped; /* The offset for ReadFile/WriteFile. */
#endif
LPVOID pOverlapped = 0;
sqlite3_int64 offset = WIN_SHM_DMS;
BYTE notUsed1 = 0;
DWORD notUsed2 = 0;
#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
if( winSeekFile(pFile, offset) ){
return SQLITE_IOERR_SEEK;
}
#else
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
pOverlapped = &overlapped;
#endif
if( !osWriteFile(pFile->h, &notUsed1, 1, &notUsed2, pOverlapped) ){
if( !osReadFile(pFile->h, &notUsed1, 1, &notUsed2, pOverlapped) ){
if( winIsLockingError(osGetLastError()) ){
*pLockType = WINSHM_WRLCK;
}else{
return SQLITE_IOERR_READ;
}
}else{
if( winIsLockingError(osGetLastError()) ){
*pLockType = WINSHM_RDLCK;
}else{
return SQLITE_IOERR_WRITE;
}
}
}else{
*pLockType = WINSHM_UNLCK;
}
return SQLITE_OK;
}
/*
** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
** take it now. Return SQLITE_OK if successful, or an SQLite error
** code otherwise.
**
** If the DMS cannot be locked because this is a readonly_shm=1
** connection and no other process already holds a lock, return
** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
*/
static int winLockSharedMemory(winFile *pDbFd, winShmNode *pShmNode){
int lockType;
int rc = SQLITE_OK;
/* Use ReadFile/WriteFile to determine the locks other processes are
** holding on the DMS byte. If it indicates that another process is
** holding a SHARED lock, then this process may also take a SHARED
** lock and proceed with opening the *-shm file.
**
** Or, if no other process is holding any lock, then this process
** is the first to open it. In this case take an EXCLUSIVE lock on the
** DMS byte and truncate the *-shm file to zero bytes in size. Then
** downgrade to a SHARED lock on the DMS byte.
**
** If another process is holding an EXCLUSIVE lock on the DMS byte,
** return SQLITE_BUSY to the caller (it will try again). An earlier
** version of this code attempted the SHARED lock at this point. But
** this introduced a subtle race condition: if the process holding
** EXCLUSIVE failed just before truncating the *-shm file, then this
** process might open and use the *-shm file without truncating it.
** And if the *-shm file has been corrupted by a power failure or
** system crash, the database itself may also become corrupt. */
if( winGetShmDmsLockType(&pShmNode->hFile, &lockType)!=SQLITE_OK ){
rc = SQLITE_IOERR_LOCK;
}else if( lockType==WINSHM_UNLCK ){
if( pShmNode->isReadonly ){
pShmNode->isUnlocked = 1;
rc = SQLITE_READONLY_CANTINIT;
}else{
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
if( rc==SQLITE_OK && winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
"winLockSharedMemory", pShmNode->zFilename);
}
}
}else if( lockType==WINSHM_WRLCK ){
rc = SQLITE_BUSY;
}
if( rc==SQLITE_OK ){
assert( lockType==WINSHM_UNLCK || lockType==WINSHM_RDLCK );
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
}
return rc;
}
/*
** Open the shared-memory area associated with database file pDbFd.
**
@ -3828,11 +3952,12 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
** the file must be truncated to zero length or have its header cleared.
*/
static int winOpenSharedMemory(winFile *pDbFd){
struct winShm *p; /* The connection to be opened */
struct winShmNode *pShmNode = 0; /* The underlying mmapped file */
int rc; /* Result code */
struct winShmNode *pNew; /* Newly allocated winShmNode */
int nName; /* Size of zName in bytes */
struct winShm *p; /* The connection to be opened */
winShmNode *pShmNode = 0; /* The underlying mmapped file */
int rc = SQLITE_OK; /* Result code */
int rc2 = SQLITE_ERROR; /* winOpen result code */
winShmNode *pNew; /* Newly allocated winShmNode */
int nName; /* Size of zName in bytes */
assert( pDbFd->pShm==0 ); /* Not previously opened */
@ -3878,30 +4003,29 @@ static int winOpenSharedMemory(winFile *pDbFd){
}
}
rc = winOpen(pDbFd->pVfs,
pShmNode->zFilename, /* Name of the file (UTF-8) */
(sqlite3_file*)&pShmNode->hFile, /* File handle here */
SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
0);
if( SQLITE_OK!=rc ){
goto shm_open_err;
if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
rc2 = winOpen(pDbFd->pVfs,
pShmNode->zFilename,
(sqlite3_file*)&pShmNode->hFile,
SQLITE_OPEN_WAL|SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,
0);
}
if( rc2!=SQLITE_OK ){
rc2 = winOpen(pDbFd->pVfs,
pShmNode->zFilename,
(sqlite3_file*)&pShmNode->hFile,
SQLITE_OPEN_WAL|SQLITE_OPEN_READONLY|SQLITE_OPEN_CREATE,
0);
if( rc2!=SQLITE_OK ){
rc = winLogError(SQLITE_CANTOPEN_BKPT, osGetLastError(),
"winOpenShm", pShmNode->zFilename);
goto shm_open_err;
}
pShmNode->isReadonly = 1;
}
/* Check to see if another process is holding the dead-man switch.
** If not, truncate the file to zero length.
*/
if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
if( rc!=SQLITE_OK ){
rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
"winOpenShm", pDbFd->zPath);
}
}
if( rc==SQLITE_OK ){
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
}
if( rc ) goto shm_open_err;
rc = winLockSharedMemory(pDbFd, pShmNode);
if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
}
/* Make the new connection a child of the winShmNode */
@ -4128,6 +4252,8 @@ static int winShmMap(
winFile *pDbFd = (winFile*)fd;
winShm *pShm = pDbFd->pShm;
winShmNode *pShmNode;
DWORD protect = PAGE_READWRITE;
DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ;
int rc = SQLITE_OK;
if( !pShm ){
@ -4138,6 +4264,11 @@ static int winShmMap(
pShmNode = pShm->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
if( pShmNode->isUnlocked ){
rc = winLockSharedMemory(pDbFd, pShmNode);
if( rc!=SQLITE_OK ) goto shmpage_out;
pShmNode->isUnlocked = 0;
}
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
if( pShmNode->nRegion<=iRegion ){
@ -4184,21 +4315,26 @@ static int winShmMap(
}
pShmNode->aRegion = apNew;
if( pShmNode->isReadonly ){
protect = PAGE_READONLY;
flags = FILE_MAP_READ;
}
while( pShmNode->nRegion<=iRegion ){
HANDLE hMap = NULL; /* file-mapping handle */
void *pMap = 0; /* Mapped memory region */
#if SQLITE_OS_WINRT
hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
NULL, PAGE_READWRITE, nByte, NULL
NULL, protect, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_WIDE)
hMap = osCreateFileMappingW(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
NULL, protect, 0, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
hMap = osCreateFileMappingA(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
NULL, protect, 0, nByte, NULL
);
#endif
OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
@ -4208,11 +4344,11 @@ static int winShmMap(
int iOffset = pShmNode->nRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
#if SQLITE_OS_WINRT
pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
pMap = osMapViewOfFileFromApp(hMap, flags,
iOffset - iOffsetShift, szRegion + iOffsetShift
);
#else
pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
pMap = osMapViewOfFile(hMap, flags,
0, iOffset - iOffsetShift, szRegion + iOffsetShift
);
#endif
@ -4243,6 +4379,7 @@ shmpage_out:
}else{
*pp = 0;
}
if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
sqlite3_mutex_leave(pShmNode->mutex);
return rc;
}

View File

@ -18,13 +18,6 @@ source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
set ::testprefix walro2
# These tests are only going to work on unix.
#
if {$::tcl_platform(platform) != "unix"} {
finish_test
return
}
# And only if the build is WAL-capable.
#
ifcapable !wal {

View File

@ -17,13 +17,6 @@ source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix walro2
# These tests are only going to work on unix.
#
if {$::tcl_platform(platform) != "unix"} {
finish_test
return
}
# And only if the build is WAL-capable.
#
ifcapable !wal {