From: drh <> Date: Wed, 7 Jan 2026 18:45:23 +0000 (+0000) Subject: Improvements to logging. Better log-file names. Log files are in a X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b5f8766fd07794ed48677b94fc31283a729c0cf;p=thirdparty%2Fsqlite.git Improvements to logging. Better log-file names. Log files are in a subdirectory named after the database. Only connections that write to the database create logs. Better documentation in the header comment. FossilOrigin-Name: 5b1cf0fe73ba1a40fe4cd8f5f6e8ee5b471f96b60aff52c03c045ad6514c363a --- diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index 1d52c0e958..739c3e614d 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -16,14 +16,19 @@ ** the WAL file for databases in WAL mode, or as the database file itself ** is modified in rollback modes. ** -** The VFS also generates log-files with names of the form: +** The VFS also tries to generate log-files with names of the form: ** -** $(DATABASE)-$(TIME)$(PID)$(ID).tmstmp +** $(DATABASE)-tmstmp/$(TIME)-$(PID)-$(ID) ** -** In the same directory as the database file. This log file contain one -** 16-byte record for various events, such as opening or close of the -** database or WAL file, writes to the WAL file, checkpoints, and similar. -** There is one log file for each open database connection. +** Log files are only generated if directory $(DATABASE)-tmstmp exists. +** The name of each log file is the current unix-epoch time in millisecond, +** the process ID, and a random 32-bit value (to disambiguate multiple +** connections from the same process) separated by spaces. The log file +** contains one 16-byte record for various events, such as opening or close +** of the database or WAL file, writes to the WAL file, checkpoints, and +** similar. The logfile is only generated if the connection attempts to +** modify the database. There is a separate log file for each open database +** connection. ** ** COMPILING ** @@ -59,6 +64,11 @@ ** correct order so that it sequences itself into the default VFS ** Shim stack in the right order. ** +** An application can see if the tmstmpvfs is being used by examining +** the results from SQLITE_FCNTL_VFSNAME (or the .vfsname command in +** the CLI). If the answer include "tmstmp", then this VFS is being +** used. +** ** USING ** ** Open database connections using the sqlite3_open() or @@ -117,19 +127,15 @@ ** ** LOGGING ** -** Every open VFS creates a log file. The Database connection and the -** WAL connection are both logged to the same file. If the name of the -** database file is BASE then the logfile is named something like: +** An open database connection that attempts to write to the database +** will create a log file if a directory name $(DATABASE)-tmstmp exists. +** The name of the log file is: ** -** $(DATABASE)-$(TIMESTAMP)$(PID)$(RANDOM) +** $(TIME)-$(PID)-$(RANDOM) ** -** Where DATABASE is the database filename, TIMESTAMP is the millisecond -** resolution timestamp of when the database connection was opened, PID -** is the process ID of the process that opened the database connection, -** and RANDOM is 32-bits of randomness used to distinguish between multiple -** connections being opened on the same database from the same process. -** The last three values are all expressed in hexadecimal and are joined -** together without punctuation. +** Where TIME is the number of milliseconds since 1970, PID is the process +** ID, and RANDOM is a 32-bit random number. All values are expressed +** in hexadecimal. ** ** The log consists of 16-byte records. Each record consists of five ** unsigned integers: @@ -141,6 +147,44 @@ ** in milliseconds since 1970-01-01. (6 bytes is sufficient for timestamps ** for almost 9000 years.) Opcodes are defined by the ELOG_* #defines ** below. +** +** ELOG_OPEN_DB "Open a connection to the database file" +** op = 0x01 +** a2 = process-ID +** +** ELOG_OPEN_WAL "Open a connection to the -wal file" +** op = 0x02 +** a2 = process-ID +** +** ELOG_WAL_PAGE "New page added to the WAL file" +** op = 0x03 +** a1 = 1 if last page of a txn. 0 otherwise. +** a2 = page number in the DB file +** a3 = frame number in the WAL file +** +** ELOG_DB_PAGE "Database page updated using rollback mode" +** op = 0x04 +** a2 = page number in the DB file +** +** ELOG_CKPT_START "Start of a checkpoint operation" +** op = 0x05 +** +** ELOG_CKPT_PAGE "Page xfer from WAL to database" +** op = 0x06 +** a2 = database page number +** +** ELOG_CKPT_END "Start of a checkpoint operation" +** op = 0x07 +** +** ELOG_WAL_RESET "WAL file header overwritten" +** op = 0x08 +** a3 = Salt1 value +** +** ELOG_CLOSE_WAL "Close the WAL file connection" +** op = 0x0e +** +** ELOG_CLOSE_DB "Close the DB connection" +** op = 0x0f */ #if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_TMSTMPVFS_STATIC) # define SQLITE_TMSTMPVFS_STATIC @@ -160,6 +204,7 @@ */ typedef struct sqlite3_vfs TmstmpVfs; typedef struct TmstmpFile TmstmpFile; +typedef struct TmstmpLog TmstmpLog; /* ** Bytes of reserved space used by this extension @@ -196,6 +241,14 @@ typedef struct TmstmpFile TmstmpFile; #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) #define ORIGFILE(p) ((sqlite3_file*)(((TmstmpFile*)(p))+1)) +/* Information for the tmstmp log file. */ +struct TmstmpLog { + char *zLogname; /* Log filename */ + FILE *log; /* Open log file */ + int n; /* Bytes of a[] used */ + unsigned char a[16*6]; /* Buffered header for the log */ +}; + /* An open WAL file */ struct TmstmpFile { sqlite3_file base; /* IO methods */ @@ -209,7 +262,7 @@ struct TmstmpFile { u8 isCommit; /* Last WAL frame header was a transaction commit */ u8 hasCorrectReserve; /* File has the correct reserve size */ u8 inCkpt; /* True if in a checkpoint */ - FILE *log; /* Write logging records on this file. DB only */ + TmstmpLog *pLog; /* Log file */ TmstmpFile *pPartner; /* DB->WAL or WAL->DB mapping */ sqlite3_int64 iOfst; /* Offset of last WAL frame header */ sqlite3_vfs *pSubVfs; /* Underlying VFS */ @@ -323,7 +376,7 @@ static const sqlite3_io_methods tmstmp_io_methods = { */ static void tmstmpPutTS(TmstmpFile *p, unsigned char *aOut){ sqlite3_uint64 tm = 0; - p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &tm); + p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, (sqlite3_int64*)&tm); aOut[0] = (tm>>40)&0xff; aOut[1] = (tm>>32)&0xff; aOut[2] = (tm>>24)&0xff; @@ -348,6 +401,30 @@ static void tmstmpPutU32(u32 v, unsigned char *a){ a[3] = v & 0xff; } +/* Free a TmstmpLog object */ +static void tmstmpLogFree(TmstmpLog *pLog){ + if( pLog==0 ) return; + sqlite3_free(pLog->zLogname); + sqlite3_free(pLog); +} + +/* Flush log content. Open the file if necessary. Return the +** number of errors. */ +static int tmstmpLogFlush(TmstmpFile *p){ + TmstmpLog *pLog = p->pLog; + assert( pLog!=0 ); + if( pLog->log==0 ){ + pLog->log = fopen(pLog->zLogname, "wb"); + if( pLog->log==0 ){ + tmstmpLogFree(pLog); + p->pLog = 0; + return 1; + } + } + (void)fwrite(pLog->a, pLog->n, 1, pLog->log); + pLog->n = 0; + return 0; +} /* ** Write a record onto the event log @@ -359,19 +436,28 @@ static void tmstmpEvent( u32 a2, u32 a3 ){ - unsigned char a[16]; + unsigned char *a; + TmstmpLog *pLog; if( p->isWal ){ p = p->pPartner; assert( p!=0 ); assert( p->isDb ); } - if( p->log==0 ) return; + pLog = p->pLog; + if( pLog==0 ) return; + if( pLog->n >= (int)sizeof(pLog->a) ){ + if( tmstmpLogFlush(p) ) return; + } + a = pLog->a + pLog->n; a[0] = op; a[1] = a1; tmstmpPutTS(p, a+2); tmstmpPutU32(a2, a+8); tmstmpPutU32(a3, a+12); - (void)fwrite(a, sizeof(a), 1, p->log); + pLog->n += 16; + if( pLog->log || (op>=ELOG_WAL_PAGE && op<=ELOG_WAL_RESET) ){ + (void)tmstmpLogFlush(p); + } } /* @@ -382,7 +468,7 @@ static int tmstmpClose(sqlite3_file *pFile){ if( p->hasCorrectReserve ){ tmstmpEvent(p, p->isDb ? ELOG_CLOSE_DB : ELOG_CLOSE_WAL, 0, 0, 0); } - if( p->log ) fclose(p->log); + tmstmpLogFree(p->pLog); if( p->pPartner ){ assert( p->pPartner->pPartner==p ); p->pPartner->pPartner = 0; @@ -643,10 +729,6 @@ static int tmstmpOpen( sqlite3_file *pSubFile; sqlite3_vfs *pSubVfs; int rc; - sqlite3_uint64 r1; - u32 r2; - u32 pid; - char *zLogName; pSubVfs = ORIGVFS(pVfs); if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ @@ -679,16 +761,24 @@ static int tmstmpOpen( p->pPartner = pDb; pDb->pPartner = p; }else{ + sqlite3_uint64 r1; + u32 r2; + u32 pid; + TmstmpLog *pLog; + p->isDb = 1; r1 = 0; - p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &r1); + pLog = sqlite3_malloc64( sizeof(TmstmpLog) ); + if( pLog==0 ){ + return SQLITE_NOMEM; + } + memset(pLog, 0, sizeof(pLog[0])); + p->pLog = pLog; + p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, (sqlite3_int64*)&r1); sqlite3_randomness(sizeof(r2), &r2); pid = GETPID; - zLogName = sqlite3_mprintf("%s-%llx%08x%08x.tmstmp", zName, r1, pid, r2); - if( zLogName ){ - p->log = fopen(zLogName, "wb"); - sqlite3_free(zLogName); - } + pLog->zLogname = sqlite3_mprintf("%s-tmstmp/%llx-%08x-%08x", + zName, r1, pid, r2); } tmstmpEvent(p, p->isWal ? ELOG_OPEN_WAL : ELOG_OPEN_DB, 0, GETPID, 0); @@ -813,6 +903,7 @@ int sqlite3_tmstmpvfs_init( int rc; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* not used */ + (void)db; /* not used */ rc = tmstmpRegisterVfs(); if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; diff --git a/manifest b/manifest index 4fd87e8e07..3591bb9662 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Documentation\stweaks. -D 2026-01-06T21:18:42.496 +C Improvements\sto\slogging.\s\sBetter\slog-file\snames.\s\sLog\sfiles\sare\sin\sa\nsubdirectory\snamed\safter\sthe\sdatabase.\s\sOnly\sconnections\sthat\swrite\sto\nthe\sdatabase\screate\slogs.\s\sBetter\sdocumentation\sin\sthe\sheader\scomment. +D 2026-01-07T18:45:23.292 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -402,7 +402,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c 05e80557222c648bc676e599343d8d33f9e2d4801476592271ffb580cebbab69 +F ext/misc/tmstmpvfs.c 2d2f92a85e9a55ae3abd9d66d1638096fad30ebc0bfcf9431f3370e34b550a0b F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2190,8 +2190,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f087c6c0cdd542ec24b4668fff9cb434f46caf554f8856a49fd062ab3f72014e -R 877edad71f16bed2b67db9da4be832cc +P b10b0aa7658a04b9354ca09a2dcb807eecd9421451537f3230ba5f47269ec5c1 +R be812e8a766a17494547e7727dd97033 U drh -Z ee16842ec8595f9621e28d3f57b47daa +Z 8f9cae05ac0b26a0b4ebaaea59bfec9f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3eb4087104..3ee21c9f49 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b10b0aa7658a04b9354ca09a2dcb807eecd9421451537f3230ba5f47269ec5c1 +5b1cf0fe73ba1a40fe4cd8f5f6e8ee5b471f96b60aff52c03c045ad6514c363a