Index: src/os_win.c ================================================================== --- src/os_win.c +++ src/os_win.c @@ -265,10 +265,11 @@ void *pMapRegion; /* Area memory mapped */ sqlite3_int64 mmapSize; /* Usable size of mapped region */ sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif + SQLiteThread *preCacheThread; /* Thread used to pre-cache file contents */ }; /* ** Allowed values for winFile.ctrlFlags */ @@ -1042,10 +1043,15 @@ #endif #define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) + { "DuplicateHandle", (SYSCALL)DuplicateHandle, 0 }, + +#define osDuplicateHandle ((BOOL(WINAPI*)(HANDLE, \ + HANDLE,HANDLE,LPHANDLE,DWORD,BOOL,DWORD))aSyscall[76].pCurrent) + }; /* End of the overrideable system calls */ /* ** This is the xSetSystemCall() method of sqlite3_vfs for all of the ** "win32" VFSes. Return SQLITE_OK opon successfully updating the @@ -2351,10 +2357,17 @@ #ifndef SQLITE_OMIT_WAL assert( pFile->pShm==0 ); #endif assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE ); OSTRACE(("CLOSE file=%p\n", pFile->h)); + +#if SQLITE_MAX_WORKER_THREADS>0 + if( pFile->preCacheThread ){ + void *pOut = 0; + sqlite3ThreadJoin(pFile->preCacheThread, &pOut); + } +#endif #if SQLITE_MAX_MMAP_SIZE>0 winUnmapfile(pFile); #endif @@ -3195,10 +3208,88 @@ static int winDeviceCharacteristics(sqlite3_file *id){ winFile *p = (winFile*)id; return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0); } + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** Thread routine that attempts to read the entire file. This is used to +** provide a hint to the operating system that the entire file should be held +** in the cache. +*/ +static void *winPreCacheThread(void *pCtx){ + winFile *pFile = (winFile*)pCtx; + void *pBuf = 0; + DWORD lastErrno; + HANDLE dupHandle = NULL; + DWORD dwSize, dwRet; + DWORD dwAmt; + DWORD nRead; + + if( !osDuplicateHandle(GetCurrentProcess(), pFile->h, GetCurrentProcess(), + &dupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) ){ + pFile->lastErrno = osGetLastError(); + OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR\n", dupHandle)); + return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR, pFile->lastErrno, + "winPreCacheThread1", pFile->zPath)); + } + dwSize = osSetFilePointer(dupHandle, 0, 0, FILE_END); + if( (dwSize==INVALID_SET_FILE_POINTER + && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ + pFile->lastErrno = lastErrno; + osCloseHandle(dupHandle); + OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_SEEK\n", dupHandle)); + return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, + "winPreCacheThread2", pFile->zPath)); + } + dwRet = osSetFilePointer(dupHandle, 0, 0, FILE_BEGIN); + if( (dwRet==INVALID_SET_FILE_POINTER + && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ + pFile->lastErrno = lastErrno; + osCloseHandle(dupHandle); + OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_SEEK\n", dupHandle)); + return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, + "winPreCacheThread3", pFile->zPath)); + } + dwAmt = 4194304; /* TODO: Tuning. */ + if( dwSizelastErrno = osGetLastError(); + sqlite3_free(pBuf); + osCloseHandle(dupHandle); + OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_READ\n", dupHandle)); + return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_READ, pFile->lastErrno, + "winPreCacheThread4", pFile->zPath)); + } + if( nReadlastErrno, + "winPreCacheThread5", pFile->zPath)); + } + dwSize -= dwAmt; + if( dwSize==0 ){ + break; + } + } + sqlite3_free(pBuf); + osCloseHandle(dupHandle); + return SQLITE_INT_TO_PTR(SQLITE_OK); +} +#endif /* ** Windows will only let you create file view mappings ** on allocation size granularity boundaries. ** During sqlite3_os_init() we do a GetSystemInfo() @@ -4702,10 +4793,19 @@ pFile->pMapRegion = 0; pFile->mmapSize = 0; pFile->mmapSizeActual = 0; pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap; #endif +#if SQLITE_MAX_WORKER_THREADS>0 + sqlite3ThreadCreate(&pFile->preCacheThread, winPreCacheThread, pFile); + + { + void *pOut = 0; + sqlite3ThreadJoin(pFile->preCacheThread, &pOut); + pFile->preCacheThread = 0; + } +#endif OpenCounter(+1); return rc; } @@ -5420,11 +5520,11 @@ }; #endif /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==76 ); + assert( ArraySize(aSyscall)==77 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); #if SQLITE_OS_WINRT osGetNativeSystemInfo(&winSysInfo);