/ Check-in [9803196d]
Login

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

Overview
Comment:Add the sqlite3_wal_checkpoint() and sqlite3_wal_autocheckpoint() APIs.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wal
Files: files | file ages | folders
SHA1: 9803196dec85e3aa4105cc477e9cfe98d370e486
User & Date: dan 2010-05-03 08:04:49
Context
2010-05-03
08:19
Merge two wal leaves. check-in: 23c0e6c3 user: dan tags: wal
08:04
Add the sqlite3_wal_checkpoint() and sqlite3_wal_autocheckpoint() APIs. check-in: 9803196d user: dan tags: wal
2010-05-01
17:57
Define an invariant to guarantee deadlock-free operation of SHM in os_unix.c and check that invariant with assert() statements. check-in: 6af2dca7 user: drh tags: wal
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/main.c.

  1181   1181     sqlite3_mutex_enter(db->mutex);
  1182   1182     pRet = db->pRollbackArg;
  1183   1183     db->xRollbackCallback = xCallback;
  1184   1184     db->pRollbackArg = pArg;
  1185   1185     sqlite3_mutex_leave(db->mutex);
  1186   1186     return pRet;
  1187   1187   }
         1188  +
         1189  +#ifndef SQLITE_OMIT_WAL
         1190  +/*
         1191  +** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
         1192  +** Return non-zero, indicating to the caller that a checkpoint should be run,
         1193  +** if the number of frames in the log file is greater than 
         1194  +** sqlite3.nDefaultCheckpoint (the value configured by wal_autocheckpoint()).
         1195  +*/ 
         1196  +static int defaultWalHook(void *p, sqlite3 *db, const char *z, int nFrame){
         1197  +  UNUSED_PARAMETER(p);
         1198  +  UNUSED_PARAMETER(z);
         1199  +  return ( nFrame>=db->nDefaultCheckpoint );
         1200  +}
         1201  +
         1202  +/*
         1203  +** Configure an sqlite3_wal_hook() callback to automatically checkpoint
         1204  +** a database after committing a transaction if there are nFrame or
         1205  +** more frames in the log file. Passing zero or a negative value as the
         1206  +** nFrame parameter disables automatic checkpoints entirely.
         1207  +**
         1208  +** The callback registered by this function replaces any existing callback
         1209  +** registered using sqlite3_wal_hook(). Likewise, registering a callback
         1210  +** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
         1211  +** configured by this function.
         1212  +*/
         1213  +int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
         1214  +  sqlite3_mutex_enter(db->mutex);
         1215  +  if( nFrame>0 ){
         1216  +    db->nDefaultCheckpoint = nFrame;
         1217  +    sqlite3_wal_hook(db, defaultWalHook, 0);
         1218  +  }else{
         1219  +    sqlite3_wal_hook(db, 0, 0);
         1220  +  }
         1221  +  sqlite3_mutex_leave(db->mutex);
         1222  +  return SQLITE_OK;
         1223  +}
  1188   1224   
  1189   1225   /*
  1190   1226   ** Register a callback to be invoked each time a transaction is written
  1191   1227   ** into the write-ahead-log by this database connection.
  1192   1228   */
  1193   1229   void *sqlite3_wal_hook(
  1194   1230     sqlite3 *db,                    /* Attach the hook to this db handle */
  1195   1231     int(*xCallback)(void *, sqlite3*, const char*, int),
  1196   1232     void *pArg                      /* First argument passed to xCallback() */
  1197   1233   ){
  1198         -#ifndef SQLITE_OMIT_WAL
  1199   1234     void *pRet;
  1200   1235     sqlite3_mutex_enter(db->mutex);
  1201   1236     pRet = db->pWalArg;
  1202   1237     db->xWalCallback = xCallback;
  1203   1238     db->pWalArg = pArg;
  1204   1239     sqlite3_mutex_leave(db->mutex);
  1205   1240     return pRet;
  1206         -#else
         1241  +}
         1242  +
         1243  +/*
         1244  +** Checkpoint database zDb. If zDb is NULL, the main database is checkpointed.
         1245  +*/
         1246  +int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
         1247  +  int rc;                         /* Return code */
         1248  +  int iDb = 0;                    /* sqlite3.aDb[] index of db to checkpoint */
         1249  +
         1250  +  sqlite3_mutex_enter(db->mutex);
         1251  +  if( zDb ){
         1252  +    iDb = sqlite3FindDbName(db, zDb);
         1253  +  }
         1254  +  if( iDb<0 ){
         1255  +    rc = SQLITE_ERROR;
         1256  +  }else{
         1257  +    rc = sqlite3Checkpoint(db, iDb);
         1258  +  }
         1259  +  sqlite3_mutex_leave(db->mutex);
         1260  +
         1261  +  return rc;
         1262  +}
         1263  +
         1264  +/*
         1265  +** Run a checkpoint on database iDb. This is a no-op if database iDb is
         1266  +** not currently open in WAL mode.
         1267  +**
         1268  +** If a transaction is open at either the database handle (db) or b-tree
         1269  +** level, this function returns SQLITE_LOCKED and a checkpoint is not
         1270  +** attempted. If an error occurs while running the checkpoint, an SQLite
         1271  +** error code is returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK.
         1272  +**
         1273  +** The mutex on database handle db should be held by the caller. The mutex
         1274  +** associated with the specific b-tree being checkpointed is taken by
         1275  +** this function while the checkpoint is running.
         1276  +*/
         1277  +int sqlite3Checkpoint(sqlite3 *db, int iDb){
         1278  +  Btree *pBt;                     /* Btree handle to checkpoint */
         1279  +  int rc;                         /* Return code */
         1280  +
         1281  +  assert( sqlite3_mutex_held(db->mutex) );
         1282  +
         1283  +  pBt = db->aDb[iDb].pBt;
         1284  +  if( sqlite3BtreeIsInReadTrans(pBt) ){
         1285  +    rc = SQLITE_LOCKED;
         1286  +  }else{
         1287  +    sqlite3BtreeEnter(pBt);
         1288  +    rc = sqlite3PagerCheckpoint(sqlite3BtreePager(pBt));
         1289  +    sqlite3BtreeLeave(pBt);
         1290  +  }
         1291  +
         1292  +  return rc;
         1293  +}
         1294  +#else /* ifndef SQLITE_OMIT_WAL */
         1295  +/*
         1296  +** If SQLITE_OMIT_WAL is defined, the following API functions are no-ops:
         1297  +**
         1298  +**   sqlite3_wal_hook()
         1299  +**   sqlite3_wal_checkpoint()
         1300  +**   sqlite3_wal_autocheckpoint()
         1301  +*/
         1302  +void *sqlite3_wal_hook(
         1303  +  sqlite3 *x,
         1304  +  int(*xCallback)(void *, sqlite3*, const char*, int),
         1305  +  void *pArg
         1306  +){
  1207   1307     return 0;
         1308  +}
         1309  +int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ return SQLITE_OK; }
         1310  +int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){ return SQLITE_OK; }
  1208   1311   #endif
  1209         -}
  1210   1312   
  1211   1313   /*
  1212   1314   ** This function returns true if main-memory should be used instead of
  1213   1315   ** a temporary file for transient pager files and statement journals.
  1214   1316   ** The value returned depends on the value of db->temp_store (runtime
  1215   1317   ** parameter) and the compile time value of SQLITE_TEMP_STORE. The
  1216   1318   ** following table describes the relationship between these two values
................................................................................
  1763   1865     sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
  1764   1866                             SQLITE_DEFAULT_LOCKING_MODE);
  1765   1867   #endif
  1766   1868   
  1767   1869     /* Enable the lookaside-malloc subsystem */
  1768   1870     setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
  1769   1871                           sqlite3GlobalConfig.nLookaside);
         1872  +
         1873  +  sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_CACHE_SIZE);
  1770   1874   
  1771   1875   opendb_out:
  1772   1876     if( db ){
  1773   1877       assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
  1774   1878       sqlite3_mutex_leave(db->mutex);
  1775   1879     }
  1776   1880     rc = sqlite3_errcode(db);

Changes to src/pragma.c.

  1403   1403   #ifndef SQLITE_OMIT_WAL
  1404   1404     /*
  1405   1405     **   PRAGMA [database.]checkpoint
  1406   1406     **
  1407   1407     ** Checkpoint the database.
  1408   1408     */
  1409   1409     if( sqlite3StrICmp(zLeft, "checkpoint")==0 ){
  1410         -    sqlite3VdbeUsesBtree(v, iDb);
  1411   1410       sqlite3VdbeAddOp3(v, OP_Checkpoint, iDb, 0, 0);
  1412   1411     }else
  1413   1412   #endif
  1414   1413   
  1415   1414   #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
  1416   1415     /*
  1417   1416     ** Report the current state of file logs for all databases

Changes to src/sqlite.h.in.

  5793   5793   */
  5794   5794   void *sqlite3_wal_hook(
  5795   5795     sqlite3*, 
  5796   5796     int(*)(void *,sqlite3*,const char*,int),
  5797   5797     void*
  5798   5798   );
  5799   5799   
         5800  +/*
         5801  +** CAPI3REF: Configure an auto-checkpoint
         5802  +*/
         5803  +int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
         5804  +
         5805  +/*
         5806  +** CAPI3REF: Checkpoint a database
         5807  +*/
         5808  +int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
         5809  +
  5800   5810   /*
  5801   5811   ** Undo the hack that converts floating point types to integer for
  5802   5812   ** builds on processors without floating point support.
  5803   5813   */
  5804   5814   #ifdef SQLITE_OMIT_FLOATING_POINT
  5805   5815   # undef double
  5806   5816   #endif
  5807   5817   
  5808   5818   #ifdef __cplusplus
  5809   5819   }  /* End of the 'extern "C"' block */
  5810   5820   #endif
  5811   5821   #endif

Changes to src/sqliteInt.h.

   820    820     void *pCommitArg;                 /* Argument to xCommitCallback() */   
   821    821     int (*xCommitCallback)(void*);    /* Invoked at every commit. */
   822    822     void *pRollbackArg;               /* Argument to xRollbackCallback() */   
   823    823     void (*xRollbackCallback)(void*); /* Invoked at every commit. */
   824    824     void *pUpdateArg;
   825    825     void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
   826    826   #ifndef SQLITE_OMIT_WAL
          827  +  int nDefaultCheckpoint;       /* Value configured by wal_autocheckpoint() */
   827    828     int (*xWalCallback)(void *, sqlite3 *, const char *, int);
   828    829     void *pWalArg;
   829    830   #endif
   830    831     void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
   831    832     void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
   832    833     void *pCollNeededArg;
   833    834     sqlite3_value *pErr;          /* Most recent error message */
................................................................................
  2994   2995   int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
  2995   2996   int sqlite3Reprepare(Vdbe*);
  2996   2997   void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
  2997   2998   CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
  2998   2999   int sqlite3TempInMemory(const sqlite3*);
  2999   3000   VTable *sqlite3GetVTable(sqlite3*, Table*);
  3000   3001   const char *sqlite3JournalModename(int);
         3002  +int sqlite3Checkpoint(sqlite3*, int);
  3001   3003   
  3002   3004   /* Declarations for functions in fkey.c. All of these are replaced by
  3003   3005   ** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
  3004   3006   ** key functionality is available. If OMIT_TRIGGER is defined but
  3005   3007   ** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In
  3006   3008   ** this case foreign keys are parsed, but no other functionality is 
  3007   3009   ** provided (enforcement of FK constraints requires the triggers sub-system).

Changes to src/vdbe.c.

  5189   5189   #ifndef SQLITE_OMIT_WAL
  5190   5190   /* Opcode: Checkpoint P1 * * * *
  5191   5191   **
  5192   5192   ** Checkpoint database P1. This is a no-op if P1 is not currently in
  5193   5193   ** WAL mode.
  5194   5194   */
  5195   5195   case OP_Checkpoint: {
  5196         -  Btree *pBt;                     /* Btree to checkpoint */
  5197         -
  5198         -  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  5199         -  assert( (p->btreeMask & (1<<pOp->p1))!=0 );
  5200         -  pBt = db->aDb[pOp->p1].pBt;
  5201         -  rc = sqlite3PagerCheckpoint(sqlite3BtreePager(pBt));
         5196  +  rc = sqlite3Checkpoint(db, pOp->p1);
  5202   5197     break;
  5203   5198   };  
  5204   5199   #endif
  5205   5200   
  5206   5201   /* Opcode: JournalMode P1 P2 P3 * *
  5207   5202   **
  5208   5203   ** Change the journal mode of database P1 to P3. P3 must be one of the

Changes to test/backup.test.

   485    485   #
   486    486   #   1) Backing up file-to-file. The writer writes via an external pager.
   487    487   #   2) Backing up file-to-file. The writer writes via the same pager as
   488    488   #      is used by the backup operation.
   489    489   #   3) Backing up memory-to-file. 
   490    490   #
   491    491   set iTest 0
          492  +file delete -force bak.db-wal
   492    493   foreach {writer file} {db test.db db3 test.db db :memory:} {
   493    494     incr iTest
   494    495     catch { file delete bak.db }
   495    496     sqlite3 db2 bak.db
   496    497     catch { file delete $file }
   497    498     sqlite3 db $file
   498    499     sqlite3 db3 $file

Changes to test/walthread.test.

   458    458   
   459    459   
   460    460   # This test case attempts to provoke a deadlock condition that existed in
   461    461   # the unix VFS at one point. The problem occurred only while recovering a 
   462    462   # very large wal file (one that requires a wal-index larger than the 
   463    463   # initial default allocation of 64KB).
   464    464   #
   465         -# When recovering a log file, mutexes are usually obtained and released
   466         -# as follows:
   467         -#
   468         -#   xShmGet                         ENTER mutexBuf
   469         -#   xShmLock(RECOVER)               ENTER mutexRecov
   470         -#     <do recovery work>
   471         -#   xShmLock(READ)                  LEAVE mutexRecov
   472         -#   xShmRelease                     LEAVE mutexBuf         
   473         -#
   474         -# However, if the initial wal-index allocation needs to be enlarged during
   475         -# the recovery process, the mutex operations become:
   476         -#
   477         -#   xShmGet                         ENTER mutexBuf
   478         -#   xShmLock(RECOVER)               ENTER mutexRecov
   479         -#     <do first part of recovery work>
   480         -#     xShmRelease                   LEAVE mutexBuf
   481         -#     xShmSize
   482         -#     xShmGet                       ENTER mutexBuf
   483         -#     <do second part of recovery work>
   484         -#   xShmLock(READ)                  LEAVE mutexRecov
   485         -#   xShmRelease                     LEAVE mutexBuf         
   486         -#
   487         -# If multiple threads attempt the above simultaneously, deadlock can occur.
   488         -#
   489    465   do_thread_test walthread-5 -seconds $seconds(walthread-5) -init {
   490    466   
   491    467     proc log_file_size {nFrame pgsz} {
   492    468       expr {12 + ($pgsz+16)*$nFrame}
   493    469     }
   494    470   
   495    471     execsql {