]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix alignment problems in btree and pager and allow page sizes that are
authordrh <drh@noemail.net>
Fri, 22 Oct 2004 16:22:57 +0000 (16:22 +0000)
committerdrh <drh@noemail.net>
Fri, 22 Oct 2004 16:22:57 +0000 (16:22 +0000)
not a multiple of 8. (CVS 2026)

FossilOrigin-Name: 0539c2d2b8e16efcbe4db3afeae9c7b426e11b05

manifest
manifest.uuid
src/btree.c
src/pager.c
test/pagesize.test

index 46adc64d72f40914845982f3bbb736c01deb6bc1..18db763866c718cabc868a0b21ad220efaa871d5 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Reinsert\scode\sdeleted\sby\s(1998)\sthat\swe\sthought\swas\sunused\sbut\swas\sin\sfact\r\nneeded.\s\sFix\sfor\sticket\s#966.\s(CVS\s2025)
-D 2004-10-19T16:40:59
+C Fix\salignment\sproblems\sin\sbtree\sand\spager\sand\sallow\spage\ssizes\sthat\sare\nnot\sa\smultiple\sof\s8.\s(CVS\s2026)
+D 2004-10-22T16:22:58
 F Makefile.in 52c1cc106cad9148d4b7cb387b458e82dc86b339
 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
@@ -30,7 +30,7 @@ F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863
 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
 F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
-F src/btree.c bb3f8cadf65cc0752d07e219733a496c1aebe020
+F src/btree.c d8426846c0db61c97a0e3e11531781be7a96f1bc
 F src/btree.h 94dfec0a1722d33359b23e7e310f2b64ffedf029
 F src/build.c cb0232e0f239d7cea8598d982039b99259074f64
 F src/date.c 34bdb0082db7ec2a83ef00063f7b44e61ee19dad
@@ -53,7 +53,7 @@ F src/os_unix.c 5824b22ba41fe9d514ef9169aac1b5fde73af229
 F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13
 F src/os_win.c 9482dfc92f289b68205bb2c9315757c7e3946bfb
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c dc0ffab9941393b072e0b1f1f3de54830727cec9
+F src/pager.c cc2e7fb3d7913862d7b1170f923d2dcfdbac3bed
 F src/pager.h 774d1973acbda341827d21b0da0150575d69f7d9
 F src/parse.y 8d97a91cba7e35b5eaac064c9f6e597dc6442b29
 F src/pragma.c 3134201e4d47be04b9fcd437e01eab682ad3a096
@@ -154,7 +154,7 @@ F test/null.test 642428b6a5408cc5b954b49e1b6e5025e4458b2b
 F test/pager.test 394455707a079804e8a4e431d12edce831a065f0
 F test/pager2.test c7e731ac56a2984a605b032ffd19b9deee820377
 F test/pager3.test 16f546293bb751b8151dc17df613fca938bbec8b
-F test/pagesize.test f8b46ec46b9fe9f708a8d757dda232588dfb7217
+F test/pagesize.test 56d11f4d6df9949d646bf87da1d6d995ed37cd78
 F test/pragma.test 66a66b7f3b273b93325c9a5794acb418f52fdcbf
 F test/printf.test 92ba4c510b4fc61120ffa4a01820446ed917ae57
 F test/progress.test 5ddba78cb6011fba36093973cfb3ac473b8fb96a x
@@ -252,7 +252,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
 F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c
-P 55b03c560d2f66c55d64c3e9f9577e33f8c63195
-R 462557c854f7b30b37ca39ec9dc0db3d
+P 370ca539506a431dbe77dcb644215886760f34e9
+R 3144c4632ba02236b46866a5c5939839
 U drh
-Z e8f25bd39be0085dd77f02f0608ae8de
+Z fbdbb4c36ca4011ce6bdf20082c190a3
index b23f520787e9d8aaeac8da53da1ad17923ded99a..c4c24c6d996643b6b48137603d4fee7129f222ac 100644 (file)
@@ -1 +1 @@
-370ca539506a431dbe77dcb644215886760f34e9
\ No newline at end of file
+0539c2d2b8e16efcbe4db3afeae9c7b426e11b05
\ No newline at end of file
index a5bd8861399e5e4b96f082bde0fc3390015370a6..677e48c61f3fdf49ed40da39ef5f5112e50c26c8 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.192 2004/10/05 02:41:42 drh Exp $
+** $Id: btree.c,v 1.193 2004/10/22 16:22:58 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
 #include "os.h"
 #include <assert.h>
 
+/*
+** This macro rounds values up so that if the value is an address it
+** is guaranteed to be an address that is aligned to an 8-byte boundary.
+*/
+#define FORCE_ALIGNMENT(X)   (((X)+7)&~7)
 
 /* The following value is the maximum cell size assuming a maximum page
 ** size give above.
@@ -300,6 +305,7 @@ struct Btree {
   u8 minLeafFrac;       /* Minimum leaf payload as % of total page size */
   u8 pageSizeFixed;     /* True if the page size can no longer be changed */
   u16 pageSize;         /* Total number of bytes on a page */
+  u16 psAligned;        /* pageSize rounded up to a multiple of 8 */
   u16 usableSize;       /* Number of usable bytes on each page */
   int maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
   int minLocal;         /* Minimum local payload in non-LEAFDATA tables */
@@ -533,7 +539,7 @@ static void _pageIntegrity(MemPage *pPage){
   used = sqliteMallocRaw( pPage->pBt->pageSize );
   if( used==0 ) return;
   usableSize = pPage->pBt->usableSize;
-  assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );
+  assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->psAligned] );
   hdr = pPage->hdrOffset;
   assert( hdr==(pPage->pgno==1 ? 100 : 0) );
   assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
@@ -837,7 +843,7 @@ static int initPage(
   assert( pBt!=0 );
   assert( pParent==0 || pParent->pBt==pBt );
   assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
-  assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
+  assert( pPage->aData == &((unsigned char*)pPage)[-pBt->psAligned] );
   if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
     /* The parent page should never change unless the file is corrupt */
     return SQLITE_CORRUPT; /* bkpt-CORRUPT */
@@ -910,7 +916,7 @@ static void zeroPage(MemPage *pPage, int flags){
   int first;
 
   assert( sqlite3pager_pagenumber(data)==pPage->pgno );
-  assert( &data[pBt->pageSize] == (unsigned char*)pPage );
+  assert( &data[pBt->psAligned] == (unsigned char*)pPage );
   assert( sqlite3pager_iswriteable(data) );
   memset(&data[hdr], 0, pBt->usableSize - hdr);
   data[hdr] = flags;
@@ -939,7 +945,7 @@ static int getPage(Btree *pBt, Pgno pgno, MemPage **ppPage){
   MemPage *pPage;
   rc = sqlite3pager_get(pBt->pPager, pgno, (void**)&aData);
   if( rc ) return rc;
-  pPage = (MemPage*)&aData[pBt->pageSize];
+  pPage = (MemPage*)&aData[pBt->psAligned];
   pPage->aData = aData;
   pPage->pBt = pBt;
   pPage->pgno = pgno;
@@ -978,7 +984,7 @@ static void releasePage(MemPage *pPage){
   if( pPage ){
     assert( pPage->aData );
     assert( pPage->pBt );
-    assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage );
+    assert( &pPage->aData[pPage->pBt->psAligned]==(unsigned char*)pPage );
     sqlite3pager_unref(pPage->aData);
   }
 }
@@ -989,7 +995,7 @@ static void releasePage(MemPage *pPage){
 ** happens.
 */
 static void pageDestructor(void *pData, int pageSize){
-  MemPage *pPage = (MemPage*)&((char*)pData)[pageSize];
+  MemPage *pPage = (MemPage*)&((char*)pData)[FORCE_ALIGNMENT(pageSize)];
   if( pPage->pParent ){
     MemPage *pParent = pPage->pParent;
     pPage->pParent = 0;
@@ -1007,7 +1013,7 @@ static void pageDestructor(void *pData, int pageSize){
 ** page to agree with the restored data.
 */
 static void pageReinit(void *pData, int pageSize){
-  MemPage *pPage = (MemPage*)&((char*)pData)[pageSize];
+  MemPage *pPage = (MemPage*)&((char*)pData)[FORCE_ALIGNMENT(pageSize)];
   if( pPage->isInit ){
     pPage->isInit = 0;
     initPage(pPage, pPage->pParent);
@@ -1078,6 +1084,7 @@ int sqlite3BtreeOpen(
     pBt->pageSizeFixed = 1;
   }
   pBt->usableSize = pBt->pageSize - nReserve;
+  pBt->psAligned = FORCE_ALIGNMENT(pBt->pageSize);
   sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
   *ppBtree = pBt;
   return SQLITE_OK;
@@ -1148,6 +1155,7 @@ int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){
   }
   if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE ){
     pBt->pageSize = pageSize;
+    pBt->psAligned = FORCE_ALIGNMENT(pageSize);
     sqlite3pager_set_pagesize(pBt->pPager, pageSize);
   }
   pBt->usableSize = pBt->pageSize - nReserve;
@@ -1199,6 +1207,7 @@ static int lockBtree(Btree *pBt){
     if( pBt->usableSize<500 ){
       goto page1_init_failed;
     }
+    pBt->psAligned = FORCE_ALIGNMENT(pBt->pageSize);
     pBt->maxEmbedFrac = page1[21];
     pBt->minEmbedFrac = page1[22];
     pBt->minLeafFrac = page1[23];
@@ -1248,7 +1257,7 @@ static void unlockBtreeIfUnused(Btree *pBt){
   if( pBt->inTrans==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
     if( pBt->pPage1->aData==0 ){
       MemPage *pPage = pBt->pPage1;
-      pPage->aData = &((char*)pPage)[-pBt->pageSize];
+      pPage->aData = &((char*)pPage)[-pBt->psAligned];
       pPage->pBt = pBt;
       pPage->pgno = 1;
     }
@@ -2673,7 +2682,7 @@ static void reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
   assert( pBt->pPager!=0 );
   aData = sqlite3pager_lookup(pBt->pPager, pgno);
   if( aData ){
-    pThis = (MemPage*)&aData[pBt->pageSize];
+    pThis = (MemPage*)&aData[pBt->psAligned];
     assert( pThis->aData==aData );
     if( pThis->isInit ){
       if( pThis->pParent!=pNewParent ){
@@ -2960,7 +2969,7 @@ static int balance_nonroot(MemPage *pPage){
   apCell = sqliteMallocRaw( 
        (mxCellPerPage+2)*NB*(sizeof(u8*)+sizeof(int))
      + sizeof(MemPage)*NB
-     + pBt->pageSize*(5+NB)
+     + pBt->psAligned*(5+NB)
   );
   if( apCell==0 ){
     return SQLITE_NOMEM;
@@ -2968,9 +2977,9 @@ static int balance_nonroot(MemPage *pPage){
   szCell = (int*)&apCell[(mxCellPerPage+2)*NB];
   aCopy[0] = (u8*)&szCell[(mxCellPerPage+2)*NB];
   for(i=1; i<NB; i++){
-    aCopy[i] = &aCopy[i-1][pBt->pageSize+sizeof(MemPage)];
+    aCopy[i] = &aCopy[i-1][pBt->psAligned+sizeof(MemPage)];
   }
-  aSpace = &aCopy[NB-1][pBt->pageSize+sizeof(MemPage)];
+  aSpace = &aCopy[NB-1][pBt->psAligned+sizeof(MemPage)];
   
   /*
   ** Find the cell in the parent page whose left child points back
@@ -3041,10 +3050,10 @@ static int balance_nonroot(MemPage *pPage){
   ** process of being overwritten.
   */
   for(i=0; i<nOld; i++){
-    MemPage *p = apCopy[i] = (MemPage*)&aCopy[i][pBt->pageSize];
-    p->aData = &((u8*)p)[-pBt->pageSize];
-    memcpy(p->aData, apOld[i]->aData, pBt->pageSize + sizeof(MemPage));
-    p->aData = &((u8*)p)[-pBt->pageSize];
+    MemPage *p = apCopy[i] = (MemPage*)&aCopy[i][pBt->psAligned];
+    p->aData = &((u8*)p)[-pBt->psAligned];
+    memcpy(p->aData, apOld[i]->aData, pBt->psAligned + sizeof(MemPage));
+    p->aData = &((u8*)p)[-pBt->psAligned];
   }
 
   /*
@@ -3088,7 +3097,7 @@ static int balance_nonroot(MemPage *pPage){
         szCell[nCell] = sz;
         pTemp = &aSpace[iSpace];
         iSpace += sz;
-        assert( iSpace<=pBt->pageSize*5 );
+        assert( iSpace<=pBt->psAligned*5 );
         memcpy(pTemp, apDiv[i], sz);
         apCell[nCell] = pTemp+leafCorrection;
         dropCell(pParent, nxDiv, sz);
@@ -3272,13 +3281,13 @@ static int balance_nonroot(MemPage *pPage){
         pCell = &aSpace[iSpace];
         fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz);
         iSpace += sz;
-        assert( iSpace<=pBt->pageSize*5 );
+        assert( iSpace<=pBt->psAligned*5 );
         pTemp = 0;
       }else{
         pCell -= 4;
         pTemp = &aSpace[iSpace];
         iSpace += sz;
-        assert( iSpace<=pBt->pageSize*5 );
+        assert( iSpace<=pBt->psAligned*5 );
       }
       insertCell(pParent, nxDiv, pCell, sz, pTemp);
       put4byte(findOverflowCell(pParent,nxDiv), pNew->pgno);
index cf0da5200d696e099b320e3a1057a1c149e7b302..fe06e2a4b32678d0461f31bd78f862be35802259 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.167 2004/10/05 02:41:43 drh Exp $
+** @(#) $Id: pager.c,v 1.168 2004/10/22 16:22:59 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
 # define SQLITE_BUSY_RESERVED_LOCK 0
 #endif
 
+/*
+** This macro rounds values up so that if the value is an address it
+** is guaranteed to be an address that is aligned to an 8-byte boundary.
+*/
+#define FORCE_ALIGNMENT(X)   (((X)+7)&~7)
+
 /*
 ** Each in-memory image of a page begins with the following header.
 ** This header is only visible to this pager module.  The client
@@ -143,7 +149,7 @@ struct PgHdr {
   u8 alwaysRollback;             /* Disable dont_rollback() for this page */
   short int nRef;                /* Number of users of this page */
   PgHdr *pDirty;                 /* Dirty pages sorted by PgHdr.pgno */
-  /* pPager->pageSize bytes of page data follow this header */
+  /* pPager->psAligned bytes of page data follow this header */
   /* Pager.nExtra bytes of local data follow the page data */
 };
 
@@ -179,9 +185,9 @@ struct PgHistory {
 */
 #define PGHDR_TO_DATA(P)  ((void*)(&(P)[1]))
 #define DATA_TO_PGHDR(D)  (&((PgHdr*)(D))[-1])
-#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize])
+#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->psAligned])
 #define PGHDR_TO_HIST(P,PGR)  \
-            ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
+            ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->psAligned+(PGR)->nExtra])
 
 /*
 ** How big to make the hash table used for locating in-memory pages
@@ -214,6 +220,7 @@ struct Pager {
   void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
   void (*xReiniter)(void*,int);   /* Call this routine when reloading pages */
   int pageSize;               /* Number of bytes in a page */
+  int psAligned;              /* pageSize rounded up to a multiple of 8 */
   int nPage;                  /* Total number of in-memory pages */
   int nRef;                   /* Number of in-memory pages with PgHdr.nRef>0 */
   int mxPage;                 /* Maximum number of pages to hold in cache */
@@ -1503,6 +1510,7 @@ int sqlite3pager_open(
   pPager->nRef = 0;
   pPager->dbSize = memDb-1;
   pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
+  pPager->psAligned = FORCE_ALIGNMENT(pPager->pageSize);
   pPager->stmtSize = 0;
   pPager->stmtJSize = 0;
   pPager->nPage = 0;
@@ -1518,7 +1526,7 @@ int sqlite3pager_open(
   pPager->pFirst = 0;
   pPager->pFirstSynced = 0;
   pPager->pLast = 0;
-  pPager->nExtra = nExtra;
+  pPager->nExtra = FORCE_ALIGNMENT(nExtra);
   pPager->sectorSize = PAGER_SECTOR_SIZE;
   pPager->pBusyHandler = 0;
   memset(pPager->aHash, 0, sizeof(pPager->aHash));
@@ -1564,6 +1572,7 @@ void sqlite3pager_set_reiniter(Pager *pPager, void (*xReinit)(void*,int)){
 void sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
   assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE );
   pPager->pageSize = pageSize;
+  pPager->psAligned = FORCE_ALIGNMENT(pageSize);
 }
 
 /*
@@ -2133,7 +2142,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
     pPager->nMiss++;
     if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || pPager->memDb ){
       /* Create a new page */
-      pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize 
+      pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->psAligned
                               + sizeof(u32) + pPager->nExtra
                               + pPager->memDb*sizeof(PgHistory) );
       if( pPg==0 ){
index f794a8f45b2faaf1ee65692962c93525da29e9d0..7fe6b8b509876a0447ca4dd5777b7de640f83bf5 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.
 # This file implements tests for the page_size PRAGMA.
 #
-# $Id: pagesize.test,v 1.3 2004/09/05 00:33:44 drh Exp $
+# $Id: pagesize.test,v 1.4 2004/10/22 16:22:59 drh Exp $
 
 
 set testdir [file dirname $argv0]
@@ -61,7 +61,7 @@ do_test pagesize-1.7 {
   
 
 
-foreach PGSZ {512 2000 2048 3000 4096} {
+foreach PGSZ {512 515 516 751 2000 2001 2002 2003 2004 2048 3000 4096} {
   do_test pagesize-2.$PGSZ.1 {
     db close
     file delete -force test.db