diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 12 | ||||
-rw-r--r-- | src/build.c | 30 | ||||
-rw-r--r-- | src/delete.c | 3 | ||||
-rw-r--r-- | src/insert.c | 4 | ||||
-rw-r--r-- | src/pager.c | 114 | ||||
-rw-r--r-- | src/pager.h | 4 | ||||
-rw-r--r-- | src/parse.y | 11 | ||||
-rw-r--r-- | src/pragma.c | 3 | ||||
-rw-r--r-- | src/sqliteInt.h | 5 | ||||
-rw-r--r-- | src/tokenize.c | 3 | ||||
-rw-r--r-- | src/trigger.c | 1 | ||||
-rw-r--r-- | src/update.c | 4 | ||||
-rw-r--r-- | src/vdbe.c | 5 |
13 files changed, 107 insertions, 92 deletions
diff --git a/src/btree.c b/src/btree.c index beb30a920..a5bd88613 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.191 2004/09/27 13:19:52 drh Exp $ +** $Id: btree.c,v 1.192 2004/10/05 02:41:42 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -1289,8 +1289,12 @@ static int newDatabase(Btree *pBt){ /* ** Attempt to start a new transaction. A write-transaction -** is started if the second argument is true, otherwise a read- -** transaction. +** is started if the second argument is nonzero, otherwise a read- +** transaction. If the second argument is 2 or more and exclusive +** transaction is started, meaning that no other process is allowed +** to access the database. A preexisting transaction may not be +** upgrade to exclusive by calling this routine a second time - the +** exclusivity flag only works for a new transaction. ** ** A write-transaction must be started before attempting any ** changes to the database. None of the following routines @@ -1329,7 +1333,7 @@ int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){ } if( rc==SQLITE_OK && wrflag ){ - rc = sqlite3pager_begin(pBt->pPage1->aData); + rc = sqlite3pager_begin(pBt->pPage1->aData, wrflag>1); if( rc==SQLITE_OK ){ rc = newDatabase(pBt); } diff --git a/src/build.c b/src/build.c index f4deb5182..2cf64573c 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.255 2004/09/30 14:22:47 drh Exp $ +** $Id: build.c,v 1.256 2004/10/05 02:41:42 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1376,8 +1376,6 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){ sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0, sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC); - - sqlite3EndWriteOperation(pParse); } /* Add the table to the in-memory representation of the database. @@ -1663,7 +1661,6 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ } } sqlite3VdbeOp3(v, OP_DropTable, pTab->iDb, 0, pTab->zName, 0); - sqlite3EndWriteOperation(pParse); } sqliteViewResetAll(db, iDb); @@ -2131,7 +2128,6 @@ void sqlite3CreateIndex( sqlite3VdbeAddOp(v, OP_Close, 1, 0); sqlite3ChangeCookie(db, v, iDb); sqlite3VdbeAddOp(v, OP_Close, 0, 0); - sqlite3EndWriteOperation(pParse); sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC); } @@ -2232,7 +2228,6 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){ sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb); sqlite3VdbeOp3(v, OP_DropIndex, pIndex->iDb, 0, pIndex->zName, 0); - sqlite3EndWriteOperation(pParse); } exit_drop_index: @@ -2398,9 +2393,10 @@ void sqlite3SrcListDelete(SrcList *pList){ /* ** Begin a transaction */ -void sqlite3BeginTransaction(Parse *pParse){ +void sqlite3BeginTransaction(Parse *pParse, int type){ sqlite3 *db; Vdbe *v; + int i; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; if( pParse->nErr || sqlite3_malloc_failed ) return; @@ -2408,6 +2404,11 @@ void sqlite3BeginTransaction(Parse *pParse){ v = sqlite3GetVdbe(pParse); if( !v ) return; + if( type!=TK_DEFERRED ){ + for(i=0; i<db->nDb; i++){ + sqlite3VdbeAddOp(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1); + } + } sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0); } @@ -2551,21 +2552,6 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ } } -/* -** Generate code that concludes an operation that may have changed -** the database. If a statement transaction was started, then emit -** an OP_Commit that will cause the changes to be committed to disk. -** -** Note that checkpoints are automatically committed at the end of -** a statement. Note also that there can be multiple calls to -** sqlite3BeginWriteOperation() but there should only be a single -** call to sqlite3EndWriteOperation() at the conclusion of the statement. -*/ -void sqlite3EndWriteOperation(Parse *pParse){ - /* Delete me! */ - return; -} - /* ** Return the transient sqlite3_value object used for encoding conversions ** during SQL compilation. diff --git a/src/delete.c b/src/delete.c index fefa45431..2b0457f0b 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** -** $Id: delete.c,v 1.81 2004/09/19 02:15:25 drh Exp $ +** $Id: delete.c,v 1.82 2004/10/05 02:41:42 drh Exp $ */ #include "sqliteInt.h" @@ -307,7 +307,6 @@ void sqlite3DeleteFrom( sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } } - sqlite3EndWriteOperation(pParse); /* ** Return the number of rows that were deleted. diff --git a/src/insert.c b/src/insert.c index 06f7d5a4b..114942e8c 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.118 2004/09/19 02:15:26 drh Exp $ +** $Id: insert.c,v 1.119 2004/10/05 02:41:42 drh Exp $ */ #include "sqliteInt.h" @@ -616,8 +616,6 @@ void sqlite3Insert( } } - sqlite3EndWriteOperation(pParse); - /* ** Return the number of rows inserted. */ diff --git a/src/pager.c b/src/pager.c index 8b20c16c5..cf0da5200 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.166 2004/10/02 20:38:28 drh Exp $ +** @(#) $Id: pager.c,v 1.167 2004/10/05 02:41:43 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -88,11 +88,27 @@ ** or sqlite_pager_commit(), the state goes back to PAGER_SHARED. */ #define PAGER_UNLOCK 0 -#define PAGER_SHARED 1 -#define PAGER_RESERVED 2 -#define PAGER_EXCLUSIVE 3 -#define PAGER_SYNCED 4 +#define PAGER_SHARED 1 /* same as SHARED_LOCK */ +#define PAGER_RESERVED 2 /* same as RESERVED_LOCK */ +#define PAGER_EXCLUSIVE 4 /* same as EXCLUSIVE_LOCK */ +#define PAGER_SYNCED 5 +/* +** If the SQLITE_BUSY_RESERVED_LOCK macro is set to true at compile-time, +** then failed attempts to get a reserved lock will invoke the busy callback. +** This is off by default. To see why, consider the following scenario: +** +** Suppose thread A already has a shared lock and wants a reserved lock. +** Thread B already has a reserved lock and wants an exclusive lock. If +** both threads are using their busy callbacks, it might be a long time +** be for one of the threads give up and allows the other to proceed. +** But if the thread trying to get the reserved lock gives up quickly +** (if it never invokes its busy callback) then the contention will be +** resolved quickly. +*/ +#ifndef SQLITE_BUSY_RESERVED_LOCK +# define SQLITE_BUSY_RESERVED_LOCK 0 +#endif /* ** Each in-memory image of a page begins with the following header. @@ -1908,6 +1924,37 @@ static int syncJournal(Pager *pPager){ } /* +** Try to obtain a lock on a file. Invoke the busy callback if the lock +** is currently not available. Repeate until the busy callback returns +** false or until the lock succeeds. +** +** Return SQLITE_OK on success and an error code if we cannot obtain +** the lock. +*/ +static int pager_wait_on_lock(Pager *pPager, int locktype){ + int rc; + assert( PAGER_SHARED==SHARED_LOCK ); + assert( PAGER_RESERVED==RESERVED_LOCK ); + assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); + if( pPager->state>=locktype ){ + rc = SQLITE_OK; + }else{ + int busy = 1; + do { + rc = sqlite3OsLock(&pPager->fd, locktype); + }while( rc==SQLITE_BUSY && + pPager->pBusyHandler && + pPager->pBusyHandler->xFunc && + pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++) + ); + if( rc==SQLITE_OK ){ + pPager->state = locktype; + } + } + return rc; +} + +/* ** Given a list of pages (connected by the PgHdr.pDirty pointer) write ** every one of those pages out to the database file and mark them all ** as clean. @@ -1915,7 +1962,6 @@ static int syncJournal(Pager *pPager){ static int pager_write_pagelist(PgHdr *pList){ Pager *pPager; int rc; - int busy = 1; if( pList==0 ) return SQLITE_OK; pPager = pList->pPager; @@ -1936,17 +1982,10 @@ static int pager_write_pagelist(PgHdr *pList){ ** EXCLUSIVE, it means the database file has been changed and any rollback ** will require a journal playback. */ - do { - rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK); - }while( rc==SQLITE_BUSY && - pPager->pBusyHandler && - pPager->pBusyHandler->xFunc && - pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++) - ); + rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ return rc; } - pPager->state = PAGER_EXCLUSIVE; while( pList ){ assert( pList->dirty ); @@ -2019,18 +2058,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){ ** on the database file. */ if( pPager->nRef==0 && !pPager->memDb ){ - int busy = 1; - do { - rc = sqlite3OsLock(&pPager->fd, SHARED_LOCK); - }while( rc==SQLITE_BUSY && - pPager->pBusyHandler && - pPager->pBusyHandler->xFunc && - pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++) - ); + rc = pager_wait_on_lock(pPager, SHARED_LOCK); if( rc!=SQLITE_OK ){ return rc; } - pPager->state = PAGER_SHARED; /* If a journal file exists, and there is no RESERVED lock on the ** database file, then it either needs to be played back or deleted. @@ -2408,8 +2439,12 @@ failed_to_open_journal: ** actual need to write to the journal. ** ** If the database is already reserved for writing, this routine is a no-op. +** +** If exFlag is true, go ahead and get an EXCLUSIVE lock on the file +** immediately instead of waiting until we try to flush the cache. The +** exFlag is ignored if a transaction is already active. */ -int sqlite3pager_begin(void *pData){ +int sqlite3pager_begin(void *pData, int exFlag){ PgHdr *pPg = DATA_TO_PGHDR(pData); Pager *pPager = pPg->pPager; int rc = SQLITE_OK; @@ -2421,29 +2456,20 @@ int sqlite3pager_begin(void *pData){ pPager->state = PAGER_EXCLUSIVE; pPager->origDbSize = pPager->dbSize; }else{ -#ifdef SQLITE_BUSY_RESERVED_LOCK - int busy = 1; - do { + if( SQLITE_BUSY_RESERVED_LOCK || exFlag ){ + rc = pager_wait_on_lock(pPager, RESERVED_LOCK); + }else{ rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK); - }while( rc==SQLITE_BUSY && - pPager->pBusyHandler && - pPager->pBusyHandler->xFunc && - pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++) - ); -#else - rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK); -#endif + } + if( rc==SQLITE_OK ){ + pPager->state = PAGER_RESERVED; + if( exFlag ){ + rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); + } + } if( rc!=SQLITE_OK ){ - /* We do not call the busy handler when we fail to get a reserved lock. - ** The only reason we might fail is because another process is holding - ** the reserved lock. But the other process will not be able to - ** release its reserved lock until this process releases its shared - ** lock. So we might as well fail in this process, let it release - ** its shared lock so that the other process can commit. - */ return rc; } - pPager->state = PAGER_RESERVED; pPager->dirtyCache = 0; TRACE2("TRANSACTION %d\n", pPager->fd.h); if( pPager->useJournal && !pPager->tempFile ){ @@ -2504,7 +2530,7 @@ int sqlite3pager_write(void *pData){ ** create it if it does not. */ assert( pPager->state!=PAGER_UNLOCK ); - rc = sqlite3pager_begin(pData); + rc = sqlite3pager_begin(pData, 0); if( rc!=SQLITE_OK ){ return rc; } diff --git a/src/pager.h b/src/pager.h index cb4a772c5..ff6dd8733 100644 --- a/src/pager.h +++ b/src/pager.h @@ -13,7 +13,7 @@ ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** -** @(#) $Id: pager.h,v 1.37 2004/07/22 01:19:35 drh Exp $ +** @(#) $Id: pager.h,v 1.38 2004/10/05 02:41:43 drh Exp $ */ /* @@ -74,7 +74,7 @@ int sqlite3pager_iswriteable(void*); int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*); int sqlite3pager_pagecount(Pager*); int sqlite3pager_truncate(Pager*,Pgno); -int sqlite3pager_begin(void*); +int sqlite3pager_begin(void*, int exFlag); int sqlite3pager_commit(Pager*); int sqlite3pager_sync(Pager*,const char *zMaster); int sqlite3pager_rollback(Pager*); diff --git a/src/parse.y b/src/parse.y index c8a95f552..7d56fed10 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.141 2004/10/04 13:38:09 drh Exp $ +** @(#) $Id: parse.y,v 1.142 2004/10/05 02:41:43 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -81,10 +81,15 @@ explain ::= . { sqlite3BeginParse(pParse, 0); } ///////////////////// Begin and end transactions. //////////////////////////// // -cmd ::= BEGIN trans_opt. {sqlite3BeginTransaction(pParse);} +cmd ::= BEGIN transtype(Y) trans_opt. {sqlite3BeginTransaction(pParse, Y);} trans_opt ::= . trans_opt ::= TRANSACTION. trans_opt ::= TRANSACTION nm. +%type transtype {int} +transtype(A) ::= . {A = TK_DEFERRED;} +transtype(A) ::= DEFERRED(X). {A = @X;} +transtype(A) ::= IMMEDIATE(X). {A = @X;} +transtype(A) ::= EXCLUSIVE(X). {A = @X;} cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);} cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);} cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);} @@ -127,7 +132,7 @@ id(A) ::= ID(X). {A = X;} // %fallback ID ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CONFLICT - DATABASE DEFERRED DESC DETACH EACH END EXPLAIN FAIL FOR + DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT TEMP TRIGGER VACUUM VIEW. diff --git a/src/pragma.c b/src/pragma.c index cf0f92d3f..1373501a7 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.67 2004/09/25 14:39:19 drh Exp $ +** $Id: pragma.c,v 1.68 2004/10/05 02:41:43 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -261,7 +261,6 @@ void sqlite3Pragma( sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3); sqlite3VdbeAddOp(v, OP_Negative, 0, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2); - sqlite3EndWriteOperation(pParse); pDb->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7b4c4fc0e..9b712ba44 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.326 2004/10/04 13:19:24 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.327 2004/10/05 02:41:43 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1310,7 +1310,7 @@ Vdbe *sqlite3GetVdbe(Parse*); void sqlite3Randomness(int, void*); void sqlite3RollbackAll(sqlite3*); void sqlite3CodeVerifySchema(Parse*, int); -void sqlite3BeginTransaction(Parse*); +void sqlite3BeginTransaction(Parse*, int); void sqlite3CommitTransaction(Parse*); void sqlite3RollbackTransaction(Parse*); int sqlite3ExprIsConstant(Expr*); @@ -1323,7 +1323,6 @@ void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int); void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int); void sqlite3OpenTableAndIndices(Parse*, Table*, int, int); void sqlite3BeginWriteOperation(Parse*, int, int); -void sqlite3EndWriteOperation(Parse*); Expr *sqlite3ExprDup(Expr*); void sqlite3TokenCopy(Token*, Token*); ExprList *sqlite3ExprListDup(ExprList*); diff --git a/src/tokenize.c b/src/tokenize.c index 5424eb047..6b3a5f713 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.89 2004/09/25 15:25:26 drh Exp $ +** $Id: tokenize.c,v 1.90 2004/10/05 02:41:43 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -71,6 +71,7 @@ static Keyword aKeywordTable[] = { { "EACH", TK_EACH, }, { "ELSE", TK_ELSE, }, { "EXCEPT", TK_EXCEPT, }, + { "EXCLUSIVE", TK_EXCLUSIVE, }, { "EXPLAIN", TK_EXPLAIN, }, { "FAIL", TK_FAIL, }, { "FOR", TK_FOR, }, diff --git a/src/trigger.c b/src/trigger.c index 50600b0af..97c830590 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -241,7 +241,6 @@ void sqlite3FinishTrigger( sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0, sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC); - sqlite3EndWriteOperation(pParse); } if( db->init.busy ){ diff --git a/src/update.c b/src/update.c index 5655bbe6e..ca1500078 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.89 2004/09/19 02:15:26 drh Exp $ +** $Id: update.c,v 1.90 2004/10/05 02:41:43 drh Exp $ */ #include "sqliteInt.h" @@ -430,8 +430,6 @@ void sqlite3Update( sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0); } - sqlite3EndWriteOperation(pParse); - /* ** Return the number of rows that were changed. */ diff --git a/src/vdbe.c b/src/vdbe.c index 327460ca2..7c5a6dea4 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.416 2004/10/04 13:19:24 drh Exp $ +** $Id: vdbe.c,v 1.417 2004/10/05 02:41:43 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -2157,7 +2157,8 @@ case OP_AutoCommit: { ** other process can start another write transaction while this transaction is ** underway. Starting a write transaction also creates a rollback journal. A ** write transaction must be started before any changes can be made to the -** database. +** database. If P2 is 2 or greater then an EXCLUSIVE lock is also obtained +** on the file. ** ** If P2 is zero, then a read-lock is obtained on the database file. */ |