/ 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 Unified Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

246
247
248
249
250
251
252
253
254

255
256
257
258
259
260
261
....
3446
3447
3448
3449
3450
3451
3452

3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467











3468
3469
3470
3471
3472
3473
3474
  char aPadding[32];
#endif
};

/*
** Allowed values for the unixFile.ctrlFlags bitmask:
*/
#define UNIXFILE_EXCL   0x01     /* Connections from one process only */
#define UNIXFILE_RDONLY 0x02     /* Connection is read only */


/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"

/*
................................................................................
  return SQLITE_OK;
}

/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){

  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((unixFile*)id)->eFileLock;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = ((unixFile*)id)->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      ((unixFile*)id)->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      return fcntlSizeHint((unixFile *)id, *(i64 *)pArg);











    }
#ifndef NDEBUG
    /* The pager calls this method to signal that it has done
    ** a rollback and that the database is therefore unchanged and
    ** it hence it is OK for the transaction change counter to be
    ** unchanged.
    */







|
|
>







 







>


|



|



|



|
>
>
>
>
>
>
>
>
>
>
>







246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
....
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
  char aPadding[32];
#endif
};

/*
** Allowed values for the unixFile.ctrlFlags bitmask:
*/
#define UNIXFILE_EXCL        0x01     /* Connections from one process only */
#define UNIXFILE_RDONLY      0x02     /* Connection is read only */
#define UNIXFILE_PERSIST_WAL 0x04     /* Persistent WAL mode */

/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"

/*
................................................................................
  return SQLITE_OK;
}

/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
  unixFile *pFile = (unixFile*)id;
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = pFile->eFileLock;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = pFile->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      pFile->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      return fcntlSizeHint(pFile, *(i64 *)pArg);
    }
    case SQLITE_FCNTL_PERSIST_WAL: {
      int bPersist = *(int*)pArg;
      if( bPersist<0 ){
        *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
      }else if( bPersist==0 ){
        pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
      }else{
        pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
      }
      return SQLITE_OK;
    }
#ifndef NDEBUG
    /* The pager calls this method to signal that it has done
    ** a rollback and that the database is therefore unchanged and
    ** it hence it is OK for the transaction change counter to be
    ** unchanged.
    */

Changes to src/os_win.c.

98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
....
1331
1332
1333
1334
1335
1336
1337

1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356









1357
1358
1359
1360
1361
1362
1363
** portability layer.
*/
typedef struct winFile winFile;
struct winFile {
  const sqlite3_io_methods *pMethod; /*** Must be first ***/
  sqlite3_vfs *pVfs;      /* The VFS used to open this file */
  HANDLE h;               /* Handle for accessing the file */
  unsigned char locktype; /* Type of lock currently held on this file */
  short sharedLockByte;   /* Randomly chosen byte used as a shared lock */

  DWORD lastErrno;        /* The Windows errno from the last I/O error */
  DWORD sectorSize;       /* Sector size of the device file is on */
  winShm *pShm;           /* Instance of shared memory on this file */
  const char *zPath;      /* Full pathname of this file */
  int szChunk;            /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
  WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
................................................................................
  return rc;
}

/*
** Control and query of the open file handle.
*/
static int winFileControl(sqlite3_file *id, int op, void *pArg){

  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((winFile*)id)->locktype;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = (int)((winFile*)id)->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      ((winFile*)id)->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      sqlite3_int64 sz = *(sqlite3_int64*)pArg;
      SimulateIOErrorBenign(1);
      winTruncate(id, sz);
      SimulateIOErrorBenign(0);
      return SQLITE_OK;









    }
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_WIN32_AV_RETRY: {
      int *a = (int*)pArg;
      if( a[0]>0 ){







|

>







 







>


|



|



|








>
>
>
>
>
>
>
>
>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
....
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
** portability layer.
*/
typedef struct winFile winFile;
struct winFile {
  const sqlite3_io_methods *pMethod; /*** Must be first ***/
  sqlite3_vfs *pVfs;      /* The VFS used to open this file */
  HANDLE h;               /* Handle for accessing the file */
  u8 locktype;            /* Type of lock currently held on this file */
  short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
  u8 bPersistWal;         /* True to persist WAL files */
  DWORD lastErrno;        /* The Windows errno from the last I/O error */
  DWORD sectorSize;       /* Sector size of the device file is on */
  winShm *pShm;           /* Instance of shared memory on this file */
  const char *zPath;      /* Full pathname of this file */
  int szChunk;            /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
  WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
................................................................................
  return rc;
}

/*
** Control and query of the open file handle.
*/
static int winFileControl(sqlite3_file *id, int op, void *pArg){
  winFile *pFile = (winFile*)id;
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = pFile->locktype;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = (int)pFile->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      pFile->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      sqlite3_int64 sz = *(sqlite3_int64*)pArg;
      SimulateIOErrorBenign(1);
      winTruncate(id, sz);
      SimulateIOErrorBenign(0);
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_PERSIST_WAL: {
      int bPersist = *(int*)pArg;
      if( bPersist<0 ){
        *(int*)pArg = pFile->bPersistWal;
      }else{
        pFile->bPersistWal = bPersist!=0;
      }
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_WIN32_AV_RETRY: {
      int *a = (int*)pArg;
      if( a[0]>0 ){

Changes to src/sqlite.h.in.

748
749
750
751
752
753
754














755
756
757
758
759
760
761
762
763
764
765

766
767
768
769
770
771
772
** to be adjusted.  The values are changed for all database connections
** within the same process.  The argument is a pointer to an array of two
** integers where the first integer i the new retry count and the second
** integer is the delay.  If either integer is negative, then the setting
** is not changed but instead the prior value of that setting is written
** into the array entry, allowing the current retry settings to be
** interrogated.  The zDbName parameter is ignored.














** 
*/
#define SQLITE_FCNTL_LOCKSTATE        1
#define SQLITE_GET_LOCKPROXYFILE      2
#define SQLITE_SET_LOCKPROXYFILE      3
#define SQLITE_LAST_ERRNO             4
#define SQLITE_FCNTL_SIZE_HINT        5
#define SQLITE_FCNTL_CHUNK_SIZE       6
#define SQLITE_FCNTL_FILE_POINTER     7
#define SQLITE_FCNTL_SYNC_OMITTED     8
#define SQLITE_FCNTL_WIN32_AV_RETRY   9


/*
** CAPI3REF: Mutex Handle
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only







>
>
>
>
>
>
>
>
>
>
>
>
>
>











>







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

/*
** CAPI3REF: Mutex Handle
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only

Changes to src/test1.c.

5125
5126
5127
5128
5129
5130
5131
































5132
5133
5134
5135
5136
5137
5138
....
5924
5925
5926
5927
5928
5929
5930

5931
5932
5933
5934
5935
5936
5937
  if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
  sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}


































/*
** tclcmd:   sqlite3_vfs_list
**
**   Return a tcl list containing the names of all registered vfs's.
*/
static int vfs_list(
................................................................................
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
     { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },

     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },

     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
....
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
  if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
  sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}

/*
** tclcmd:   file_control_persist_wal DB PERSIST-FLAG
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_PERSIST_WAL opcode.
*/
static int file_control_persist_wal(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;
  int rc;
  int bPersist;
  char z[100];

  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
        Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist);
  sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}


/*
** tclcmd:   sqlite3_vfs_list
**
**   Return a tcl list containing the names of all registered vfs's.
*/
static int vfs_list(
................................................................................
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
     { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
     { "file_control_persist_wal",    file_control_persist_wal,     0   },
     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },

     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },

Changes to src/wal.c.

1800
1801
1802
1803
1804
1805
1806

1807
1808
1809
1810
1811
1812

1813
1814
1815
1816
1817
1818
1819
1820
    ** the database. In this case checkpoint the database and unlink both
    ** the wal and wal-index files.
    **
    ** The EXCLUSIVE lock is not released before returning.
    */
    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
    if( rc==SQLITE_OK ){

      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
      }
      rc = sqlite3WalCheckpoint(
          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
      );

      if( rc==SQLITE_OK ){
        isDelete = 1;
      }
    }

    walIndexClose(pWal, isDelete);
    sqlite3OsClose(pWal->pWalFd);
    if( isDelete ){







>






>
|







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

    walIndexClose(pWal, isDelete);
    sqlite3OsClose(pWal->pWalFd);
    if( isDelete ){

Added test/walpersist.test.









































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 2011 July 26
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains tests for using WAL with persistent WAL file mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
set ::testprefix walpersist

do_test walpersist-1.0 {
  db eval {
    PRAGMA journal_mode=WAL;
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES(randomblob(5000));
  }
  file exists test.db-wal
} {1}
do_test walpersist-1.1 {
  file exists test.db-shm
} {1}
do_test walpersist-1.2 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 0 0}
do_test walpersist-1.3 {
  sqlite3 db test.db
  db eval {SELECT length(a) FROM t1}
} {5000}
do_test walpersist-1.4 {
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 1 1}
do_test walpersist-1.5 {
  file_control_persist_wal db -1
} {0 0}
do_test walpersist-1.6 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.7 {
  file_control_persist_wal db -1
} {0 1}
do_test walpersist-1.8 {
  file_control_persist_wal db 0
} {0 0}
do_test walpersist-1.9 {
  file_control_persist_wal db -1
} {0 0}
do_test walpersist-1.10 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.11 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 1 1}

  


finish_test