/ Check-in [0539c2d2]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix alignment problems in btree and pager and allow page sizes that are not a multiple of 8. (CVS 2026)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0539c2d2b8e16efcbe4db3afeae9c7b426e11b05
User & Date: drh 2004-10-22 16:22:58
Context
2004-10-22
20:29
Add the experimental and scary pragma "writable_schema". (CVS 2027) check-in: 39f7870a user: drh tags: trunk
16:22
Fix alignment problems in btree and pager and allow page sizes that are not a multiple of 8. (CVS 2026) check-in: 0539c2d2 user: drh tags: trunk
2004-10-19
16:40
Reinsert code deleted by (1998) that we thought was unused but was in fact needed. Fix for ticket #966. (CVS 2025) check-in: 370ca539 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.192 2004/10/05 02:41:42 drh Exp $
           12  +** $Id: btree.c,v 1.193 2004/10/22 16:22:58 drh Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** For a detailed discussion of BTrees, refer to
    16     16   **
    17     17   **     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
    18     18   **     "Sorting And Searching", pages 473-480. Addison-Wesley
    19     19   **     Publishing Company, Reading, Massachusetts.
................................................................................
   207    207   */
   208    208   #include "sqliteInt.h"
   209    209   #include "pager.h"
   210    210   #include "btree.h"
   211    211   #include "os.h"
   212    212   #include <assert.h>
   213    213   
          214  +/*
          215  +** This macro rounds values up so that if the value is an address it
          216  +** is guaranteed to be an address that is aligned to an 8-byte boundary.
          217  +*/
          218  +#define FORCE_ALIGNMENT(X)   (((X)+7)&~7)
   214    219   
   215    220   /* The following value is the maximum cell size assuming a maximum page
   216    221   ** size give above.
   217    222   */
   218    223   #define MX_CELL_SIZE(pBt)  (pBt->pageSize-8)
   219    224   
   220    225   /* The maximum number of cells on a single page of the database.  This
................................................................................
   296    301     u8 inStmt;            /* True if we are in a statement subtransaction */
   297    302     u8 readOnly;          /* True if the underlying file is readonly */
   298    303     u8 maxEmbedFrac;      /* Maximum payload as % of total page size */
   299    304     u8 minEmbedFrac;      /* Minimum payload as % of total page size */
   300    305     u8 minLeafFrac;       /* Minimum leaf payload as % of total page size */
   301    306     u8 pageSizeFixed;     /* True if the page size can no longer be changed */
   302    307     u16 pageSize;         /* Total number of bytes on a page */
          308  +  u16 psAligned;        /* pageSize rounded up to a multiple of 8 */
   303    309     u16 usableSize;       /* Number of usable bytes on each page */
   304    310     int maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
   305    311     int minLocal;         /* Minimum local payload in non-LEAFDATA tables */
   306    312     int maxLeaf;          /* Maximum local payload in a LEAFDATA table */
   307    313     int minLeaf;          /* Minimum local payload in a LEAFDATA table */
   308    314   };
   309    315   typedef Btree Bt;
................................................................................
   529    535     int cellOffset;
   530    536     int nCell, cellLimit;
   531    537     u8 *used;
   532    538   
   533    539     used = sqliteMallocRaw( pPage->pBt->pageSize );
   534    540     if( used==0 ) return;
   535    541     usableSize = pPage->pBt->usableSize;
   536         -  assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );
          542  +  assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->psAligned] );
   537    543     hdr = pPage->hdrOffset;
   538    544     assert( hdr==(pPage->pgno==1 ? 100 : 0) );
   539    545     assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
   540    546     c = pPage->aData[hdr];
   541    547     if( pPage->isInit ){
   542    548       assert( pPage->leaf == ((c & PTF_LEAF)!=0) );
   543    549       assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) );
................................................................................
   833    839     int nFree;         /* Number of unused bytes on the page */
   834    840     int top;           /* First byte of the cell content area */
   835    841   
   836    842     pBt = pPage->pBt;
   837    843     assert( pBt!=0 );
   838    844     assert( pParent==0 || pParent->pBt==pBt );
   839    845     assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
   840         -  assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
          846  +  assert( pPage->aData == &((unsigned char*)pPage)[-pBt->psAligned] );
   841    847     if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
   842    848       /* The parent page should never change unless the file is corrupt */
   843    849       return SQLITE_CORRUPT; /* bkpt-CORRUPT */
   844    850     }
   845    851     if( pPage->isInit ) return SQLITE_OK;
   846    852     if( pPage->pParent==0 && pParent!=0 ){
   847    853       pPage->pParent = pParent;
................................................................................
   906    912   static void zeroPage(MemPage *pPage, int flags){
   907    913     unsigned char *data = pPage->aData;
   908    914     Btree *pBt = pPage->pBt;
   909    915     int hdr = pPage->hdrOffset;
   910    916     int first;
   911    917   
   912    918     assert( sqlite3pager_pagenumber(data)==pPage->pgno );
   913         -  assert( &data[pBt->pageSize] == (unsigned char*)pPage );
          919  +  assert( &data[pBt->psAligned] == (unsigned char*)pPage );
   914    920     assert( sqlite3pager_iswriteable(data) );
   915    921     memset(&data[hdr], 0, pBt->usableSize - hdr);
   916    922     data[hdr] = flags;
   917    923     first = hdr + 8 + 4*((flags&PTF_LEAF)==0);
   918    924     memset(&data[hdr+1], 0, 4);
   919    925     data[hdr+7] = 0;
   920    926     put2byte(&data[hdr+5], pBt->usableSize);
................................................................................
   935    941   */
   936    942   static int getPage(Btree *pBt, Pgno pgno, MemPage **ppPage){
   937    943     int rc;
   938    944     unsigned char *aData;
   939    945     MemPage *pPage;
   940    946     rc = sqlite3pager_get(pBt->pPager, pgno, (void**)&aData);
   941    947     if( rc ) return rc;
   942         -  pPage = (MemPage*)&aData[pBt->pageSize];
          948  +  pPage = (MemPage*)&aData[pBt->psAligned];
   943    949     pPage->aData = aData;
   944    950     pPage->pBt = pBt;
   945    951     pPage->pgno = pgno;
   946    952     pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;
   947    953     *ppPage = pPage;
   948    954     return SQLITE_OK;
   949    955   }
................................................................................
   974    980   ** Release a MemPage.  This should be called once for each prior
   975    981   ** call to getPage.
   976    982   */
   977    983   static void releasePage(MemPage *pPage){
   978    984     if( pPage ){
   979    985       assert( pPage->aData );
   980    986       assert( pPage->pBt );
   981         -    assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage );
          987  +    assert( &pPage->aData[pPage->pBt->psAligned]==(unsigned char*)pPage );
   982    988       sqlite3pager_unref(pPage->aData);
   983    989     }
   984    990   }
   985    991   
   986    992   /*
   987    993   ** This routine is called when the reference count for a page
   988    994   ** reaches zero.  We need to unref the pParent pointer when that
   989    995   ** happens.
   990    996   */
   991    997   static void pageDestructor(void *pData, int pageSize){
   992         -  MemPage *pPage = (MemPage*)&((char*)pData)[pageSize];
          998  +  MemPage *pPage = (MemPage*)&((char*)pData)[FORCE_ALIGNMENT(pageSize)];
   993    999     if( pPage->pParent ){
   994   1000       MemPage *pParent = pPage->pParent;
   995   1001       pPage->pParent = 0;
   996   1002       releasePage(pParent);
   997   1003     }
   998   1004     pPage->isInit = 0;
   999   1005   }
................................................................................
  1003   1009   ** so that the cache is restored to its original state at the start of
  1004   1010   ** the transaction, for each page restored this routine is called.
  1005   1011   **
  1006   1012   ** This routine needs to reset the extra data section at the end of the
  1007   1013   ** page to agree with the restored data.
  1008   1014   */
  1009   1015   static void pageReinit(void *pData, int pageSize){
  1010         -  MemPage *pPage = (MemPage*)&((char*)pData)[pageSize];
         1016  +  MemPage *pPage = (MemPage*)&((char*)pData)[FORCE_ALIGNMENT(pageSize)];
  1011   1017     if( pPage->isInit ){
  1012   1018       pPage->isInit = 0;
  1013   1019       initPage(pPage, pPage->pParent);
  1014   1020     }
  1015   1021   }
  1016   1022   
  1017   1023   /*
................................................................................
  1074   1080       nReserve = zDbHeader[20];
  1075   1081       pBt->maxEmbedFrac = zDbHeader[21];
  1076   1082       pBt->minEmbedFrac = zDbHeader[22];
  1077   1083       pBt->minLeafFrac = zDbHeader[23];
  1078   1084       pBt->pageSizeFixed = 1;
  1079   1085     }
  1080   1086     pBt->usableSize = pBt->pageSize - nReserve;
         1087  +  pBt->psAligned = FORCE_ALIGNMENT(pBt->pageSize);
  1081   1088     sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
  1082   1089     *ppBtree = pBt;
  1083   1090     return SQLITE_OK;
  1084   1091   }
  1085   1092   
  1086   1093   /*
  1087   1094   ** Close an open database and invalidate all cursors.
................................................................................
  1144   1151       return SQLITE_READONLY;
  1145   1152     }
  1146   1153     if( nReserve<0 ){
  1147   1154       nReserve = pBt->pageSize - pBt->usableSize;
  1148   1155     }
  1149   1156     if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE ){
  1150   1157       pBt->pageSize = pageSize;
         1158  +    pBt->psAligned = FORCE_ALIGNMENT(pageSize);
  1151   1159       sqlite3pager_set_pagesize(pBt->pPager, pageSize);
  1152   1160     }
  1153   1161     pBt->usableSize = pBt->pageSize - nReserve;
  1154   1162     return SQLITE_OK;
  1155   1163   }
  1156   1164   
  1157   1165   /*
................................................................................
  1195   1203         goto page1_init_failed;
  1196   1204       }
  1197   1205       pBt->pageSize = get2byte(&page1[16]);
  1198   1206       pBt->usableSize = pBt->pageSize - page1[20];
  1199   1207       if( pBt->usableSize<500 ){
  1200   1208         goto page1_init_failed;
  1201   1209       }
         1210  +    pBt->psAligned = FORCE_ALIGNMENT(pBt->pageSize);
  1202   1211       pBt->maxEmbedFrac = page1[21];
  1203   1212       pBt->minEmbedFrac = page1[22];
  1204   1213       pBt->minLeafFrac = page1[23];
  1205   1214     }
  1206   1215   
  1207   1216     /* maxLocal is the maximum amount of payload to store locally for
  1208   1217     ** a cell.  Make sure it is small enough so that at least minFanout
................................................................................
  1244   1253   **
  1245   1254   ** If there is a transaction in progress, this routine is a no-op.
  1246   1255   */
  1247   1256   static void unlockBtreeIfUnused(Btree *pBt){
  1248   1257     if( pBt->inTrans==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
  1249   1258       if( pBt->pPage1->aData==0 ){
  1250   1259         MemPage *pPage = pBt->pPage1;
  1251         -      pPage->aData = &((char*)pPage)[-pBt->pageSize];
         1260  +      pPage->aData = &((char*)pPage)[-pBt->psAligned];
  1252   1261         pPage->pBt = pBt;
  1253   1262         pPage->pgno = 1;
  1254   1263       }
  1255   1264       releasePage(pBt->pPage1);
  1256   1265       pBt->pPage1 = 0;
  1257   1266       pBt->inStmt = 0;
  1258   1267     }
................................................................................
  2669   2678     MemPage *pThis;
  2670   2679     unsigned char *aData;
  2671   2680   
  2672   2681     if( pgno==0 ) return;
  2673   2682     assert( pBt->pPager!=0 );
  2674   2683     aData = sqlite3pager_lookup(pBt->pPager, pgno);
  2675   2684     if( aData ){
  2676         -    pThis = (MemPage*)&aData[pBt->pageSize];
         2685  +    pThis = (MemPage*)&aData[pBt->psAligned];
  2677   2686       assert( pThis->aData==aData );
  2678   2687       if( pThis->isInit ){
  2679   2688         if( pThis->pParent!=pNewParent ){
  2680   2689           if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
  2681   2690           pThis->pParent = pNewParent;
  2682   2691           if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
  2683   2692         }
................................................................................
  2956   2965     /*
  2957   2966     ** Allocate space for memory structures
  2958   2967     */
  2959   2968     mxCellPerPage = MX_CELL(pBt);
  2960   2969     apCell = sqliteMallocRaw( 
  2961   2970          (mxCellPerPage+2)*NB*(sizeof(u8*)+sizeof(int))
  2962   2971        + sizeof(MemPage)*NB
  2963         -     + pBt->pageSize*(5+NB)
         2972  +     + pBt->psAligned*(5+NB)
  2964   2973     );
  2965   2974     if( apCell==0 ){
  2966   2975       return SQLITE_NOMEM;
  2967   2976     }
  2968   2977     szCell = (int*)&apCell[(mxCellPerPage+2)*NB];
  2969   2978     aCopy[0] = (u8*)&szCell[(mxCellPerPage+2)*NB];
  2970   2979     for(i=1; i<NB; i++){
  2971         -    aCopy[i] = &aCopy[i-1][pBt->pageSize+sizeof(MemPage)];
         2980  +    aCopy[i] = &aCopy[i-1][pBt->psAligned+sizeof(MemPage)];
  2972   2981     }
  2973         -  aSpace = &aCopy[NB-1][pBt->pageSize+sizeof(MemPage)];
         2982  +  aSpace = &aCopy[NB-1][pBt->psAligned+sizeof(MemPage)];
  2974   2983     
  2975   2984     /*
  2976   2985     ** Find the cell in the parent page whose left child points back
  2977   2986     ** to pPage.  The "idx" variable is the index of that cell.  If pPage
  2978   2987     ** is the rightmost child of pParent then set idx to pParent->nCell 
  2979   2988     */
  2980   2989     if( pParent->idxShift ){
................................................................................
  3037   3046     /*
  3038   3047     ** Make copies of the content of pPage and its siblings into aOld[].
  3039   3048     ** The rest of this function will use data from the copies rather
  3040   3049     ** that the original pages since the original pages will be in the
  3041   3050     ** process of being overwritten.
  3042   3051     */
  3043   3052     for(i=0; i<nOld; i++){
  3044         -    MemPage *p = apCopy[i] = (MemPage*)&aCopy[i][pBt->pageSize];
  3045         -    p->aData = &((u8*)p)[-pBt->pageSize];
  3046         -    memcpy(p->aData, apOld[i]->aData, pBt->pageSize + sizeof(MemPage));
  3047         -    p->aData = &((u8*)p)[-pBt->pageSize];
         3053  +    MemPage *p = apCopy[i] = (MemPage*)&aCopy[i][pBt->psAligned];
         3054  +    p->aData = &((u8*)p)[-pBt->psAligned];
         3055  +    memcpy(p->aData, apOld[i]->aData, pBt->psAligned + sizeof(MemPage));
         3056  +    p->aData = &((u8*)p)[-pBt->psAligned];
  3048   3057     }
  3049   3058   
  3050   3059     /*
  3051   3060     ** Load pointers to all cells on sibling pages and the divider cells
  3052   3061     ** into the local apCell[] array.  Make copies of the divider cells
  3053   3062     ** into space obtained form aSpace[] and remove the the divider Cells
  3054   3063     ** from pParent.
................................................................................
  3084   3093           */
  3085   3094           dropCell(pParent, nxDiv, sz);
  3086   3095         }else{
  3087   3096           u8 *pTemp;
  3088   3097           szCell[nCell] = sz;
  3089   3098           pTemp = &aSpace[iSpace];
  3090   3099           iSpace += sz;
  3091         -        assert( iSpace<=pBt->pageSize*5 );
         3100  +        assert( iSpace<=pBt->psAligned*5 );
  3092   3101           memcpy(pTemp, apDiv[i], sz);
  3093   3102           apCell[nCell] = pTemp+leafCorrection;
  3094   3103           dropCell(pParent, nxDiv, sz);
  3095   3104           szCell[nCell] -= leafCorrection;
  3096   3105           assert( get4byte(pTemp)==pgnoOld[i] );
  3097   3106           if( !pOld->leaf ){
  3098   3107             assert( leafCorrection==0 );
................................................................................
  3268   3277         }else if( leafData ){
  3269   3278           CellInfo info;
  3270   3279           j--;
  3271   3280           parseCellPtr(pNew, apCell[j], &info);
  3272   3281           pCell = &aSpace[iSpace];
  3273   3282           fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz);
  3274   3283           iSpace += sz;
  3275         -        assert( iSpace<=pBt->pageSize*5 );
         3284  +        assert( iSpace<=pBt->psAligned*5 );
  3276   3285           pTemp = 0;
  3277   3286         }else{
  3278   3287           pCell -= 4;
  3279   3288           pTemp = &aSpace[iSpace];
  3280   3289           iSpace += sz;
  3281         -        assert( iSpace<=pBt->pageSize*5 );
         3290  +        assert( iSpace<=pBt->psAligned*5 );
  3282   3291         }
  3283   3292         insertCell(pParent, nxDiv, pCell, sz, pTemp);
  3284   3293         put4byte(findOverflowCell(pParent,nxDiv), pNew->pgno);
  3285   3294         j++;
  3286   3295         nxDiv++;
  3287   3296       }
  3288   3297     }

Changes to src/pager.c.

    14     14   ** The pager is used to access a database disk file.  It implements
    15     15   ** atomic commit and rollback through the use of a journal file that
    16     16   ** is separate from the database file.  The pager also implements file
    17     17   ** locking to prevent two processes from writing the same database
    18     18   ** file simultaneously, or one process from reading the database while
    19     19   ** another is writing.
    20     20   **
    21         -** @(#) $Id: pager.c,v 1.167 2004/10/05 02:41:43 drh Exp $
           21  +** @(#) $Id: pager.c,v 1.168 2004/10/22 16:22:59 drh Exp $
    22     22   */
    23     23   #include "sqliteInt.h"
    24     24   #include "os.h"
    25     25   #include "pager.h"
    26     26   #include <assert.h>
    27     27   #include <string.h>
    28     28   
................................................................................
   106    106   ** (if it never invokes its busy callback) then the contention will be
   107    107   ** resolved quickly.
   108    108   */
   109    109   #ifndef SQLITE_BUSY_RESERVED_LOCK
   110    110   # define SQLITE_BUSY_RESERVED_LOCK 0
   111    111   #endif
   112    112   
          113  +/*
          114  +** This macro rounds values up so that if the value is an address it
          115  +** is guaranteed to be an address that is aligned to an 8-byte boundary.
          116  +*/
          117  +#define FORCE_ALIGNMENT(X)   (((X)+7)&~7)
          118  +
   113    119   /*
   114    120   ** Each in-memory image of a page begins with the following header.
   115    121   ** This header is only visible to this pager module.  The client
   116    122   ** code that calls pager sees only the data that follows the header.
   117    123   **
   118    124   ** Client code should call sqlite3pager_write() on a page prior to making
   119    125   ** any modifications to that page.  The first time sqlite3pager_write()
................................................................................
   139    145     u8 inJournal;                  /* TRUE if has been written to journal */
   140    146     u8 inStmt;                     /* TRUE if in the statement subjournal */
   141    147     u8 dirty;                      /* TRUE if we need to write back changes */
   142    148     u8 needSync;                   /* Sync journal before writing this page */
   143    149     u8 alwaysRollback;             /* Disable dont_rollback() for this page */
   144    150     short int nRef;                /* Number of users of this page */
   145    151     PgHdr *pDirty;                 /* Dirty pages sorted by PgHdr.pgno */
   146         -  /* pPager->pageSize bytes of page data follow this header */
          152  +  /* pPager->psAligned bytes of page data follow this header */
   147    153     /* Pager.nExtra bytes of local data follow the page data */
   148    154   };
   149    155   
   150    156   /*
   151    157   ** For an in-memory only database, some extra information is recorded about
   152    158   ** each page so that changes can be rolled back.  (Journal files are not
   153    159   ** used for in-memory databases.)  The following information is added to
................................................................................
   175    181   
   176    182   /*
   177    183   ** Convert a pointer to a PgHdr into a pointer to its data
   178    184   ** and back again.
   179    185   */
   180    186   #define PGHDR_TO_DATA(P)  ((void*)(&(P)[1]))
   181    187   #define DATA_TO_PGHDR(D)  (&((PgHdr*)(D))[-1])
   182         -#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize])
          188  +#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->psAligned])
   183    189   #define PGHDR_TO_HIST(P,PGR)  \
   184         -            ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
          190  +            ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->psAligned+(PGR)->nExtra])
   185    191   
   186    192   /*
   187    193   ** How big to make the hash table used for locating in-memory pages
   188    194   ** by page number.
   189    195   */
   190    196   #define N_PG_HASH 2048
   191    197   
................................................................................
   210    216     int nRec;                   /* Number of pages written to the journal */
   211    217     u32 cksumInit;              /* Quasi-random value added to every checksum */
   212    218     int stmtNRec;               /* Number of records in stmt subjournal */
   213    219     int nExtra;                 /* Add this many bytes to each in-memory page */
   214    220     void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
   215    221     void (*xReiniter)(void*,int);   /* Call this routine when reloading pages */
   216    222     int pageSize;               /* Number of bytes in a page */
          223  +  int psAligned;              /* pageSize rounded up to a multiple of 8 */
   217    224     int nPage;                  /* Total number of in-memory pages */
   218    225     int nRef;                   /* Number of in-memory pages with PgHdr.nRef>0 */
   219    226     int mxPage;                 /* Maximum number of pages to hold in cache */
   220    227     int nHit, nMiss, nOvfl;     /* Cache hits, missing, and LRU overflows */
   221    228     void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
   222    229     void *pCodecArg;            /* First argument to xCodec() */
   223    230     u8 journalOpen;             /* True if journal file descriptors is valid */
................................................................................
  1499   1506     pPager->journalOpen = 0;
  1500   1507     pPager->useJournal = useJournal && !memDb;
  1501   1508     pPager->stmtOpen = 0;
  1502   1509     pPager->stmtInUse = 0;
  1503   1510     pPager->nRef = 0;
  1504   1511     pPager->dbSize = memDb-1;
  1505   1512     pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
         1513  +  pPager->psAligned = FORCE_ALIGNMENT(pPager->pageSize);
  1506   1514     pPager->stmtSize = 0;
  1507   1515     pPager->stmtJSize = 0;
  1508   1516     pPager->nPage = 0;
  1509   1517     pPager->mxPage = 100;
  1510   1518     pPager->state = PAGER_UNLOCK;
  1511   1519     pPager->errMask = 0;
  1512   1520     pPager->tempFile = tempFile;
................................................................................
  1514   1522     pPager->readOnly = readOnly;
  1515   1523     pPager->needSync = 0;
  1516   1524     pPager->noSync = pPager->tempFile || !useJournal;
  1517   1525     pPager->fullSync = (pPager->noSync?0:1);
  1518   1526     pPager->pFirst = 0;
  1519   1527     pPager->pFirstSynced = 0;
  1520   1528     pPager->pLast = 0;
  1521         -  pPager->nExtra = nExtra;
         1529  +  pPager->nExtra = FORCE_ALIGNMENT(nExtra);
  1522   1530     pPager->sectorSize = PAGER_SECTOR_SIZE;
  1523   1531     pPager->pBusyHandler = 0;
  1524   1532     memset(pPager->aHash, 0, sizeof(pPager->aHash));
  1525   1533     *ppPager = pPager;
  1526   1534     return SQLITE_OK;
  1527   1535   }
  1528   1536   
................................................................................
  1560   1568   ** Set the page size.
  1561   1569   **
  1562   1570   ** The page size must only be changed when the cache is empty.
  1563   1571   */
  1564   1572   void sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
  1565   1573     assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE );
  1566   1574     pPager->pageSize = pageSize;
         1575  +  pPager->psAligned = FORCE_ALIGNMENT(pageSize);
  1567   1576   }
  1568   1577   
  1569   1578   /*
  1570   1579   ** Read the first N bytes from the beginning of the file into memory
  1571   1580   ** that pDest points to.  No error checking is done.
  1572   1581   */
  1573   1582   void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
................................................................................
  2129   2138     }
  2130   2139     if( pPg==0 ){
  2131   2140       /* The requested page is not in the page cache. */
  2132   2141       int h;
  2133   2142       pPager->nMiss++;
  2134   2143       if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || pPager->memDb ){
  2135   2144         /* Create a new page */
  2136         -      pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize 
         2145  +      pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->psAligned
  2137   2146                                 + sizeof(u32) + pPager->nExtra
  2138   2147                                 + pPager->memDb*sizeof(PgHistory) );
  2139   2148         if( pPg==0 ){
  2140   2149           if( !pPager->memDb ){
  2141   2150             pager_unwritelock(pPager);
  2142   2151           }
  2143   2152           pPager->errMask |= PAGER_ERR_MEM;

Changes to test/pagesize.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.
    12     12   # This file implements tests for the page_size PRAGMA.
    13     13   #
    14         -# $Id: pagesize.test,v 1.3 2004/09/05 00:33:44 drh Exp $
           14  +# $Id: pagesize.test,v 1.4 2004/10/22 16:22:59 drh Exp $
    15     15   
    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   
    20     20   do_test pagesize-1.1 {
    21     21     execsql {PRAGMA page_size}
................................................................................
    57     57       PRAGMA page_size=65537;
    58     58       PRAGMA page_size;
    59     59     }
    60     60   } 8192
    61     61     
    62     62   
    63     63   
    64         -foreach PGSZ {512 2000 2048 3000 4096} {
           64  +foreach PGSZ {512 515 516 751 2000 2001 2002 2003 2004 2048 3000 4096} {
    65     65     do_test pagesize-2.$PGSZ.1 {
    66     66       db close
    67     67       file delete -force test.db
    68     68       sqlite3 db test.db
    69     69       execsql "PRAGMA page_size=$PGSZ"
    70     70       execsql {
    71     71         CREATE TABLE t1(x);