/ Check-in [1b56677b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge changes for the new sqlite3_file_control() that will cause the -wal and -shm files to persist after the last database connection closes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1b56677bdfb102d070a2057a65ba424fec81131d
User & Date: mistachkin 2011-07-28 20:48:38
Context
2011-07-30
23:50
Fix a (humorous) typo in the lemon documentation. check-in: ed630b01 user: drh tags: trunk
2011-07-28
20:48
Merge changes for the new sqlite3_file_control() that will cause the -wal and -shm files to persist after the last database connection closes. check-in: 1b56677b user: mistachkin tags: trunk
19:16
Remove redundant sub-expression from retry loop invariant in winAccess. Also, make check for SQLITE_ACCESS_READWRITE formally correct. check-in: 93079a92 user: mistachkin tags: trunk
2011-07-26
16:23
Test cases added. Fix the query mode. Closed-Leaf check-in: a9d8794a user: drh tags: persistent-wal-patch
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

   246    246     char aPadding[32];
   247    247   #endif
   248    248   };
   249    249   
   250    250   /*
   251    251   ** Allowed values for the unixFile.ctrlFlags bitmask:
   252    252   */
   253         -#define UNIXFILE_EXCL   0x01     /* Connections from one process only */
   254         -#define UNIXFILE_RDONLY 0x02     /* Connection is read only */
          253  +#define UNIXFILE_EXCL        0x01     /* Connections from one process only */
          254  +#define UNIXFILE_RDONLY      0x02     /* Connection is read only */
          255  +#define UNIXFILE_PERSIST_WAL 0x04     /* Persistent WAL mode */
   255    256   
   256    257   /*
   257    258   ** Include code that is common to all os_*.c files
   258    259   */
   259    260   #include "os_common.h"
   260    261   
   261    262   /*
................................................................................
  3446   3447     return SQLITE_OK;
  3447   3448   }
  3448   3449   
  3449   3450   /*
  3450   3451   ** Information and control of an open file handle.
  3451   3452   */
  3452   3453   static int unixFileControl(sqlite3_file *id, int op, void *pArg){
         3454  +  unixFile *pFile = (unixFile*)id;
  3453   3455     switch( op ){
  3454   3456       case SQLITE_FCNTL_LOCKSTATE: {
  3455         -      *(int*)pArg = ((unixFile*)id)->eFileLock;
         3457  +      *(int*)pArg = pFile->eFileLock;
  3456   3458         return SQLITE_OK;
  3457   3459       }
  3458   3460       case SQLITE_LAST_ERRNO: {
  3459         -      *(int*)pArg = ((unixFile*)id)->lastErrno;
         3461  +      *(int*)pArg = pFile->lastErrno;
  3460   3462         return SQLITE_OK;
  3461   3463       }
  3462   3464       case SQLITE_FCNTL_CHUNK_SIZE: {
  3463         -      ((unixFile*)id)->szChunk = *(int *)pArg;
         3465  +      pFile->szChunk = *(int *)pArg;
  3464   3466         return SQLITE_OK;
  3465   3467       }
  3466   3468       case SQLITE_FCNTL_SIZE_HINT: {
  3467         -      return fcntlSizeHint((unixFile *)id, *(i64 *)pArg);
         3469  +      return fcntlSizeHint(pFile, *(i64 *)pArg);
         3470  +    }
         3471  +    case SQLITE_FCNTL_PERSIST_WAL: {
         3472  +      int bPersist = *(int*)pArg;
         3473  +      if( bPersist<0 ){
         3474  +        *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
         3475  +      }else if( bPersist==0 ){
         3476  +        pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
         3477  +      }else{
         3478  +        pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
         3479  +      }
         3480  +      return SQLITE_OK;
  3468   3481       }
  3469   3482   #ifndef NDEBUG
  3470   3483       /* The pager calls this method to signal that it has done
  3471   3484       ** a rollback and that the database is therefore unchanged and
  3472   3485       ** it hence it is OK for the transaction change counter to be
  3473   3486       ** unchanged.
  3474   3487       */

Changes to src/os_win.c.

    98     98   ** portability layer.
    99     99   */
   100    100   typedef struct winFile winFile;
   101    101   struct winFile {
   102    102     const sqlite3_io_methods *pMethod; /*** Must be first ***/
   103    103     sqlite3_vfs *pVfs;      /* The VFS used to open this file */
   104    104     HANDLE h;               /* Handle for accessing the file */
   105         -  unsigned char locktype; /* Type of lock currently held on this file */
          105  +  u8 locktype;            /* Type of lock currently held on this file */
   106    106     short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
          107  +  u8 bPersistWal;         /* True to persist WAL files */
   107    108     DWORD lastErrno;        /* The Windows errno from the last I/O error */
   108    109     DWORD sectorSize;       /* Sector size of the device file is on */
   109    110     winShm *pShm;           /* Instance of shared memory on this file */
   110    111     const char *zPath;      /* Full pathname of this file */
   111    112     int szChunk;            /* Chunk size configured by FCNTL_CHUNK_SIZE */
   112    113   #if SQLITE_OS_WINCE
   113    114     WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
................................................................................
  1331   1332     return rc;
  1332   1333   }
  1333   1334   
  1334   1335   /*
  1335   1336   ** Control and query of the open file handle.
  1336   1337   */
  1337   1338   static int winFileControl(sqlite3_file *id, int op, void *pArg){
         1339  +  winFile *pFile = (winFile*)id;
  1338   1340     switch( op ){
  1339   1341       case SQLITE_FCNTL_LOCKSTATE: {
  1340         -      *(int*)pArg = ((winFile*)id)->locktype;
         1342  +      *(int*)pArg = pFile->locktype;
  1341   1343         return SQLITE_OK;
  1342   1344       }
  1343   1345       case SQLITE_LAST_ERRNO: {
  1344         -      *(int*)pArg = (int)((winFile*)id)->lastErrno;
         1346  +      *(int*)pArg = (int)pFile->lastErrno;
  1345   1347         return SQLITE_OK;
  1346   1348       }
  1347   1349       case SQLITE_FCNTL_CHUNK_SIZE: {
  1348         -      ((winFile*)id)->szChunk = *(int *)pArg;
         1350  +      pFile->szChunk = *(int *)pArg;
  1349   1351         return SQLITE_OK;
  1350   1352       }
  1351   1353       case SQLITE_FCNTL_SIZE_HINT: {
  1352   1354         sqlite3_int64 sz = *(sqlite3_int64*)pArg;
  1353   1355         SimulateIOErrorBenign(1);
  1354   1356         winTruncate(id, sz);
  1355   1357         SimulateIOErrorBenign(0);
  1356   1358         return SQLITE_OK;
         1359  +    }
         1360  +    case SQLITE_FCNTL_PERSIST_WAL: {
         1361  +      int bPersist = *(int*)pArg;
         1362  +      if( bPersist<0 ){
         1363  +        *(int*)pArg = pFile->bPersistWal;
         1364  +      }else{
         1365  +        pFile->bPersistWal = bPersist!=0;
         1366  +      }
         1367  +      return SQLITE_OK;
  1357   1368       }
  1358   1369       case SQLITE_FCNTL_SYNC_OMITTED: {
  1359   1370         return SQLITE_OK;
  1360   1371       }
  1361   1372       case SQLITE_FCNTL_WIN32_AV_RETRY: {
  1362   1373         int *a = (int*)pArg;
  1363   1374         if( a[0]>0 ){

Changes to src/sqlite.h.in.

   748    748   ** to be adjusted.  The values are changed for all database connections
   749    749   ** within the same process.  The argument is a pointer to an array of two
   750    750   ** integers where the first integer i the new retry count and the second
   751    751   ** integer is the delay.  If either integer is negative, then the setting
   752    752   ** is not changed but instead the prior value of that setting is written
   753    753   ** into the array entry, allowing the current retry settings to be
   754    754   ** interrogated.  The zDbName parameter is ignored.
          755  +**
          756  +** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
          757  +** persistent [WAL | Write AHead Log] setting.  By default, the auxiliary
          758  +** write ahead log and shared memory files used for transaction control
          759  +** are automatically deleted when the latest connection to the database
          760  +** closes.  Setting persistent WAL mode causes those files to persist after
          761  +** close.  Persisting the files is useful when other processes that do not
          762  +** have write permission on the directory containing the database file want
          763  +** to read the database file, as the WAL and shared memory files must exist
          764  +** in order for the database to be readable.  The fourth parameter to
          765  +** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
          766  +** That integer is 0 to disable persistent WAL mode or 1 to enable persistent
          767  +** WAL mode.  If the integer is -1, then it is overwritten with the current
          768  +** WAL persistence setting.
   755    769   ** 
   756    770   */
   757    771   #define SQLITE_FCNTL_LOCKSTATE        1
   758    772   #define SQLITE_GET_LOCKPROXYFILE      2
   759    773   #define SQLITE_SET_LOCKPROXYFILE      3
   760    774   #define SQLITE_LAST_ERRNO             4
   761    775   #define SQLITE_FCNTL_SIZE_HINT        5
   762    776   #define SQLITE_FCNTL_CHUNK_SIZE       6
   763    777   #define SQLITE_FCNTL_FILE_POINTER     7
   764    778   #define SQLITE_FCNTL_SYNC_OMITTED     8
   765    779   #define SQLITE_FCNTL_WIN32_AV_RETRY   9
          780  +#define SQLITE_FCNTL_PERSIST_WAL     10
   766    781   
   767    782   /*
   768    783   ** CAPI3REF: Mutex Handle
   769    784   **
   770    785   ** The mutex module within SQLite defines [sqlite3_mutex] to be an
   771    786   ** abstract type for a mutex object.  The SQLite core never looks
   772    787   ** at the internal representation of an [sqlite3_mutex].  It only

Changes to src/test1.c.

  5125   5125     if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
  5126   5126     rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
  5127   5127     sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
  5128   5128     Tcl_AppendResult(interp, z, (char*)0);
  5129   5129     return TCL_OK;  
  5130   5130   }
  5131   5131   
         5132  +/*
         5133  +** tclcmd:   file_control_persist_wal DB PERSIST-FLAG
         5134  +**
         5135  +** This TCL command runs the sqlite3_file_control interface with
         5136  +** the SQLITE_FCNTL_PERSIST_WAL opcode.
         5137  +*/
         5138  +static int file_control_persist_wal(
         5139  +  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
         5140  +  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
         5141  +  int objc,              /* Number of arguments */
         5142  +  Tcl_Obj *CONST objv[]  /* Command arguments */
         5143  +){
         5144  +  sqlite3 *db;
         5145  +  int rc;
         5146  +  int bPersist;
         5147  +  char z[100];
         5148  +
         5149  +  if( objc!=3 ){
         5150  +    Tcl_AppendResult(interp, "wrong # args: should be \"",
         5151  +        Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
         5152  +    return TCL_ERROR;
         5153  +  }
         5154  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
         5155  +    return TCL_ERROR;
         5156  +  }
         5157  +  if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR;
         5158  +  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist);
         5159  +  sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist);
         5160  +  Tcl_AppendResult(interp, z, (char*)0);
         5161  +  return TCL_OK;  
         5162  +}
         5163  +
  5132   5164   
  5133   5165   /*
  5134   5166   ** tclcmd:   sqlite3_vfs_list
  5135   5167   **
  5136   5168   **   Return a tcl list containing the names of all registered vfs's.
  5137   5169   */
  5138   5170   static int vfs_list(
................................................................................
  5924   5956        { "vfs_reregister_all",         vfs_reregister_all,  0   },
  5925   5957        { "file_control_test",          file_control_test,   0   },
  5926   5958        { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
  5927   5959        { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
  5928   5960        { "file_control_chunksize_test", file_control_chunksize_test,  0   },
  5929   5961        { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
  5930   5962        { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
         5963  +     { "file_control_persist_wal",    file_control_persist_wal,     0   },
  5931   5964        { "sqlite3_vfs_list",           vfs_list,     0   },
  5932   5965        { "sqlite3_create_function_v2", test_create_function_v2, 0 },
  5933   5966   
  5934   5967        /* Functions from os.h */
  5935   5968   #ifndef SQLITE_OMIT_UTF16
  5936   5969        { "add_test_collate",        test_collate, 0            },
  5937   5970        { "add_test_collate_needed", test_collate_needed, 0     },

Changes to src/wal.c.

  1800   1800       ** the database. In this case checkpoint the database and unlink both
  1801   1801       ** the wal and wal-index files.
  1802   1802       **
  1803   1803       ** The EXCLUSIVE lock is not released before returning.
  1804   1804       */
  1805   1805       rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
  1806   1806       if( rc==SQLITE_OK ){
         1807  +      int bPersistWal = -1;
  1807   1808         if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
  1808   1809           pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
  1809   1810         }
  1810   1811         rc = sqlite3WalCheckpoint(
  1811   1812             pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
  1812   1813         );
  1813         -      if( rc==SQLITE_OK ){
         1814  +      sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal);
         1815  +      if( rc==SQLITE_OK && bPersistWal!=1 ){
  1814   1816           isDelete = 1;
  1815   1817         }
  1816   1818       }
  1817   1819   
  1818   1820       walIndexClose(pWal, isDelete);
  1819   1821       sqlite3OsClose(pWal->pWalFd);
  1820   1822       if( isDelete ){

Added test/walpersist.test.

            1  +# 2011 July 26
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +# This file contains tests for using WAL with persistent WAL file mode.
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +source $testdir/lock_common.tcl
           18  +set ::testprefix walpersist
           19  +
           20  +do_test walpersist-1.0 {
           21  +  db eval {
           22  +    PRAGMA journal_mode=WAL;
           23  +    CREATE TABLE t1(a);
           24  +    INSERT INTO t1 VALUES(randomblob(5000));
           25  +  }
           26  +  file exists test.db-wal
           27  +} {1}
           28  +do_test walpersist-1.1 {
           29  +  file exists test.db-shm
           30  +} {1}
           31  +do_test walpersist-1.2 {
           32  +  db close
           33  +  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
           34  +} {1 0 0}
           35  +do_test walpersist-1.3 {
           36  +  sqlite3 db test.db
           37  +  db eval {SELECT length(a) FROM t1}
           38  +} {5000}
           39  +do_test walpersist-1.4 {
           40  +  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
           41  +} {1 1 1}
           42  +do_test walpersist-1.5 {
           43  +  file_control_persist_wal db -1
           44  +} {0 0}
           45  +do_test walpersist-1.6 {
           46  +  file_control_persist_wal db 1
           47  +} {0 1}
           48  +do_test walpersist-1.7 {
           49  +  file_control_persist_wal db -1
           50  +} {0 1}
           51  +do_test walpersist-1.8 {
           52  +  file_control_persist_wal db 0
           53  +} {0 0}
           54  +do_test walpersist-1.9 {
           55  +  file_control_persist_wal db -1
           56  +} {0 0}
           57  +do_test walpersist-1.10 {
           58  +  file_control_persist_wal db 1
           59  +} {0 1}
           60  +do_test walpersist-1.11 {
           61  +  db close
           62  +  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
           63  +} {1 1 1}
           64  +
           65  +  
           66  +
           67  +
           68  +finish_test