From: dan Date: Wed, 2 Sep 2020 15:26:28 +0000 (+0000) Subject: Fix reporting on locks from external processes. Various other fixes. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=148920e52a080adf20eccf6ec043876dfa8d4b53;p=thirdparty%2Fsqlite.git Fix reporting on locks from external processes. Various other fixes. FossilOrigin-Name: 459de23e869c79357221100e81d2c8e0b812ed3260e58d7d7acb3419876f41a3 --- diff --git a/ext/misc/shmlockvtab.c b/ext/misc/shmlockvtab.c index f45e395108..9d0e16a06d 100644 --- a/ext/misc/shmlockvtab.c +++ b/ext/misc/shmlockvtab.c @@ -10,6 +10,9 @@ ** ************************************************************************* ** +** This file contains the implementation of the "shmlock" eponymous +** virtual table module. The schema of which is effectively: +** ** CREATE TABLE shmlock( ** connid TEXT, ** lock TEXT, @@ -17,6 +20,48 @@ ** mxFrame INTEGER, ** dbname HIDDEN ** ); +** +** This virtual table may be used to query for the locks held on the main or +** any attached database that is in wal mode. If the database is not in +** wal mode, zero rows are returned. Otherwise, one row is returned for +** each lock held on the database by a connection in either the current +** process, as well as - to the extent possible - one row for each lock held +** by another process. On unix, "to the extent possible" means that if +** two or more external processes hold a SHARED wal-mode lock on the same +** locking-slot, only one of them is reported on. +** +** To query for locks on the main database, either of: +** +** SELECT * FROM shmlock; +** SELECT * FROM shmlock('main'); +** +** To query for locks on the attached database named 'aux': +** +** SELECT * FROM shmlock('aux'); +** +** The non-HIDDEN columns of each row may be interpreted as follows: +** +** connid: +** String identifying the connection. For a local connection lock, this is +** either the string representation of an internal pointer value, or else a +** string configured using the file-control SQLITE_FCNTL_SHMLOCK_NAME. +** For a lock from an external process, the id takes the form "pid.123", +** where 123 is the process-id of the lock holder. +** +** lock: +** A text value representing the particular wal mode lock held. One of +** "WRITE", "CHECKPOINT", "RECOVER" or "READ(n)", where n is between 0 and +** 4, inclusive. +** +** locktype: +** 'R' for a shared (reader) lock, or 'W' for an exclusive (writer) lock. +** +** mxframe: +** When the lock is a shared lock held on a READ(n) slot, the integer value +** of the corresponding read-mark slot in shared-memory. +** +** This module currently only works with the "unix" VFS. +** */ #if !defined(SQLITEINT_H) #include "sqlite3ext.h" @@ -43,9 +88,9 @@ struct shmlock_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ char *zFcntl; int iFcntl; + char *aSpace; /* Space to use for dequoted strings */ const char *azCol[4]; - int anCol[4]; sqlite3_int64 iRowid; }; @@ -108,6 +153,7 @@ static int shmlockOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ static int shmlockClose(sqlite3_vtab_cursor *cur){ shmlock_cursor *pCur = (shmlock_cursor*)cur; sqlite3_free(pCur->zFcntl); + sqlite3_free(pCur->aSpace); sqlite3_free(pCur); return SQLITE_OK; } @@ -120,17 +166,30 @@ static int shmlockNext(sqlite3_vtab_cursor *cur){ shmlock_cursor *pCur = (shmlock_cursor*)cur; int ii = pCur->iFcntl; const char *z = pCur->zFcntl; + char *a = pCur->aSpace; int iCol; memset(pCur->azCol, 0, sizeof(char*)*4); - memset(pCur->anCol, 0, sizeof(int)*4); + if( z[ii]=='\0' ) return SQLITE_OK;; for(iCol=0; iCol<4; iCol++){ - pCur->azCol[iCol] = &z[ii]; - while( z[ii]!=' ' && z[ii]!='\n' && z[ii]!='\0' ) ii++; - pCur->anCol[iCol] = &z[ii] - pCur->azCol[iCol]; - if( z[ii]=='\0' ) break; + if( z[ii]!='\'' ) return SQLITE_ERROR; + + pCur->azCol[iCol] = a; ii++; - if( z[ii-1]=='\n' ) break; + while( z[ii] ){ + if( z[ii]=='\'' ){ + ii++; + if( z[ii]!='\'' ) break; + } + *a++ = z[ii++]; + } + *a++ = '\0'; + while( z[ii]==' ' ) ii++; + if( z[ii]=='\0' ) break; + if( z[ii]=='\n' ){ + ii++; + break; + } } pCur->iFcntl = ii; @@ -149,7 +208,7 @@ static int shmlockColumn( ){ shmlock_cursor *pCur = (shmlock_cursor*)cur; if( i<=3 && pCur->azCol[i] ){ - sqlite3_result_text(ctx, pCur->azCol[i], pCur->anCol[i], SQLITE_TRANSIENT); + sqlite3_result_text(ctx, pCur->azCol[i], -1, SQLITE_TRANSIENT); } return SQLITE_OK; } @@ -193,8 +252,9 @@ static int shmlockFilter( assert( argc==1 ); zDb = (const char*)sqlite3_value_text(argv[0]); } - sqlite3_free(pCur->zFcntl); + sqlite3_free(pCur->aSpace); pCur->zFcntl = 0; + pCur->aSpace = 0; rc = sqlite3_file_control( pTab->db, zDb, SQLITE_FCNTL_SHMLOCK_GET, (void*)&pCur->zFcntl ); @@ -204,7 +264,13 @@ static int shmlockFilter( rc = SQLITE_OK; } if( pCur->zFcntl ){ - rc = shmlockNext(pVtabCursor); + int n = strlen(pCur->zFcntl); + pCur->aSpace = sqlite3_malloc(n); + if( pCur->aSpace==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = shmlockNext(pVtabCursor); + } } return rc; } diff --git a/manifest b/manifest index 1090c25429..e625218eb4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sfile-controls\sand\sa\svtab\sfrontend\sfor\squerying\sthe\sunix\sVFS\sfor\sthe\scurrently\sheld\sshm-locks.\sStill\ssome\sissues. -D 2020-09-01T20:56:28.962 +C Fix\sreporting\son\slocks\sfrom\sexternal\sprocesses.\sVarious\sother\sfixes. +D 2020-09-02T15:26:28.763 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -317,7 +317,7 @@ F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a F ext/misc/series.c 4057dda3579b38ff88b2d3b13b4dd92dbd9d6f90dac2b55c19b0a8ed87ee4959 F ext/misc/sha1.c c8f2253c8792ffab9517695ea7d88c079f0395a5505eefef5c8198fe184ed5ac F ext/misc/shathree.c 135b7c145db4a09b1650c3e7aff9cb538763a9a361e834c015dd1aaf8d5c9a00 -F ext/misc/shmlockvtab.c 2cf63c9c57c47e551a92fe1f126f718a67a2de7d3714a6183b548ef3585a3639 w ext/misc/shmlocksvtab.c +F ext/misc/shmlockvtab.c d218fd9eeacd8406b72cb12d4b80409734415350d3c1dfc3b504ce10cb01f072 F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52 F ext/misc/spellfix.c 94df9bbfa514a563c1484f684a2df3d128a2f7209a84ca3ca100c68a0163e29f F ext/misc/sqlar.c 0ace5d3c10fe736dc584bf1159a36b8e2e60fab309d310cd8a0eecd9036621b6 @@ -520,7 +520,7 @@ F src/os.c 80e4cf3e5da06be03ca641661e331ce60eeeeabf0d7354dbb1c0e166d0eedbbe F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c 1f65273dc9635f4aeab61c4893d3cb809008c9658c5fce56bc069618f0cfa6eb +F src/os_unix.c 695560d6427b8d45d1bb0595c4ec9ce944d0b1cbb8bc97d9345141301abf28d2 F src/os_win.c a2149ff0a85c1c3f9cc102a46c673ce87e992396ba3411bfb53db66813b32f1d F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 3700a1c55427a3d4168ad1f1b8a8b0cb9ace1d107e4506e30a8f1e66d8a1195e @@ -538,7 +538,7 @@ F src/resolve.c 97b91fb25d86881ff20c9ad2ad98412c6c1bb5f7d6c9bb044db250cbc9cfcd4b F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 233e884d7da6601486c7b93aedb97fd29302ae5c03742d0e0eccb4790638bb77 F src/shell.c.in 9bae0c8397e7b592fb404678c4c1fc7944d9dc798a928d1eb40bcd608c33d21b -F src/sqlite.h.in 67c266c9e0893f8959ccba1de14b21df9c284315a60f2bb040adbbf82868389c +F src/sqlite.h.in 7c248cbaedb64e39071cda07e7ff7ab47a4bbebc279ccb1676f47b353a89360d F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197 F src/sqliteInt.h d8d69318b1ba3906d4860da1cd1c6b3650b81c9595e5bc360c6469a1e54e09e1 @@ -1880,10 +1880,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 d34caf3bb63d0512ea116a8c8c8343b76aa39441bd4b3e98231747a705b91d54 -R 70d4b88230a783c0d9a1569eb690c6e9 -T *branch * shmlock-vtab -T *sym-shmlock-vtab * -T -sym-trunk * +P ef10e1b386d7a9028eab64e1f4802e3d6b2df11c6723130a29e5effc8dcb2e80 +R 1fe025e21af9295b836249b2ab87a4c4 U dan -Z 051d13975a42f6e641461833c8ed92f1 +Z 312afa0e4b2458b1639f92694294c2f3 diff --git a/manifest.uuid b/manifest.uuid index f1ab915fa5..22bd28ae64 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ef10e1b386d7a9028eab64e1f4802e3d6b2df11c6723130a29e5effc8dcb2e80 \ No newline at end of file +459de23e869c79357221100e81d2c8e0b812ed3260e58d7d7acb3419876f41a3 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 4ad408ea00..5136772965 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4297,7 +4297,7 @@ struct unixShm { u8 id; /* Id of this connection within its unixShmNode */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ - const char *zShmlockName; + const char *zShmlockName; /* Name to use for FCNTL_SHMLOCK_GET */ }; /* @@ -4306,23 +4306,30 @@ struct unixShm { #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ +/* +** This is the implementation of the SQLITE_FCNTL_SHMLOCK_NAME file-control. +*/ static int unixFcntlShmlockName(unixFile *pFile, const char *zName){ int rc = SQLITE_OK; assert( !pFile->pShm || pFile->pShm->zShmlockName==pFile->zShmlockName ); + if( pFile->pShm ){ + sqlite3_mutex_enter(pFile->pShm->pShmNode->pShmMutex); + } sqlite3_free(pFile->zShmlockName); pFile->zShmlockName = sqlite3_mprintf("%s", zName); if( pFile->zShmlockName==0 ){ rc = SQLITE_NOMEM; } - if( pFile->pShm){ - unixShmNode *pShmNode = pFile->pShm->pShmNode; - sqlite3_mutex_enter(pShmNode->pShmMutex); + if( pFile->pShm ){ pFile->pShm->zShmlockName = pFile->zShmlockName; - sqlite3_mutex_leave(pShmNode->pShmMutex); + sqlite3_mutex_leave(pFile->pShm->pShmNode->pShmMutex); } return rc; } +/* +** This is the implementation of the SQLITE_FCNTL_SHMLOCK_GET file-control. +*/ static int unixFcntlShmlockGet(unixFile *pFile, char **pzOut){ int rc = SQLITE_OK; unixShm *p = pFile->pShm; @@ -4357,11 +4364,11 @@ static int unixFcntlShmlockGet(unixFile *pFile, char **pzOut){ if( (1<exclMask|pX->sharedMask) ){ int bWrite = (1<exclMask; if( bWrite==0 && i>=3 ){ - sqlite3_str_appendf(pStr, "%s %s R %d\n", + sqlite3_str_appendf(pStr, "%Q %Q 'R' '%d'\n", zName, aLockName[i], aReadMark[i-3] ); }else{ - sqlite3_str_appendf(pStr, "%s %s %s\n", + sqlite3_str_appendf(pStr, "%Q %Q %Q\n", zName, aLockName[i], bWrite ? "W" : "R" ); } @@ -4371,21 +4378,21 @@ static int unixFcntlShmlockGet(unixFile *pFile, char **pzOut){ } } for(i=0; iaLock[i]==0 ){ + if( pShmNode->aLock[i]>=0 ){ struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = UNIX_SHM_BASE+i; lock.l_len = 1; lock.l_type = F_WRLCK; - if( osFcntl(pFile->h, F_GETLK, &lock) ){ + if( osFcntl(pShmNode->hShm, F_GETLK, &lock) ){ rc = SQLITE_IOERR_LOCK; }else if( lock.l_type!=F_UNLCK ){ if( lock.l_type==F_RDLCK && i>=3 ){ - sqlite3_str_appendf(pStr, "pid.%d %s R %d\n", - lock.l_pid, aLockName[i], aReadMark[i] + sqlite3_str_appendf(pStr, "'pid.%d' %Q 'R' '%d'\n", + lock.l_pid, aLockName[i], aReadMark[i-3] ); }else{ - sqlite3_str_appendf(pStr, "pid.%d %s %s\n", + sqlite3_str_appendf(pStr, "'pid.%d' %Q %Q\n", lock.l_pid, aLockName[i], lock.l_type==F_WRLCK ? "W" : "R" ); } diff --git a/src/sqlite.h.in b/src/sqlite.h.in index d8c738d716..b71915f0a3 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -1126,6 +1126,24 @@ struct sqlite3_io_methods { ** in wal mode after the client has finished copying pages from the wal ** file to the database file, but before the *-shm file is updated to ** record the fact that the pages have been checkpointed. +** +**
  • [[SQLITE_FCNTL_SHMLOCK_GET]] +** This file-control is currently only supported by the "unix" VFS. The +** (void*) argument passed with this file-control must actually be +** a (char**) pointer. If the database is in wal-mode, the target of the +** pointer is set to point to a human readable description of all the +** wal-mode locks held on the database, by the current and external +** processes. It is the responsibility of the caller to eventually free +** this string using sqlite3_free(). See also the virtual table module in +** file "shmlockvtab.c" of the source distribution. +** +** +**
  • [[SQLITE_FCNTL_SHMLOCK_NAME]] +** This file-control is currently only supported by the "unix" VFS. The +** (void*) argument passed with this file-control should point to a +** nul-terminated string. A copy of this string will be used in reports +** returned by future calls to SQLITE_FCNTL_SHMLOCK_GET within the current +** process to identify this connection. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1168,7 +1186,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_CKPT_START 39 #define SQLITE_FCNTL_SHMLOCK_GET 40 -#define SQLITE_FCNTL_SHMLOCK_NAME 42 +#define SQLITE_FCNTL_SHMLOCK_NAME 41 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE