/ Check-in [c88d36e2]
Login

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

Overview
Comment:Changes to support interrupting a checkpoint using sqlite3_interrupt().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c88d36e251abec24aa7e37cf550e148904b9fd2d
User & Date: dan 2016-10-17 15:28:39
Context
2016-10-17
18:33
Corrections to a couple recently added 'filectrl.test' results. check-in: 3d89dc45 user: mistachkin tags: trunk
15:28
Changes to support interrupting a checkpoint using sqlite3_interrupt(). check-in: c88d36e2 user: dan tags: trunk
00:48
Small size reduction and performance increase in the string duplicator. check-in: cda998f0 user: drh tags: trunk
2016-08-13
14:30
Questionable changes to support interruptible checkpoint in ZipVFS. Leaf check-in: c7a9f26d user: dan tags: interruptible-checkpoint
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to src/btree.c.

  2391   2391     }
  2392   2392   #endif
  2393   2393     *ppBtree = p;
  2394   2394   
  2395   2395   btree_open_out:
  2396   2396     if( rc!=SQLITE_OK ){
  2397   2397       if( pBt && pBt->pPager ){
  2398         -      sqlite3PagerClose(pBt->pPager);
         2398  +      sqlite3PagerClose(pBt->pPager, 0);
  2399   2399       }
  2400   2400       sqlite3_free(pBt);
  2401   2401       sqlite3_free(p);
  2402   2402       *ppBtree = 0;
  2403   2403     }else{
         2404  +    sqlite3_file *pFile;
         2405  +
  2404   2406       /* If the B-Tree was successfully opened, set the pager-cache size to the
  2405   2407       ** default value. Except, when opening on an existing shared pager-cache,
  2406   2408       ** do not change the pager-cache size.
  2407   2409       */
  2408   2410       if( sqlite3BtreeSchema(p, 0, 0)==0 ){
  2409   2411         sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
  2410   2412       }
         2413  +
         2414  +    pFile = sqlite3PagerFile(pBt->pPager);
         2415  +    if( pFile->pMethods ){
         2416  +      sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db);
         2417  +    }
  2411   2418     }
  2412   2419     if( mutexOpen ){
  2413   2420       assert( sqlite3_mutex_held(mutexOpen) );
  2414   2421       sqlite3_mutex_leave(mutexOpen);
  2415   2422     }
  2416   2423     assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 );
  2417   2424     return rc;
................................................................................
  2533   2540     if( !p->sharable || removeFromSharingList(pBt) ){
  2534   2541       /* The pBt is no longer on the sharing list, so we can access
  2535   2542       ** it without having to hold the mutex.
  2536   2543       **
  2537   2544       ** Clean out and delete the BtShared object.
  2538   2545       */
  2539   2546       assert( !pBt->pCursor );
  2540         -    sqlite3PagerClose(pBt->pPager);
         2547  +    sqlite3PagerClose(pBt->pPager, p->db);
  2541   2548       if( pBt->xFreeSchema && pBt->pSchema ){
  2542   2549         pBt->xFreeSchema(pBt->pSchema);
  2543   2550       }
  2544   2551       sqlite3DbFree(0, pBt->pSchema);
  2545   2552       freeTempSpace(pBt);
  2546   2553       sqlite3_free(pBt);
  2547   2554     }
................................................................................
  9473   9480     int rc = SQLITE_OK;
  9474   9481     if( p ){
  9475   9482       BtShared *pBt = p->pBt;
  9476   9483       sqlite3BtreeEnter(p);
  9477   9484       if( pBt->inTransaction!=TRANS_NONE ){
  9478   9485         rc = SQLITE_LOCKED;
  9479   9486       }else{
  9480         -      rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt);
         9487  +      rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt);
  9481   9488       }
  9482   9489       sqlite3BtreeLeave(p);
  9483   9490     }
  9484   9491     return rc;
  9485   9492   }
  9486   9493   #endif
  9487   9494   

Changes to src/main.c.

  2102   2102       sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
  2103   2103     }else{
  2104   2104       db->busyHandler.nBusy = 0;
  2105   2105       rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
  2106   2106       sqlite3Error(db, rc);
  2107   2107     }
  2108   2108     rc = sqlite3ApiExit(db, rc);
         2109  +
         2110  +  /* If there are no active statements, clear the interrupt flag at this
         2111  +  ** point.  */
         2112  +  if( db->nVdbeActive==0 ){
         2113  +    db->u1.isInterrupted = 0;
         2114  +  }
         2115  +
  2109   2116     sqlite3_mutex_leave(db->mutex);
  2110   2117     return rc;
  2111   2118   #endif
  2112   2119   }
  2113   2120   
  2114   2121   
  2115   2122   /*

Changes to src/pager.c.

  4017   4017   ** result in a coredump.
  4018   4018   **
  4019   4019   ** This function always succeeds. If a transaction is active an attempt
  4020   4020   ** is made to roll it back. If an error occurs during the rollback 
  4021   4021   ** a hot journal may be left in the filesystem but no error is returned
  4022   4022   ** to the caller.
  4023   4023   */
  4024         -int sqlite3PagerClose(Pager *pPager){
         4024  +int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
  4025   4025     u8 *pTmp = (u8 *)pPager->pTmpSpace;
  4026   4026   
         4027  +  assert( db || pagerUseWal(pPager)==0 );
  4027   4028     assert( assert_pager_state(pPager) );
  4028   4029     disable_simulated_io_errors();
  4029   4030     sqlite3BeginBenignMalloc();
  4030   4031     pagerFreeMapHdrs(pPager);
  4031   4032     /* pPager->errCode = 0; */
  4032   4033     pPager->exclusiveMode = 0;
  4033   4034   #ifndef SQLITE_OMIT_WAL
  4034         -  sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
         4035  +  sqlite3WalClose(pPager->pWal,db,pPager->ckptSyncFlags,pPager->pageSize,pTmp);
  4035   4036     pPager->pWal = 0;
  4036   4037   #endif
  4037   4038     pager_reset(pPager);
  4038   4039     if( MEMDB ){
  4039   4040       pager_unlock(pPager);
  4040   4041     }else{
  4041   4042       /* If it is open, sync the journal file before calling UnlockAndRollback.
................................................................................
  7190   7191   /*
  7191   7192   ** This function is called when the user invokes "PRAGMA wal_checkpoint",
  7192   7193   ** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint()
  7193   7194   ** or wal_blocking_checkpoint() API functions.
  7194   7195   **
  7195   7196   ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
  7196   7197   */
  7197         -int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
         7198  +int sqlite3PagerCheckpoint(
         7199  +  Pager *pPager,                  /* Checkpoint on this pager */
         7200  +  sqlite3 *db,                    /* Db handle used to check for interrupts */
         7201  +  int eMode,                      /* Type of checkpoint */
         7202  +  int *pnLog,                     /* OUT: Final number of frames in log */
         7203  +  int *pnCkpt                     /* OUT: Final number of checkpointed frames */
         7204  +){
  7198   7205     int rc = SQLITE_OK;
  7199   7206     if( pPager->pWal ){
  7200         -    rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
         7207  +    rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
  7201   7208           (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
  7202   7209           pPager->pBusyHandlerArg,
  7203   7210           pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
  7204   7211           pnLog, pnCkpt
  7205   7212       );
  7206   7213     }
  7207   7214     return rc;
................................................................................
  7325   7332   ** to switching from WAL to rollback mode.
  7326   7333   **
  7327   7334   ** Before closing the log file, this function attempts to take an 
  7328   7335   ** EXCLUSIVE lock on the database file. If this cannot be obtained, an
  7329   7336   ** error (SQLITE_BUSY) is returned and the log connection is not closed.
  7330   7337   ** If successful, the EXCLUSIVE lock is not released before returning.
  7331   7338   */
  7332         -int sqlite3PagerCloseWal(Pager *pPager){
         7339  +int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
  7333   7340     int rc = SQLITE_OK;
  7334   7341   
  7335   7342     assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
  7336   7343   
  7337   7344     /* If the log file is not already open, but does exist in the file-system,
  7338   7345     ** it may need to be checkpointed before the connection can switch to
  7339   7346     ** rollback mode. Open it now so this can happen.
................................................................................
  7353   7360       
  7354   7361     /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
  7355   7362     ** the database file, the log and log-summary files will be deleted.
  7356   7363     */
  7357   7364     if( rc==SQLITE_OK && pPager->pWal ){
  7358   7365       rc = pagerExclusiveLock(pPager);
  7359   7366       if( rc==SQLITE_OK ){
  7360         -      rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
         7367  +      rc = sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags,
  7361   7368                              pPager->pageSize, (u8*)pPager->pTmpSpace);
  7362   7369         pPager->pWal = 0;
  7363   7370         pagerFixMaplimit(pPager);
  7364   7371         if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
  7365   7372       }
  7366   7373     }
  7367   7374     return rc;

Changes to src/pager.h.

   118    118     Pager **ppPager,
   119    119     const char*,
   120    120     int,
   121    121     int,
   122    122     int,
   123    123     void(*)(DbPage*)
   124    124   );
   125         -int sqlite3PagerClose(Pager *pPager);
          125  +int sqlite3PagerClose(Pager *pPager, sqlite3*);
   126    126   int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
   127    127   
   128    128   /* Functions used to configure a Pager object. */
   129    129   void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
   130    130   int sqlite3PagerSetPagesize(Pager*, u32*, int);
   131    131   #ifdef SQLITE_HAS_CODEC
   132    132   void sqlite3PagerAlignReserve(Pager*,Pager*);
................................................................................
   169    169   int sqlite3PagerCommitPhaseTwo(Pager*);
   170    170   int sqlite3PagerRollback(Pager*);
   171    171   int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
   172    172   int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
   173    173   int sqlite3PagerSharedLock(Pager *pPager);
   174    174   
   175    175   #ifndef SQLITE_OMIT_WAL
   176         -  int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
          176  +  int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
   177    177     int sqlite3PagerWalSupported(Pager *pPager);
   178    178     int sqlite3PagerWalCallback(Pager *pPager);
   179    179     int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
   180         -  int sqlite3PagerCloseWal(Pager *pPager);
          180  +  int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
   181    181   # ifdef SQLITE_ENABLE_SNAPSHOT
   182    182     int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
   183    183     int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
   184    184   # endif
   185    185   #endif
   186    186   
   187    187   #ifdef SQLITE_ENABLE_ZIPVFS

Changes to src/sqlite.h.in.

  1031   1031   #define SQLITE_FCNTL_WIN32_SET_HANDLE       23
  1032   1032   #define SQLITE_FCNTL_WAL_BLOCK              24
  1033   1033   #define SQLITE_FCNTL_ZIPVFS                 25
  1034   1034   #define SQLITE_FCNTL_RBU                    26
  1035   1035   #define SQLITE_FCNTL_VFS_POINTER            27
  1036   1036   #define SQLITE_FCNTL_JOURNAL_POINTER        28
  1037   1037   #define SQLITE_FCNTL_WIN32_GET_HANDLE       29
         1038  +#define SQLITE_FCNTL_PDB                    30
  1038   1039   
  1039   1040   /* deprecated names */
  1040   1041   #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
  1041   1042   #define SQLITE_SET_LOCKPROXYFILE      SQLITE_FCNTL_SET_LOCKPROXYFILE
  1042   1043   #define SQLITE_LAST_ERRNO             SQLITE_FCNTL_LAST_ERRNO
  1043   1044   
  1044   1045   

Changes to src/test2.c.

    89     89     int rc;
    90     90     if( argc!=2 ){
    91     91       Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    92     92          " ID\"", 0);
    93     93       return TCL_ERROR;
    94     94     }
    95     95     pPager = sqlite3TestTextToPtr(argv[1]);
    96         -  rc = sqlite3PagerClose(pPager);
           96  +  rc = sqlite3PagerClose(pPager, 0);
    97     97     if( rc!=SQLITE_OK ){
    98     98       Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    99     99       return TCL_ERROR;
   100    100     }
   101    101     return TCL_OK;
   102    102   }
   103    103   

Changes to src/vdbe.c.

  6269   6269    
  6270   6270         if( eOld==PAGER_JOURNALMODE_WAL ){
  6271   6271           /* If leaving WAL mode, close the log file. If successful, the call
  6272   6272           ** to PagerCloseWal() checkpoints and deletes the write-ahead-log 
  6273   6273           ** file. An EXCLUSIVE lock may still be held on the database file 
  6274   6274           ** after a successful return. 
  6275   6275           */
  6276         -        rc = sqlite3PagerCloseWal(pPager);
         6276  +        rc = sqlite3PagerCloseWal(pPager, db);
  6277   6277           if( rc==SQLITE_OK ){
  6278   6278             sqlite3PagerSetJournalMode(pPager, eNew);
  6279   6279           }
  6280   6280         }else if( eOld==PAGER_JOURNALMODE_MEMORY ){
  6281   6281           /* Cannot transition directly from MEMORY to WAL.  Use mode OFF
  6282   6282           ** as an intermediate */
  6283   6283           sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF);

Changes to src/wal.c.

  1719   1719   **
  1720   1720   ** The caller must be holding sufficient locks to ensure that no other
  1721   1721   ** checkpoint is running (in any other thread or process) at the same
  1722   1722   ** time.
  1723   1723   */
  1724   1724   static int walCheckpoint(
  1725   1725     Wal *pWal,                      /* Wal connection */
         1726  +  sqlite3 *db,                    /* Check for interrupts on this handle */
  1726   1727     int eMode,                      /* One of PASSIVE, FULL or RESTART */
  1727   1728     int (*xBusy)(void*),            /* Function to call when busy */
  1728   1729     void *pBusyArg,                 /* Context argument for xBusyHandler */
  1729   1730     int sync_flags,                 /* Flags for OsSync() (or 0) */
  1730   1731     u8 *zBuf                        /* Temporary buffer to use */
  1731   1732   ){
  1732   1733     int rc = SQLITE_OK;             /* Return code */
................................................................................
  1813   1814         }
  1814   1815   
  1815   1816   
  1816   1817         /* Iterate through the contents of the WAL, copying data to the db file */
  1817   1818         while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
  1818   1819           i64 iOffset;
  1819   1820           assert( walFramePgno(pWal, iFrame)==iDbpage );
         1821  +        if( db->u1.isInterrupted ){
         1822  +          rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
         1823  +          break;
         1824  +        }
  1820   1825           if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
  1821   1826             continue;
  1822   1827           }
  1823   1828           iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
  1824   1829           /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
  1825   1830           rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
  1826   1831           if( rc!=SQLITE_OK ) break;
................................................................................
  1917   1922   }
  1918   1923   
  1919   1924   /*
  1920   1925   ** Close a connection to a log file.
  1921   1926   */
  1922   1927   int sqlite3WalClose(
  1923   1928     Wal *pWal,                      /* Wal to close */
         1929  +  sqlite3 *db,                    /* For interrupt flag */
  1924   1930     int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
  1925   1931     int nBuf,
  1926   1932     u8 *zBuf                        /* Buffer of at least nBuf bytes */
  1927   1933   ){
  1928   1934     int rc = SQLITE_OK;
  1929   1935     if( pWal ){
  1930   1936       int isDelete = 0;             /* True to unlink wal and wal-index files */
................................................................................
  1938   1944       ** The EXCLUSIVE lock is not released before returning.
  1939   1945       */
  1940   1946       rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
  1941   1947       if( rc==SQLITE_OK ){
  1942   1948         if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
  1943   1949           pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
  1944   1950         }
  1945         -      rc = sqlite3WalCheckpoint(
  1946         -          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
         1951  +      rc = sqlite3WalCheckpoint(pWal, db, 
         1952  +          SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
  1947   1953         );
  1948   1954         if( rc==SQLITE_OK ){
  1949   1955           int bPersist = -1;
  1950   1956           sqlite3OsFileControlHint(
  1951   1957               pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
  1952   1958           );
  1953   1959           if( bPersist!=1 ){
................................................................................
  3187   3193   ** we can from WAL into the database.
  3188   3194   **
  3189   3195   ** If parameter xBusy is not NULL, it is a pointer to a busy-handler
  3190   3196   ** callback. In this case this function runs a blocking checkpoint.
  3191   3197   */
  3192   3198   int sqlite3WalCheckpoint(
  3193   3199     Wal *pWal,                      /* Wal connection */
         3200  +  sqlite3 *db,                    /* Check this handle's interrupt flag */
  3194   3201     int eMode,                      /* PASSIVE, FULL, RESTART, or TRUNCATE */
  3195   3202     int (*xBusy)(void*),            /* Function to call when busy */
  3196   3203     void *pBusyArg,                 /* Context argument for xBusyHandler */
  3197   3204     int sync_flags,                 /* Flags to sync db file with (or 0) */
  3198   3205     int nBuf,                       /* Size of temporary buffer */
  3199   3206     u8 *zBuf,                       /* Temporary buffer to use */
  3200   3207     int *pnLog,                     /* OUT: Number of frames in WAL */
................................................................................
  3261   3268   
  3262   3269     /* Copy data from the log to the database file. */
  3263   3270     if( rc==SQLITE_OK ){
  3264   3271   
  3265   3272       if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
  3266   3273         rc = SQLITE_CORRUPT_BKPT;
  3267   3274       }else{
  3268         -      rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
         3275  +      rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
  3269   3276       }
  3270   3277   
  3271   3278       /* If no error occurred, set the output variables. */
  3272   3279       if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
  3273   3280         if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
  3274   3281         if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
  3275   3282       }

Changes to src/wal.h.

    24     24   */
    25     25   #define WAL_SYNC_TRANSACTIONS  0x20   /* Sync at the end of each transaction */
    26     26   #define SQLITE_SYNC_MASK       0x13   /* Mask off the SQLITE_SYNC_* values */
    27     27   
    28     28   #ifdef SQLITE_OMIT_WAL
    29     29   # define sqlite3WalOpen(x,y,z)                   0
    30     30   # define sqlite3WalLimit(x,y)
    31         -# define sqlite3WalClose(w,x,y,z)                0
           31  +# define sqlite3WalClose(v,w,x,y,z)              0
    32     32   # define sqlite3WalBeginReadTransaction(y,z)     0
    33     33   # define sqlite3WalEndReadTransaction(z)
    34     34   # define sqlite3WalDbsize(y)                     0
    35     35   # define sqlite3WalBeginWriteTransaction(y)      0
    36     36   # define sqlite3WalEndWriteTransaction(x)        0
    37     37   # define sqlite3WalUndo(x,y,z)                   0
    38     38   # define sqlite3WalSavepoint(y,z)
    39     39   # define sqlite3WalSavepointUndo(y,z)            0
    40     40   # define sqlite3WalFrames(u,v,w,x,y,z)           0
    41         -# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
           41  +# define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0
    42     42   # define sqlite3WalCallback(z)                   0
    43     43   # define sqlite3WalExclusiveMode(y,z)            0
    44     44   # define sqlite3WalHeapMemory(z)                 0
    45     45   # define sqlite3WalFramesize(z)                  0
    46     46   # define sqlite3WalFindFrame(x,y,z)              0
    47     47   # define sqlite3WalFile(x)                       0
    48     48   #else
................................................................................
    52     52   /* Connection to a write-ahead log (WAL) file. 
    53     53   ** There is one object of this type for each pager. 
    54     54   */
    55     55   typedef struct Wal Wal;
    56     56   
    57     57   /* Open and close a connection to a write-ahead log. */
    58     58   int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
    59         -int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
           59  +int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *);
    60     60   
    61     61   /* Set the limiting size of a WAL file. */
    62     62   void sqlite3WalLimit(Wal*, i64);
    63     63   
    64     64   /* Used by readers to open (lock) and close (unlock) a snapshot.  A 
    65     65   ** snapshot is like a read-transaction.  It is the state of the database
    66     66   ** at an instant in time.  sqlite3WalOpenSnapshot gets a read lock and
................................................................................
    95     95   
    96     96   /* Write a frame or frames to the log. */
    97     97   int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
    98     98   
    99     99   /* Copy pages from the log to the database file */ 
   100    100   int sqlite3WalCheckpoint(
   101    101     Wal *pWal,                      /* Write-ahead log connection */
          102  +  sqlite3 *db,                    /* Check this handle's interrupt flag */
   102    103     int eMode,                      /* One of PASSIVE, FULL and RESTART */
   103    104     int (*xBusy)(void*),            /* Function to call when busy */
   104    105     void *pBusyArg,                 /* Context argument for xBusyHandler */
   105    106     int sync_flags,                 /* Flags to sync db file with (or 0) */
   106    107     int nBuf,                       /* Size of buffer nBuf */
   107    108     u8 *zBuf,                       /* Temporary buffer to use */
   108    109     int *pnLog,                     /* OUT: Number of frames in WAL */

Added test/interrupt2.test.

            1  +# 2016 Aug 12
            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  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this script is using the sqlite_interrupt() API to 
           13  +# interrupt WAL checkpoint operations.
           14  +#
           15  +
           16  +set testdir [file dirname $argv0]
           17  +source $testdir/tester.tcl
           18  +source $testdir/wal_common.tcl
           19  +set testprefix interrupt2
           20  +
           21  +db close
           22  +testvfs tvfs -default 1
           23  +
           24  +tvfs filter xWrite
           25  +tvfs script write_cb
           26  +
           27  +set ::trigger_interrupt 0
           28  +proc write_cb {method args} {
           29  +  set filename [lindex $args 0]
           30  +  if {[file tail $filename]=="test.db" && $::trigger_interrupt} {
           31  +    if {$::trigger_interrupt} {
           32  +      incr ::trigger_interrupt -1
           33  +      if {$::trigger_interrupt==0} { sqlite3_interrupt db }
           34  +    }
           35  +  }
           36  +  return 0
           37  +}
           38  +
           39  +sqlite3 db test.db 
           40  +do_execsql_test 1.0 {
           41  +  CREATE TABLE t1(a, b);
           42  +  CREATE INDEX t1a ON t1(a);
           43  +  CREATE INDEX t1b ON t1(b);
           44  +  PRAGMA journal_mode = wal;
           45  +
           46  +  WITH ii(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM ii WHERE i<1000 )
           47  +  INSERT INTO t1 SELECT i, i FROM ii;
           48  +} {wal}
           49  +
           50  +foreach idelay {
           51  +  5
           52  +  10
           53  +  15
           54  +  20
           55  +} {
           56  +
           57  +  set ::trigger_interrupt $idelay
           58  +  do_catchsql_test 1.$idelay.1 { PRAGMA wal_checkpoint; } {1 interrupted}
           59  +  do_execsql_test  1.$idelay.2 { SELECT count(*) FROM t1 } 1000
           60  +
           61  +  set ::trigger_interrupt $idelay
           62  +  do_test 1.$idelay.3 { 
           63  +    list [catch { sqlite3_wal_checkpoint_v2 db truncate } msg] $msg
           64  +  } {1 {SQLITE_INTERRUPT - interrupted}}
           65  +  do_execsql_test  1.$idelay.4 { SELECT count(*) FROM t1 } 1000
           66  +}
           67  +
           68  +#-------------------------------------------------------------------------
           69  +# Check that if there are other SQL statements running, a checkpoint does
           70  +# not clear the isInterrupted flag.
           71  +#
           72  +do_execsql_test 2.0 {
           73  +  CREATE TEMP TABLE z1(a, b);
           74  +  INSERT INTO z1 SELECT * FROM t1;
           75  +}
           76  +
           77  +do_test 2.1 {
           78  +  set i 10
           79  +  set res [list [catch {
           80  +    set i 10
           81  +    db eval {SELECT * FROM z1} {
           82  +      incr i -1
           83  +      if {$i==0} {
           84  +        set ::trigger_interrupt 10
           85  +        set cres [catch { sqlite3_wal_checkpoint_v2 db truncate } msg] 
           86  +        lappend cres $msg
           87  +      }
           88  +    }
           89  +  } msg] $msg]
           90  +
           91  +  list $cres $res
           92  +} {{1 {SQLITE_INTERRUPT - interrupted}} {1 interrupted}}
           93  +
           94  +do_execsql_test 2.0 {
           95  +  SELECT count(*) FROM t1
           96  +  UNION ALL
           97  +  SELECT count(*) FROM z1
           98  +} {1000 1000}
           99  +
          100  +#-------------------------------------------------------------------------
          101  +# Check the effect of an interrupt during sqlite3_close().
          102  +#
          103  +db_save_and_close
          104  +
          105  +db_restore_and_reopen
          106  +do_test 3.1.1 {
          107  +  set ::trigger_interrupt 10
          108  +  db eval { SELECT * FROM sqlite_master }
          109  +  db close
          110  +  set {} {}
          111  +} {}
          112  +do_test 3.1.2 {
          113  +  list [file exists test.db] [file exists test.db-wal]
          114  +} {1 1}
          115  +
          116  +db_restore_and_reopen
          117  +do_test 3.2.1 {
          118  +  db eval { SELECT * FROM sqlite_master }
          119  +  db close
          120  +  set {} {}
          121  +} {}
          122  +do_test 3.2.2 {
          123  +  list [file exists test.db] [file exists test.db-wal]
          124  +} {1 0}
          125  +
          126  +#-------------------------------------------------------------------------
          127  +# Check the effect of an interrupt during an automatic checkpoint
          128  +#
          129  +db_restore_and_reopen
          130  +do_test 4.0 { 
          131  +  execsql { PRAGMA wal_autocheckpoint = 10 }
          132  +  set ::trigger_interrupt 10
          133  +  execsql { CREATE TABLE t2(x, y) }
          134  +} {}
          135  +
          136  +# The auto-checkpoint in test 4.0 should have been interrupted. So this
          137  +# db write should cause the wal file to grow.
          138  +do_test 4.1 {
          139  +  set nFrame1 [wal_frame_count test.db-wal 1024]
          140  +  execsql { CREATE TABLE t3(x, y) }
          141  +  set nFrame2 [wal_frame_count test.db-wal 1024]
          142  +  expr $nFrame2 > $nFrame1
          143  +} {1}
          144  +
          145  +# The auto-checkpoint in test 4.0 should not have been interrupted. So 
          146  +# this db write should not cause the wal file to grow.
          147  +do_test 4.2 {
          148  +  set nFrame1 [wal_frame_count test.db-wal 1024]
          149  +  execsql { CREATE TABLE t4(x, y) }
          150  +  set nFrame2 [wal_frame_count test.db-wal 1024]
          151  +  expr $nFrame2 == $nFrame1
          152  +} {1}
          153  +
          154  +finish_test