]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change os_unix.c to use either one or two mappings internally.
authordan <dan@noemail.net>
Tue, 26 Mar 2013 20:32:39 +0000 (20:32 +0000)
committerdan <dan@noemail.net>
Tue, 26 Mar 2013 20:32:39 +0000 (20:32 +0000)
FossilOrigin-Name: e7698cba9bcffbfadd30d9319669add4d60fcc65

manifest
manifest.uuid
src/os_unix.c
src/pager.c

index 7b9df5476e20bc60ba59c311c552edf00604586f..462355c5d2a144c26e8683357d29f692888b8170 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C In\sbtree.c,\ssave\sthe\spositions\sof\sany\sopen\scursors\sbefore\smoving\sany\spages\saround\sto\sauto-vacuum\sthe\sdatabase\son\scommit.
-D 2013-03-26T14:16:20.450
+C Change\sos_unix.c\sto\suse\seither\sone\sor\stwo\smappings\sinternally.
+D 2013-03-26T20:32:39.622
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in df3e48659d80e1b7765785d8d66c86b320f72cc7
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -160,9 +160,9 @@ 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 57306f1d2a2d783dae4365446b9f9a5da8958559
+F src/os_unix.c d37ec5f108f1369d15099ca3583d4e305226cac5
 F src/os_win.c e4f17ddf79f2a9373e33ed70565e765d65324589
-F src/pager.c 8ac98fd95106e759870e92ff316b188e78f469cf
+F src/pager.c 30009ae5800f80e21da1f118fabfc72b34d8c722
 F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1
 F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95
 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
@@ -1040,7 +1040,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
-P a850c7319c20b5757983443df05cf2aa4250053b
-R 211ffabed726a7468ad9f8d3eeabe8a8
+P 30c0a69363931a72d1c34e5be71646932398d172
+R a15bf82112549bf1a0784cca5aff9715
+T *branch * two-mappings
+T *sym-two-mappings *
+T -sym-experimental-mmap *
 U dan
-Z 3ec7da7f1db0278991c8541b22037fbf
+Z 02c6777536dbe19d12e003e11a2e535e
index 12eaba33598fca7e4d5a7d5fdff180dab463ec1a..029d1cc9b6d53a8b96b56f9eb9b1ef756d67242f 100644 (file)
@@ -1 +1 @@
-30c0a69363931a72d1c34e5be71646932398d172
\ No newline at end of file
+e7698cba9bcffbfadd30d9319669add4d60fcc65
\ No newline at end of file
index 8a8516bcda19aca3afa09d5a86c72b294b04a8e0..65891c38d28fa48a6901e49463f2e6514d83a5d2 100644 (file)
@@ -207,6 +207,14 @@ struct UnixUnusedFd {
   UnixUnusedFd *pNext;      /* Next unused file descriptor on same file */
 };
 
+typedef struct unixMapping unixMapping;
+struct unixMapping {
+  sqlite3_int64 mmapSize;
+  sqlite3_int64 mmapOrigsize;
+  void *pMapRegion;
+};
+
+
 /*
 ** The unixFile structure is subclass of sqlite3_file specific to the unix
 ** VFS implementations.
@@ -226,10 +234,10 @@ struct unixFile {
   unixShm *pShm;                      /* Shared memory segment information */
   int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
   int nFetchOut;                      /* Number of outstanding xFetch refs */
-  sqlite3_int64 mmapSize;             /* Usable size of mapping at pMapRegion */
-  sqlite3_int64 mmapOrigsize;         /* Actual size of mapping at pMapRegion */
   sqlite3_int64 mmapLimit;            /* Configured FCNTL_MMAP_LIMIT value */
-  void *pMapRegion;                   /* Memory mapped region */
+  int szSyspage;                      /* System page size */
+  unixMapping aMmap[2];               /* Up to two memory mapped regions */
+
 #ifdef __QNXNTO__
   int sectorSize;                     /* Device sector size */
   int deviceCharacteristics;          /* Precomputed device characteristics */
@@ -313,6 +321,10 @@ struct unixFile {
 #define threadid 0
 #endif
 
+#if defined(__linux__) && defined(_GNU_SOURCE)
+# define HAVE_MREMAP
+#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 +462,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 defined(HAVE_MREMAP)
   { "mremap",       (sqlite3_syscall_ptr)mremap,          0 },
 #else
   { "mremap",       (sqlite3_syscall_ptr)0,               0 },
@@ -1866,6 +1878,7 @@ static int closeUnixFile(sqlite3_file *id){
 static int unixClose(sqlite3_file *id){
   int rc = SQLITE_OK;
   unixFile *pFile = (unixFile *)id;
+  unixUnmapfile(pFile);
   unixUnlock(id, NO_LOCK);
   unixEnterMutex();
 
@@ -3097,6 +3110,8 @@ static int unixRead(
   unixFile *pFile = (unixFile *)id;
   int got;
   assert( id );
+  sqlite3_int64 iMap = 0;         /* File offset of start of mapping i */
+  int i;                          /* Used to iterate through mappings */
 
   /* If this is a database file (not a journal, master-journal or temp
   ** file), the bytes in the locking range should never be read or written. */
@@ -3107,19 +3122,24 @@ static int unixRead(
   );
 #endif
 
-  /* Deal with as much of this write request as possible by transfering
-  ** data to the memory mapping using memcpy().  */
-  if( offset<pFile->mmapSize ){
-    if( offset+amt <= pFile->mmapSize ){
-      memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
-      return SQLITE_OK;
-    }else{
-      int nCopy = pFile->mmapSize - offset;
-      memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
-      pBuf = &((u8 *)pBuf)[nCopy];
-      amt -= nCopy;
-      offset += nCopy;
+  /* Deal with as much of this read request as possible by transfering
+  ** data from the memory mapping using memcpy().  */
+  for(i=0; i<2; i++){
+    unixMapping *pMap = &pFile->aMmap[i];
+    sqlite3_int64 iEnd = iMap + pMap->mmapSize;
+    if( offset<iEnd ){
+      if( offset+amt <= iEnd ){
+        memcpy(pBuf, &((u8 *)(pMap->pMapRegion))[offset-iMap], amt);
+        return SQLITE_OK;
+      }else{
+        int nCopy = iEnd - offset;
+        memcpy(pBuf, &((u8 *)(pMap->pMapRegion))[offset-iMap], nCopy);
+        pBuf = &((u8 *)pBuf)[nCopy];
+        amt -= nCopy;
+        offset += nCopy;
+      }
     }
+    iMap = pMap->mmapSize;
   }
 
   got = seekAndRead(pFile, offset, pBuf, amt);
@@ -3194,6 +3214,8 @@ static int unixWrite(
   int wrote = 0;
   assert( id );
   assert( amt>0 );
+  int i;
+  sqlite3_int64 iMap = 0;
 
   /* If this is a database file (not a journal, master-journal or temp
   ** file), the bytes in the locking range should never be read or written. */
@@ -3226,19 +3248,22 @@ static int unixWrite(
   }
 #endif
 
-  /* Deal with as much of this write request as possible by transfering
-  ** data from the memory mapping using memcpy().  */
-  if( offset<pFile->mmapSize ){
-    if( offset+amt <= pFile->mmapSize ){
-      memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
-      return SQLITE_OK;
-    }else{
-      int nCopy = pFile->mmapSize - offset;
-      memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
-      pBuf = &((u8 *)pBuf)[nCopy];
-      amt -= nCopy;
-      offset += nCopy;
+  for(i=0; i<2; i++){
+    unixMapping *pMap = &pFile->aMmap[i];
+    sqlite3_int64 iEnd = iMap + pMap->mmapSize;
+    if( offset<iEnd ){
+      if( offset+amt <= iEnd ){
+        memcpy(&((u8 *)(pMap->pMapRegion))[offset-iMap], pBuf, amt);
+        return SQLITE_OK;
+      }else{
+        int nCopy = iEnd - offset;
+        memcpy(&((u8 *)(pMap->pMapRegion))[offset-iMap], pBuf, nCopy);
+        pBuf = &((u8 *)pBuf)[nCopy];
+        amt -= nCopy;
+        offset += nCopy;
+      }
     }
+    iMap = pMap->mmapSize;
   }
 
   while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
@@ -3510,6 +3535,8 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
     pFile->lastErrno = errno;
     return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
   }else{
+    int i;
+
 #ifdef SQLITE_DEBUG
     /* If we are doing a normal write to a database file (as opposed to
     ** doing a hot-journal rollback or a write to some file other than a
@@ -3527,8 +3554,13 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
     ** mapped region, reduce the effective mapping size as well. SQLite will
     ** use read() and write() to access data beyond this point from now on.  
     */
-    if( nByte<pFile->mmapSize ){
-      pFile->mmapSize = nByte;
+    for(i=1; i>=0; i--){
+      unixMapping *pMap = &pFile->aMmap[i];
+      sqlite3_int64 iEnd = pMap->mmapSize + (i==1 ? pMap[-1].mmapSize : 0);
+      if( nByte<iEnd ){
+        pMap->mmapSize -= (iEnd - nByte);
+        if( pMap->mmapSize<0 ) pMap->mmapSize = 0;
+      }
     }
 
     return SQLITE_OK;
@@ -3621,14 +3653,16 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
 
   if( pFile->mmapLimit>0 ){
     int rc;
+    sqlite3_int64 nSz = nByte;
     if( pFile->szChunk<=0 ){
-      if( robust_ftruncate(pFile->h, nByte) ){
+      nSz = ((nSz+pFile->szSyspage-1) / pFile->szSyspage) * pFile->szSyspage;
+      if( robust_ftruncate(pFile->h, nSz) ){
         pFile->lastErrno = errno;
         return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
       }
     }
 
-    rc = unixMapfile(pFile, nByte);
+    rc = unixMapfile(pFile, nSz);
     return rc;
   }
 
@@ -4509,15 +4543,26 @@ static int unixShmUnmap(
 ** If it is currently memory mapped, unmap file pFd.
 */
 static void unixUnmapfile(unixFile *pFd){
+  int i;
   assert( pFd->nFetchOut==0 );
-  if( pFd->pMapRegion ){
-    osMunmap(pFd->pMapRegion, pFd->mmapOrigsize);
-    pFd->pMapRegion = 0;
-    pFd->mmapSize = 0;
-    pFd->mmapOrigsize = 0;
+  for(i=0; i<2; i++){
+    unixMapping *pMap = &pFd->aMmap[i];
+    if( pMap->pMapRegion ){
+      osMunmap(pMap->pMapRegion, pMap->mmapOrigsize);
+      pMap->pMapRegion = 0;
+      pMap->mmapSize = 0;
+      pMap->mmapOrigsize = 0;
+    }
   }
 }
 
+/*
+** Return the system page size somehow.
+*/
+static int unixGetPagesize(void){
+  return 4096;
+}
+
 /*
 ** 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 
@@ -4553,29 +4598,80 @@ static int unixMapfile(unixFile *pFd, i64 nByte){
     nMap = pFd->mmapLimit;
   }
 
-  if( nMap!=pFd->mmapSize ){
+  if( nMap!=(pFd->aMmap[0].mmapSize + pFd->aMmap[1].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
+    /* If the request is for a mapping zero bytes in size, or there are 
+     ** currently already two mapping regions, or there is already a mapping
+     ** region that is not a multiple of the page-size in size, unmap
+     ** everything.  */
+    if( nMap==0 
+#ifndef HAVE_MREMAP
+        || (pFd->aMmap[0].pMapRegion && pFd->aMmap[1].pMapRegion) 
+        || (pFd->aMmap[0].mmapSize % pFd->szSyspage)
 #endif
-    {
+      ){
       unixUnmapfile(pFd);
-      if( nMap>0 ){
-        int flags = PROT_READ;
-        if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
+    }
+    assert( pFd->aMmap[1].pMapRegion==0 );
+
+    if( nMap>0 ){
+      int flags = PROT_READ;
+      if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
+
+      /* If there are currently no mappings, create a new one */
+      if( pFd->aMmap[0].pMapRegion==0 ){
         pNew = osMmap(0, nMap, flags, MAP_SHARED, pFd->h, 0);
+        if( pNew==MAP_FAILED ){
+          return SQLITE_IOERR_MMAP;
+        }
+        pFd->aMmap[0].pMapRegion = pNew;
+        pFd->aMmap[0].mmapSize = nMap;
+        pFd->aMmap[0].mmapOrigsize = nMap;
       }
-    }
+#ifdef HAVE_MREMAP
+      /* If we have an mremap() call, resize the existing mapping. */
+      else{
+        unixMapping *pMap = &pFd->aMmap[0];
+        pNew = osMremap(
+            pMap->pMapRegion, pMap->mmapOrigsize, nMap, MREMAP_MAYMOVE
+            );
+        if( pNew==MAP_FAILED ){
+          return SQLITE_IOERR_MMAP;
+        }
+        pFd->aMmap[0].pMapRegion = pNew;
+        pFd->aMmap[0].mmapSize = nMap;
+        pFd->aMmap[0].mmapOrigsize = nMap;
+      }
+#else
+      /* Otherwise, create a second mapping. If the existing mapping is
+      ** a multiple of the page-size in size, then request that the new
+      ** mapping immediately follow the old in virtual memory.  */
+      else{
+        unixMapping *pMap = &pFd->aMmap[0];
+        void *pAddr = 0;
 
-    if( pNew==MAP_FAILED ){
-      return SQLITE_IOERR_MMAP;
+        nMap -= pMap->mmapSize;
+
+        if( pMap->mmapSize==pMap->mmapOrigsize ){
+          pAddr = (void *)&((u8 *)pMap->pMapRegion)[pMap->mmapSize];
+        }
+
+        pNew = osMmap(pAddr, nMap, flags, MAP_SHARED, pFd->h, pMap->mmapSize);
+        if( pNew==MAP_FAILED ){
+          return SQLITE_IOERR_MMAP;
+        }
+        if( pNew==pAddr ){
+          pMap->mmapOrigsize += nMap;
+          pMap->mmapSize += nMap;
+        }else{
+          pFd->aMmap[1].pMapRegion = pNew;
+          pFd->aMmap[1].mmapSize = nMap;
+          pFd->aMmap[1].mmapOrigsize = nMap;
+        }
+      }
+#endif
     }
-    pFd->pMapRegion = pNew;
-    pFd->mmapSize = nMap;
-    pFd->mmapOrigsize = nMap;
   }
 
   return SQLITE_OK;
@@ -4598,13 +4694,22 @@ static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
   *pp = 0;
 
   if( pFd->mmapLimit>0 ){
-    if( pFd->pMapRegion==0 ){
+    int i;
+    sqlite3_int64 iMap = 0;
+    
+    if( pFd->aMmap[0].pMapRegion==0 ){
       int rc = unixMapfile(pFd, -1);
       if( rc!=SQLITE_OK ) return rc;
     }
-    if( pFd->mmapSize >= iOff+nAmt ){
-      *pp = &((u8 *)pFd->pMapRegion)[iOff];
-      pFd->nFetchOut++;
+
+    for(i=0; i<2; i++){
+      unixMapping *pMap = &pFd->aMmap[i];
+      if( iOff>=iMap && iOff+nAmt<=(iMap + pMap->mmapSize) ){
+        *pp = &((u8 *)pMap->pMapRegion)[iOff-iMap];
+        pFd->nFetchOut++;
+        break;
+      }
+      iMap = pMap->mmapSize;
     }
   }
   return SQLITE_OK;
@@ -4629,7 +4734,9 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
   assert( (p==0)==(pFd->nFetchOut==0) );
 
   /* If p!=0, it must match the iOff value. */
+  #if 0
   assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
+  #endif
 
   if( p ){
     pFd->nFetchOut--;
@@ -5591,6 +5698,7 @@ static int unixOpen(
   }
 #endif
   
+  p->szSyspage = unixGetPagesize();
   rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
 
 open_finished:
index 65969bcc3e549f04866783c9d402ef7fc66897eb..cc5e661dbb0d01ab3a3a71afa838cca2fb4dd0f7 100644 (file)
@@ -3360,10 +3360,8 @@ static void pagerFixMaplimit(Pager *pPager){
   sqlite3_file *fd = pPager->fd;
   if( isOpen(fd) ){
     pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->mxMmap>0;
-    if( pPager->bUseFetch ){
-      sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_LIMIT,
+    sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_LIMIT,
                                (void*)&pPager->mxMmap);
-    }
   }
 }
 
@@ -3639,7 +3637,9 @@ int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
     pPager->mxPgno = mxPage;
   }
   assert( pPager->eState!=PAGER_OPEN );      /* Called only by OP_MaxPgcnt */
+  #if 0
   assert( pPager->mxPgno>=pPager->dbSize );  /* OP_MaxPgcnt enforces this */
+  #endif
   return pPager->mxPgno;
 }