Fix alignment problems in btree and pager and allow page sizes that are
not a multiple of 8. (CVS 2026) FossilOrigin-Name: 0539c2d2b8e16efcbe4db3afeae9c7b426e11b05
This commit is contained in:
parent
6138df56e7
commit
887dc4c275
16
manifest
16
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
|
||||
|
@ -1 +1 @@
|
||||
370ca539506a431dbe77dcb644215886760f34e9
|
||||
0539c2d2b8e16efcbe4db3afeae9c7b426e11b05
|
49
src/btree.c
49
src/btree.c
@ -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
|
||||
@ -211,6 +211,11 @@
|
||||
#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);
|
||||
|
21
src/pager.c
21
src/pager.c
@ -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"
|
||||
@ -110,6 +110,12 @@
|
||||
# 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 ){
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user