?? btree.c
字號:
moveToParent(pCur); pPage = pCur->pPage; }while( pCur->idx>=pPage->nCell ); *pRes = 0; return SQLITE_OK; } *pRes = 0; if( pPage->u.hdr.rightChild==0 ){ return SQLITE_OK; } rc = moveToLeftmost(pCur); return rc;}/*** Step the cursor to the back to the previous entry in the database. If** successful then set *pRes=0. If the cursor** was already pointing to the first entry in the database before** this routine was called, then set *pRes=1.*/static int fileBtreePrevious(BtCursor *pCur, int *pRes){ int rc; Pgno pgno; MemPage *pPage; pPage = pCur->pPage; if( pPage==0 ){ *pRes = 1; return SQLITE_ABORT; } assert( pPage->isInit ); assert( pCur->eSkip!=SKIP_INVALID ); if( pPage->nCell==0 ){ *pRes = 1; return SQLITE_OK; } if( pCur->eSkip==SKIP_PREV ){ pCur->eSkip = SKIP_NONE; *pRes = 0; return SQLITE_OK; } pCur->eSkip = SKIP_NONE; assert( pCur->idx>=0 ); if( (pgno = pPage->apCell[pCur->idx]->h.leftChild)!=0 ){ rc = moveToChild(pCur, pgno); if( rc ) return rc; rc = moveToRightmost(pCur); }else{ while( pCur->idx==0 ){ if( pPage->pParent==0 ){ if( pRes ) *pRes = 1; return SQLITE_OK; } moveToParent(pCur); pPage = pCur->pPage; } pCur->idx--; rc = SQLITE_OK; } *pRes = 0; return rc;}/*** Allocate a new page from the database file.**** The new page is marked as dirty. (In other words, sqlitepager_write()** has already been called on the new page.) The new page has also** been referenced and the calling routine is responsible for calling** sqlitepager_unref() on the new page when it is done.**** SQLITE_OK is returned on success. Any other return value indicates** an error. *ppPage and *pPgno are undefined in the event of an error.** Do not invoke sqlitepager_unref() on *ppPage if an error is returned.**** If the "nearby" parameter is not 0, then a (feeble) effort is made to ** locate a page close to the page number "nearby". This can be used in an** attempt to keep related pages close to each other in the database file,** which in turn can make database access faster.*/static int allocatePage(Btree *pBt, MemPage **ppPage, Pgno *pPgno, Pgno nearby){ PageOne *pPage1 = pBt->page1; int rc; if( pPage1->freeList ){ OverflowPage *pOvfl; FreelistInfo *pInfo; rc = sqlitepager_write(pPage1); if( rc ) return rc; SWAB_ADD(pBt, pPage1->nFree, -1); rc = sqlitepager_get(pBt->pPager, SWAB32(pBt, pPage1->freeList), (void**)&pOvfl); if( rc ) return rc; rc = sqlitepager_write(pOvfl); if( rc ){ sqlitepager_unref(pOvfl); return rc; } pInfo = (FreelistInfo*)pOvfl->aPayload; if( pInfo->nFree==0 ){ *pPgno = SWAB32(pBt, pPage1->freeList); pPage1->freeList = pOvfl->iNext; *ppPage = (MemPage*)pOvfl; }else{ int closest, n; n = SWAB32(pBt, pInfo->nFree); if( n>1 && nearby>0 ){ int i, dist; closest = 0; dist = SWAB32(pBt, pInfo->aFree[0]) - nearby; if( dist<0 ) dist = -dist; for(i=1; i<n; i++){ int d2 = SWAB32(pBt, pInfo->aFree[i]) - nearby; if( d2<0 ) d2 = -d2; if( d2<dist ) closest = i; } }else{ closest = 0; } SWAB_ADD(pBt, pInfo->nFree, -1); *pPgno = SWAB32(pBt, pInfo->aFree[closest]); pInfo->aFree[closest] = pInfo->aFree[n-1]; rc = sqlitepager_get(pBt->pPager, *pPgno, (void**)ppPage); sqlitepager_unref(pOvfl); if( rc==SQLITE_OK ){ sqlitepager_dont_rollback(*ppPage); rc = sqlitepager_write(*ppPage); } } }else{ *pPgno = sqlitepager_pagecount(pBt->pPager) + 1; rc = sqlitepager_get(pBt->pPager, *pPgno, (void**)ppPage); if( rc ) return rc; rc = sqlitepager_write(*ppPage); } return rc;}/*** Add a page of the database file to the freelist. Either pgno or** pPage but not both may be 0. **** sqlitepager_unref() is NOT called for pPage.*/static int freePage(Btree *pBt, void *pPage, Pgno pgno){ PageOne *pPage1 = pBt->page1; OverflowPage *pOvfl = (OverflowPage*)pPage; int rc; int needUnref = 0; MemPage *pMemPage; if( pgno==0 ){ assert( pOvfl!=0 ); pgno = sqlitepager_pagenumber(pOvfl); } assert( pgno>2 ); assert( sqlitepager_pagenumber(pOvfl)==pgno ); pMemPage = (MemPage*)pPage; pMemPage->isInit = 0; if( pMemPage->pParent ){ sqlitepager_unref(pMemPage->pParent); pMemPage->pParent = 0; } rc = sqlitepager_write(pPage1); if( rc ){ return rc; } SWAB_ADD(pBt, pPage1->nFree, 1); if( pPage1->nFree!=0 && pPage1->freeList!=0 ){ OverflowPage *pFreeIdx; rc = sqlitepager_get(pBt->pPager, SWAB32(pBt, pPage1->freeList), (void**)&pFreeIdx); if( rc==SQLITE_OK ){ FreelistInfo *pInfo = (FreelistInfo*)pFreeIdx->aPayload; int n = SWAB32(pBt, pInfo->nFree); if( n<(sizeof(pInfo->aFree)/sizeof(pInfo->aFree[0])) ){ rc = sqlitepager_write(pFreeIdx); if( rc==SQLITE_OK ){ pInfo->aFree[n] = SWAB32(pBt, pgno); SWAB_ADD(pBt, pInfo->nFree, 1); sqlitepager_unref(pFreeIdx); sqlitepager_dont_write(pBt->pPager, pgno); return rc; } } sqlitepager_unref(pFreeIdx); } } if( pOvfl==0 ){ assert( pgno>0 ); rc = sqlitepager_get(pBt->pPager, pgno, (void**)&pOvfl); if( rc ) return rc; needUnref = 1; } rc = sqlitepager_write(pOvfl); if( rc ){ if( needUnref ) sqlitepager_unref(pOvfl); return rc; } pOvfl->iNext = pPage1->freeList; pPage1->freeList = SWAB32(pBt, pgno); memset(pOvfl->aPayload, 0, OVERFLOW_SIZE); if( needUnref ) rc = sqlitepager_unref(pOvfl); return rc;}/*** Erase all the data out of a cell. This involves returning overflow** pages back the freelist.*/static int clearCell(Btree *pBt, Cell *pCell){ Pager *pPager = pBt->pPager; OverflowPage *pOvfl; Pgno ovfl, nextOvfl; int rc; if( NKEY(pBt, pCell->h) + NDATA(pBt, pCell->h) <= MX_LOCAL_PAYLOAD ){ return SQLITE_OK; } ovfl = SWAB32(pBt, pCell->ovfl); pCell->ovfl = 0; while( ovfl ){ rc = sqlitepager_get(pPager, ovfl, (void**)&pOvfl); if( rc ) return rc; nextOvfl = SWAB32(pBt, pOvfl->iNext); rc = freePage(pBt, pOvfl, ovfl); if( rc ) return rc; sqlitepager_unref(pOvfl); ovfl = nextOvfl; } return SQLITE_OK;}/*** Create a new cell from key and data. Overflow pages are allocated as** necessary and linked to this cell. */static int fillInCell( Btree *pBt, /* The whole Btree. Needed to allocate pages */ Cell *pCell, /* Populate this Cell structure */ const void *pKey, int nKey, /* The key */ const void *pData,int nData /* The data */){ OverflowPage *pOvfl, *pPrior; Pgno *pNext; int spaceLeft; int n, rc; int nPayload; const char *pPayload; char *pSpace; Pgno nearby = 0; pCell->h.leftChild = 0; pCell->h.nKey = SWAB16(pBt, nKey & 0xffff); pCell->h.nKeyHi = nKey >> 16; pCell->h.nData = SWAB16(pBt, nData & 0xffff); pCell->h.nDataHi = nData >> 16; pCell->h.iNext = 0; pNext = &pCell->ovfl; pSpace = pCell->aPayload; spaceLeft = MX_LOCAL_PAYLOAD; pPayload = pKey; pKey = 0; nPayload = nKey; pPrior = 0; while( nPayload>0 ){ if( spaceLeft==0 ){ rc = allocatePage(pBt, (MemPage**)&pOvfl, pNext, nearby); if( rc ){ *pNext = 0; }else{ nearby = *pNext; } if( pPrior ) sqlitepager_unref(pPrior); if( rc ){ clearCell(pBt, pCell); return rc; } if( pBt->needSwab ) *pNext = swab32(*pNext); pPrior = pOvfl; spaceLeft = OVERFLOW_SIZE; pSpace = pOvfl->aPayload; pNext = &pOvfl->iNext; } n = nPayload; if( n>spaceLeft ) n = spaceLeft; memcpy(pSpace, pPayload, n); nPayload -= n; if( nPayload==0 && pData ){ pPayload = pData; nPayload = nData; pData = 0; }else{ pPayload += n; } spaceLeft -= n; pSpace += n; } *pNext = 0; if( pPrior ){ sqlitepager_unref(pPrior); } return SQLITE_OK;}/*** Change the MemPage.pParent pointer on the page whose number is** given in the second argument so that MemPage.pParent holds the** pointer in the third argument.*/static void reparentPage(Pager *pPager, Pgno pgno, MemPage *pNewParent,int idx){ MemPage *pThis; if( pgno==0 ) return; assert( pPager!=0 ); pThis = sqlitepager_lookup(pPager, pgno); if( pThis && pThis->isInit ){ if( pThis->pParent!=pNewParent ){ if( pThis->pParent ) sqlitepager_unref(pThis->pParent); pThis->pParent = pNewParent; if( pNewParent ) sqlitepager_ref(pNewParent); } pThis->idxParent = idx; sqlitepager_unref(pThis); }}/*** Reparent all children of the given page to be the given page.** In other words, for every child of pPage, invoke reparentPage()** to make sure that each child knows that pPage is its parent.**** This routine gets called after you memcpy() one page into** another.*/static void reparentChildPages(Btree *pBt, MemPage *pPage){ int i; Pager *pPager = pBt->pPager; for(i=0; i<pPage->nCell; i++){ reparentPage(pPager, SWAB32(pBt, pPage->apCell[i]->h.leftChild), pPage, i); } reparentPage(pPager, SWAB32(pBt, pPage->u.hdr.rightChild), pPage, i); pPage->idxShift = 0;}/*** Remove the i-th cell from pPage. This routine effects pPage only.** The cell content is not freed or deallocated. It is assumed that** the cell content has been copied someplace else. This routine just** removes the reference to the cell from pPage.**** "sz" must be the number of bytes in the cell.**** Do not bother maintaining the integrity of the linked list of Cells.** Only the pPage->apCell[] array is important. The relinkCellList() ** routine will be called soon after this routine in order to rebuild ** the linked list.*/static void dropCell(Btree *pBt, MemPage *pPage, int idx, int sz){ int j; assert( idx>=0 && idx<pPage->nCell ); assert( sz==cellSize(pBt, pPage->apCell[idx]) ); assert( sqlitepager_iswriteable(pPage) ); freeSpace(pBt, pPage, Addr(pPage->apCell[idx]) - Addr(pPage), sz); for(j=idx; j<pPage->nCell-1; j++){ pPage->apCell[j] = pPage->apCell[j+1]; } pPage->nCell--; pPage->idxShift = 1;}/*** Insert a new cell on pPage at cell index "i". pCell points to the** content of the cell.**** If the cell content will fit on the page, then put it there. If it** will not fit, then just make pPage->apCell[i] point to the content** and set pPage->isOverfull. **** Do not bother maintaining the integrity of the linked list of Cells.** Only the pPage->apCell[] array is important. The relinkCellList() ** routine will be called soon after this routine in order to rebuild ** the linked list.*/static void insertCell(Btree *pBt, MemPage *pPage, int i, Cell *pCell, int sz){ int idx, j; assert( i>=0 && i<=pPage->nCell ); assert( sz==cellSize(pBt, pCell) ); assert( sqlitepager_iswriteable(pPage) ); idx = allocateSpace(pBt, pPage, sz); for(j=pPage->nCell; j>i; j--){ pPage->apCell[j] = pPage->apCell[j-1]; } pPage->nCell++; if( idx<=0 ){ pPage->isOverfull = 1; pPage->apCell[i] = pCell; }else{ memcpy(&pPage->u.aDisk[idx], pCell, sz); pPage->apCell[i] = (Cell*)&pPage->u.aDisk[idx]; } pPage->idxShift = 1;}/*** Rebuild the linked list of cells on a page so that the cells** occur in the order specified by the pPage->apCell[] array. ** Invoke this routine once to repair damage after one or more** invocations of either insertCell() or dropCell().*/static void relinkCellList(Btree *pBt, MemPage *pPage){ int i; u16 *pIdx; assert(
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -