-C Consolidate\stwo\sblocks\sof\ssimilar\scode\sin\sbtreeFixUnlocked().
-D 2015-08-24T10:05:03.012
+C Fix\scompilation\swithout\sSQLITE_ENABLE_UNLOCKED.\sAlso\sother\scode\sorganization\sissues.
+D 2015-08-24T16:00:08.023
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in e2218eb228374422969de7b1680eda6864affcef
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/backup.c 4d9134dc988a87838c06056c89c0e8c4700a0452
F src/bitvec.c d1f21d7d91690747881f03940584f4cc548c9d3d
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
-F src/btree.c e807409602996359211c855078fa5cbcf59da032
+F src/btree.c 13f924763ebd6bd55e0b74d139ee363a42abbe0f
F src/btree.h 00d4cdb747c4172a5566faf037116985dbbc377e
F src/btreeInt.h 0c19847f87ab82e4f5e67750a069f10829475da6
F src/build.c e47b6fffe14a28d9050e6747beebb01597d37542
F src/os_unix.c 388c023582b17890f10c980b30ec1922b471753b
F src/os_win.c 40b3af7a47eb1107d0d69e592bec345a3b7b798a
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
-F src/pager.c a952e4b4c2e85e1588df5972688de9b6c989dbdd
+F src/pager.c 57e5775ba3d8059e37e760f8a6f064079196eb9d
F src/pager.h 1e7b0fc3846b71bd95b4b3300820d756895cb4ef
F src/parse.y e9accdb2cb1795f75f478e7ce89e17b19d7d4da7
F src/pcache.c cde06aa50962595e412d497e22fd2e07878ba1f0
F src/test_backup.c 2e6e6a081870150f20c526a2e9d0d29cda47d803
F src/test_blob.c e5a7a81d61a780da79101aeb1e60d300af169e07
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
-F src/test_config.c fb2e5d354d9a077f5fbb261652eff4787deb104f
+F src/test_config.c 8870dbb8809e2bf7f766828934db7d70c907f346
F src/test_demovfs.c 0de72c2c89551629f58486fde5734b7d90758852
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
F src/vdbe.h 7a75045d879118b9d3af7e8b3c108f2f27c51473
F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816
F src/vdbeapi.c bda74ef4b5103d7b4a4be36f936d3cf2b56a7d6f
-F src/vdbeaux.c 4fae90f55736b7537d0fcd2afe52849edbbb7ecd
+F src/vdbeaux.c 5a07e354850fcc96c535f9b0b6ded4c705483a01
F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90
F src/vdbemem.c ae38a0d35ae71cf604381a887c170466ba518090
F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
F src/vtab.c d31174e4c8f592febab3fa7f69e18320b4fd657a
F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
-F src/wal.c b8811f666d785820437d95386c12b85951418c50
+F src/wal.c 7b8c8d1cb09f128d014a1677bc3d3935f729a2f9
F src/wal.h 903ef67e17f8b466dc7cfc4186fc23e80be10ff8
F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba
F src/where.c 66518a14a1238611aa0744d6980b6b7f544f4816
F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
F test/unique2.test 41e7f83c6827605991160a31380148a9fc5f1339
F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825
-F test/unlocked.test d143a871bd874311d4e5c98ce458218ca6b579fd
-F test/unlocked2.test aaa42a08052a146466220b6c3a062ff3c4776ad6
-F test/unlocked3.test 2cacc31742561f6924706ed9472d0095839da9e4
+F test/unlocked.test 51be7f150c8d3bad50b22693e87a91a628e654be
+F test/unlocked2.test 2d969d1b4c3e832169d0c97f522fa5955877785a
+F test/unlocked3.test 6c99bc0c3f19ad8ca8c1632b09b089164718dc35
F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
F test/update.test 6c68446b8a0a33d522a7c72b320934596a2d7d32
F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 876810c28b3ad573ae46050ec699ef7eea4e313d
-R 11d77b8f4d3f6d9b5ad54020bb4092ee
+P 701302b4bd62ca7aefe643eac096a0ee672a62fa
+R 736937b7bbb824036427389285348275
U dan
-Z 46d9657b2162cb9e544c380eb188ec18
+Z a958ab41b63a16e8331a9ac18c76c8a0
-701302b4bd62ca7aefe643eac096a0ee672a62fa
\ No newline at end of file
+041135575417201bbcf0544cc69dcb7369c7fb34
\ No newline at end of file
if( rc==SQLITE_OK ){
rc = newDatabase(pBt);
}
+#ifdef SQLITE_ENABLE_UNLOCKED
if( rc==SQLITE_OK && sqlite3PagerIsUnlocked(pBt->pPager) ){
rc = btreePtrmapAllocate(pBt);
}
+#endif
}
}
*/
static void pagerFreeBitvecs(Pager *pPager){
sqlite3BitvecDestroy(pPager->pInJournal);
- sqlite3BitvecDestroy(pPager->pAllRead);
pPager->pInJournal = 0;
+#ifdef SQLITE_ENABLE_UNLOCKED
+ sqlite3BitvecDestroy(pPager->pAllRead);
pPager->pAllRead = 0;
+#endif
}
/*
static int pagerRollbackWal(Pager *pPager){
int rc; /* Return Code */
PgHdr *pList; /* List of dirty pages to revert */
- int bPage1 = 0; /* True if page 1 has been undone */
/* For all pages in the cache that are currently dirty or have already
** been written (but not committed) to the log file, do one of the
pPager->dbSize = pPager->dbOrigSize;
rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager);
pList = sqlite3PcacheDirtyList(pPager->pPCache);
+
+ /* If this is an UNLOCKED transaction, then page 1 must be reread from
+ ** the db file, even if it is not dirty. This is because the b-tree layer
+ ** may have already zeroed the nFree and iTrunk header fields. */
+#ifdef SQLITE_ENABLE_UNLOCKED
+ if( rc==SQLITE_OK && (pList==0 || pList->pgno!=1) && pPager->pAllRead ){
+ rc = pagerUndoCallback((void*)pPager, 1);
+ }
+#endif
+
while( pList && rc==SQLITE_OK ){
PgHdr *pNext = pList->pDirty;
- if( pList->pgno==1 ) bPage1 = 1;
rc = pagerUndoCallback((void *)pPager, pList->pgno);
pList = pNext;
}
- /* If this is an UNLOCKED transaction, then page 1 must be reread from the
- ** db file, even if it is not dirty. This is because the b-tree layer may
- ** have already zeroed the nFree and iTrunk header fields. */
- if( rc==SQLITE_OK && bPage1==0 && pPager->pAllRead ){
- rc = pagerUndoCallback((void*)pPager, 1);
- }
-
return rc;
}
** list here. */
PgHdr **ppNext = &pList;
nList = 0;
-
for(p=pList; (*ppNext = p)!=0; p=p->pDirty){
if( p->pgno<=nTruncate ){
ppNext = &p->pDirty;
if( pagerUseWal(pPager) ){
/* If the transaction is a "BEGIN UNLOCKED" transaction, the page
** cannot be flushed to disk. Return early in this case. */
+#ifdef SQLITE_ENABLE_UNLOCKED
if( pPager->pAllRead ) return SQLITE_OK;
+#endif
/* Write a single frame for this page to the log. */
rc = subjournalPageIfRequired(pPg);
/* If this is an UNLOCKED transaction and the page being read was
** present in the database file when the transaction was opened,
** mark it as read in the pAllRead vector. */
+#ifdef SQLITE_ENABLE_UNLOCKED
if( pPager->pAllRead && pgno<=pPager->dbOrigSize ){
rc = sqlite3BitvecSet(pPager->pAllRead, pgno);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
}
+#endif
/* If the pager is in the error state, return an error immediately.
** Otherwise, request the page from the PCache layer. */
if( ALWAYS(pPager->eState==PAGER_READER) ){
assert( pPager->pInJournal==0 );
+#ifdef SQLITE_ENABLE_UNLOCKED
assert( pPager->pAllRead==0 );
+#endif
if( pagerUseWal(pPager) ){
/* If the pager is configured to use locking_mode=exclusive, and an
** The busy-handler is not invoked if another connection already
** holds the write-lock. If possible, the upper layer will call it.
*/
- if( exFlag>=0 ){
- rc = sqlite3WalBeginWriteTransaction(pPager->pWal);
- }else{
+#ifdef SQLITE_ENABLE_UNLOCKED
+ if( exFlag<0 ){
pPager->pAllRead = sqlite3BitvecCreate(pPager->dbSize);
if( pPager->pAllRead==0 ){
rc = SQLITE_NOMEM;
}
+ }else
+#endif
+ {
+ rc = sqlite3WalBeginWriteTransaction(pPager->pWal);
}
}else{
/* Obtain a RESERVED lock on the database file. If the exFlag parameter
** to sqlite3PagerWrite(). In other words, return TRUE if it is ok
** to change the content of the page.
*/
+#if defined(SQLITE_ENABLE_UNLOCKED) || !defined(NDEBUG)
int sqlite3PagerIswriteable(DbPage *pPg){
return pPg->flags & PGHDR_WRITEABLE;
}
+#endif
/*
** A call to this routine tells the pager that it is not necessary to
}
/*
-** This function may only be called while a write-transaction is active in
-** rollback. If the connection is in WAL mode, this call is a no-op.
-** Otherwise, if the connection does not already have an EXCLUSIVE lock on
-** the database file, an attempt is made to obtain one.
+** This function is called to ensure that all locks required to commit the
+** current write-transaction to the database file are held. If the db is
+** in rollback mode, this means the EXCLUSIVE lock on the database file.
**
-** If the EXCLUSIVE lock is already held or the attempt to obtain it is
-** successful, or the connection is in WAL mode, SQLITE_OK is returned.
-** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is
-** returned.
+** Or, if this is a non-UNLOCKED transaction on a wal-mode database, this
+** function is a no-op.
+**
+** If this is an UNLOCKED transaction on a wal-mode database, this function
+** attempts to obtain the WRITER lock on the wal file and also checks to
+** see that the transaction can be safely committed (does not commit with
+** any other transaction committed since it was opened).
+**
+** If the required locks are already held or successfully obtained and
+** the transaction can be committed, SQLITE_OK is returned. If a required lock
+** cannot be obtained, SQLITE_BUSY is returned. Or, if the current transaction
+** is UNLOCKED and cannot be committed due to a conflict, SQLITE_BUSY_SNAPSHOT
+** is returned. Otherwise, if some other error occurs (IO error, OOM etc.),
+** and SQLite error code is returned.
*/
int sqlite3PagerExclusiveLock(Pager *pPager, PgHdr *pPage1){
int rc = SQLITE_OK;
assert( assert_pager_state(pPager) );
if( 0==pagerUseWal(pPager) ){
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
- }else{
+ }
+#ifdef SQLITE_ENABLE_UNLOCKED
+ else{
if( pPager->pAllRead ){
/* This is an UNLOCKED transaction. Attempt to lock the wal database
** here. If SQLITE_BUSY (but not SQLITE_BUSY_SNAPSHOT) is returned,
** invoke the busy-handler and try again for as long as it returns
** non-zero. */
do {
- /* rc = sqlite3WalBeginWriteTransaction(pWal); */
rc = sqlite3WalLockForCommit(pPager->pWal, pPage1, pPager->pAllRead);
}while( rc==SQLITE_BUSY
&& pPager->xBusyHandler(pPager->pBusyHandlerArg)
);
}
}
+#endif
return rc;
}
+#ifdef SQLITE_ENABLE_UNLOCKED
+/*
+** This function is called as part of committing an UNLOCKED transaction.
+** At this point the wal WRITER lock is held, and all pages in the cache
+** except for page 1 are compatible with the snapshot at the head of the
+** wal file.
+**
+** This function updates the in-memory data structures and reloads the
+** contents of page 1 so that the client is operating on the snapshot
+** at the head of the wal file.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+*/
int sqlite3PagerUpgradeSnapshot(Pager *pPager, DbPage *pPage1){
int rc;
u32 iFrame = 0;
return rc;
}
-void sqlite3PagerSetDbsize(Pager *pPager, Pgno nFinal){
- pPager->dbSize = nFinal;
+/*
+** Set the in-memory cache of the database file size to nSz pages.
+*/
+void sqlite3PagerSetDbsize(Pager *pPager, Pgno nSz){
+ pPager->dbSize = nSz;
+}
+
+/*
+** Return true if this pager is currently within an UNLOCKED transaction.
+*/
+int sqlite3PagerIsUnlocked(Pager *pPager){
+ return pPager->pAllRead!=0;
}
/*
sqlite3WalEndWriteTransaction(pPager->pWal);
}
}
-
-/*
-** Return true if this pager is currently within an UNLOCKED transaction.
-*/
-int sqlite3PagerIsUnlocked(Pager *pPager){
- return pPager->pAllRead!=0;
-}
+#endif /* ifdef SQLITE_ENABLE_UNLOCKED */
/*
Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_ENABLE_UNLOCKED
+ Tcl_SetVar2(interp, "sqlite_options", "unlocked", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "unlocked", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_UTF16
Tcl_SetVar2(interp, "sqlite_options", "utf16", "0", TCL_GLOBAL_ONLY);
#else
}
}
+#ifdef SQLITE_ENABLE_UNLOCKED
if( db->bUnlocked && (rc & 0xFF)==SQLITE_BUSY ){
/* An SQLITE_BUSY or SQLITE_BUSY_SNAPSHOT was encountered while
** attempting to take the WRITER lock on a wal file. Release the
}
}
}
+#endif
if( rc!=SQLITE_OK ){
return rc;
return rc;
}
-/*
-** TODO: Combine some code with BeginWriteTransaction()
+/*
+** This function is called by a writer that has a read-lock on aReadmark[0]
+** (pWal->readLock==0). This function relinquishes that lock and takes a
+** lock on a different aReadmark[] slot.
**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+*/
+static int walUpgradeReadlock(Wal *pWal){
+ int cnt;
+ int rc;
+ assert( pWal->writeLock && pWal->readLock==0 );
+ walUnlockShared(pWal, WAL_READ_LOCK(0));
+ pWal->readLock = -1;
+ cnt = 0;
+ do{
+ int notUsed;
+ rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt);
+ }while( rc==WAL_RETRY );
+ assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
+ testcase( (rc&0xff)==SQLITE_IOERR );
+ testcase( rc==SQLITE_PROTOCOL );
+ testcase( rc==SQLITE_OK );
+ return rc;
+}
+
+
+#ifdef SQLITE_ENABLE_UNLOCKED
+/*
** This function is only ever called when committing a "BEGIN UNLOCKED"
** transaction. It may be assumed that no frames have been written to
-** the wal file.
+** the wal file. The second parameter is a pointer to the in-memory
+** representation of page 1 of the database (which may or may not be
+** dirty). The third is a bitvec with a bit set for each page in the
+** database file that was read by the current unlocked transaction.
+**
+** This function performs three tasks:
+**
+** 1) It obtains the WRITER lock on the wal file,
+**
+** 2) It checks that there are no conflicts between the current
+** transaction and any transactions committed to the wal file since
+** it was opened, and
+**
+** 3) It ejects any non-dirty pages from the page-cache that have been
+** written by another client since the UNLOCKED transaction was started
+** (so as to avoid ending up with an inconsistent cache after the
+** current transaction is committed).
+**
+** If no error occurs and the caller may proceed with committing the
+** transaction, SQLITE_OK is returned. SQLITE_BUSY is returned if the WRITER
+** lock cannot be obtained. Or, if the WRITER lock can be obtained but there
+** are conflicts with a committed transaction, SQLITE_BUSY_SNAPSHOT. Finally,
+** if an error (i.e. an OOM condition or IO error), an SQLite error code
+** is returned.
*/
int sqlite3WalLockForCommit(Wal *pWal, PgHdr *pPage1, Bitvec *pAllRead){
Pager *pPager = pPage1->pPager;
}
/*
-** This function is called by a writer that has a read-lock on aReadmark[0]
-** (pWal->readLock==0). This function relinquishes that lock and takes a
-** lock on a different aReadmark[] slot.
+** This function is called as part of committing an UNLOCKED transaction.
+** It is assumed that sqlite3WalLockForCommit() has already been successfully
+** called and so (a) the WRITER lock is held and (b) it is known that the
+** wal-index-header stored in shared memory is not corrupt.
+**
+** Before returning, this function upgrades the client so that it is
+** operating on the database snapshot currently at the head of the wal file
+** (even if the UNLOCKED transaction ran against an older snapshot).
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
-static int walUpgradeReadlock(Wal *pWal){
- int cnt;
- int rc;
- assert( pWal->writeLock && pWal->readLock==0 );
- walUnlockShared(pWal, WAL_READ_LOCK(0));
- pWal->readLock = -1;
- cnt = 0;
- do{
- int notUsed;
- rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt);
- }while( rc==WAL_RETRY );
- assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
- testcase( (rc&0xff)==SQLITE_IOERR );
- testcase( rc==SQLITE_PROTOCOL );
- testcase( rc==SQLITE_OK );
- return rc;
-}
-
int sqlite3WalUpgradeSnapshot(Wal *pWal){
int rc = SQLITE_OK;
assert( pWal->writeLock );
}
return rc;
}
+#endif /* SQLITE_ENABLE_UNLOCKED */
/*
** End a write transaction. The commit has already been done. This
source $testdir/lock_common.tcl
set ::testprefix unlocked
+ifcapable !unlocked {
+ finish_test
+ return
+}
do_execsql_test 1.0 {
PRAGMA journal_mode = wal;
source $testdir/lock_common.tcl
set ::testprefix unlocked2
+ifcapable !unlocked {
+ finish_test
+ return
+}
do_multiclient_test tn {
set ::testprefix unlocked3
if {$AUTOVACUUM} { finish_test ; return }
+ifcapable !unlocked {
+ finish_test
+ return
+}
proc create_schema {} {
db eval {