From: mistachkin Date: Thu, 15 Jul 2021 23:12:27 +0000 (+0000) Subject: Initial work on blocking locks for the Win32 VFS. Various other small enhancements. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=07444ecf8c2681c5c798861c4de3ccc26ada1046;p=thirdparty%2Fsqlite.git Initial work on blocking locks for the Win32 VFS. Various other small enhancements. FossilOrigin-Name: 584c24252a37ef050ced5926a93e52fc47a41d9017b291dc1c1c796712e391d7 --- diff --git a/manifest b/manifest index e552a4aba7..ff54209df4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\sWindows\sVFS\sto\srecognize\sSQLITE_FCNTL_LOCK_TIMEOUT\sand\smake\nthe\svalue\sset\sthere\savailable\sto\sthe\swinLockFile()\sfunction. -D 2021-07-14T19:35:45.291 +C Initial\swork\son\sblocking\slocks\sfor\sthe\sWin32\sVFS.\s\sVarious\sother\ssmall\senhancements. +D 2021-07-15T23:12:27.529 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -529,7 +529,7 @@ 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 dc54e0a4b15a0c151dc9f01e64976d8f435d8020f0a8507d7acc5452b438d229 +F src/os_win.c 15c4dce3a03801a18d6de2f636373cbe6d3843b99932d1bfe16758336ada818a F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 95c255256b13827caf038c8f963d334784073f38ab6ef9d70371d9d04f3c43e0 F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f @@ -1920,10 +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 c378e99250fe06fae8ca40c62185b607f004d6806e07dbb9f964dd849b4e55f8 -R 21f9449dd33d80268629340267e31b8d -T *branch * win-blocking-locks -T *sym-win-blocking-locks * -T -sym-trunk * -U drh -Z 229f4697970d0911e5dbcc6bd7ebdd8d +P 954b5d61299d82312a9ca2764f904e2d8318c469f6749d84f8a6871d12a575a8 +R ce6cfd7eda001c4ee216459a1054a7c1 +U mistachkin +Z b59d01fb46dfdd3d864282a4891b32ce diff --git a/manifest.uuid b/manifest.uuid index bfa8f19f1e..8b4119f506 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -954b5d61299d82312a9ca2764f904e2d8318c469f6749d84f8a6871d12a575a8 \ No newline at end of file +584c24252a37ef050ced5926a93e52fc47a41d9017b291dc1c1c796712e391d7 \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index 059e884ee3..e54708faff 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -1127,7 +1127,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 @@ -1156,6 +1156,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 */ /* @@ -1380,18 +1397,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 @@ -2155,13 +2179,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; } @@ -2526,11 +2550,25 @@ static BOOL winLockFile( numBytesLow, numBytesHigh); #else if( osIsNT() ){ + BOOL bResult; OVERLAPPED ovlp; memset(&ovlp, 0, sizeof(OVERLAPPED)); ovlp.Offset = offsetLow; ovlp.OffsetHigh = offsetHigh; - return osLockFileEx(pFile->h, 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 && iTotalDelayiBusyTimeout ); + } + } + return bResult; }else{ return osLockFile(pFile->h, offsetLow, offsetHigh, numBytesLow, numBytesHigh); @@ -2678,7 +2716,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 && ++cntzDeleteOnClose)!=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); } @@ -3298,7 +3336,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 ){ @@ -3835,6 +3873,134 @@ 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, 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, 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. @@ -3951,10 +4117,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); @@ -5002,7 +5171,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; @@ -5289,7 +5458,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; } @@ -5896,7 +6065,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; } @@ -6117,7 +6286,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));