From 2f9311c5cbe99e303e4f79458f5c4da8b9174530 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 24 Oct 2025 20:04:16 +0000 Subject: [PATCH] Flesh out the sqlite_file_info() function further, and in particular show locks based in /proc/PID/fdinfo/FD, when that information is available. FossilOrigin-Name: ce75111cced8a03f05cf47ef809b9f017f2dac3c64c6008d595f28dbfec32057 --- manifest | 17 +++--- manifest.uuid | 2 +- src/os_unix.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/os_win.c | 18 +++++- 4 files changed, 169 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 8255cb8cef..49e87628d9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\sdiagnostic\sSQL\sfunction\s"sqlite_file_info()"\sand\sits\sassociated\nfile-control\sSQLITE_FCNTL_GET_INFO. -D 2025-10-24T17:42:03.293 +C Flesh\sout\sthe\ssqlite_file_info()\sfunction\sfurther,\sand\sin\sparticular\nshow\slocks\sbased\sin\s/proc/PID/fdinfo/FD,\swhen\sthat\sinformation\sis\navailable. +D 2025-10-24T20:04:16.194 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -720,8 +720,8 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63 F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06 F src/os_kv.c fb7ba8d6204197357f1eb7e1c7450d09c10043bf7e99aba602f4aa46b8fb11a3 F src/os_setup.h 8efc64eda6a6c2f221387eefc2e7e45fd5a3d5c8337a7a83519ba4fbd2957ae2 -F src/os_unix.c 77431f8598277cec13faa80f2a25efd8e1473dc173fb276a238d2f28a8b91ac7 -F src/os_win.c 898016b346c27cff61ddec30a3c9a9b8df7b6413c1a8e14c784a6806003d912b +F src/os_unix.c 4e4b97b4a1d915bbc268517fe16d5e4970358fae6a122934f0d9ff5778bcb161 +F src/os_win.c 5b14841f9c3ab76841c06a4eca20ba3e7747f44253eba9dfd3d918797e753d49 F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19 F src/pager.c 113f9149092ccff6cf90e97c2611200e5a237f13d26c394bc9fd933377852764 F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8 @@ -2171,11 +2171,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 62917cd4297e734477d3201481548ddb7f79ec977b9da7d9313bc7f1c0091187 -R 2dc6b0d73ecbb9f5657ef932a2fcf96a -T *branch * file-info -T *sym-file-info * -T -sym-trunk * +P 56ab9692583d5b64e1ab727e08a01c0a65b4e318b455c94397663ef8d3d7b6b8 +R 51358186c41fbead92cefc106db30235 U drh -Z be14a1f750cc9c17383cbb1543249676 +Z f2165d703890ae202e9f45a83048419c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8fcbafa49c..12340ad267 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -56ab9692583d5b64e1ab727e08a01c0a65b4e318b455c94397663ef8d3d7b6b8 +ce75111cced8a03f05cf47ef809b9f017f2dac3c64c6008d595f28dbfec32057 diff --git a/src/os_unix.c b/src/os_unix.c index f5f9975014..dc6be15242 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -3981,6 +3981,106 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ return SQLITE_OK; } +#if __linux__ && \ + (defined(SQLITE_DEBUG) \ + || defined(SQLITE_ENABLE_FILE_INFO) \ + || defined(SQLITE_ENABLE_PROC_ASSERT)) +/* +** Examine locking information from the /proc/PID/fdinfo/FD pseudo-file. +** +** If pStr is not NULL, append text that describes the locks to pStr. +** +** if iAssert is not 0, then verify that the byte iAssert/4 is either: +** +** * No locks are held if iAssert%4==0 +** * A read-lock is held if iAssert%4==1 +** * A write-lock is held if iAssert%4==2 +** * Any lock is held if iAssert%4==3 +** +** This routine no-ops if /proc/PID/fdinfo/FD cannot be opened. +** +** This routine is intended for diagnostic purposes only and is not a part +** of ordinary builds. +*/ +static void unixProcFSLocks(int fd, sqlite3_str *pStr, sqlite3_uint64 iAssert){ + int in; + ssize_t n; + char *p, *pNext, *x; + char *zSp = ""; + char z[2000]; + + sqlite3_snprintf(sizeof(z), z, "/proc/%d/fdinfo/%d", getpid(), fd); + in = open(z, O_RDONLY); + if( in<0 ){ + if( pStr ) sqlite3_str_appendall(pStr,"(not-available)"); + return; + } + n = read(in, z, sizeof(z)-1); + close(in); + if( n>0 ){ + z[n] = 0; + pNext = strstr(z, "lock:\t"); + while( pNext ){ + char cType = 0; + sqlite3_int64 iFirst, iLast; + p = pNext+6; + pNext = strstr(p, "lock:\t"); + if( pNext ) pNext[-1] = 0; + if( strstr(p, " READ ")!=0 ){ + cType = 'R'; + }else if( strstr(p, " WRITE ")!=0 ){ + cType = 'W'; + } + if( cType ){ + x = strrchr(p, ' '); + if( x ){ + iLast = strtoll(x+1, 0, 10); + *x = 0; + x = strrchr(p, ' '); + if( x ){ + iFirst = strtoll(x+1, 0, 10); + if( pStr ){ + sqlite3_str_appendf(pStr,"%s%c %lld %lld",zSp,cType,iFirst,iLast); + zSp = " "; + } + if( iAssert!=0 ){ + if( iAssert/4>=iFirst && iAssert/4<=iLast ){ + switch( iAssert%4 ){ + case 0: + sqlite3_snprintf(sizeof(z), z, + "byte %lld for fd %d should be unlocked\n", + iAssert/4, fd); + write(2, z, strlen(z)); + abort(); + case 1: + if( cType=='R' ) iAssert = 0; + break; + case 2: + if( cType=='W' ) iAssert = 0; + break; + case 3: + iAssert = 0; + break; + } + } + } + } + } + } + } + if( iAssert ){ + sqlite3_snprintf(sizeof(z), z, + "byte %lld of fd %d should be locked\n", + iAssert/4, fd); + write(2, z, strlen(z)); + abort(); + } + } +} +#else +# define verifyProcLocks(A,B,C) /* no-op */ +#endif /* __linux__ && (SQLITE_DEBUG || SQLITE_ENABLE_) */ + /* ** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. @@ -4002,6 +4102,10 @@ static int unixGetTempname(int nBuf, char *zBuf); #if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL) static int unixFcntlExternalReader(unixFile*, int*); #endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILE_INFO) + static void unixDescribeShm(sqlite3_str*,unixShm*); +#endif + /* ** Information and control of an open file handle. @@ -4147,13 +4251,31 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ #if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILE_INFO) case SQLITE_FCNTL_GET_INFO: { - static const char *azLock[] = { "NONE", "SHARED", "RESERVED", - "PENDING", "EXCLUSIVE" }; sqlite3_str *pStr = (sqlite3_str*)pArg; - sqlite3_str_appendf(pStr, "{\"h\":%d,", pFile->h); - sqlite3_str_appendf(pStr, "\"vfs\":\"%s\",", pFile->pVfs->zName); - sqlite3_str_appendf(pStr, "\"eFileLock\":\"%s\"}", - azLock[pFile->eFileLock]); + sqlite3_str_appendf(pStr, "{\"h\":%d", pFile->h); + sqlite3_str_appendf(pStr, ",\"vfs\":\"%s\"", pFile->pVfs->zName); + if( pFile->eFileLock ){ + static const char *azLock[] = { "SHARED", "RESERVED", + "PENDING", "EXCLUSIVE" }; + sqlite3_str_appendf(pStr, ",\"eFileLock\":\"%s\"", + azLock[pFile->eFileLock-1]); + } +#if __linux__ + sqlite3_str_appendall(pStr, ",\"locks\":\""); + unixProcFSLocks(pFile->h, pStr, 0); + sqlite3_str_append(pStr, "\"", 1); +#endif /* __linux__ */ + if( pFile->pShm ){ + sqlite3_str_appendall(pStr, ",\"shm\":"); + unixDescribeShm(pStr, pFile->pShm); + } +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFile->mmapSize ){ + sqlite3_str_appendf(pStr, ",\"mmapSize\":%lld", pFile->mmapSize); + sqlite3_str_appendf(pStr, ",\"nFetchOut\":%d", pFile->nFetchOut); + } +#endif + sqlite3_str_append(pStr, "}", 1); return SQLITE_OK; } #endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILE_INFO */ @@ -4423,6 +4545,24 @@ 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 */ +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILE_INFO) +/* +** Describe the pShm object using JSON. Used for diagnostics only. +*/ +static void unixDescribeShm(sqlite3_str *pStr, unixShm *pShm){ + unixShmNode *pNode = pShm->pShmNode; + sqlite3_str_appendf(pStr, "{\"sharedMask\":%d", pShm->sharedMask); + sqlite3_str_appendf(pStr, ",\"exclMask\":%d", pShm->exclMask); + sqlite3_str_appendf(pStr, ",\"hShm\":%d", pNode->hShm); +#if __linux__ + sqlite3_str_appendall(pStr, ",\"locks\":\""); + unixProcFSLocks(pNode->hShm, pStr, 0); + sqlite3_str_append(pStr, "\"", 1); +#endif /* __linux__ */ + sqlite3_str_append(pStr, "}", 1); +} +#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILE_INFO */ + /* ** Use F_GETLK to check whether or not there are any readers with open ** wal-mode transactions in other processes on database file pFile. If diff --git a/src/os_win.c b/src/os_win.c index ca58dbd752..af9fdd49fa 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -3956,9 +3956,21 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ #if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILE_INFO) case SQLITE_FCNTL_GET_INFO: { sqlite3_str *pStr = (sqlite3_str*)pArg; - sqlite3_str_appendf(pStr, "{\n \"h\":%llu", (sqlite3_uint64)pFile->h); - sqlite3_str_appendf(pStr, ",\n \"vfs\":\"%s\"", pFile->pVfs->zName); - sqlite3_str_append(pStr, ",\n}", 3); + sqlite3_str_appendf(pStr, "{\"h\":%llu", (sqlite3_uint64)pFile->h); + sqlite3_str_appendf(pStr, ",\"vfs\":\"%s\"", pFile->pVfs->zName); + if( pFile->locktype ){ + static const char *azLock[] = { "SHARED", "RESERVED", + "PENDING", "EXCLUSIVE" }; + sqlite3_str_appendf(pStr, ",\"locktype\":\"%s\"", + azLock[pFile->locktype-1]); + } +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFile->mmapSize ){ + sqlite3_str_appendf(pStr, ",\"mmapSize\":%lld", pFile->mmapSize); + sqlite3_str_appendf(pStr, ",\"nFetchOut\":%d", pFile->nFetchOut); + } +#endif + sqlite3_str_append(pStr, "}", 1); return SQLITE_OK; } #endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILE_INFO */ -- 2.47.3