From: dan Date: Mon, 1 Apr 2013 17:56:59 +0000 (+0000) Subject: Attempt to emulate mremap() on non-Linux systems by allocating a second mapping immed... X-Git-Tag: version-3.7.17~114^2~30 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e6ecd6630dd7fadec974ffd94ea678212e959717;p=thirdparty%2Fsqlite.git Attempt to emulate mremap() on non-Linux systems by allocating a second mapping immediately following the first in virtual memory. FossilOrigin-Name: 4d67433db8fb4754ae6b192945e479f3d7bad579 --- diff --git a/manifest b/manifest index e6eca96ae6..52c1269c2e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sxFetch\sand\sxUnfetch\smethods\sto\sthe\sos_win.c\sVFS. -D 2013-04-01T17:22:51.830 +C Attempt\sto\semulate\smremap()\son\snon-Linux\ssystems\sby\sallocating\sa\ssecond\smapping\simmediately\sfollowing\sthe\sfirst\sin\svirtual\smemory. +D 2013-04-01T17:56:59.408 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in df3e48659d80e1b7765785d8d66c86b320f72cc7 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -160,7 +160,7 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c 809d0707cec693e1b9b376ab229271ad74c3d35d F src/os.h ae08bcc5f6ec6b339f4a2adf3931bb88cc14c3e4 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 -F src/os_unix.c d6981218583748080374ed98a03f6a87e2bdc9e0 +F src/os_unix.c d136eca0cff2f8a5ac2f45867d5e5153d60e377c F src/os_win.c f705e7ce230f86104dedcc2987a21d564b236659 F src/pager.c 2b9980e87296812a6ce51121a3335550ae25e3ec F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 @@ -1040,7 +1040,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P a1040f0397d57855500926494c978623286ddc77 -R 52b13f77704d4760e77e0cfd9ab57bff -U drh -Z 878a27609130450cef13cc90a8feab48 +P a1653a257d6af6e8b10c819e68b12f6c2f485811 +R 144bfd1ec5d6fde06365c0d3ea4b879a +U dan +Z 4e8a79b712821b5d3d9730a626894d79 diff --git a/manifest.uuid b/manifest.uuid index c685b6feac..694ae46ba8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a1653a257d6af6e8b10c819e68b12f6c2f485811 \ No newline at end of file +4d67433db8fb4754ae6b192945e479f3d7bad579 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index f91f4c4e7a..e92c7cc4a4 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -313,6 +313,17 @@ struct unixFile { #define threadid 0 #endif +/* +** HAVE_MREMAP defaults to true on Linux and false everywhere else. +*/ +#if !defined(HAVE_MREMAP) +# if defined(__linux__) && defined(_GNU_SOURCE) +# define HAVE_MREMAP 1 +# else +# define HAVE_MREMAP 0 +# endif +#endif + /* ** Different Unix systems declare open() in different ways. Same use ** open(const char*,int,mode_t). Others use open(const char*,int,...). @@ -450,7 +461,7 @@ static struct unix_syscall { { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, #define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent) -#if defined(__linux__) && defined(_GNU_SOURCE) +#if HAVE_MREMAP { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, #else { "mremap", (sqlite3_syscall_ptr)0, 0 }, @@ -1124,7 +1135,6 @@ static int unixLogErrorAtLine( zErr = strerror(iErrno); #endif - assert( errcode!=SQLITE_OK ); if( zPath==0 ) zPath = ""; sqlite3_log(errcode, "os_unix.c:%d: (%d) %s(%s) - %s", @@ -3619,7 +3629,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ } } - if( pFile->mmapLimit>0 ){ + if( pFile->mmapLimit>0 && nByte>pFile->mmapSize ){ int rc; if( pFile->szChunk<=0 ){ if( robust_ftruncate(pFile->h, nByte) ){ @@ -4518,6 +4528,104 @@ static void unixUnmapfile(unixFile *pFd){ } } +/* +** Return the system page size. +*/ +static int unixGetPagesize(void){ +#if HAVE_MREMAP + return 512; +#elif _BSD_SOURCE + return getpagesize(); +#else + return (int)sysconf(_SC_PAGESIZE); +#endif +} + +/* +** Attempt to set the size of the memory mapping maintained by file +** descriptor pFd to nNew bytes. Any existing mapping is discarded. +** +** If successful, this function sets the following variables: +** +** unixFile.pMapRegion +** unixFile.mmapSize +** unixFile.mmapOrigsize +** +** If unsuccessful, an error message is logged via sqlite3_log() and +** the three variables above are zeroed. In this case SQLite should +** continue accessing the database using the xRead() and xWrite() +** methods. +*/ +static void unixRemapfile( + unixFile *pFd, /* File descriptor object */ + i64 nNew /* Required mapping size */ +){ + int h = pFd->h; /* File descriptor open on db file */ + u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */ + i64 nOrig = pFd->mmapOrigsize; /* Size of pOrig region in bytes */ + u8 *pNew = 0; /* Location of new mapping */ + int flags = PROT_READ; /* Flags to pass to mmap() */ + + assert( pFd->nFetchOut==0 ); + assert( nNew>pFd->mmapSize ); + assert( nNew<=pFd->mmapLimit ); + assert( nNew>0 ); + assert( pFd->mmapOrigsize>=pFd->mmapSize ); + + if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; + + if( pOrig ){ + const int szSyspage = unixGetPagesize(); + i64 nReuse = (pFd->mmapSize & ~(szSyspage-1)); + u8 *pReq = &pOrig[nReuse]; + + /* Unmap any pages of the existing mapping that cannot be reused. */ + if( nReuse!=nOrig ){ + osMunmap(pReq, nOrig-nReuse); + } + +#if HAVE_MREMAP + pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE); +#else + pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse); + if( pNew!=MAP_FAILED ){ + if( pNew!=pReq ){ + osMunmap(pNew, nNew - nReuse); + pNew = MAP_FAILED; + }else{ + pNew = pOrig; + } + } +#endif + + /* The attempt to extend the existing mapping failed. Free the existing + ** mapping and set pNew to NULL so that the code below will create a + ** new mapping from scratch. */ + if( pNew==MAP_FAILED ){ + pNew = 0; + osMunmap(pOrig, nReuse); + } + } + + /* If pNew is still NULL, try to create an entirely new mapping. */ + if( pNew==0 ){ + pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0); + if( pNew==MAP_FAILED ){ + pNew = 0; + nNew = 0; + unixLogError(SQLITE_OK, "mmap", pFd->zPath); + + /* If the mmap() above failed, assume that all subsequent mmap() calls + ** will probably fail too. Fall back to using xRead/xWrite exclusively + ** in this case. */ + pFd->mmapLimit = 0; + } + } + + pFd->pMapRegion = (void *)pNew; + pFd->mmapSize = pFd->mmapOrigsize = nNew; +} + /* ** Memory map or remap the file opened by file-descriptor pFd (if the file ** is already mapped, the existing mapping is replaced by the new). Or, if @@ -4554,28 +4662,11 @@ static int unixMapfile(unixFile *pFd, i64 nByte){ } if( nMap!=pFd->mmapSize ){ - void *pNew = 0; - -#if defined(__linux__) && defined(_GNU_SOURCE) - if( pFd->pMapRegion && nMap>0 ){ - pNew = osMremap(pFd->pMapRegion, pFd->mmapOrigsize, nMap, MREMAP_MAYMOVE); - }else -#endif - { + if( nMap>0 ){ + unixRemapfile(pFd, nMap); + }else{ unixUnmapfile(pFd); - if( nMap>0 ){ - int flags = PROT_READ; - if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; - pNew = osMmap(0, nMap, flags, MAP_SHARED, pFd->h, 0); - } - } - - if( pNew==MAP_FAILED ){ - return SQLITE_IOERR_MMAP; } - pFd->pMapRegion = pNew; - pFd->mmapSize = nMap; - pFd->mmapOrigsize = nMap; } return SQLITE_OK;