summary refs log tree commit diff
path: root/gnu
diff options
context:
space:
mode:
authorMark H Weaver <mhw@netris.org>2014-04-02 12:14:46 -0400
committerMark H Weaver <mhw@netris.org>2014-04-02 15:31:28 -0400
commit8ead71b4b03a888d846c7b7c5bbc3addc8013df7 (patch)
treead92d321363a862418a9f91343946789123f3e34 /gnu
parentd6a601816fd5b254d99f0c11127388b46ce234ae (diff)
downloadguix-8ead71b4b03a888d846c7b7c5bbc3addc8013df7.tar.gz
gnu: sqlite: Fix sqlite on systems with page size larger than 32K.
Based on a patch by Dan Kennedy <danielk1977@gmail.com>.

* gnu/packages/patches/sqlite-large-page-size-fix.patch: New file.
* gnu/packages/sqlite.scm (sqlite): Add it.
* gnu-system.am (dist_patch_DATA): Add it.
Diffstat (limited to 'gnu')
-rw-r--r--gnu/packages/patches/sqlite-large-page-size-fix.patch180
-rw-r--r--gnu/packages/sqlite.scm4
2 files changed, 183 insertions, 1 deletions
diff --git a/gnu/packages/patches/sqlite-large-page-size-fix.patch b/gnu/packages/patches/sqlite-large-page-size-fix.patch
new file mode 100644
index 0000000000..c561fa20a2
--- /dev/null
+++ b/gnu/packages/patches/sqlite-large-page-size-fix.patch
@@ -0,0 +1,180 @@
+Add an experimental fix to avoid attempting to mmap memory from an
+offset that is not a multiple of the system page size on systems with
+page sizes larger than 32KB.
+
+Patch by Dan Kennedy <danielk1977@gmail.com>.
+
+--- sqlite-autoconf/sqlite3.c.orig	2014-03-22 23:44:47.055908203 -0400
++++ sqlite-autoconf/sqlite3.c	2014-03-22 23:44:06.716552734 -0400
+@@ -24010,6 +24010,7 @@
+ 
+ /* Forward reference */
+ static int openDirectory(const char*, int*);
++static int unixGetpagesize(void);
+ 
+ /*
+ ** Many system calls are accessed through pointer-to-functions so that
+@@ -24133,6 +24134,9 @@
+ #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
+ #endif
+ 
++  { "getpagesize",  (sqlite3_syscall_ptr)unixGetpagesize, 0 },
++#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
++
+ }; /* End of the overrideable system calls */
+ 
+ /*
+@@ -27792,6 +27796,36 @@
+   return rc;        
+ }
+ 
++/*
++** Return the system page size.
++**
++** This function should not be called directly by other code in this file. 
++** Instead, it should be called via macro osGetpagesize().
++*/
++static int unixGetpagesize(void){
++#if defined(_BSD_SOURCE)
++  return getpagesize();
++#else
++  return (int)sysconf(_SC_PAGESIZE);
++#endif
++}
++
++/*
++** Return the minimum number of 32KB shm regions that should be mapped at
++** a time, assuming that each mapping must be an integer multiple of the
++** current system page-size.
++**
++** Usually, this is 1. The exception seems to be systems that are configured
++** to use 64KB pages - in this case each mapping must cover at least two
++** shm regions.
++*/
++static int unixShmRegionPerMap(void){
++  int shmsz = 32*1024;            /* SHM region size */
++  int pgsz = osGetpagesize();   /* System page size */
++  assert( ((pgsz-1)&pgsz)==0 );   /* Page size must be a power of 2 */
++  if( pgsz<shmsz ) return 1;
++  return pgsz/shmsz;
++}
+ 
+ /*
+ ** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
+@@ -27803,10 +27837,11 @@
+   unixShmNode *p = pFd->pInode->pShmNode;
+   assert( unixMutexHeld() );
+   if( p && p->nRef==0 ){
++    int nShmPerMap = unixShmRegionPerMap();
+     int i;
+     assert( p->pInode==pFd->pInode );
+     sqlite3_mutex_free(p->mutex);
+-    for(i=0; i<p->nRegion; i++){
++    for(i=0; i<p->nRegion; i+=nShmPerMap){
+       if( p->h>=0 ){
+         osMunmap(p->apRegion[i], p->szRegion);
+       }else{
+@@ -28013,6 +28048,8 @@
+   unixShm *p;
+   unixShmNode *pShmNode;
+   int rc = SQLITE_OK;
++  int nShmPerMap = unixShmRegionPerMap();
++  int nReqRegion;
+ 
+   /* If the shared-memory file has not yet been opened, open it now. */
+   if( pDbFd->pShm==0 ){
+@@ -28028,9 +28065,12 @@
+   assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
+   assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
+ 
+-  if( pShmNode->nRegion<=iRegion ){
++  /* Minimum number of regions required to be mapped. */
++  nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
++
++  if( pShmNode->nRegion<nReqRegion ){
+     char **apNew;                      /* New apRegion[] array */
+-    int nByte = (iRegion+1)*szRegion;  /* Minimum required file size */
++    int nByte = nReqRegion*szRegion;   /* Minimum required file size */
+     struct stat sStat;                 /* Used by fstat() */
+ 
+     pShmNode->szRegion = szRegion;
+@@ -28079,17 +28119,19 @@
+ 
+     /* Map the requested memory region into this processes address space. */
+     apNew = (char **)sqlite3_realloc(
+-        pShmNode->apRegion, (iRegion+1)*sizeof(char *)
++        pShmNode->apRegion, nReqRegion*sizeof(char *)
+     );
+     if( !apNew ){
+       rc = SQLITE_IOERR_NOMEM;
+       goto shmpage_out;
+     }
+     pShmNode->apRegion = apNew;
+-    while(pShmNode->nRegion<=iRegion){
++    while( pShmNode->nRegion<nReqRegion ){
++      int nMap = szRegion*nShmPerMap;
++      int i;
+       void *pMem;
+       if( pShmNode->h>=0 ){
+-        pMem = osMmap(0, szRegion,
++        pMem = osMmap(0, nMap,
+             pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, 
+             MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
+         );
+@@ -28105,8 +28147,11 @@
+         }
+         memset(pMem, 0, szRegion);
+       }
+-      pShmNode->apRegion[pShmNode->nRegion] = pMem;
+-      pShmNode->nRegion++;
++
++      for(i=0; i<nShmPerMap; i++){
++        pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i];
++      }
++      pShmNode->nRegion += nShmPerMap;
+     }
+   }
+ 
+@@ -28321,19 +28366,6 @@
+ }
+ 
+ /*
+-** Return the system page size.
+-*/
+-static int unixGetPagesize(void){
+-#if HAVE_MREMAP
+-  return 512;
+-#elif defined(_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.
+ **
+@@ -28369,8 +28401,12 @@
+   if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
+ 
+   if( pOrig ){
+-    const int szSyspage = unixGetPagesize();
++#if HAVE_MREMAP
++    i64 nReuse = pFd->mmapSize;
++#else
++    const int szSyspage = osGetpagesize();
+     i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
++#endif
+     u8 *pReq = &pOrig[nReuse];
+ 
+     /* Unmap any pages of the existing mapping that cannot be reused. */
+@@ -31116,7 +31152,7 @@
+ 
+   /* Double-check that the aSyscall[] array has been constructed
+   ** correctly.  See ticket [bb3a86e890c8e96ab] */
+-  assert( ArraySize(aSyscall)==24 );
++  assert( ArraySize(aSyscall)==25 );
+ 
+   /* Register all VFSes defined in the aVfs[] array */
+   for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
diff --git a/gnu/packages/sqlite.scm b/gnu/packages/sqlite.scm
index 5b6a96f4b0..0475b6c77e 100644
--- a/gnu/packages/sqlite.scm
+++ b/gnu/packages/sqlite.scm
@@ -49,7 +49,9 @@
                     "/sqlite-autoconf-" numeric-version ".tar.gz")))
             (sha256
              (base32
-              "19gicv5vdi5c0p8shr1bmihldj409aqz3r4wr7d3pwb6xf1xv4p4"))))
+              "19gicv5vdi5c0p8shr1bmihldj409aqz3r4wr7d3pwb6xf1xv4p4"))
+            (patches
+             (list (search-patch "sqlite-large-page-size-fix.patch")))))
    (build-system gnu-build-system)
    (home-page "http://www.sqlite.org/")
    (synopsis "The SQLite database management system")