diff options
Diffstat (limited to 'lib/libsqlite3/src/test_superlock.c')
-rw-r--r-- | lib/libsqlite3/src/test_superlock.c | 356 |
1 files changed, 0 insertions, 356 deletions
diff --git a/lib/libsqlite3/src/test_superlock.c b/lib/libsqlite3/src/test_superlock.c deleted file mode 100644 index cac789842d3..00000000000 --- a/lib/libsqlite3/src/test_superlock.c +++ /dev/null @@ -1,356 +0,0 @@ -/* -** 2010 November 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. -** -************************************************************************* -** Example code for obtaining an exclusive lock on an SQLite database -** file. This method is complicated, but works for both WAL and rollback -** mode database files. The interface to the example code in this file -** consists of the following two functions: -** -** sqlite3demo_superlock() -** sqlite3demo_superunlock() -*/ - -#include "sqlite3.h" -#include <string.h> /* memset(), strlen() */ -#include <assert.h> /* assert() */ - -/* -** A structure to collect a busy-handler callback and argument and a count -** of the number of times it has been invoked. -*/ -struct SuperlockBusy { - int (*xBusy)(void*,int); /* Pointer to busy-handler function */ - void *pBusyArg; /* First arg to pass to xBusy */ - int nBusy; /* Number of times xBusy has been invoked */ -}; -typedef struct SuperlockBusy SuperlockBusy; - -/* -** An instance of the following structure is allocated for each active -** superlock. The opaque handle returned by sqlite3demo_superlock() is -** actually a pointer to an instance of this structure. -*/ -struct Superlock { - sqlite3 *db; /* Database handle used to lock db */ - int bWal; /* True if db is a WAL database */ -}; -typedef struct Superlock Superlock; - -/* -** The pCtx pointer passed to this function is actually a pointer to a -** SuperlockBusy structure. Invoke the busy-handler function encapsulated -** by the structure and return the result. -*/ -static int superlockBusyHandler(void *pCtx, int UNUSED){ - SuperlockBusy *pBusy = (SuperlockBusy *)pCtx; - if( pBusy->xBusy==0 ) return 0; - return pBusy->xBusy(pBusy->pBusyArg, pBusy->nBusy++); -} - -/* -** This function is used to determine if the main database file for -** connection db is open in WAL mode or not. If no error occurs and the -** database file is in WAL mode, set *pbWal to true and return SQLITE_OK. -** If it is not in WAL mode, set *pbWal to false. -** -** If an error occurs, return an SQLite error code. The value of *pbWal -** is undefined in this case. -*/ -static int superlockIsWal(Superlock *pLock){ - int rc; /* Return Code */ - sqlite3_stmt *pStmt; /* Compiled PRAGMA journal_mode statement */ - - rc = sqlite3_prepare(pLock->db, "PRAGMA main.journal_mode", -1, &pStmt, 0); - if( rc!=SQLITE_OK ) return rc; - - pLock->bWal = 0; - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - const char *zMode = (const char *)sqlite3_column_text(pStmt, 0); - if( zMode && strlen(zMode)==3 && sqlite3_strnicmp("wal", zMode, 3)==0 ){ - pLock->bWal = 1; - } - } - - return sqlite3_finalize(pStmt); -} - -/* -** Obtain an exclusive shm-lock on nByte bytes starting at offset idx -** of the file fd. If the lock cannot be obtained immediately, invoke -** the busy-handler until either it is obtained or the busy-handler -** callback returns 0. -*/ -static int superlockShmLock( - sqlite3_file *fd, /* Database file handle */ - int idx, /* Offset of shm-lock to obtain */ - int nByte, /* Number of consective bytes to lock */ - SuperlockBusy *pBusy /* Busy-handler wrapper object */ -){ - int rc; - int (*xShmLock)(sqlite3_file*, int, int, int) = fd->pMethods->xShmLock; - do { - rc = xShmLock(fd, idx, nByte, SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE); - }while( rc==SQLITE_BUSY && superlockBusyHandler((void *)pBusy, 0) ); - return rc; -} - -/* -** Obtain the extra locks on the database file required for WAL databases. -** Invoke the supplied busy-handler as required. -*/ -static int superlockWalLock( - sqlite3 *db, /* Database handle open on WAL database */ - SuperlockBusy *pBusy /* Busy handler wrapper object */ -){ - int rc; /* Return code */ - sqlite3_file *fd = 0; /* Main database file handle */ - void volatile *p = 0; /* Pointer to first page of shared memory */ - - /* Obtain a pointer to the sqlite3_file object open on the main db file. */ - rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd); - if( rc!=SQLITE_OK ) return rc; - - /* Obtain the "recovery" lock. Normally, this lock is only obtained by - ** clients running database recovery. - */ - rc = superlockShmLock(fd, 2, 1, pBusy); - if( rc!=SQLITE_OK ) return rc; - - /* Zero the start of the first shared-memory page. This means that any - ** clients that open read or write transactions from this point on will - ** have to run recovery before proceeding. Since they need the "recovery" - ** lock that this process is holding to do that, no new read or write - ** transactions may now be opened. Nor can a checkpoint be run, for the - ** same reason. - */ - rc = fd->pMethods->xShmMap(fd, 0, 32*1024, 1, &p); - if( rc!=SQLITE_OK ) return rc; - memset((void *)p, 0, 32); - - /* Obtain exclusive locks on all the "read-lock" slots. Once these locks - ** are held, it is guaranteed that there are no active reader, writer or - ** checkpointer clients. - */ - rc = superlockShmLock(fd, 3, SQLITE_SHM_NLOCK-3, pBusy); - return rc; -} - -/* -** Release a superlock held on a database file. The argument passed to -** this function must have been obtained from a successful call to -** sqlite3demo_superlock(). -*/ -void sqlite3demo_superunlock(void *pLock){ - Superlock *p = (Superlock *)pLock; - if( p->bWal ){ - int rc; /* Return code */ - int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE; - sqlite3_file *fd = 0; - rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd); - if( rc==SQLITE_OK ){ - fd->pMethods->xShmLock(fd, 2, 1, flags); - fd->pMethods->xShmLock(fd, 3, SQLITE_SHM_NLOCK-3, flags); - } - } - sqlite3_close(p->db); - sqlite3_free(p); -} - -/* -** Obtain a superlock on the database file identified by zPath, using the -** locking primitives provided by VFS zVfs. If successful, SQLITE_OK is -** returned and output variable *ppLock is populated with an opaque handle -** that may be used with sqlite3demo_superunlock() to release the lock. -** -** If an error occurs, *ppLock is set to 0 and an SQLite error code -** (e.g. SQLITE_BUSY) is returned. -** -** If a required lock cannot be obtained immediately and the xBusy parameter -** to this function is not NULL, then xBusy is invoked in the same way -** as a busy-handler registered with SQLite (using sqlite3_busy_handler()) -** until either the lock can be obtained or the busy-handler function returns -** 0 (indicating "give up"). -*/ -int sqlite3demo_superlock( - const char *zPath, /* Path to database file to lock */ - const char *zVfs, /* VFS to use to access database file */ - int (*xBusy)(void*,int), /* Busy handler callback */ - void *pBusyArg, /* Context arg for busy handler */ - void **ppLock /* OUT: Context to pass to superunlock() */ -){ - SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */ - int rc; /* Return code */ - Superlock *pLock; - - pLock = sqlite3_malloc(sizeof(Superlock)); - if( !pLock ) return SQLITE_NOMEM; - memset(pLock, 0, sizeof(Superlock)); - - /* Open a database handle on the file to superlock. */ - rc = sqlite3_open_v2( - zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs - ); - - /* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not - ** a WAL database, this is all we need to do. - ** - ** A wrapper function is used to invoke the busy-handler instead of - ** registering the busy-handler function supplied by the user directly - ** with SQLite. This is because the same busy-handler function may be - ** invoked directly later on when attempting to obtain the extra locks - ** required in WAL mode. By using the wrapper, we are able to guarantee - ** that the "nBusy" integer parameter passed to the users busy-handler - ** represents the total number of busy-handler invocations made within - ** this call to sqlite3demo_superlock(), including any made during the - ** "BEGIN EXCLUSIVE". - */ - if( rc==SQLITE_OK ){ - busy.xBusy = xBusy; - busy.pBusyArg = pBusyArg; - sqlite3_busy_handler(pLock->db, superlockBusyHandler, (void *)&busy); - rc = sqlite3_exec(pLock->db, "BEGIN EXCLUSIVE", 0, 0, 0); - } - - /* If the BEGIN EXCLUSIVE was executed successfully and this is a WAL - ** database, call superlockWalLock() to obtain the extra locks required - ** to prevent readers, writers and/or checkpointers from accessing the - ** db while this process is holding the superlock. - ** - ** Before attempting any WAL locks, commit the transaction started above - ** to drop the WAL read and write locks currently held. Otherwise, the - ** new WAL locks may conflict with the old. - */ - if( rc==SQLITE_OK ){ - if( SQLITE_OK==(rc = superlockIsWal(pLock)) && pLock->bWal ){ - rc = sqlite3_exec(pLock->db, "COMMIT", 0, 0, 0); - if( rc==SQLITE_OK ){ - rc = superlockWalLock(pLock->db, &busy); - } - } - } - - if( rc!=SQLITE_OK ){ - sqlite3demo_superunlock(pLock); - *ppLock = 0; - }else{ - *ppLock = pLock; - } - - return rc; -} - -/* -** End of example code. Everything below here is the test harness. -************************************************************************** -************************************************************************** -*************************************************************************/ - - -#ifdef SQLITE_TEST - -#include <tcl.h> - -struct InterpAndScript { - Tcl_Interp *interp; - Tcl_Obj *pScript; -}; -typedef struct InterpAndScript InterpAndScript; - -static void superunlock_del(ClientData cd){ - sqlite3demo_superunlock((void *)cd); -} - -static int superunlock_cmd( - ClientData cd, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - if( objc!=1 ){ - Tcl_WrongNumArgs(interp, 1, objv, ""); - return TCL_ERROR; - } - Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); - return TCL_OK; -} - -static int superlock_busy(void *pCtx, int nBusy){ - InterpAndScript *p = (InterpAndScript *)pCtx; - Tcl_Obj *pEval; /* Script to evaluate */ - int iVal = 0; /* Value to return */ - - pEval = Tcl_DuplicateObj(p->pScript); - Tcl_IncrRefCount(pEval); - Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewIntObj(nBusy)); - Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL); - Tcl_GetIntFromObj(p->interp, Tcl_GetObjResult(p->interp), &iVal); - Tcl_DecrRefCount(pEval); - - return iVal; -} - -/* -** Tclcmd: sqlite3demo_superlock CMDNAME PATH VFS BUSY-HANDLER-SCRIPT -*/ -static int superlock_cmd( - ClientData cd, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - void *pLock; /* Lock context */ - char *zPath; - char *zVfs = 0; - InterpAndScript busy = {0, 0}; - int (*xBusy)(void*,int) = 0; /* Busy handler callback */ - int rc; /* Return code from sqlite3demo_superlock() */ - - if( objc<3 || objc>5 ){ - Tcl_WrongNumArgs( - interp, 1, objv, "CMDNAME PATH ?VFS? ?BUSY-HANDLER-SCRIPT?"); - return TCL_ERROR; - } - - zPath = Tcl_GetString(objv[2]); - - if( objc>3 ){ - zVfs = Tcl_GetString(objv[3]); - if( strlen(zVfs)==0 ) zVfs = 0; - } - if( objc>4 ){ - busy.interp = interp; - busy.pScript = objv[4]; - xBusy = superlock_busy; - } - - rc = sqlite3demo_superlock(zPath, zVfs, xBusy, &busy, &pLock); - assert( rc==SQLITE_OK || pLock==0 ); - assert( rc!=SQLITE_OK || pLock!=0 ); - - if( rc!=SQLITE_OK ){ - extern const char *sqlite3ErrStr(int); - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); - return TCL_ERROR; - } - - Tcl_CreateObjCommand( - interp, Tcl_GetString(objv[1]), superunlock_cmd, pLock, superunlock_del - ); - Tcl_SetObjResult(interp, objv[1]); - return TCL_OK; -} - -int SqliteSuperlock_Init(Tcl_Interp *interp){ - Tcl_CreateObjCommand(interp, "sqlite3demo_superlock", superlock_cmd, 0, 0); - return TCL_OK; -} -#endif |