Compare commits

...

2 Commits

Author SHA1 Message Date
dan ce876a49f5 Add test cases for the instrumentation on this branch. Fix some OOM handling
issues in the same.

FossilOrigin-Name: 50ca94b919ccb462f523513fd7fe99957f0b9204
2017-01-19 11:52:13 +00:00
dan 21ff59fa46 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.

FossilOrigin-Name: 2a8f6c890cfa5f61b491ddf8f560b6ba8c6cdc32
2017-01-18 20:14:50 +00:00
13 changed files with 492 additions and 28 deletions
+16 -15
View File
@@ -1,5 +1,5 @@
C Fix\sa\sproblem\sthat\scould\scause\sa\sspurious\sSQLITE_NOMEM\serror\swhen\sattempting\nto\sresume\san\sRBU\soperation\sif\sthe\sprevious\sclient\sfailed\sright\safter\ncompleting\sthe\sincremental\scheckpoint.\sAlso\sa\s"cannot\svacuum\swal\sdb"\serror\nthat\scould\soccur\swhen\sresuming\san\sRBU\svacuum\sif\san\serror\s(OOM\sor\sIO\serror)\noccurs\sduring\sthe\sincremental\scheckpoint.
D 2017-01-17T10:41:42.780
C Add\stest\scases\sfor\sthe\sinstrumentation\son\sthis\sbranch.\sFix\ssome\sOOM\shandling\nissues\sin\sthe\ssame.
D 2017-01-19T11:52:13.715
F Makefile.in 41bd4cad981487345c4a84081074bcdb876e4b2e
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da
@@ -331,11 +331,11 @@ F src/analyze.c 317dbaf31c16050582b09bf4f323b4e0f1813251
F src/attach.c 8c476f8bd5d2afe11d925f890d30e527e5b0ce43
F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/bitvec.c 263395e75ac122a7138f0797172868be700cf22a
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
F src/btree.c 69966fb2c574954cd3216f09407c9a02c52d3bd7
F src/btree.h e6d352808956ec163a17f832193a3e198b3fb0ac
F src/btreeInt.h 10c4b77c2fb399580babbcc7cf652ac10dba796e
F src/btree.c 9e3d38d2d93384c6d8b765b39c0c80b6a8a6dacd
F src/btree.h a25d8121baf921ed56cdf5bb65a37233b4fa059a
F src/btreeInt.h d528379e5da9aa33ef046e3c210a5d82acd2740b
F src/build.c 9e799f1edd910dfa8a0bc29bd390d35d310596af
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
@@ -355,7 +355,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 05e47e2de7b712a3a4148cd469e5f60873f5ef13
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
F src/loadext.c 5d6642d141c07d366e43d359e94ec9de47add41d
F src/main.c e207b81542d13b9f13d61e78ca441f9781f055b0
F src/main.c 504a2a6cbd4596584fa8a5489bb5fa1c8a8ee226
F src/malloc.c fc1b9f445290f2145da48fc08730c26e6082b640
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
@@ -377,8 +377,8 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c 30e2c43e4955db990e5b5a81e901f8aa74cc8820
F src/os_win.c cf90abd4e50d9f56d2c20ce8e005aff55d7bd8e9
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 9dc72d23eebbdf992bd69f2ab954d0d3a27c7340
F src/pager.h d1e944291030351f362a0a7da9b5c3e34e603e39
F src/pager.c fcdfc9ef832281c49870ac703ecb317fbea93891
F src/pager.h f15b4fe1c773ba428d9c983ddac342b30a99a8f4
F src/parse.y 29153738a7322054359320eb00b5a4cd44389f20
F src/pcache.c 51070ec9b8251bbf9c6ea3d35fd96a458752929e
F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
@@ -392,15 +392,15 @@ F src/resolve.c bb070cf5f23611c44ab7e4788803684e385fc3fb
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 3856db523b942062bca8722ba03b61c324ff94d6
F src/shell.c 6095531aa900decdaa765e0f3993fba7153c92c1
F src/sqlite.h.in e71655293c9bde26939496f3aac9d1821d2c07a2
F src/sqlite.h.in b0e0ef521c53afeff0c5fbdacc166dd92f7963bb
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
F src/sqliteInt.h ce3e07c720b0cebc8887ea86b3b128da0913c5d3
F src/sqliteInt.h 7a4cf01ef33c0df033104b4caaf97c59497624f9
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
F src/tclsqlite.c 418f5e5e0840425a7e5b33f3600dccd378a57549
F src/test1.c 8a98191a1da8e100f77cdb5cc716df67d405028d
F src/test1.c ef72568ab6eebf1691706e9b29ea2ab7fd5481d8
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
@@ -1318,6 +1318,7 @@ F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
F test/tkt4018.test 18dbc6617f7a4b90e938d1bd6d26ad18daafaf08
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
F test/tpages.test 20b7cae49b46fae6aacdd14a44f531a5a1fab33f
F test/tpch01.test 04adbf8d8300fa60a222f28d901abd76e7be6dd4
F test/trace.test 6f676313e3ebd2a50585036d2f212a3319dd5836
F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
@@ -1547,7 +1548,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 7fd560c6d2ff470b755ad118287a0a8825b3009e
R 3b5f909693e02732236a5ff9d24ebb43
P 2a8f6c890cfa5f61b491ddf8f560b6ba8c6cdc32
R ae523458281bb3a9a28803814e720ed6
U dan
Z 623656530433c4c90deab7fe9f3d0d79
Z 5b5cdeb9ebac248f4328063c950d744e
+1 -1
View File
@@ -1 +1 @@
681d96eb822e606da53700867191d4738bda20c8
50ca94b919ccb462f523513fd7fe99957f0b9204
+57
View File
@@ -293,6 +293,63 @@ 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
+124 -10
View File
@@ -2026,6 +2026,19 @@ static int getAndInitPage(
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:
@@ -3106,6 +3119,27 @@ int sqlite3BtreeNewDb(Btree *p){
return rc;
}
#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
/*
** If the b-tree is not currently in a write transaction, free the various
** resources allocated for the sqlite3_transaction_pages() functionality.
*/
static void freeTransactionPagesBitvec(BtShared *pBt){
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;
}
}
#else
# define freeTransactionPagesBitvec(x)
#endif
/*
** Attempt to start a new transaction. A write-transaction
** is started if the second argument is nonzero, otherwise a read-
@@ -3191,6 +3225,20 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
#endif
#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
if( wrflag ){
assert( pBt->pBtRead==0 && pBt->pBtWrite==0 && pBt->pBtAlloc==0 );
assert( rc==SQLITE_OK );
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;
goto trans_begun;
}
}
#endif
/* Any read-only or read-write transaction implies a read-lock on
** page 1. So if some other shared-cache client already has a write-lock
** on page 1, the transaction cannot be opened. */
@@ -3266,7 +3314,6 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
}
trans_begun:
if( rc==SQLITE_OK && wrflag ){
/* This call makes sure that the pager has the correct number of
@@ -3276,6 +3323,7 @@ trans_begun:
rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
}
freeTransactionPagesBitvec(pBt);
btreeIntegrity(p);
sqlite3BtreeLeave(p);
return rc;
@@ -3790,6 +3838,7 @@ static void btreeEndTransaction(Btree *p){
unlockBtreeIfUnused(pBt);
}
freeTransactionPagesBitvec(pBt);
btreeIntegrity(p);
}
@@ -4417,6 +4466,24 @@ static int copyPayload(
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
@@ -4493,7 +4560,14 @@ static int accessPayload(
if( a+offset>pCur->info.nLocal ){
a = pCur->info.nLocal - offset;
}
rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
#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;
@@ -5830,6 +5904,16 @@ static int allocateBtreePage(
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);
@@ -6286,6 +6370,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
}
}
/*
** Insert a new cell on pPage at cell index "i". pCell points to the
** content of the cell.
@@ -6351,7 +6436,7 @@ static void insertCell(
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 = sqlite3PagerWrite(pPage->pDbPage);
int rc = pagerWrite(pPage->pBt, pPage->pDbPage);
if( rc!=SQLITE_OK ){
*pRC = rc;
return;
@@ -7385,7 +7470,7 @@ static int balance_nonroot(
if( i<nOld ){
pNew = apNew[i] = apOld[i];
apOld[i] = 0;
rc = sqlite3PagerWrite(pNew->pDbPage);
rc = pagerWrite(pBt, pNew->pDbPage);
nNew++;
if( rc ) goto balance_cleanup;
}else{
@@ -7755,7 +7840,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
** 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 = sqlite3PagerWrite(pRoot->pDbPage);
rc = pagerWrite(pBt, pRoot->pDbPage);
if( rc==SQLITE_OK ){
rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0);
copyNodeContent(pRoot, pChild, &rc);
@@ -7837,7 +7922,7 @@ static int balance(BtCursor *pCur){
MemPage * const pParent = pCur->apPage[iPage-1];
int const iIdx = pCur->aiIdx[iPage-1];
rc = sqlite3PagerWrite(pParent->pDbPage);
rc = pagerWrite(pParent->pBt, pParent->pDbPage);
if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_QUICKBALANCE
if( pPage->intKeyLeaf
@@ -8058,7 +8143,7 @@ int sqlite3BtreeInsert(
if( loc==0 ){
CellInfo info;
assert( idx<pPage->nCell );
rc = sqlite3PagerWrite(pPage->pDbPage);
rc = pagerWrite(pBt, pPage->pDbPage);
if( rc ){
goto end_insert;
}
@@ -8238,7 +8323,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
/* 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 = sqlite3PagerWrite(pPage->pDbPage);
rc = pagerWrite(pBt, pPage->pDbPage);
if( rc ) return rc;
rc = clearCell(pPage, pCell, &info);
dropCell(pPage, iCellIdx, info.nSize, &rc);
@@ -8261,7 +8346,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( MX_CELL_SIZE(pBt) >= nCell );
pTmp = pBt->pTmpSpace;
assert( pTmp!=0 );
rc = sqlite3PagerWrite(pLeaf->pDbPage);
rc = pagerWrite(pBt, pLeaf->pDbPage);
if( rc==SQLITE_OK ){
insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
}
@@ -8524,7 +8609,7 @@ static int clearDatabasePage(
}
if( freePageFlag ){
freePage(pPage, &rc);
}else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){
}else if( (rc = pagerWrite(pBt, pPage->pDbPage))==0 ){
zeroPage(pPage, pPage->aData[hdr] | PTF_LEAF);
}
@@ -9726,6 +9811,35 @@ int sqlite3BtreeIsReadonly(Btree *p){
*/
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.
+4
View File
@@ -366,5 +366,9 @@ void sqlite3BtreeCursorList(Btree*);
# define sqlite3SchemaMutexHeld(X,Y,Z) 1
#endif
#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
int sqlite3BtreeTransactionPages(Btree*, int*, u32**, int*, u32**);
#endif
#endif /* SQLITE_BTREE_H */
+10
View File
@@ -440,6 +440,16 @@ struct BtShared {
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
};
/*
+29
View File
@@ -4077,4 +4077,33 @@ int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
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 */
+1 -1
View File
@@ -4113,7 +4113,7 @@ int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
return SQLITE_OK;
}
#if !defined(NDEBUG) || defined(SQLITE_TEST)
#if !defined(NDEBUG) || defined(SQLITE_TEST) || defined(SQLITE_ENABLE_TRANSACTION_PAGES)
/*
** Return the page number for page pPg.
*/
+3 -1
View File
@@ -220,8 +220,10 @@ void *sqlite3PagerCodec(DbPage *);
#endif
/* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST)
#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
+47
View File
@@ -8448,6 +8448,53 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
*/
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.
+4
View File
@@ -3631,6 +3631,10 @@ u32 sqlite3BitvecSize(Bitvec*);
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);
+52
View File
@@ -2550,6 +2550,55 @@ static int SQLITE_TCLAPI test_delete_database(
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
**
@@ -7686,6 +7735,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "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);
+144
View File
@@ -0,0 +1,144 @@
# 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
}
#-------------------------------------------------------------------------
#
proc do_transaction_pages_test {tn sql pages} {
uplevel [list execsql $sql]
uplevel [list \
do_test $tn {sqlite3_transaction_pages db main} [list {*}$pages]
]
}
reset_db
do_transaction_pages_test 2.0 {
PRAGMA auto_vacuum = 0;
PRAGMA page_size = 1024;
CREATE TABLE t1(x);
BEGIN;
INSERT INTO t1 VALUES(randomblob(1500));
} {2 2}
do_transaction_pages_test 2.1 {
COMMIT;
BEGIN;
DELETE FROM t1;
} {2 2}
reset_db
do_execsql_test 2.2 {
PRAGMA auto_vacuum = 0;
PRAGMA page_size = 1024;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(randomblob(900));
INSERT INTO t1 VALUES(randomblob(900));
CREATE TABLE t2(y);
}
do_transaction_pages_test 2.3 {
BEGIN;
UPDATE t1 SET x=randomblob(899);
} {{2 3 4} {3 4}}
do_transaction_pages_test 2.4 {
DELETE FROM t1;
COMMIT;
} {{} {}}
do_transaction_pages_test 2.5 {
BEGIN;
INSERT INTO t2 VALUES(randomblob(900));
INSERT INTO t2 VALUES(randomblob(900));
} {5 5}
do_transaction_pages_test 2.6 {
COMMIT;
BEGIN;
INSERT INTO t1 VALUES(randomblob(900));
} {2 2}
do_transaction_pages_test 2.7 {
INSERT INTO t1 VALUES(randomblob(900));
INSERT INTO t1 VALUES(randomblob(900));
INSERT INTO t1 VALUES(randomblob(900));
INSERT INTO t1 VALUES(randomblob(900));
} {2 2}
finish_test