Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add temporary code to record and report on the set of b-tree pages read and written by the current transaction. This is likely still buggy. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | transaction-pages |
Files: | files | file ages | folders |
SHA1: |
2a8f6c890cfa5f61b491ddf8f560b6ba |
User & Date: | dan 2017-01-18 20:14:50.383 |
Context
2017-01-19
| ||
11:52 | Add test cases for the instrumentation on this branch. Fix some OOM handling issues in the same. (Leaf check-in: 50ca94b919 user: dan tags: transaction-pages) | |
2017-01-18
| ||
20:14 | Add temporary code to record and report on the set of b-tree pages read and written by the current transaction. This is likely still buggy. (check-in: 2a8f6c890c user: dan tags: transaction-pages) | |
2017-01-17
| ||
10:41 | Fix a problem that could cause a spurious SQLITE_NOMEM error when attempting to resume an RBU operation if the previous client failed right after completing the incremental checkpoint. Also a "cannot vacuum wal db" error that could occur when resuming an RBU vacuum if an error (OOM or IO error) occurs during the incremental checkpoint. (check-in: 681d96eb82 user: dan tags: trunk) | |
Changes
Changes to src/bitvec.c.
︙ | ︙ | |||
288 289 290 291 292 293 294 295 296 297 298 299 300 301 | /* ** Return the value of the iSize parameter specified when Bitvec *p ** was created. */ u32 sqlite3BitvecSize(Bitvec *p){ return p->iSize; } #ifndef SQLITE_UNTESTABLE /* ** Let V[] be an array of unsigned characters sufficient to hold ** up to N bits. Let I be an integer between 0 and N. 0<=I<N. ** Then the following macros can be used to set, clear, or test ** individual bits within V. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | /* ** Return the value of the iSize parameter specified when Bitvec *p ** was created. */ u32 sqlite3BitvecSize(Bitvec *p){ return p->iSize; } int bitvecAppendArrayElem(int *pnAlloc, int *pnElem, u32 **paElem, u32 iNew){ if( *pnElem==*pnAlloc ){ int nNew = *pnAlloc ? (*pnAlloc)*2 : 128; u32 *aNew; aNew = sqlite3_realloc(*paElem, nNew*sizeof(u32)); if( aNew==0 ){ sqlite3_free(*paElem); *paElem = 0; return SQLITE_NOMEM; } *paElem = aNew; *pnAlloc = nNew; } (*paElem)[(*pnElem)++] = iNew; return SQLITE_OK; } #ifdef SQLITE_ENABLE_TRANSACTION_PAGES int bitvecToArray(Bitvec *p, int iOff, int *pnAlloc, int *pnElem, u32 **paElem){ int rc = SQLITE_OK; int i; if( p->iDivisor ){ for(i=0; rc==SQLITE_OK && i<BITVEC_NPTR; i++){ if( p->u.apSub[i] ){ int iOff2 = iOff + i*p->iDivisor; rc = bitvecToArray(p->u.apSub[i], iOff2, pnAlloc, pnElem, paElem); } } }else{ if( p->iSize<=BITVEC_NBIT ){ for(i=0; rc==SQLITE_OK && i<BITVEC_NBIT; i++){ if( p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))) ){ rc = bitvecAppendArrayElem(pnAlloc, pnElem, paElem, i+iOff); } } }else{ for(i=0; rc==SQLITE_OK && i<BITVEC_NINT; i++){ u32 iVal = p->u.aHash[i]; if( iVal ){ rc = bitvecAppendArrayElem(pnAlloc, pnElem, paElem, iVal-1+iOff); } } } } return rc; } int sqlite3BitvecToArray(Bitvec *p, int *pnElem, u32 **paElem){ int nAlloc = 0; *pnElem = 0; *paElem = 0; return bitvecToArray(p, 1, &nAlloc, pnElem, paElem); } #endif #ifndef SQLITE_UNTESTABLE /* ** Let V[] be an array of unsigned characters sufficient to hold ** up to N bits. Let I be an integer between 0 and N. 0<=I<N. ** Then the following macros can be used to set, clear, or test ** individual bits within V. |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 | /* If obtaining a child page for a cursor, we must verify that the page is ** compatible with the root page. */ if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ rc = SQLITE_CORRUPT_BKPT; releasePage(*ppPage); goto getAndInitPage_error; } return SQLITE_OK; getAndInitPage_error: if( pCur ) pCur->iPage--; testcase( pgno==0 ); assert( pgno!=0 || rc==SQLITE_CORRUPT ); return rc; | > > > > > > > > > > > > > | 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 | /* If obtaining a child page for a cursor, we must verify that the page is ** compatible with the root page. */ if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ rc = SQLITE_CORRUPT_BKPT; releasePage(*ppPage); goto getAndInitPage_error; } #ifdef SQLITE_ENABLE_TRANSACTION_PAGES if( pBt->inTransaction==TRANS_WRITE && pgno<=sqlite3BitvecSize(pBt->pBtRead) ){ rc = sqlite3BitvecSet(pBt->pBtRead, pgno); if( rc!=SQLITE_OK ){ releasePage(*ppPage); goto getAndInitPage_error; } } #endif return SQLITE_OK; getAndInitPage_error: if( pCur ) pCur->iPage--; testcase( pgno==0 ); assert( pgno!=0 || rc==SQLITE_CORRUPT ); return rc; |
︙ | ︙ | |||
3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 | if( rc==SQLITE_OK ){ put4byte(&pPage1->aData[28], pBt->nPage); } } } } trans_begun: if( rc==SQLITE_OK && wrflag ){ /* This call makes sure that the pager has the correct number of ** open savepoints. If the second parameter is greater than 0 and ** the sub-journal is not already open, then it will be opened here. */ | > > > > > > > > > > > > > > > | 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 | if( rc==SQLITE_OK ){ put4byte(&pPage1->aData[28], pBt->nPage); } } } } #ifdef SQLITE_ENABLE_TRANSACTION_PAGES if( rc==SQLITE_OK && wrflag ){ assert( pBt->pBtRead==0 && pBt->pBtWrite==0 ); pBt->pBtRead = sqlite3BitvecCreate(pBt->nPage); pBt->pBtWrite = sqlite3BitvecCreate(pBt->nPage); pBt->pBtAlloc = sqlite3BitvecCreate(pBt->nPage); if( pBt->pBtRead==0 || pBt->pBtWrite==0 || pBt->pBtAlloc==0 ){ rc = SQLITE_NOMEM; sqlite3BitvecDestroy(pBt->pBtRead); sqlite3BitvecDestroy(pBt->pBtWrite); sqlite3BitvecDestroy(pBt->pBtAlloc); pBt->pBtAlloc = pBt->pBtRead = pBt->pBtWrite = 0; } } #endif trans_begun: if( rc==SQLITE_OK && wrflag ){ /* This call makes sure that the pager has the correct number of ** open savepoints. If the second parameter is greater than 0 and ** the sub-journal is not already open, then it will be opened here. */ |
︙ | ︙ | |||
3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 | } /* Set the current transaction state to TRANS_NONE and unlock the ** pager if this call closed the only read or write transaction. */ p->inTrans = TRANS_NONE; unlockBtreeIfUnused(pBt); } btreeIntegrity(p); } /* ** Commit the transaction currently in progress. ** | > > > > > > > > > > > > > | 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 | } /* Set the current transaction state to TRANS_NONE and unlock the ** pager if this call closed the only read or write transaction. */ p->inTrans = TRANS_NONE; unlockBtreeIfUnused(pBt); } #ifdef SQLITE_ENABLE_TRANSACTION_PAGES if( pBt->inTransaction!=TRANS_WRITE ){ sqlite3BitvecDestroy(pBt->pBtRead); sqlite3BitvecDestroy(pBt->pBtWrite); sqlite3BitvecDestroy(pBt->pBtAlloc); pBt->pBtAlloc = pBt->pBtRead = pBt->pBtWrite = 0; sqlite3_free(pBt->aiRead); sqlite3_free(pBt->aiWrite); pBt->aiRead = pBt->aiWrite = 0; pBt->nRead = pBt->nWrite = 0; } #endif btreeIntegrity(p); } /* ** Commit the transaction currently in progress. ** |
︙ | ︙ | |||
4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 | memcpy(pPayload, pBuf, nByte); }else{ /* Copy data from page to buffer (a read operation) */ memcpy(pBuf, pPayload, nByte); } return SQLITE_OK; } /* ** This function is used to read or overwrite payload information ** for the entry that the pCur cursor is pointing to. The eOp ** argument is interpreted as follows: ** ** 0: The operation is a read. Populate the overflow cache. | > > > > > > > > > > > > > > > > > > | 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 | memcpy(pPayload, pBuf, nByte); }else{ /* Copy data from page to buffer (a read operation) */ memcpy(pBuf, pPayload, nByte); } return SQLITE_OK; } /* ** Call PagerWrite() on pager page pDbPage. And, if the page is currently ** in the pBtRead bit vector, add it to pBtWrite as well. */ static int pagerWrite(BtShared *pBt, DbPage *pDbPage){ Pgno pgno = sqlite3PagerPagenumber(pDbPage); int rc = SQLITE_OK; #ifdef SQLITE_ENABLE_TRANSACTION_PAGES if( sqlite3BitvecTestNotNull(pBt->pBtRead, pgno) ){ rc = sqlite3BitvecSet(pBt->pBtWrite, pgno); } #endif if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pDbPage); } return rc; } /* ** This function is used to read or overwrite payload information ** for the entry that the pCur cursor is pointing to. The eOp ** argument is interpreted as follows: ** ** 0: The operation is a read. Populate the overflow cache. |
︙ | ︙ | |||
4489 4490 4491 4492 4493 4494 4495 | /* Check if data must be read/written to/from the btree page itself. */ if( offset<pCur->info.nLocal ){ int a = amt; if( a+offset>pCur->info.nLocal ){ a = pCur->info.nLocal - offset; } | > > > > > > | > | 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 | /* Check if data must be read/written to/from the btree page itself. */ if( offset<pCur->info.nLocal ){ int a = amt; if( a+offset>pCur->info.nLocal ){ a = pCur->info.nLocal - offset; } #ifdef SQLITE_ENABLE_TRANSACTION_PAGES if( eOp & 0x01 ){ rc = pagerWrite(pBt, pPage->pDbPage); } #endif if( rc==SQLITE_OK ){ rc = copyPayload(&aPayload[offset], pBuf, a, (eOp&0x01), pPage->pDbPage); } offset = 0; pBuf += a; amt -= a; }else{ offset -= pCur->info.nLocal; } |
︙ | ︙ | |||
5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 | releasePage(*ppPage); *ppPage = 0; } TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); end_allocate_page: releasePage(pTrunk); releasePage(pPrevTrunk); assert( rc!=SQLITE_OK || sqlite3PagerPageRefcount((*ppPage)->pDbPage)<=1 ); assert( rc!=SQLITE_OK || (*ppPage)->isInit==0 ); return rc; | > > > > > > > > > > | 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 | releasePage(*ppPage); *ppPage = 0; } TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); #ifdef SQLITE_ENABLE_TRANSACTION_PAGES if( rc==SQLITE_OK && *pPgno<sqlite3BitvecSize(pBt->pBtAlloc) ){ rc = sqlite3BitvecSet(pBt->pBtAlloc, *pPgno); if( rc!=SQLITE_OK ){ releasePage(*ppPage); *ppPage = 0; } } #endif end_allocate_page: releasePage(pTrunk); releasePage(pPrevTrunk); assert( rc!=SQLITE_OK || sqlite3PagerPageRefcount((*ppPage)->pDbPage)<=1 ); assert( rc!=SQLITE_OK || (*ppPage)->isInit==0 ); return rc; |
︙ | ︙ | |||
6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 | - pPage->childPtrSize - 8; }else{ memmove(ptr, ptr+2, 2*(pPage->nCell - idx)); put2byte(&data[hdr+3], pPage->nCell); pPage->nFree += 2; } } /* ** 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 make a copy of the cell content into pTemp if | > | 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 | - pPage->childPtrSize - 8; }else{ memmove(ptr, ptr+2, 2*(pPage->nCell - idx)); put2byte(&data[hdr+3], pPage->nCell); pPage->nFree += 2; } } /* ** 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 make a copy of the cell content into pTemp if |
︙ | ︙ | |||
6347 6348 6349 6350 6351 6352 6353 | ** sorted order. This invariants arise because multiple overflows can ** only occur when inserting divider cells into the parent page during ** balancing, and the dividers are adjacent and sorted. */ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */ }else{ | | | 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 | ** sorted order. This invariants arise because multiple overflows can ** only occur when inserting divider cells into the parent page during ** balancing, and the dividers are adjacent and sorted. */ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */ }else{ int rc = pagerWrite(pPage->pBt, pPage->pDbPage); if( rc!=SQLITE_OK ){ *pRC = rc; return; } assert( sqlite3PagerIswriteable(pPage->pDbPage) ); data = pPage->aData; assert( &data[pPage->cellOffset]==pPage->aCellIdx ); |
︙ | ︙ | |||
7381 7382 7383 7384 7385 7386 7387 | */ pageFlags = apOld[0]->aData[0]; for(i=0; i<k; i++){ MemPage *pNew; if( i<nOld ){ pNew = apNew[i] = apOld[i]; apOld[i] = 0; | | | 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 | */ pageFlags = apOld[0]->aData[0]; for(i=0; i<k; i++){ MemPage *pNew; if( i<nOld ){ pNew = apNew[i] = apOld[i]; apOld[i] = 0; rc = pagerWrite(pBt, pNew->pDbPage); nNew++; if( rc ) goto balance_cleanup; }else{ assert( i>0 ); rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0); if( rc ) goto balance_cleanup; zeroPage(pNew, pageFlags); |
︙ | ︙ | |||
7751 7752 7753 7754 7755 7756 7757 | assert( pRoot->nOverflow>0 ); assert( sqlite3_mutex_held(pBt->mutex) ); /* Make pRoot, the root page of the b-tree, writable. Allocate a new ** page that will become the new right-child of pPage. Copy the contents ** of the node stored on pRoot into the new child page. */ | | | 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 | assert( pRoot->nOverflow>0 ); assert( sqlite3_mutex_held(pBt->mutex) ); /* Make pRoot, the root page of the b-tree, writable. Allocate a new ** page that will become the new right-child of pPage. Copy the contents ** of the node stored on pRoot into the new child page. */ rc = pagerWrite(pBt, pRoot->pDbPage); if( rc==SQLITE_OK ){ rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0); copyNodeContent(pRoot, pChild, &rc); if( ISAUTOVACUUM ){ ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc); } } |
︙ | ︙ | |||
7833 7834 7835 7836 7837 7838 7839 | } }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ break; }else{ MemPage * const pParent = pCur->apPage[iPage-1]; int const iIdx = pCur->aiIdx[iPage-1]; | | | 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 | } }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ break; }else{ MemPage * const pParent = pCur->apPage[iPage-1]; int const iIdx = pCur->aiIdx[iPage-1]; rc = pagerWrite(pParent->pBt, pParent->pDbPage); if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_QUICKBALANCE if( pPage->intKeyLeaf && pPage->nOverflow==1 && pPage->aiOvfl[0]==pPage->nCell && pParent->pgno!=1 && pParent->nCell==iIdx |
︙ | ︙ | |||
8054 8055 8056 8057 8058 8059 8060 | if( rc ) goto end_insert; assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); idx = pCur->aiIdx[pCur->iPage]; if( loc==0 ){ CellInfo info; assert( idx<pPage->nCell ); | | | 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 | if( rc ) goto end_insert; assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); idx = pCur->aiIdx[pCur->iPage]; if( loc==0 ){ CellInfo info; assert( idx<pPage->nCell ); rc = pagerWrite(pBt, pPage->pDbPage); if( rc ){ goto end_insert; } oldCell = findCell(pPage, idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } |
︙ | ︙ | |||
8234 8235 8236 8237 8238 8239 8240 | if( pCur->pKeyInfo==0 ){ invalidateIncrblobCursors(p, pCur->info.nKey, 0); } /* Make the page containing the entry to be deleted writable. Then free any ** overflow pages associated with the entry and finally remove the cell ** itself from within the page. */ | | | 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 | if( pCur->pKeyInfo==0 ){ invalidateIncrblobCursors(p, pCur->info.nKey, 0); } /* Make the page containing the entry to be deleted writable. Then free any ** overflow pages associated with the entry and finally remove the cell ** itself from within the page. */ rc = pagerWrite(pBt, pPage->pDbPage); if( rc ) return rc; rc = clearCell(pPage, pCell, &info); dropCell(pPage, iCellIdx, info.nSize, &rc); if( rc ) return rc; /* If the cell deleted was not located on a leaf page, then the cursor ** is currently pointing to the largest entry in the sub-tree headed |
︙ | ︙ | |||
8257 8258 8259 8260 8261 8262 8263 | pCell = findCell(pLeaf, pLeaf->nCell-1); if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); | | | 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 | pCell = findCell(pLeaf, pLeaf->nCell-1); if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = pagerWrite(pBt, pLeaf->pDbPage); if( rc==SQLITE_OK ){ insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); } dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); if( rc ) return rc; } |
︙ | ︙ | |||
8520 8521 8522 8523 8524 8525 8526 | }else if( pnChange ){ assert( pPage->intKey || CORRUPT_DB ); testcase( !pPage->intKey ); *pnChange += pPage->nCell; } if( freePageFlag ){ freePage(pPage, &rc); | | | 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 | }else if( pnChange ){ assert( pPage->intKey || CORRUPT_DB ); testcase( !pPage->intKey ); *pnChange += pPage->nCell; } if( freePageFlag ){ freePage(pPage, &rc); }else if( (rc = pagerWrite(pBt, pPage->pDbPage))==0 ){ zeroPage(pPage, pPage->aData[hdr] | PTF_LEAF); } cleardatabasepage_out: pPage->bBusy = 0; releasePage(pPage); return rc; |
︙ | ︙ | |||
9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 | } /* ** Return the size of the header added to each page by this module. */ int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } #if !defined(SQLITE_OMIT_SHARED_CACHE) /* ** Return true if the Btree passed as the only argument is sharable. */ int sqlite3BtreeSharable(Btree *p){ return p->sharable; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 | } /* ** Return the size of the header added to each page by this module. */ int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } #ifdef SQLITE_ENABLE_TRANSACTION_PAGES int sqlite3BtreeTransactionPages( Btree *pBtree, /* Btree handle */ int *pnRead, u32 **paiRead, /* OUT: Pages read */ int *pnWrite, u32 **paiWrite /* OUT: Pages written */ ){ int rc = SQLITE_OK; BtShared *pBt = pBtree->pBt; sqlite3BtreeEnter(pBtree); sqlite3_free(pBt->aiRead); sqlite3_free(pBt->aiWrite); pBt->nRead = pBt->nWrite = 0; pBt->aiRead = pBt->aiWrite = 0; if( pBtree->inTrans==TRANS_WRITE ){ assert( pBt->inTransaction==TRANS_WRITE ); rc = sqlite3BitvecToArray(pBt->pBtRead, &pBt->nRead, &pBt->aiRead); if( rc==SQLITE_OK ){ rc = sqlite3BitvecToArray(pBt->pBtWrite, &pBt->nWrite, &pBt->aiWrite); } } *pnRead = pBt->nRead; *paiRead = pBt->aiRead; *pnWrite = pBt->nWrite; *paiWrite = pBt->aiWrite; sqlite3BtreeLeave(pBtree); return rc; } #endif /* SQLITE_ENABLE_TRANSACTION_PAGES */ #if !defined(SQLITE_OMIT_SHARED_CACHE) /* ** Return true if the Btree passed as the only argument is sharable. */ int sqlite3BtreeSharable(Btree *p){ return p->sharable; } |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
361 362 363 364 365 366 367 368 369 370 | # define sqlite3BtreeLeaveCursor(X) # define sqlite3BtreeLeaveAll(X) # define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif #endif /* SQLITE_BTREE_H */ | > > > > | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | # define sqlite3BtreeLeaveCursor(X) # define sqlite3BtreeLeaveAll(X) # define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif #ifdef SQLITE_ENABLE_TRANSACTION_PAGES int sqlite3BtreeTransactionPages(Btree*, int*, u32**, int*, u32**); #endif #endif /* SQLITE_BTREE_H */ |
Changes to src/btreeInt.h.
︙ | ︙ | |||
436 437 438 439 440 441 442 443 444 445 446 447 448 449 | #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ }; /* ** Allowed values for BtShared.btsFlags */ #define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ #define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ | > > > > > > > > > > | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ #ifdef SQLITE_ENABLE_TRANSACTION_PAGES Bitvec *pBtRead; /* Btree pages read during current write transaction */ Bitvec *pBtWrite; /* Btree pages written during current transaction */ Bitvec *pBtAlloc; /* Btree pages allocated during current transaction */ int nRead; /* Number of entries in aiRead[] array */ u32 *aiRead; /* Array returned to sqlite3_transaction_pages() */ int nWrite; /* Number of entries in aiWrite[] array */ u32 *aiWrite; /* Array returned to sqlite3_transaction_pages() */ #endif }; /* ** Allowed values for BtShared.btsFlags */ #define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ #define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
4073 4074 4075 4076 4077 4078 4079 4080 | /* ** Free a snapshot handle obtained from sqlite3_snapshot_get(). */ void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ sqlite3_free(pSnapshot); } #endif /* SQLITE_ENABLE_SNAPSHOT */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 | /* ** Free a snapshot handle obtained from sqlite3_snapshot_get(). */ void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ sqlite3_free(pSnapshot); } #ifdef SQLITE_ENABLE_TRANSACTION_PAGES /* ** Return the pages read and written by the current write transaction. */ int sqlite3_transaction_pages( sqlite3 *db, const char *zDbName, int *pnRead, unsigned int **paRead, int *pnWrite, unsigned int **paWrite ){ Btree *pBt; /* Btree to query */ int rc; /* Return code */ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pBt = sqlite3DbNameToBtree(db, zDbName); if( pBt==0 ) return SQLITE_ERROR; rc = sqlite3BtreeTransactionPages(pBt, pnRead, paRead, pnWrite, paWrite); sqlite3_mutex_leave(db->mutex); return rc; } #endif /* SQLITE_ENABLE_TRANSACTION_PAGES */ #endif /* SQLITE_ENABLE_SNAPSHOT */ |
Changes to src/pager.c.
︙ | ︙ | |||
4109 4110 4111 4112 4113 4114 4115 | assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); sqlite3_free(pPager); return SQLITE_OK; } | | | 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 | assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); sqlite3_free(pPager); return SQLITE_OK; } #if !defined(NDEBUG) || defined(SQLITE_TEST) || defined(SQLITE_ENABLE_TRANSACTION_PAGES) /* ** Return the page number for page pPg. */ Pgno sqlite3PagerPagenumber(DbPage *pPg){ return pPg->pgno; } #endif |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
216 217 218 219 220 221 222 | void sqlite3PagerRekey(DbPage*, Pgno, u16); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ | | > > | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | void sqlite3PagerRekey(DbPage*, Pgno, u16); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) || defined(SQLITE_ENABLE_TRANSACTION_PAGES) Pgno sqlite3PagerPagenumber(DbPage*); #endif #if !defined(NDEBUG) || defined(SQLITE_TEST) int sqlite3PagerIswriteable(DbPage*); #endif #ifdef SQLITE_TEST int *sqlite3PagerStats(Pager*); void sqlite3PagerRefdump(Pager*); void disable_simulated_io_errors(void); void enable_simulated_io_errors(void); |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 | ** sqlite3_snapshot_open(). It is an error if there is already a read ** transaction open on the database, or if the database is not a wal mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 | ** sqlite3_snapshot_open(). It is an error if there is already a read ** transaction open on the database, or if the database is not a wal mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** THIS API IS A HACK ONLY. ** ** Return the page numbers of all b-tree pages read from or written to ** database zDb ("main", "temp" etc.) belonging to handle db since the ** current write transaction was started. A page is only reported on if: ** ** + It is a b-tree page, not an overflow, free or pointer-map page, and ** ** + it was a b-tree page when the transaction was started (i.e. is not a ** b-tree page created by reusing free page or extending the database ** file). ** ** If successful, this function returns SQLITE_OK and sets the four output ** variables as follows: ** ** + (*paRead) is set to point to an array containing the page numbers ** of all pages read since the current write transaction was opened. ** (*pnRead) is set to the number of elements in this array. ** ** + (*paWrite) is set to point to an array containing the page numbers ** of all pages written since the current write transaction was opened. ** (*paRead) is set to the number of elements in this array. ** ** The array references are valid until the next call to this API function ** on the same database or until the database is DETACHed from the database ** handle. ** ** If this function is called when there is no write transaction opened ** on the specified database, all four output parameters are set to 0. ** ** If an error occurs, an SQLite error code is returned (e.g. SQLITE_NOMEM) ** and the final values of the four output parameters are undefined. ** ** This function is only enabled if SQLITE_ENABLE_TRANSACTION_PAGES is ** defined during compilation. */ SQLITE_EXPERIMENTAL int sqlite3_transaction_pages( sqlite3 *db, const char *zDb, int *pnRead, unsigned int **paRead, int *pnWrite, unsigned int **paWrite ); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 | int sqlite3BitvecSet(Bitvec*, u32); void sqlite3BitvecClear(Bitvec*, u32, void*); void sqlite3BitvecDestroy(Bitvec*); u32 sqlite3BitvecSize(Bitvec*); #ifndef SQLITE_UNTESTABLE int sqlite3BitvecBuiltinTest(int,int*); #endif RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); void sqlite3RowSetClear(RowSet*); void sqlite3RowSetInsert(RowSet*, i64); int sqlite3RowSetTest(RowSet*, int iBatch, i64); int sqlite3RowSetNext(RowSet*, i64*); | > > > > | 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 | int sqlite3BitvecSet(Bitvec*, u32); void sqlite3BitvecClear(Bitvec*, u32, void*); void sqlite3BitvecDestroy(Bitvec*); u32 sqlite3BitvecSize(Bitvec*); #ifndef SQLITE_UNTESTABLE int sqlite3BitvecBuiltinTest(int,int*); #endif #ifdef SQLITE_ENABLE_TRANSACTION_PAGES int sqlite3BitvecToArray(Bitvec *p, int *pnElem, u32 **paElem); #endif RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); void sqlite3RowSetClear(RowSet*); void sqlite3RowSetInsert(RowSet*, i64); int sqlite3RowSetTest(RowSet*, int iBatch, i64); int sqlite3RowSetNext(RowSet*, i64*); |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 | zFile = (const char*)Tcl_GetString(objv[1]); rc = sqlite3_delete_database(zFile); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_OK; } /* ** Usage: sqlite3_next_stmt DB STMT ** ** Return the next statment in sequence after STMT. */ static int SQLITE_TCLAPI test_next_stmt( void * clientData, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 | zFile = (const char*)Tcl_GetString(objv[1]); rc = sqlite3_delete_database(zFile); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_OK; } /* ** Usage: sqlite3_transaction_pages DB FILENAME */ #ifdef SQLITE_ENABLE_TRANSACTION_PAGES static int SQLITE_TCLAPI test_transaction_pages( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zDb; sqlite3 *db; int rc; int nRead; int nWrite; unsigned int *aiRead; unsigned int *aiWrite; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB FILE"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zDb = (const char*)Tcl_GetString(objv[2]); rc = sqlite3_transaction_pages(db, zDb, &nRead, &aiRead, &nWrite, &aiWrite); if( rc==SQLITE_OK ){ Tcl_Obj *pList = Tcl_NewObj(); Tcl_Obj *p = Tcl_NewObj(); int i; for(i=0; i<nRead; i++){ Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj((int)aiRead[i])); } Tcl_ListObjAppendElement(interp, pList, p); p = Tcl_NewObj(); for(i=0; i<nWrite; i++){ Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj((int)aiWrite[i])); } Tcl_ListObjAppendElement(interp, pList, p); Tcl_SetObjResult(interp, pList); }else{ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_ERROR; } return TCL_OK; } #endif /* ** Usage: sqlite3_next_stmt DB STMT ** ** Return the next statment in sequence after STMT. */ static int SQLITE_TCLAPI test_next_stmt( void * clientData, |
︙ | ︙ | |||
7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 | { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 }, { "sqlite3_snapshot_recover", test_snapshot_recover, 0 }, { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 }, { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 }, { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 }, #endif { "sqlite3_delete_database", test_delete_database, 0 }, }; static int bitmask_size = sizeof(Bitmask)*8; static int longdouble_size = sizeof(LONGDOUBLE_TYPE); int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; | > > > | 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 | { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 }, { "sqlite3_snapshot_recover", test_snapshot_recover, 0 }, { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 }, { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 }, { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 }, #endif { "sqlite3_delete_database", test_delete_database, 0 }, #ifdef SQLITE_ENABLE_TRANSACTION_PAGES { "sqlite3_transaction_pages", test_transaction_pages, 0 }, #endif }; static int bitmask_size = sizeof(Bitmask)*8; static int longdouble_size = sizeof(LONGDOUBLE_TYPE); int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; |
︙ | ︙ |
Added test/tpages.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # 2017-01-19 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix tpages sqlite3_test_control_pending_byte 0x1000000 proc integers {iFirst n} { set ret [list] for {set i $iFirst} {$i<$iFirst+$n} {incr i} { lappend ret $i } set ret } do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<99 ) INSERT INTO t1 SELECT randomblob(10), randomblob(400), randomblob(400) FROM s; } foreach {n1 n2} { 0 10 10 20 5000 20 5000 5000 5001 5001 60000 5001 60000 5 5000 1000 6000 1000 7000 1000 } { set n1 [expr $n1] set n2 [expr $n2] reset_db do_execsql_test 1.$n1.1 { CREATE TABLE t1(a, b, c); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$n1 ) INSERT INTO t1 SELECT randomblob(10), randomblob(400), randomblob(400) FROM s; } set iFirst [expr [db one {PRAGMA page_count}] + 1] do_execsql_test 1.$n1.2 { CREATE TABLE t2(a, b, c); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$n2 ) INSERT INTO t2 SELECT randomblob(10), randomblob(400), randomblob(400) FROM s; } set nInt [expr [db one {PRAGMA page_count}] - $iFirst + 1] do_test 1.$n1.3 { execsql { BEGIN IMMEDIATE; SELECT * FROM t2; } sqlite3_transaction_pages db main } [list [integers $iFirst $nInt] {}] execsql cOMMIT } finish_test |