From: drh Date: Sun, 15 Jan 2006 00:13:15 +0000 (+0000) Subject: Documentation updates. Fix to date.c. But most importantly: database X-Git-Tag: version-3.6.10~3223 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=029b44bdd396478ffe00bce730023a7eae047eec;p=thirdparty%2Fsqlite.git Documentation updates. Fix to date.c. But most importantly: database connections are now allowed to change threads as long as they are not holding a lock. (CVS 2944) FossilOrigin-Name: 03c422ecb508dd84dfafc8b7a0b790a43f5dadda --- diff --git a/manifest b/manifest index 64601a8e08..4e6240681f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fixes\sfor\sOMIT_SUBQUERY\sbuilds:\sDisable\swhere\sclause\sOR->IN\soptimization.\sInclude\sEXISTS\skeyword\s(for\snew\sCREATE\sTABLE\ssyntax).\sTest\sfile\sfixes.\s(CVS\s2943) -D 2006-01-14T08:02:28 +C Documentation\supdates.\s\sFix\sto\sdate.c.\s\sBut\smost\simportantly:\sdatabase\nconnections\sare\snow\sallowed\sto\schange\sthreads\sas\slong\sas\sthey\sare\snot\nholding\sa\slock.\s(CVS\s2944) +D 2006-01-15T00:13:16 F Makefile.in ab3ffd8d469cef4477257169b82810030a6bb967 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -39,7 +39,7 @@ F src/btree.h 5663c4f43e8521546ccebc8fc95acb013b8f3184 F src/build.c 206c891028158668691f27bcbf7c3c4f15248a94 F src/callback.c ba3e6cc7a6beb562e7a66f92e26fabcb21aab1e2 F src/complete.c df1681cef40dec33a286006981845f87b194e7a4 -F src/date.c 5b86bc41754ffffb2b5742fbd71ea687f01cc6ca +F src/date.c 5f5850c6b5da68fdc47d124573715ba948c9d8e0 F src/delete.c c7bd5708a629585e073ce34cf3b1fcb52c2fef38 F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d F src/expr.c f885cfe73fb235635fba72e78bb858c64529771f @@ -55,7 +55,7 @@ F src/os.h 9debc3d3ca4cdafde222a0ea74a4c8415aef4f22 F src/os_common.h 6b76efa9b252e288de53b202ed5a0d48f48dc8db F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3 -F src/os_unix.c bc35a237a10c2ecb5c5b038d31d20ecb098dcc7d +F src/os_unix.c e6ff5035b3d06fc69773e52e1bc6f7f7ccace084 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c cd4ca2753aeaad11f5c9b9b6ef28752f45ed4529 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b @@ -67,13 +67,13 @@ F src/prepare.c 1058dcb102005a880d757551d52a0a2830c05f27 F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812 F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261 F src/select.c 28d449c7762dd580aaba49a9c6c16e93ca951e49 -F src/server.c e425729aa7ff374637033a38ba9fd9938c432244 +F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 66b073375efbdee19045e7e0cd38b85f9aff71da F src/sqlite.h.in 492580f7e3ff71eb43193eb7bb98e2d549889ce3 F src/sqliteInt.h ed482d6de58fa79000f9c3bb00d7740126fb55fb F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316 F src/tclsqlite.c d650bea0248fc0a310ddc2cb94273a3a5021fddf -F src/test1.c 30ed0d4d594db0bb2beb98be7024cde1fe686f14 +F src/test1.c 22709543ac2f7a5979ec51c3130ba93cf6e82951 F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b F src/test3.c 9742aa146eb750cab81c1d5605286c3a0eb88054 F src/test4.c 0f95de81629a53fc6ab104f64a7ccb1dcbb8af90 @@ -224,7 +224,7 @@ F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca F test/select5.test 07a90ab3c7e3f0a241a9cdea1d997b2c8a89ff0b F test/select6.test f459a19bdac0501c4d3eb1a4df4b7a76f1bb8ad4 F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6 -F test/server1.test 9d2d5b17b537911214a7e2a2728ff4f6ff16319c +F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5 F test/shared.test 2a7ae35bbf0f805cb9782146f5e812003ee8d1dc F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5 F test/subquery.test e6de53332c0301b3cfa34edc3f3cd5fa1e859efd @@ -340,7 +340,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P d634f8b28abd7af4565c644bd7972b067caa0133 -R e68269cdd28a8797bb4063cb46df0175 -U danielk1977 -Z 2134ba8d1976f430c91af4baa4a445ff +P 8e79a0c24a03ccf960d6ccfb7c6b9b0f7c614e9b +R 9d07ce30bc69528746c99ed3d4ba8921 +U drh +Z 392783876068e8090d13d0e230d0bba8 diff --git a/manifest.uuid b/manifest.uuid index 50029f624d..9672413366 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8e79a0c24a03ccf960d6ccfb7c6b9b0f7c614e9b \ No newline at end of file +03c422ecb508dd84dfafc8b7a0b790a43f5dadda \ No newline at end of file diff --git a/src/date.c b/src/date.c index b4ff3509b5..dfb693c4c1 100644 --- a/src/date.c +++ b/src/date.c @@ -16,7 +16,7 @@ ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: date.c,v 1.50 2006/01/13 01:17:21 drh Exp $ +** $Id: date.c,v 1.51 2006/01/15 00:13:16 drh Exp $ ** ** NOTES: ** @@ -105,19 +105,20 @@ static int getDigits(const char *zDate, ...){ val = 0; while( N-- ){ if( !isdigit(*(u8*)zDate) ){ - return cnt; + goto end_getDigits; } val = val*10 + *zDate - '0'; zDate++; } if( valmax || (nextC!=0 && nextC!=*zDate) ){ - return cnt; + goto end_getDigits; } *pVal = val; zDate++; cnt++; }while( nextC ); va_end(ap); +end_getDigits: return cnt; } diff --git a/src/os_unix.c b/src/os_unix.c index 45fc61f855..1e49657201 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -165,9 +165,10 @@ struct unixFile { ** to another. This logic makes sure a user does not try to do that ** by mistake. */ -#if defined(SQLITE_UNIX_THREADS) && !defined(SQLITE_ALLOW_XTHREAD_CONNECTIONS) +#if defined(SQLITE_UNIX_THREADS) # define SET_THREADID(X) (X)->tid = pthread_self() -# define CHECK_THREADID(X) (!pthread_equal((X)->tid, pthread_self())) +# define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \ + !pthread_equal((X)->tid, pthread_self())) #else # define SET_THREADID(X) # define CHECK_THREADID(X) 0 @@ -348,7 +349,11 @@ static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; ** 1: Yes. Threads can override each others locks. ** -1: We don't know yet. */ +#ifdef SQLITE_TEST +int threadsOverrideEachOthersLocks = -1; +#else static int threadsOverrideEachOthersLocks = -1; +#endif /* ** This structure holds information passed into individual test @@ -465,6 +470,7 @@ static void testThreadLockingBehavior(fd_orig){ ** Release a lockInfo structure previously allocated by findLockInfo(). */ static void releaseLockInfo(struct lockInfo *pLock){ + assert( sqlite3OsInMutex() ); pLock->nRef--; if( pLock->nRef==0 ){ sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); @@ -476,6 +482,7 @@ static void releaseLockInfo(struct lockInfo *pLock){ ** Release a openCnt structure previously allocated by findLockInfo(). */ static void releaseOpenCnt(struct openCnt *pOpen){ + assert( sqlite3OsInMutex() ); pOpen->nRef--; if( pOpen->nRef==0 ){ sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); @@ -486,8 +493,8 @@ static void releaseOpenCnt(struct openCnt *pOpen){ /* ** Given a file descriptor, locate lockInfo and openCnt structures that -** describes that file descriptor. Create a new ones if necessary. The -** return values might be unset if an error occurs. +** describes that file descriptor. Create new ones if necessary. The +** return values might be uninitialized if an error occurs. ** ** Return the number of errors. */ @@ -505,6 +512,7 @@ static int findLockInfo( rc = fstat(fd, &statbuf); if( rc!=0 ) return 1; + assert( sqlite3OsInMutex() ); memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev; key1.ino = statbuf.st_ino; @@ -540,37 +548,76 @@ static int findLockInfo( pLock->nRef++; } *ppLock = pLock; - pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2)); - if( pOpen==0 ){ - struct openCnt *pOld; - pOpen = sqliteMallocRaw( sizeof(*pOpen) ); + if( ppOpen!=0 ){ + pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2)); if( pOpen==0 ){ - releaseLockInfo(pLock); - rc = 1; - goto exit_findlockinfo; - } - pOpen->key = key2; - pOpen->nRef = 1; - pOpen->nLock = 0; - pOpen->nPending = 0; - pOpen->aPending = 0; - pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); - if( pOld!=0 ){ - assert( pOld==pOpen ); - sqliteFree(pOpen); - releaseLockInfo(pLock); - rc = 1; - goto exit_findlockinfo; + struct openCnt *pOld; + pOpen = sqliteMallocRaw( sizeof(*pOpen) ); + if( pOpen==0 ){ + releaseLockInfo(pLock); + rc = 1; + goto exit_findlockinfo; + } + pOpen->key = key2; + pOpen->nRef = 1; + pOpen->nLock = 0; + pOpen->nPending = 0; + pOpen->aPending = 0; + pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); + if( pOld!=0 ){ + assert( pOld==pOpen ); + sqliteFree(pOpen); + releaseLockInfo(pLock); + rc = 1; + goto exit_findlockinfo; + } + }else{ + pOpen->nRef++; } - }else{ - pOpen->nRef++; + *ppOpen = pOpen; } - *ppOpen = pOpen; exit_findlockinfo: return rc; } +/* +** If we are currently in a different thread than the thread that the +** unixFile argument belongs to, then transfer ownership of the unixFile +** over to the current thread. +** +** A unixFile is only owned by a thread on systems where one thread is +** unable to override locks created by a different thread. RedHat9 is +** an example of such a system. +** +** Ownership transfer is only allowed if the unixFile is currently unlocked. +** If the unixFile is locked and an ownership is wrong, then return +** SQLITE_MISUSE. Otherwise return SQLITE_OK. +*/ +#ifdef SQLITE_UNIX_THREADS +static int transferOwnership(unixFile *pFile){ + pthread_t hSelf; + if( threadsOverrideEachOthersLocks ){ + /* Ownership transfers not needed on this system */ + return SQLITE_OK; + } + hSelf = pthread_self(); + if( pthread_equal(pFile->tid, hSelf) ){ + /* We are still in the same thread */ + return SQLITE_OK; + } + if( pFile->locktype!=NO_LOCK ){ + /* We cannot change ownership while we are holding a lock! */ + return SQLITE_MISUSE; + } + pFile->tid = hSelf; + releaseLockInfo(pFile->pLock); + return findLockInfo(pFile->h, &pFile->pLock, 0); +} +#else +# define transferOwnership(X) SQLITE_OK +#endif + /* ** Delete the named file */ @@ -1047,7 +1094,6 @@ static int unixCheckReservedLock(OsFile *id){ unixFile *pFile = (unixFile*)id; assert( pFile ); - if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE; sqlite3OsEnterMutex(); /* Because pFile->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ @@ -1166,7 +1212,6 @@ static int unixLock(OsFile *id, int locktype){ TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h, locktypeName(locktype), locktypeName(pFile->locktype), locktypeName(pLock->locktype), pLock->cnt , getpid()); - if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE; /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as @@ -1188,6 +1233,14 @@ static int unixLock(OsFile *id, int locktype){ */ sqlite3OsEnterMutex(); + /* Make sure the current thread owns the pFile. + */ + rc = transferOwnership(pFile); + if( rc!=SQLITE_OK ){ + sqlite3OsLeaveMutex(); + return rc; + } + /* If some thread using this PID has a lock via a different OsFile* ** handle that precludes the requested lock, return BUSY. */ @@ -1324,12 +1377,12 @@ static int unixUnlock(OsFile *id, int locktype){ assert( pFile ); TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype, pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid()); - if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE; assert( locktype<=SHARED_LOCK ); if( pFile->locktype<=locktype ){ return SQLITE_OK; } + if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE; sqlite3OsEnterMutex(); pLock = pFile->pLock; assert( pLock->cnt!=0 ); @@ -1401,9 +1454,11 @@ static int unixUnlock(OsFile *id, int locktype){ */ static int unixClose(OsFile **pId){ unixFile *id = (unixFile*)*pId; + int rc; + if( !id ) return SQLITE_OK; - if( CHECK_THREADID(id) ) return SQLITE_MISUSE; - unixUnlock(*pId, NO_LOCK); + rc = unixUnlock(*pId, NO_LOCK); + if( rc ) return rc; if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; sqlite3OsEnterMutex(); @@ -1516,8 +1571,10 @@ static int allocateUnixFile(unixFile *pInit, OsFile **pId){ pNew = sqliteMalloc( sizeof(unixFile) ); if( pNew==0 ){ close(pInit->h); + sqlite3OsEnterMutex(); releaseLockInfo(pInit->pLock); releaseOpenCnt(pInit->pOpen); + sqlite3OsLeaveMutex(); *pId = 0; return SQLITE_NOMEM; }else{ diff --git a/src/server.c b/src/server.c index 8348286989..d32c59007b 100644 --- a/src/server.c +++ b/src/server.c @@ -18,7 +18,7 @@ ** The configure script will never generate a Makefile with the option ** above. You will need to manually modify the Makefile if you want to ** include any of the code from this file in your project. Or, at your -** option, you may want to copy and paste the code from this file and +** option, you may copy and paste the code from this file and ** thereby avoiding a recompile of SQLite. ** ** @@ -40,8 +40,9 @@ ** ** (2) Beginning with SQLite version 3.3.0, when two or more ** connections to the same database occur within the same thread, -** they will share their database cache. This reduces I/O -** and memory requirements. +** they can optionally share their database cache. This reduces +** I/O and memory requirements. Cache shared is controlled using +** the sqlite3_enable_shared_cache() API. ** ** (3) Database connections on a shared cache use table-level locking ** instead of file-level locking for improved concurrency. @@ -96,7 +97,8 @@ ** These interfaces work exactly like the standard core SQLite interfaces ** having the same names without the "_client_" infix. Many other SQLite ** interfaces can be used directly without having to send messages to the -** server. The following interfaces fall into this second category: +** server as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. +** The following interfaces fall into this second category: ** ** sqlite3_bind_* ** sqlite3_changes @@ -110,16 +112,17 @@ ** sqlite3_errcode ** sqlite3_errmsg ** sqlite3_last_insert_rowid -** sqlite3_libversion -** sqlite3_mprintf ** sqlite3_total_changes ** sqlite3_transfer_bindings -** sqlite3_vmprintf ** ** A single SQLite connection (an sqlite3* object) or an SQLite statement ** (an sqlite3_stmt* object) should only be passed to a single interface -** function at a time. The connections and statements can be freely used -** by any thread as long as only one thread is using them at a time. +** function at a time. The connections and statements can be passed from +** any thread to any of the functions listed in the second group above as +** long as the same connection is not in use by two threads at once and +** as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. Additional +** information about the SQLITE_ENABLE_MEMORY_MANAGEMENT constraint is +** below. ** ** The busy handler for all database connections should remain turned ** off. That means that any lock contention will cause the associated @@ -132,12 +135,65 @@ ** the queue to be tried again later. But such enhanced processing is ** not included here, in order to keep the example simple. ** -** This code assumes the use of pthreads. Pthreads implementations -** are available for windows. (See, for example +** This example code assumes the use of pthreads. Pthreads +** implementations are available for windows. (See, for example ** http://sourceware.org/pthreads-win32/announcement.html.) Or, you ** can translate the locking and thread synchronization code to use ** windows primitives easily enough. The details are left as an ** exercise to the reader. +** +**** Restrictions Associated With SQLITE_ENABLE_MEMORY_MANAGEMENT **** +** +** If you compile with SQLITE_ENABLE_MEMORY_MANAGEMENT defined, then +** SQLite includes code that tracks how much memory is being used by +** each thread. These memory counts can become confused if memory +** is allocated by one thread and then freed by another. For that +** reason, when SQLITE_ENABLE_MEMORY_MANAGEMENT is used, all operations +** that might allocate or free memory should be performanced in the same +** thread that originally created the database connection. In that case, +** many of the operations that are listed above as safe to be performed +** in separate threads would need to be sent over to the server to be +** done there. If SQLITE_ENABLE_MEMORY_MANAGEMENT is defined, then +** the following functions can be used safely from different threads +** without messing up the allocation counts: +** +** sqlite3_bind_parameter_name +** sqlite3_bind_parameter_index +** sqlite3_changes +** sqlite3_column_blob +** sqlite3_column_count +** sqlite3_complete +** sqlite3_data_count +** sqlite3_db_handle +** sqlite3_errcode +** sqlite3_errmsg +** sqlite3_last_insert_rowid +** sqlite3_total_changes +** +** The remaining functions are not thread-safe when memory management +** is enabled. So one would have to define some new interface routines +** along the following lines: +** +** sqlite3_client_bind_* +** sqlite3_client_clear_bindings +** sqlite3_client_column_* +** sqlite3_client_create_collation +** sqlite3_client_create_function +** sqlite3_client_transfer_bindings +** +** The example code in this file is intended for use with memory +** management turned off. So the implementation of these additional +** client interfaces is left as an exercise to the reader. +** +** It may seem surprising to the reader that the list of safe functions +** above does not include things like sqlite3_bind_int() or +** sqlite3_column_int(). But those routines might, in fact, allocate +** or deallocate memory. In the case of sqlite3_bind_int(), if the +** parameter was previously bound to a string that string might need +** to be deallocated before the new integer value is inserted. In +** the case of sqlite3_column_int(), the value of the column might be +** a UTF-16 string which will need to be converted to UTF-8 then into +** an integer. */ /* diff --git a/src/test1.c b/src/test1.c index 282a53f4a8..beff4a59f8 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.189 2006/01/11 23:40:34 drh Exp $ +** $Id: test1.c,v 1.190 2006/01/15 00:13:16 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -3487,6 +3487,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_memMax; extern int sqlite3_like_count; extern int sqlite3_tsd_count; +#if OS_UNIX && defined(SQLITE_TEST) && defined(THREADSAFE) && THREADSAFE + extern int threadsOverrideEachOthersLocks; +#endif #if OS_WIN extern int sqlite3_os_type; #endif @@ -3521,6 +3524,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ (char*)&sqlite3_os_trace, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite3_tsd_count", (char*)&sqlite3_tsd_count, TCL_LINK_INT); +#if OS_UNIX && defined(SQLITE_TEST) && defined(THREADSAFE) && THREADSAFE + Tcl_LinkVar(interp, "threadsOverrideEachOthersLocks", + (char*)&threadsOverrideEachOthersLocks, TCL_LINK_INT); +#endif #ifndef SQLITE_OMIT_UTF16 Tcl_LinkVar(interp, "sqlite_last_needed_collation", (char*)&pzNeededCollation, TCL_LINK_STRING|TCL_LINK_READ_ONLY); diff --git a/test/server1.test b/test/server1.test index d19a6e39d0..136427ba9a 100644 --- a/test/server1.test +++ b/test/server1.test @@ -13,7 +13,7 @@ # # This file is derived from thread1.test # -# $Id: server1.test,v 1.3 2006/01/10 20:36:40 drh Exp $ +# $Id: server1.test,v 1.4 2006/01/15 00:13:16 drh Exp $ set testdir [file dirname $argv0] @@ -26,6 +26,14 @@ if {[llength [info command client_step]]==0 || [sqlite3 -has-codec]} { return } +# The sample server implementation does not work right when memory +# management is enabled. +# +ifcapable memorymanage { + finish_test + return +} + # Create some data to work with # do_test server1-1.1 {