diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 118 |
1 files changed, 63 insertions, 55 deletions
diff --git a/src/btree.c b/src/btree.c index 252a433bd..e128d7dbc 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.107 2004/05/02 21:12:19 drh Exp $ +** $Id: btree.c,v 1.108 2004/05/03 19:49:33 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -467,7 +467,7 @@ static int allocateSpace(MemPage *pPage, int nByte){ if( nByte<4 ) nByte = 4; if( pPage->nFree<nByte || pPage->isOverfull ) return 0; hdr = pPage->hdrOffset; - if( data[hdr+5]>=252 ){ + if( data[hdr+5]>=60 ){ defragmentPage(pPage); } addr = hdr+1; @@ -1098,7 +1098,7 @@ int sqlite3BtreeBeginStmt(Btree *pBt){ if( !pBt->inTrans || pBt->inStmt ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } - rc = pBt->readOnly ? SQLITE_OK : sqlitepager_ckpt_begin(pBt->pPager); + rc = pBt->readOnly ? SQLITE_OK : sqlitepager_stmt_begin(pBt->pPager); pBt->inStmt = 1; return rc; } @@ -1111,7 +1111,7 @@ int sqlite3BtreeBeginStmt(Btree *pBt){ int sqlite3BtreeCommitStmt(Btree *pBt){ int rc; if( pBt->inStmt && !pBt->readOnly ){ - rc = sqlitepager_ckpt_commit(pBt->pPager); + rc = sqlitepager_stmt_commit(pBt->pPager); }else{ rc = SQLITE_OK; } @@ -1131,7 +1131,7 @@ int sqlite3BtreeRollbackStmt(Btree *pBt){ int rc; BtCursor *pCur; if( pBt->inStmt==0 || pBt->readOnly ) return SQLITE_OK; - rc = sqlitepager_ckpt_rollback(pBt->pPager); + rc = sqlitepager_stmt_rollback(pBt->pPager); for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ MemPage *pPage = pCur->pPage; if( pPage && !pPage->isInit ){ @@ -1991,7 +1991,7 @@ static int allocatePage(Btree *pBt, MemPage **ppPage, Pgno *pPgno, Pgno nearby){ pPage1 = pBt->pPage1; n = get4byte(&pPage1->aData[36]); if( n>0 ){ - /* There exists pages on the freelist. Reuse one of those pages. */ + /* There are pages on the freelist. Reuse one of those pages. */ MemPage *pTrunk; rc = sqlitepager_write(pPage1->aData); if( rc ) return rc; @@ -2133,28 +2133,16 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){ } /* -** Compute the number of bytes required by a cell header. Fill in -** the nData and nKey values of the header that pHeader points to. -*/ -static int makeCellHeader( - MemPage *pPage, /* The page that will contain the cell */ - u64 nKey, /* Size of key, or the key value if intKey */ - int nData, /* Size of data. Ignored for zerodata */ - unsigned char *pHeader /* Write header bytes here */ -){ - int n = 2; - if( !pPage->leaf ) n += 4; - if( !pPage->zeroData ){ - n += putVarint(&pHeader[n], nData); - } - n += putVarint(&pHeader[n], nKey); - return n; -} - -/* -** Fill in the payload section of a cell into the space provided. If -** the payload will not completely fit in the cell, allocate additional -** overflow pages and fill them in. +** Create the byte sequence used to represent a cell on page pPage +** and write that byte sequence into pCell[]. Overflow pages are +** allocated and filled in as necessary. The calling procedure +** is responsible for making sure sufficient space has been allocated +** for pCell[]. +** +** Note that pCell does not necessary need to point to the pPage->aData +** area. pCell might point to some temporary storage. The cell will +** be constructed in this temporary area then copied into pPage->aData +** later. */ static int fillInCell( MemPage *pPage, /* The page that contains the cell */ @@ -2174,12 +2162,25 @@ static int fillInCell( Pgno pgnoOvfl = 0; int nHeader; - nHeader = makeCellHeader(pPage, pCell, nKey, nData); + /* Fill in the header. */ + nHeader = 2; + if( !pPage->leaf ){ + nHeader += 4; + } + if( !pPage->zeroData ){ + nHeader += putVarint(&pCell[nHeader], nData); + } + nHeader += putVarint(&pCell[nHeader], nKey); + + /* Fill in the payload */ + if( pPage->zeroData ){ + nData = 0; + } nPayload = nData; if( pPage->intKey ){ pSrc = pData; nSrc = nData; - nSrc2 = 0; + nData = 0; }else{ nPayload += nKey; pSrc = pKey; @@ -2354,10 +2355,12 @@ static void relinkCellList(MemPage *pPage){ } /* -** Make a copy of the contents of pFrom into pTo. The pFrom->aCell[] +** Move the content of the page at pFrom over to pTo. The pFrom->aCell[] ** pointers that point into pFrom->aData[] must be adjusted to point ** into pTo->aData[] instead. But some pFrom->aCell[] entries might ** not point to pFrom->aData[]. Those are unchanged. +** +** Over this operation completes, the meta data for pFrom is zeroed. */ static void copyPage(MemPage *pTo, MemPage *pFrom){ uptr from, to; @@ -2368,23 +2371,18 @@ static void copyPage(MemPage *pTo, MemPage *pFrom){ assert( pTo->hdrOffset==0 ); ofst = pFrom->hdrOffset; pageSize = pTo->pBt->pageSize; - memcpy(pTo->aData, &pFrom->aData[ofst], pageSize - ofst); - pTo->pParent = 0; - pTo->isInit = 1; - resizeCellArray(pTo, pFrom->nCell); - pTo->nCell = pFrom->nCell; - pTo->nFree = pFrom->nFree + ofst; + sqliteFree(pTo->aCell); + memcpy(pTo->aData, &pFrom->aData[ofst], pageSize - ofst + sizeof(MemPage)); + memset(pFrom, 0, sizeof(MemPage)); assert( pTo->aData[5]<155 ); pTo->aData[5] += ofst; pTo->isOverfull = pFrom->isOverfull; to = Addr(pTo->aData); - from = Addr(pFrom->aData); + from = Addr(&pFrom->aData[ofst]); for(i=0; i<pTo->nCell; i++){ - uptr x = Addr(pFrom->aCell[i]); - if( x>from && x<from+pageSize ){ + uptr x = Addr(pTo->aCell[i]); + if( x>from && x<from+pageSize-ofst ){ *((uptr*)&pTo->aCell[i]) = x + to - from; - }else{ - pTo->aCell[i] = pFrom->aCell[i]; } } } @@ -2451,6 +2449,9 @@ static int balance(MemPage *pPage){ int nxDiv; /* Next divider slot in pParent->apCell[] */ int rc; /* The return code */ int iCur; /* apCell[iCur] is the cell of the cursor */ + int leafCorrection; /* 4 if pPage is a leaf. 0 if not */ + int usableSpace; /* Bytes in pPage beyond the header */ + int pageFlags; /* Value of pPage->aData[0] */ MemPage *pOldCurPage; /* The cursor originally points to this page */ int subtotal; /* Subtotal of bytes in cells on one page */ MemPage *apOld[NB]; /* pPage and up to two siblings */ @@ -2630,6 +2631,8 @@ static int balance(MemPage *pPage){ rc = initPage(apOld[i], pParent); if( rc ) goto balance_cleanup; apOld[i]->idxParent = k; + apCopy[i] = 0; + assert( i==nOld ); nOld++; } @@ -2844,12 +2847,16 @@ static int balance(MemPage *pPage){ */ balance_cleanup: for(i=0; i<nOld; i++){ - if( apOld[i]!=0 ) sqlitepager_unref(apOld[i]->aData); + releasePage(apOld[i]); + if( apCopy[i] ){ + releasePage(apCopy[i]->pParent); + sqliteFree(apCopy[i]->aCell); + } } for(i=0; i<nNew; i++){ - sqlitepager_unref(apNew[i]->aData); + releasePage(apNew[i]); } - sqlitepager_unref(pParent->aData); + releasePage(pParent); return rc; } @@ -2874,8 +2881,9 @@ static int checkReadLocks(BtCursor *pCur){ for(p=pCur->pShared; p!=pCur; p=p->pShared){ assert( p ); assert( p->pgnoRoot==pCur->pgnoRoot ); + assert( p->pPage->pgno==sqlitepager_pagenumber(p->pPage->aData); if( p->wrFlag==0 ) return SQLITE_LOCKED; - if( sqlitepager_pagenumber(p->pPage)!=p->pgnoRoot ){ + if( p->pPage->pgno!=p->pgnoRoot ){ moveToRoot(p); } } @@ -2885,7 +2893,7 @@ static int checkReadLocks(BtCursor *pCur){ /* ** Insert a new record into the BTree. The key is given by (pKey,nKey) ** and the data is given by (pData,nData). The cursor is used only to -** define what database the record should be inserted into. The cursor +** define what table the record should be inserted into. The cursor ** is left pointing at a random location. ** ** For an INTKEY table, only the nKey value of the key is used. pKey is @@ -2920,9 +2928,8 @@ int sqlite3BtreeInsert( rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc); if( rc ) return rc; pPage = pCur->pPage; - assert( nData==0 || pPage->zeroData!=0 ); assert( pPage->isInit ); - rc = sqlitepager_write(pPage); + rc = sqlitepager_write(pPage->aData); if( rc ) return rc; rc = fillInCell(pPage, &newCell, pKey, nKey, pData, nData, &szNew); if( rc ) return rc; @@ -2982,7 +2989,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ if( checkReadLocks(pCur) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } - rc = sqlitepager_write(pPage); + rc = sqlitepager_write(pPage->aData); if( rc ) return rc; pCell = pPage->aCell[pCur->idx]; if( !pPage->leaf ){ @@ -3007,7 +3014,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ if( rc!=SQLITE_NOMEM ) rc = SQLITE_CORRUPT; return rc; } - rc = sqlitepager_write(leafCur.pPage); + rc = sqlitepager_write(leafCur.pPage->aData); if( rc ) return rc; dropCell(pPage, pCur->idx, cellSize(pPage, pCell)); pNext = leafCur.pPage->aCell[leafCur.idx]; @@ -3052,7 +3059,7 @@ int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){ if( rc ) return rc; assert( sqlitepager_iswriteable(pRoot->aData) ); zeroPage(pBt, pRoot); - sqlitepager_unref(pRoot); + sqlitepager_unref(pRoot->aData); *piTable = (int)pgnoRoot; return SQLITE_OK; } @@ -3276,7 +3283,7 @@ static int fileBtreePageDump(Btree *pBt, int pgno, int recursive){ } fileBtreePageDump(pBt, get4byte(&pPage->aData[hdrOffset+6]), 1); } - sqlitepager_unref(pPage); + sqlitepager_unref(pPage->aData); return SQLITE_OK; } #endif @@ -3302,7 +3309,8 @@ static int fileBtreeCursorDump(BtCursor *pCur, int *aResult){ MemPage *pPage = pCur->pPage; Btree *pBt = pCur->pBt; assert( pPage->isInit ); - aResult[0] = sqlitepager_pagenumber(pPage); + aResult[0] = sqlitepager_pagenumber(pPage->aData); + assert( aResult[0]==pPage->pgno ); aResult[1] = pCur->idx; aResult[2] = pPage->nCell; if( pCur->idx>=0 && pCur->idx<pPage->nCell ){ @@ -3492,7 +3500,7 @@ static int checkTreePage( if( (rc = initPage(pPage, pParent))!=0 ){ sprintf(zMsg, "initPage() returns error code %d", rc); checkAppendMsg(pCheck, zContext, zMsg); - sqlitepager_unref(pPage); + releasePage(pPage); return 0; } |