From: dan Date: Mon, 29 May 2017 14:27:37 +0000 (+0000) Subject: Enhance the log messages emitted when a page conflict is detected. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7fff2e1cb9c838edc392ee1edd9070fac53d96bb;p=thirdparty%2Fsqlite.git Enhance the log messages emitted when a page conflict is detected. FossilOrigin-Name: 92618492b048867af38922825f3d094eaaa2dd919b1ed2f7372483cc53f892bf --- diff --git a/manifest b/manifest index 61e52657d5..9c926fb54c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Adjust\sthe\sbitvec\srelated\ssqlite3_log\smessages\sadded\sby\s[9527089b]. -D 2017-05-26T18:18:51.758 +C Enhance\sthe\slog\smessages\semitted\swhen\sa\spage\sconflict\sis\sdetected. +D 2017-05-29T14:27:37.696 F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 8eeb80162074004e906b53d7340a12a14c471a83743aab975947e95ce061efcc @@ -350,9 +350,9 @@ F src/auth.c 79f96c6f33bf0e5da8d1c282cee5ebb1852bb8a6ccca3e485d7c459b035d9c3c F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b F src/bitvec.c c77b7f5759e413c1c8b53267d633c952e66db79c1171964c7e24c0f92f5019cf F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca -F src/btree.c ca942fd75c1b791bd3fdf647e283473acf63e97d2252077216cdc1d56cb3a25e +F src/btree.c 3c5409453a17294ed8fe7b44dc87c0434b2418f447ad768f4624ead69d5dfa18 F src/btree.h 14e99cc2b666beb60322173c761d16b668ec2e07c18bbb74e8a49fe85946f8a0 -F src/btreeInt.h 42c3e3d9534aed0b99ee68678b0311c33134c7c015037a319900eddd148584d6 +F src/btreeInt.h 7429915fc8f51bbd78b7ac023aa4afbe5b9660fc1e6970f144b07540a34a4623 F src/build.c ba3f389668754c407805bbc5f8ab140f063ba6b04a6a86f63006b63b3c7319a8 F src/callback.c 2e76147783386374bf01b227f752c81ec872d730 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e @@ -485,7 +485,7 @@ F src/vdbesort.c e72fe02a2121386ba767ede8942e9450878b8fc873abf3d1b6824485f092570 F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834 F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c 0c4faf368f51abb3f077fa5c175920b73b6a07584688a287c8d77296b6af582e +F src/wal.c 4b857e74548bb0f9bc0c7f56517327421f925b1263ac65a6e58e9c176194857e F src/wal.h 79378c5cd2127f32060d4952d827a7abdd490f8f9e5cbb14a4c39657ed99ad15 F src/walker.c b71a992b413b3a022572eccf29ef4b4890223791 F src/where.c c6352f15be5031907c68bcbde96cad1a6da20e9f4051d10168a59235de9a8566 @@ -613,6 +613,7 @@ F test/concurrent.test 3eb5e6a911dc6ff72e3a679f563e683b436f6c701e6e1d6050173df2b F test/concurrent2.test 9dfbeb0a323733fe1d13443371734bb94a674dbf777f464365475903873111f8 F test/concurrent3.test 0a5f7e3036d1eccf0782d7153ac21f5f222e9468 F test/concurrent4.test 989c6575225f9c4ef5d2392a9b9d0405665567c7501a3e44129598794d9b1b5f +F test/concurrent5.test 06fd0b5294586d170a3b12d68153394fbfe642c8346e249a6240bc6ababc5f4b F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c F test/conflict3.test a83db76a6c3503b2fa057c7bfb08c318d8a422202d8bc5b86226e078e5b49ff9 @@ -1590,7 +1591,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 9df0195780306a26709e87daabf9d426856aebf2082060b98818f2d48c7472ec -R ef448b68266e15a0b11a8140036a504f +P a7e0e7a4835314a04e065839a7f88b074eda795da2b2da5741b2afc096421a32 +R beb58ff81a99fbcff0806ad7e4f3b8ee U dan -Z e753798d60e27266ad4ce7eb0092b295 +Z a8b4d17828fb801d4b09ca76008d7042 diff --git a/manifest.uuid b/manifest.uuid index 4b2ca7af23..d27dbec941 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a7e0e7a4835314a04e065839a7f88b074eda795da2b2da5741b2afc096421a32 \ No newline at end of file +92618492b048867af38922825f3d094eaaa2dd919b1ed2f7372483cc53f892bf \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index af57d4148e..e9a09b69bd 100644 --- a/src/btree.c +++ b/src/btree.c @@ -2289,6 +2289,17 @@ getAndInitPage_error: return rc; } +#ifndef SQLITE_OMIT_CONCURRENT +/* +** Set the value of the MemPage.pgnoRoot variable, if it exists. +*/ +static void setMempageRoot(MemPage *pPg, u32 pgnoRoot){ + pPg->pgnoRoot = pgnoRoot; +} +#else +# define setMempageRoot(x,y) +#endif + /* ** Release a MemPage. This should be called once for each prior ** call to btreeGetPage. @@ -5222,6 +5233,7 @@ const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){ */ static int moveToChild(BtCursor *pCur, u32 newPgno){ BtShared *pBt = pCur->pBt; + int rc; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); @@ -5234,8 +5246,12 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); pCur->aiIdx[pCur->iPage++] = pCur->ix; pCur->ix = 0; - return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage], + rc = getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage], pCur, pCur->curPagerFlags); + if( rc==SQLITE_OK ){ + setMempageRoot(pCur->apPage[pCur->iPage], pCur->pgnoRoot); + } + return rc; } #ifdef SQLITE_DEBUG @@ -5341,6 +5357,7 @@ static int moveToRoot(BtCursor *pCur){ pCur->eState = CURSOR_INVALID; return rc; } + setMempageRoot(pCur->apPage[0], pCur->pgnoRoot); pCur->iPage = 0; pCur->curIntKey = pCur->apPage[0]->intKey; } @@ -7500,7 +7517,8 @@ static int balance_nonroot( int iParentIdx, /* Index of "the page" in pParent */ u8 *aOvflSpace, /* page-size bytes of space for parent ovfl */ int isRoot, /* True if pParent is a root-page */ - int bBulk /* True if this call is part of a bulk load */ + int bBulk, /* True if this call is part of a bulk load */ + Pgno pgnoRoot /* Root page of b-tree being balanced */ ){ BtShared *pBt; /* The whole database */ int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ @@ -7592,6 +7610,8 @@ static int balance_nonroot( memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } + setMempageRoot(apOld[i], pgnoRoot); + nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; if( (i--)==0 ) break; @@ -8400,7 +8420,7 @@ static int balance(BtCursor *pCur){ */ u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize); rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, - pCur->hints&BTREE_BULKLOAD); + pCur->hints&BTREE_BULKLOAD, pCur->pgnoRoot); if( pFree ){ /* If pFree is not NULL, it points to the pSpace buffer used ** by a previous call to balance_nonroot(). Its contents are @@ -8998,7 +9018,8 @@ static int clearDatabasePage( BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ int freePageFlag, /* Deallocate page if true */ - int *pnChange /* Add number of Cells freed to this counter */ + int *pnChange, /* Add number of Cells freed to this counter */ + Pgno pgnoRoot ){ MemPage *pPage; int rc; @@ -9013,6 +9034,7 @@ static int clearDatabasePage( } rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); if( rc ) return rc; + setMempageRoot(pPage, pgnoRoot); if( pPage->bBusy ){ rc = SQLITE_CORRUPT_BKPT; goto cleardatabasepage_out; @@ -9022,14 +9044,16 @@ static int clearDatabasePage( for(i=0; inCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ - rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); + rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange, pgnoRoot); if( rc ) goto cleardatabasepage_out; } rc = clearCell(pPage, pCell, &info); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ - rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); + rc = clearDatabasePage( + pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange, pgnoRoot + ); if( rc ) goto cleardatabasepage_out; }else if( pnChange ){ assert( pPage->intKey || CORRUPT_DB ); @@ -9074,7 +9098,7 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ ** is the root of a table b-tree - if it is not, the following call is ** a no-op). */ invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); - rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange); + rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange, (Pgno)iTable); } sqlite3BtreeLeave(p); return rc; diff --git a/src/btreeInt.h b/src/btreeInt.h index d924f08ff2..5820db64c3 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -301,6 +301,9 @@ struct MemPage { DbPage *pDbPage; /* Pager page handle */ u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */ void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */ +#ifndef SQLITE_OMIT_CONCURRENT + u32 pgnoRoot; /* Root page of b-tree that this page belongs to */ +#endif }; /* diff --git a/src/wal.c b/src/wal.c index 73b5f7ad82..4139b7c563 100644 --- a/src/wal.c +++ b/src/wal.c @@ -243,6 +243,7 @@ #ifndef SQLITE_OMIT_WAL #include "wal.h" +#include "btreeInt.h" /* ** Trace output macros @@ -2916,11 +2917,26 @@ int sqlite3WalLockForCommit(Wal *pWal, PgHdr *pPage1, Bitvec *pAllRead){ rc = SQLITE_BUSY_SNAPSHOT; } }else if( sqlite3BitvecTestNotNull(pAllRead, aPgno[i]) ){ - sqlite3_log(SQLITE_OK, - "cannot commit CONCURRENT transaction (conflict at page %d)", - (int)aPgno[i] - ); - rc = SQLITE_BUSY_SNAPSHOT; + PgHdr *pPg = 0; + rc = sqlite3PagerGet(pPage1->pPager, aPgno[i], &pPg, 0); + if( rc==SQLITE_OK ){ + Pgno pgnoRoot = 0; + int bWrite = -1; + if( pPg ){ + pgnoRoot = ((MemPage*)sqlite3PagerGetExtra(pPg))->pgnoRoot; + bWrite = sqlite3PagerIswriteable(pPg); + sqlite3PagerUnref(pPg); + } + sqlite3_log(SQLITE_OK, + "cannot commit CONCURRENT transaction " + "- conflict at page %d " + "(%s page; part of b-tree with root page %d)", + (int)aPgno[i], + (bWrite==0?"read-only":(bWrite>0?"read/write":"unknown")), + (int)pgnoRoot + ); + rc = SQLITE_BUSY_SNAPSHOT; + } }else if( (pPg = sqlite3PagerLookup(pPager, aPgno[i])) ){ /* Page aPgno[i], which is present in the pager cache, has been ** modified since the current CONCURRENT transaction was started. diff --git a/test/concurrent5.test b/test/concurrent5.test new file mode 100644 index 0000000000..e77c794048 --- /dev/null +++ b/test/concurrent5.test @@ -0,0 +1,109 @@ +# 2017 May 26 +# +# 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 +source $testdir/lock_common.tcl +source $testdir/wal_common.tcl +set ::testprefix concurrent5 + +ifcapable !concurrent { + finish_test + return +} + +db close +sqlite3_shutdown +test_sqlite3_log [list lappend ::log] +set ::log [list] + +sqlite3 db test.db + +proc do_test_conflict_msg {tn msg} { + set msg "cannot commit CONCURRENT transaction - [string trim $msg]" + uplevel [list do_test $tn {lindex $::log end} $msg] +} + +do_execsql_test 1.0 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(x, y); + CREATE TABLE t2(c); + WITH s(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100) + INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s; +} {wal} + +sqlite3 db2 test.db + +do_test 1.1.1 { + set ::log [list] + db2 eval { + BEGIN CONCURRENT; + SELECT count(*) FROM t1; + INSERT INTO t2 VALUES(10); + } + + db eval { + INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); + } + + catchsql COMMIT db2 +} {1 {database is locked}} +do_test_conflict_msg 1.1.2 { + conflict at page 2 (read-only page; part of b-tree with root page 2) +} + +do_test 1.2.1 { + set ::log [list] + db2 eval { + ROLLBACK; + BEGIN CONCURRENT; + INSERT INTO t1 VALUES(11, 12); + } + + db eval { + INSERT INTO t1 VALUES(12, 11); + } + + catchsql COMMIT db2 +} {1 {database is locked}} + +do_test_conflict_msg 1.2.2 { + conflict at page 105 (read/write page; part of b-tree with root page 2) +} + +do_test 1.3.1 { + set ::log [list] + db2 eval { + ROLLBACK; + BEGIN CONCURRENT; + INSERT INTO t2 VALUES('x'); + } + + db eval { + INSERT INTO t2 VALUES('y'); + } + + catchsql COMMIT db2 +} {1 {database is locked}} + +do_test_conflict_msg 1.3.2 { + conflict at page 3 (read/write page; part of b-tree with root page 3) +} + +db close +db2 close +sqlite3_shutdown +test_sqlite3_log +sqlite3_initialize +finish_test +