/ Check-in [56fe5d76]
Login

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

Overview
Comment:Change the names of the log.c and log.h source files to wal.c and wal.h.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wal
Files: files | file ages | folders
SHA1: 56fe5d7624f840417152bcc63efbe21a5f557920
User & Date: drh 2010-04-26 00:19:45
Context
2010-04-26
10:40
Add mutexes to fix a race condition in wal.c. This isn't a very good fix. check-in: 3d159939 user: dan tags: wal
00:19
Change the names of the log.c and log.h source files to wal.c and wal.h. check-in: 56fe5d76 user: drh tags: wal
00:04
Begin moving WAL-specific I/O into the VFS. This checkin contains VFS infrastructure but it is untested and is not yet hooked up to the WAL. The version number is bumped to 3.7.0 because of the VFS extension. check-in: f5e615c2 user: drh tags: wal
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

272
273
274
275
276
277
278


279
280
281
282
283
284
285
...
738
739
740
741
742
743
744



745
746
747
748
749
750
751
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbeblob.c \
  $(TOP)/src/vdbemem.c \
  $(TOP)/src/vdbetrace.c \
  $(TOP)/src/vdbeInt.h \
  $(TOP)/src/vtab.c \


  $(TOP)/src/walker.c \
  $(TOP)/src/where.c

# Generated source code files
#
SRC += \
  keywordhash.h \
................................................................................

vdbetrace.lo:	$(TOP)/src/vdbetrace.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c

vtab.lo:	$(TOP)/src/vtab.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c




walker.lo:	$(TOP)/src/walker.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/walker.c

where.lo:	$(TOP)/src/where.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/where.c

tclsqlite-shell.lo:	$(TOP)/src/tclsqlite.c $(HDR)







>
>







 







>
>
>







272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
...
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbeblob.c \
  $(TOP)/src/vdbemem.c \
  $(TOP)/src/vdbetrace.c \
  $(TOP)/src/vdbeInt.h \
  $(TOP)/src/vtab.c \
  $(TOP)/src/wal.c \
  $(TOP)/src/wal.h \
  $(TOP)/src/walker.c \
  $(TOP)/src/where.c

# Generated source code files
#
SRC += \
  keywordhash.h \
................................................................................

vdbetrace.lo:	$(TOP)/src/vdbetrace.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c

vtab.lo:	$(TOP)/src/vtab.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c

wal.lo:	$(TOP)/src/wal.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/wal.c

walker.lo:	$(TOP)/src/walker.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/walker.c

where.lo:	$(TOP)/src/where.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/where.c

tclsqlite-shell.lo:	$(TOP)/src/tclsqlite.c $(HDR)

Changes to main.mk.

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
..
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
156
157
158
159
160
161
162


163
164
165
166
167
168
169
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#
LIBOBJ+= alter.o analyze.o attach.o auth.o \
         backup.o bitvec.o btmutex.o btree.o build.o \
         callback.o complete.o ctime.o date.o delete.o expr.o fault.o fkey.o \
         fts3.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
         fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o fts3_write.o \
         func.o global.o hash.o \
         icu.o insert.o journal.o legacy.o loadext.o log.o \
         main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
         memjournal.o \
         mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \
         notify.o opcodes.o os.o os_os2.o os_unix.o os_win.o \
         pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \
         random.o resolve.o rowset.o rtree.o select.o status.o \
         table.o tokenize.o trigger.o \
         update.o util.o vacuum.o \
         vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbetrace.o \
         walker.o where.o utf.o vtab.o



# All of the source code files.
#
SRC = \
  $(TOP)/src/alter.c \
................................................................................
  $(TOP)/src/hash.c \
  $(TOP)/src/hash.h \
  $(TOP)/src/hwtime.h \
  $(TOP)/src/insert.c \
  $(TOP)/src/journal.c \
  $(TOP)/src/legacy.c \
  $(TOP)/src/loadext.c \
  $(TOP)/src/log.c \
  $(TOP)/src/log.h \
  $(TOP)/src/main.c \
  $(TOP)/src/malloc.c \
  $(TOP)/src/mem0.c \
  $(TOP)/src/mem1.c \
  $(TOP)/src/mem2.c \
  $(TOP)/src/mem3.c \
  $(TOP)/src/mem5.c \
................................................................................
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbeblob.c \
  $(TOP)/src/vdbemem.c \
  $(TOP)/src/vdbetrace.c \
  $(TOP)/src/vdbeInt.h \
  $(TOP)/src/vtab.c \


  $(TOP)/src/walker.c \
  $(TOP)/src/where.c

# Source code for extensions
#
SRC += \
  $(TOP)/ext/fts1/fts1.c \
................................................................................

#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c

TESTSRC2 = \
  $(TOP)/src/attach.c $(TOP)/src/backup.c $(TOP)/src/btree.c                   \
  $(TOP)/src/build.c $(TOP)/src/date.c                                         \
  $(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/log.c     \
  $(TOP)/src/mem5.c $(TOP)/src/os.c                                            \
  $(TOP)/src/os_os2.c $(TOP)/src/os_unix.c $(TOP)/src/os_win.c                 \
  $(TOP)/src/pager.c $(TOP)/src/pragma.c $(TOP)/src/prepare.c                  \
  $(TOP)/src/printf.c $(TOP)/src/random.c $(TOP)/src/pcache.c                  \
  $(TOP)/src/pcache1.c $(TOP)/src/select.c $(TOP)/src/tokenize.c               \
  $(TOP)/src/utf.c $(TOP)/src/util.c $(TOP)/src/vdbeapi.c $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbe.c $(TOP)/src/vdbemem.c $(TOP)/src/where.c parse.c            \







|









|







 







<
<







 







>
>







 







|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
..
97
98
99
100
101
102
103


104
105
106
107
108
109
110
...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#
LIBOBJ+= alter.o analyze.o attach.o auth.o \
         backup.o bitvec.o btmutex.o btree.o build.o \
         callback.o complete.o ctime.o date.o delete.o expr.o fault.o fkey.o \
         fts3.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
         fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o fts3_write.o \
         func.o global.o hash.o \
         icu.o insert.o journal.o legacy.o loadext.o \
         main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
         memjournal.o \
         mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \
         notify.o opcodes.o os.o os_os2.o os_unix.o os_win.o \
         pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \
         random.o resolve.o rowset.o rtree.o select.o status.o \
         table.o tokenize.o trigger.o \
         update.o util.o vacuum.o \
         vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbetrace.o \
         wal.o walker.o where.o utf.o vtab.o



# All of the source code files.
#
SRC = \
  $(TOP)/src/alter.c \
................................................................................
  $(TOP)/src/hash.c \
  $(TOP)/src/hash.h \
  $(TOP)/src/hwtime.h \
  $(TOP)/src/insert.c \
  $(TOP)/src/journal.c \
  $(TOP)/src/legacy.c \
  $(TOP)/src/loadext.c \


  $(TOP)/src/main.c \
  $(TOP)/src/malloc.c \
  $(TOP)/src/mem0.c \
  $(TOP)/src/mem1.c \
  $(TOP)/src/mem2.c \
  $(TOP)/src/mem3.c \
  $(TOP)/src/mem5.c \
................................................................................
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbeblob.c \
  $(TOP)/src/vdbemem.c \
  $(TOP)/src/vdbetrace.c \
  $(TOP)/src/vdbeInt.h \
  $(TOP)/src/vtab.c \
  $(TOP)/src/wal.c \
  $(TOP)/src/wal.h \
  $(TOP)/src/walker.c \
  $(TOP)/src/where.c

# Source code for extensions
#
SRC += \
  $(TOP)/ext/fts1/fts1.c \
................................................................................

#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c

TESTSRC2 = \
  $(TOP)/src/attach.c $(TOP)/src/backup.c $(TOP)/src/btree.c                   \
  $(TOP)/src/build.c $(TOP)/src/date.c                                         \
  $(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/wal.c     \
  $(TOP)/src/mem5.c $(TOP)/src/os.c                                            \
  $(TOP)/src/os_os2.c $(TOP)/src/os_unix.c $(TOP)/src/os_win.c                 \
  $(TOP)/src/pager.c $(TOP)/src/pragma.c $(TOP)/src/prepare.c                  \
  $(TOP)/src/printf.c $(TOP)/src/random.c $(TOP)/src/pcache.c                  \
  $(TOP)/src/pcache1.c $(TOP)/src/select.c $(TOP)/src/tokenize.c               \
  $(TOP)/src/utf.c $(TOP)/src/util.c $(TOP)/src/vdbeapi.c $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbe.c $(TOP)/src/vdbemem.c $(TOP)/src/where.c parse.c            \

Changes to src/pager.c.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
....
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
....
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
....
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
....
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
....
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
....
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
....
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
....
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
....
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
....
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
....
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
....
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
....
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "log.h"

/*
******************** NOTES ON THE DESIGN OF THE PAGER ************************
**
** Within this comment block, a page is deemed to have been synced
** automatically as soon as it is written when PRAGMA synchronous=OFF.
** Otherwise, the page is not synced until the xSync method of the VFS
................................................................................
    ** this happens.  One can argue that this doesn't need to be cleared
    ** until the change-counter check fails in PagerSharedLock().
    ** Clearing the page size cache here is being conservative.
    */
    pPager->dbSizeValid = 0;

    if( pagerUseLog(pPager) ){
      sqlite3LogCloseSnapshot(pPager->pLog);
    }else{
      rc = osUnlock(pPager->fd, NO_LOCK);
    }
    if( rc ){
      pPager->errCode = rc;
    }
    IOTRACE(("UNLOCK %p\n", pPager))
................................................................................
  }
  sqlite3BitvecDestroy(pPager->pInJournal);
  pPager->pInJournal = 0;
  pPager->nRec = 0;
  sqlite3PcacheCleanAll(pPager->pPCache);

  if( pagerUseLog(pPager) ){
    rc2 = sqlite3LogWriteLock(pPager->pLog, 0);
    pPager->state = PAGER_SHARED;
  }else if( !pPager->exclusiveMode ){
    rc2 = osUnlock(pPager->fd, SHARED_LOCK);
    pPager->state = PAGER_SHARED;
    pPager->changeCountDone = 0;
  }else if( pPager->state==PAGER_SYNCED ){
    pPager->state = PAGER_EXCLUSIVE;
................................................................................
    assert( pPager->tempFile );
    memset(pPg->pData, 0, pPager->pageSize);
    return SQLITE_OK;
  }

  if( pagerUseLog(pPager) ){
    /* Try to pull the page from the write-ahead log. */
    rc = sqlite3LogRead(pPager->pLog, pgno, &isInLog, pPg->pData);
  }
  if( rc==SQLITE_OK && !isInLog ){
    iOffset = (pgno-1)*(i64)pPager->pageSize;
    rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
    if( rc==SQLITE_IOERR_SHORT_READ ){
      rc = SQLITE_OK;
    }
................................................................................
  ** updated as data is copied out of the rollback journal and into the
  ** database. This is not generally possible with a WAL database, as
  ** rollback involves simply truncating the log file. Therefore, if one
  ** or more frames have already been written to the log (and therefore 
  ** also copied into the backup databases) as part of this transaction,
  ** the backups must be restarted.
  */
  if( sqlite3LogDirty(pPager->pLog) ){
    sqlite3BackupRestart(pPager->pBackup);
  }

  /* For all pages in the cache that are currently dirty or have already
  ** been written (but not committed) to the log file, do one of the 
  ** following:
  **
  **   + Discard the cached page (if refcount==0), or
  **   + Reload page content from the database (if refcount>0).
  */
  pPager->dbSize = pPager->dbOrigSize;
  rc = sqlite3LogUndo(pPager->pLog, pagerUndoCallback, (void *)pPager);
  pList = sqlite3PcacheDirtyList(pPager->pPCache);
  while( pList && rc==SQLITE_OK ){
    PgHdr *pNext = pList->pDirty;
    rc = pagerUndoCallback((void *)pPager, pList->pgno);
    pList = pNext;
  }

................................................................................
  if( pPager->dbSizeValid ){
    nPage = pPager->dbSize;
  }else{
    int rc;                 /* Error returned by OsFileSize() */
    i64 n = 0;              /* File size in bytes returned by OsFileSize() */

    if( pagerUseLog(pPager) ){
      sqlite3LogDbsize(pPager->pLog, &nPage);
    }

    if( nPage==0 ){
      assert( isOpen(pPager->fd) || pPager->tempFile );
      if( isOpen(pPager->fd) ){
        if( SQLITE_OK!=(rc = sqlite3OsFileSize(pPager->fd, &n)) ){
          pager_error(pPager, rc);
................................................................................
int sqlite3PagerClose(Pager *pPager){
  u8 *pTmp = (u8 *)pPager->pTmpSpace;

  disable_simulated_io_errors();
  sqlite3BeginBenignMalloc();
  pPager->errCode = 0;
  pPager->exclusiveMode = 0;
  sqlite3LogClose(pPager->pLog, pPager->fd, 
    (pPager->noSync ? 0 : pPager->sync_flags), pTmp
  );
  pPager->pLog = 0;
  pager_reset(pPager);
  if( MEMDB ){
    pager_unlock(pPager);
  }else{
................................................................................
    assert( pPager->nSavepoint>0 );
    rc = addToSavepointBitvecs(pPager, pPg->pgno);
  }
  return rc;
}

/*
** This function is a wrapper around sqlite3LogFrames(). As well as logging
** the contents of the list of pages headed by pList (connected by pDirty),
** this function notifies any active backup processes that the pages have
** changed. 
*/ 
static int pagerLogFrames(
  Pager *pPager,                  /* Pager object */
  PgHdr *pList,                   /* List of frames to log */
................................................................................
  Pgno nTruncate,                 /* Database size after this commit */
  int isCommit,                   /* True if this is a commit */
  int sync_flags                  /* Flags to pass to OsSync() (or 0) */
){
  int rc;                         /* Return code */

  assert( pPager->pLog );
  rc = sqlite3LogFrames(pPager->pLog, 
      pPager->pageSize, pList, nTruncate, isCommit, sync_flags
  );
  if( rc==SQLITE_OK && pPager->pBackup ){
    PgHdr *p;
    for(p=pList; p; p=p->pDirty){
      sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
    }
................................................................................

static int pagerOpenSnapshot(Pager *pPager){
  int rc;                         /* Return code */
  int changed = 0;                /* True if cache must be reset */

  assert( pagerUseLog(pPager) );

  rc = sqlite3LogOpenSnapshot(pPager->pLog, &changed);
  if( rc==SQLITE_OK ){
    int dummy;
    if( changed ){
      pager_reset(pPager);
      assert( pPager->errCode || pPager->dbSizeValid==0 );
    }
    rc = sqlite3PagerPagecount(pPager, &dummy);
................................................................................

    if( pagerUseLog(pPager) ){
      /* Grab the write lock on the log file. If successful, upgrade to
      ** PAGER_EXCLUSIVE state. Otherwise, return an error code to the caller.
      ** The busy-handler is not invoked if another connection already
      ** holds the write-lock. If possible, the upper layer will call it.
      */
      rc = sqlite3LogWriteLock(pPager->pLog, 1);
      if( rc==SQLITE_OK ){
        pPager->dbOrigSize = pPager->dbSize;
        pPager->state = PAGER_RESERVED;
        pPager->journalOff = 0;
      }
    }else{
      /* Obtain a RESERVED lock on the database file. If the exFlag parameter
................................................................................
/*
** This function is called when the user invokes "PRAGMA checkpoint".
*/
int sqlite3PagerCheckpoint(Pager *pPager){
  int rc = SQLITE_OK;
  if( pPager->pLog ){
    u8 *zBuf = (u8 *)pPager->pTmpSpace;
    rc = sqlite3LogCheckpoint(pPager->pLog, pPager->fd, 
        (pPager->noSync ? 0 : pPager->sync_flags),
        zBuf, pPager->xBusyHandler, pPager->pBusyHandlerArg
    );
  }
  return rc;
}

int sqlite3PagerLogCallback(Pager *pPager){
  return sqlite3LogCallback(pPager->pLog);
}

/*
** Open a connection to the write-ahead log file for pager pPager. If
** the log connection is already open, this function is a no-op.
**
** The caller must be holding a SHARED lock on the database file to call
................................................................................
  assert( pPager->state>=PAGER_SHARED );
  if( !pPager->pLog ){

    /* Open the connection to the log file. If this operation fails, 
    ** (e.g. due to malloc() failure), unlock the database file and 
    ** return an error code.
    */
    rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
    if( rc==SQLITE_OK ){
      pPager->journalMode = PAGER_JOURNALMODE_WAL;
    }
  }else{
    *pisOpen = 1;
  }

................................................................................
  if( !pPager->pLog ){
    int logexists = 0;
    rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_SHARED);
    if( rc==SQLITE_OK ){
      rc = pagerHasWAL(pPager, &logexists);
    }
    if( rc==SQLITE_OK && logexists ){
      rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
    }
  }
    
  /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
  ** the database file, the log and log-summary files will be deleted.
  */
  if( rc==SQLITE_OK && pPager->pLog ){
    rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_EXCLUSIVE);
    if( rc==SQLITE_OK ){
      rc = sqlite3LogClose(pPager->pLog, pPager->fd,
        (pPager->noSync ? 0 : pPager->sync_flags), 
        (u8*)pPager->pTmpSpace
      );
      pPager->pLog = 0;
    }
  }
  return rc;
}

#endif /* SQLITE_OMIT_DISKIO */







|







 







|







 







|







 







|







 







|











|







 







|







 







|







 







|







 







|







 







|







 







|







 







|








|







 







|







 







|









|










16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
....
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
....
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
....
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
....
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
....
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
....
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
....
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
....
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
....
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
....
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
....
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
....
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
....
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "wal.h"

/*
******************** NOTES ON THE DESIGN OF THE PAGER ************************
**
** Within this comment block, a page is deemed to have been synced
** automatically as soon as it is written when PRAGMA synchronous=OFF.
** Otherwise, the page is not synced until the xSync method of the VFS
................................................................................
    ** this happens.  One can argue that this doesn't need to be cleared
    ** until the change-counter check fails in PagerSharedLock().
    ** Clearing the page size cache here is being conservative.
    */
    pPager->dbSizeValid = 0;

    if( pagerUseLog(pPager) ){
      sqlite3WalCloseSnapshot(pPager->pLog);
    }else{
      rc = osUnlock(pPager->fd, NO_LOCK);
    }
    if( rc ){
      pPager->errCode = rc;
    }
    IOTRACE(("UNLOCK %p\n", pPager))
................................................................................
  }
  sqlite3BitvecDestroy(pPager->pInJournal);
  pPager->pInJournal = 0;
  pPager->nRec = 0;
  sqlite3PcacheCleanAll(pPager->pPCache);

  if( pagerUseLog(pPager) ){
    rc2 = sqlite3WalWriteLock(pPager->pLog, 0);
    pPager->state = PAGER_SHARED;
  }else if( !pPager->exclusiveMode ){
    rc2 = osUnlock(pPager->fd, SHARED_LOCK);
    pPager->state = PAGER_SHARED;
    pPager->changeCountDone = 0;
  }else if( pPager->state==PAGER_SYNCED ){
    pPager->state = PAGER_EXCLUSIVE;
................................................................................
    assert( pPager->tempFile );
    memset(pPg->pData, 0, pPager->pageSize);
    return SQLITE_OK;
  }

  if( pagerUseLog(pPager) ){
    /* Try to pull the page from the write-ahead log. */
    rc = sqlite3WalRead(pPager->pLog, pgno, &isInLog, pPg->pData);
  }
  if( rc==SQLITE_OK && !isInLog ){
    iOffset = (pgno-1)*(i64)pPager->pageSize;
    rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
    if( rc==SQLITE_IOERR_SHORT_READ ){
      rc = SQLITE_OK;
    }
................................................................................
  ** updated as data is copied out of the rollback journal and into the
  ** database. This is not generally possible with a WAL database, as
  ** rollback involves simply truncating the log file. Therefore, if one
  ** or more frames have already been written to the log (and therefore 
  ** also copied into the backup databases) as part of this transaction,
  ** the backups must be restarted.
  */
  if( sqlite3WalDirty(pPager->pLog) ){
    sqlite3BackupRestart(pPager->pBackup);
  }

  /* For all pages in the cache that are currently dirty or have already
  ** been written (but not committed) to the log file, do one of the 
  ** following:
  **
  **   + Discard the cached page (if refcount==0), or
  **   + Reload page content from the database (if refcount>0).
  */
  pPager->dbSize = pPager->dbOrigSize;
  rc = sqlite3WalUndo(pPager->pLog, pagerUndoCallback, (void *)pPager);
  pList = sqlite3PcacheDirtyList(pPager->pPCache);
  while( pList && rc==SQLITE_OK ){
    PgHdr *pNext = pList->pDirty;
    rc = pagerUndoCallback((void *)pPager, pList->pgno);
    pList = pNext;
  }

................................................................................
  if( pPager->dbSizeValid ){
    nPage = pPager->dbSize;
  }else{
    int rc;                 /* Error returned by OsFileSize() */
    i64 n = 0;              /* File size in bytes returned by OsFileSize() */

    if( pagerUseLog(pPager) ){
      sqlite3WalDbsize(pPager->pLog, &nPage);
    }

    if( nPage==0 ){
      assert( isOpen(pPager->fd) || pPager->tempFile );
      if( isOpen(pPager->fd) ){
        if( SQLITE_OK!=(rc = sqlite3OsFileSize(pPager->fd, &n)) ){
          pager_error(pPager, rc);
................................................................................
int sqlite3PagerClose(Pager *pPager){
  u8 *pTmp = (u8 *)pPager->pTmpSpace;

  disable_simulated_io_errors();
  sqlite3BeginBenignMalloc();
  pPager->errCode = 0;
  pPager->exclusiveMode = 0;
  sqlite3WalClose(pPager->pLog, pPager->fd, 
    (pPager->noSync ? 0 : pPager->sync_flags), pTmp
  );
  pPager->pLog = 0;
  pager_reset(pPager);
  if( MEMDB ){
    pager_unlock(pPager);
  }else{
................................................................................
    assert( pPager->nSavepoint>0 );
    rc = addToSavepointBitvecs(pPager, pPg->pgno);
  }
  return rc;
}

/*
** This function is a wrapper around sqlite3WalFrames(). As well as logging
** the contents of the list of pages headed by pList (connected by pDirty),
** this function notifies any active backup processes that the pages have
** changed. 
*/ 
static int pagerLogFrames(
  Pager *pPager,                  /* Pager object */
  PgHdr *pList,                   /* List of frames to log */
................................................................................
  Pgno nTruncate,                 /* Database size after this commit */
  int isCommit,                   /* True if this is a commit */
  int sync_flags                  /* Flags to pass to OsSync() (or 0) */
){
  int rc;                         /* Return code */

  assert( pPager->pLog );
  rc = sqlite3WalFrames(pPager->pLog, 
      pPager->pageSize, pList, nTruncate, isCommit, sync_flags
  );
  if( rc==SQLITE_OK && pPager->pBackup ){
    PgHdr *p;
    for(p=pList; p; p=p->pDirty){
      sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
    }
................................................................................

static int pagerOpenSnapshot(Pager *pPager){
  int rc;                         /* Return code */
  int changed = 0;                /* True if cache must be reset */

  assert( pagerUseLog(pPager) );

  rc = sqlite3WalOpenSnapshot(pPager->pLog, &changed);
  if( rc==SQLITE_OK ){
    int dummy;
    if( changed ){
      pager_reset(pPager);
      assert( pPager->errCode || pPager->dbSizeValid==0 );
    }
    rc = sqlite3PagerPagecount(pPager, &dummy);
................................................................................

    if( pagerUseLog(pPager) ){
      /* Grab the write lock on the log file. If successful, upgrade to
      ** PAGER_EXCLUSIVE state. Otherwise, return an error code to the caller.
      ** The busy-handler is not invoked if another connection already
      ** holds the write-lock. If possible, the upper layer will call it.
      */
      rc = sqlite3WalWriteLock(pPager->pLog, 1);
      if( rc==SQLITE_OK ){
        pPager->dbOrigSize = pPager->dbSize;
        pPager->state = PAGER_RESERVED;
        pPager->journalOff = 0;
      }
    }else{
      /* Obtain a RESERVED lock on the database file. If the exFlag parameter
................................................................................
/*
** This function is called when the user invokes "PRAGMA checkpoint".
*/
int sqlite3PagerCheckpoint(Pager *pPager){
  int rc = SQLITE_OK;
  if( pPager->pLog ){
    u8 *zBuf = (u8 *)pPager->pTmpSpace;
    rc = sqlite3WalCheckpoint(pPager->pLog, pPager->fd, 
        (pPager->noSync ? 0 : pPager->sync_flags),
        zBuf, pPager->xBusyHandler, pPager->pBusyHandlerArg
    );
  }
  return rc;
}

int sqlite3PagerLogCallback(Pager *pPager){
  return sqlite3WalCallback(pPager->pLog);
}

/*
** Open a connection to the write-ahead log file for pager pPager. If
** the log connection is already open, this function is a no-op.
**
** The caller must be holding a SHARED lock on the database file to call
................................................................................
  assert( pPager->state>=PAGER_SHARED );
  if( !pPager->pLog ){

    /* Open the connection to the log file. If this operation fails, 
    ** (e.g. due to malloc() failure), unlock the database file and 
    ** return an error code.
    */
    rc = sqlite3WalOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
    if( rc==SQLITE_OK ){
      pPager->journalMode = PAGER_JOURNALMODE_WAL;
    }
  }else{
    *pisOpen = 1;
  }

................................................................................
  if( !pPager->pLog ){
    int logexists = 0;
    rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_SHARED);
    if( rc==SQLITE_OK ){
      rc = pagerHasWAL(pPager, &logexists);
    }
    if( rc==SQLITE_OK && logexists ){
      rc = sqlite3WalOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
    }
  }
    
  /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
  ** the database file, the log and log-summary files will be deleted.
  */
  if( rc==SQLITE_OK && pPager->pLog ){
    rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_EXCLUSIVE);
    if( rc==SQLITE_OK ){
      rc = sqlite3WalClose(pPager->pLog, pPager->fd,
        (pPager->noSync ? 0 : pPager->sync_flags), 
        (u8*)pPager->pTmpSpace
      );
      pPager->pLog = 0;
    }
  }
  return rc;
}

#endif /* SQLITE_OMIT_DISKIO */

Name change from src/log.c to src/wal.c.

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
....
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
....
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
....
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
....
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
....
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
....
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
....
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
....
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
....
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
** The fields in the log-summary file header are described in the comment 
** directly above the definition of struct LogSummaryHdr (see below). 
** Immediately following the fields in the LogSummaryHdr structure is
** an 8 byte checksum based on the contents of the header. This field is
** not the same as the iCheck1 and iCheck2 fields of the LogSummaryHdr.
*/

#include "log.h"

#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

typedef struct LogSummaryHdr LogSummaryHdr;
typedef struct LogSummary LogSummary;
................................................................................
**
** A SHARED lock should be held on the database file when this function
** is called. The purpose of this SHARED lock is to prevent any other
** client from unlinking the log or log-summary file. If another process
** were to do this just after this client opened one of these files, the
** system would be badly broken.
*/
int sqlite3LogOpen(
  sqlite3_vfs *pVfs,              /* vfs module to open log file with */
  const char *zDb,                /* Name of database file */
  Log **ppLog                     /* OUT: Allocated Log handle */
){
  int rc = SQLITE_OK;             /* Return Code */
  Log *pRet;                      /* Object to allocate and return */
  LogSummary *pSummary = 0;       /* Summary object */
................................................................................
  logIteratorFree(pIter);
  return rc;
}

/*
** Close a connection to a log file.
*/
int sqlite3LogClose(
  Log *pLog,                      /* Log to close */
  sqlite3_file *pFd,              /* Database file */
  int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
  u8 *zBuf                        /* Buffer of at least page-size bytes */
){
  int rc = SQLITE_OK;
  if( pLog ){
................................................................................
**
** If this call obtains a new read-lock and the database contents have been
** modified since the most recent call to LogCloseSnapshot() on this Log
** connection, then *pChanged is set to 1 before returning. Otherwise, it 
** is left unmodified. This is used by the pager layer to determine whether 
** or not any cached pages may be safely reused.
*/
int sqlite3LogOpenSnapshot(Log *pLog, int *pChanged){
  int rc = SQLITE_OK;
  if( pLog->isLocked==0 ){
    int nAttempt;

    /* Obtain a snapshot-lock on the log-summary file. The procedure
    ** for obtaining the snapshot log is:
    **
................................................................................
    if( rc!=SQLITE_OK ){
      return rc;
    }

    rc = logSummaryReadHdr(pLog, pChanged);
    if( rc!=SQLITE_OK ){
      /* An error occured while attempting log recovery. */
      sqlite3LogCloseSnapshot(pLog);
    }
  }
  return rc;
}

/*
** Unlock the current snapshot.
*/
void sqlite3LogCloseSnapshot(Log *pLog){
  if( pLog->isLocked ){
    assert( pLog->isLocked==LOG_REGION_A || pLog->isLocked==LOG_REGION_D );
    logLockRegion(pLog, pLog->isLocked, LOG_UNLOCK);
  }
  pLog->isLocked = 0;
}

/* 
** Read a page from the log, if it is present. 
*/
int sqlite3LogRead(Log *pLog, Pgno pgno, int *pInLog, u8 *pOut){
  u32 iRead = 0;
  u32 *aData = pLog->pSummary->aData;
  int iFrame = (pLog->hdr.iLastPg & 0xFFFFFF00);

  assert( pLog->isLocked );

  /* Do a linear search of the unindexed block of page-numbers (if any) 
................................................................................
  return SQLITE_OK;
}


/* 
** Set *pPgno to the size of the database file (or zero, if unknown).
*/
void sqlite3LogDbsize(Log *pLog, Pgno *pPgno){
  assert( pLog->isLocked );
  *pPgno = pLog->hdr.nPage;
}

/* 
** This function returns SQLITE_OK if the caller may write to the database.
** Otherwise, if the caller is operating on a snapshot that has already
** been overwritten by another writer, SQLITE_BUSY is returned.
*/
int sqlite3LogWriteLock(Log *pLog, int op){
  assert( pLog->isLocked );
  if( op ){

    /* Obtain the writer lock */
    int rc = logLockRegion(pLog, LOG_REGION_C|LOG_REGION_D, LOG_WRLOCK);
    if( rc!=SQLITE_OK ){
      return rc;
................................................................................
** to the log since the start of the transaction. If the callback returns
** other than SQLITE_OK, it is not invoked again and the error code is
** returned to the caller.
**
** Otherwise, if the callback function does not return an error, this
** function returns SQLITE_OK.
*/
int sqlite3LogUndo(Log *pLog, int (*xUndo)(void *, Pgno), void *pUndoCtx){
  int rc = SQLITE_OK;
  Pgno iMax = pLog->hdr.iLastPg;
  Pgno iFrame;

  assert( pLog->isWriteLocked );
  logSummaryReadHdr(pLog, 0);
  for(iFrame=pLog->hdr.iLastPg+1; iFrame<=iMax && rc==SQLITE_OK; iFrame++){
................................................................................
  }
  return rc;
}

/* 
** Return true if data has been written but not committed to the log file. 
*/
int sqlite3LogDirty(Log *pLog){
  assert( pLog->isWriteLocked );
  return( pLog->hdr.iLastPg!=((LogSummaryHdr*)pLog->pSummary->aData)->iLastPg );
}

/* 
** Write a set of frames to the log. The caller must hold at least a
** RESERVED lock on the database file.
*/
int sqlite3LogFrames(
  Log *pLog,                      /* Log handle to write to */
  int nPgsz,                      /* Database page-size in bytes */
  PgHdr *pList,                   /* List of dirty pages to write */
  Pgno nTruncate,                 /* Database size after this commit */
  int isCommit,                   /* True if this is a commit */
  int sync_flags                  /* Flags to pass to OsSync() (or 0) */
){
................................................................................
**
**   1. Wait for an EXCLUSIVE lock on regions B and C.
**   2. Wait for an EXCLUSIVE lock on region A.
**   3. Copy the contents of the log into the database file.
**   4. Zero the log-summary header (so new readers will ignore the log).
**   5. Drop the locks obtained in steps 1 and 2.
*/
int sqlite3LogCheckpoint(
  Log *pLog,                      /* Log connection */
  sqlite3_file *pFd,              /* File descriptor open on db file */
  int sync_flags,                 /* Flags to sync db file with (or 0) */
  u8 *zBuf,                       /* Temporary buffer to use */
  int (*xBusyHandler)(void *),    /* Pointer to busy-handler function */
  void *pBusyHandlerArg           /* Argument to pass to xBusyHandler */
){
................................................................................
  }

  /* Release the locks. */
  logLockRegion(pLog, LOG_REGION_A|LOG_REGION_B|LOG_REGION_C, LOG_UNLOCK);
  return rc;
}

int sqlite3LogCallback(Log *pLog){
  u32 ret = 0;
  if( pLog ){
    ret = pLog->iCallback;
    pLog->iCallback = 0;
  }
  return (int)ret;
}








|







 







|







 







|







 







|







 







|








|










|







 







|









|







 







|







 







|








|







 







|







 







|







<
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
....
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
....
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
....
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
....
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
....
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
....
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
....
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
....
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
....
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849

** The fields in the log-summary file header are described in the comment 
** directly above the definition of struct LogSummaryHdr (see below). 
** Immediately following the fields in the LogSummaryHdr structure is
** an 8 byte checksum based on the contents of the header. This field is
** not the same as the iCheck1 and iCheck2 fields of the LogSummaryHdr.
*/

#include "wal.h"

#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

typedef struct LogSummaryHdr LogSummaryHdr;
typedef struct LogSummary LogSummary;
................................................................................
**
** A SHARED lock should be held on the database file when this function
** is called. The purpose of this SHARED lock is to prevent any other
** client from unlinking the log or log-summary file. If another process
** were to do this just after this client opened one of these files, the
** system would be badly broken.
*/
int sqlite3WalOpen(
  sqlite3_vfs *pVfs,              /* vfs module to open log file with */
  const char *zDb,                /* Name of database file */
  Log **ppLog                     /* OUT: Allocated Log handle */
){
  int rc = SQLITE_OK;             /* Return Code */
  Log *pRet;                      /* Object to allocate and return */
  LogSummary *pSummary = 0;       /* Summary object */
................................................................................
  logIteratorFree(pIter);
  return rc;
}

/*
** Close a connection to a log file.
*/
int sqlite3WalClose(
  Log *pLog,                      /* Log to close */
  sqlite3_file *pFd,              /* Database file */
  int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
  u8 *zBuf                        /* Buffer of at least page-size bytes */
){
  int rc = SQLITE_OK;
  if( pLog ){
................................................................................
**
** If this call obtains a new read-lock and the database contents have been
** modified since the most recent call to LogCloseSnapshot() on this Log
** connection, then *pChanged is set to 1 before returning. Otherwise, it 
** is left unmodified. This is used by the pager layer to determine whether 
** or not any cached pages may be safely reused.
*/
int sqlite3WalOpenSnapshot(Log *pLog, int *pChanged){
  int rc = SQLITE_OK;
  if( pLog->isLocked==0 ){
    int nAttempt;

    /* Obtain a snapshot-lock on the log-summary file. The procedure
    ** for obtaining the snapshot log is:
    **
................................................................................
    if( rc!=SQLITE_OK ){
      return rc;
    }

    rc = logSummaryReadHdr(pLog, pChanged);
    if( rc!=SQLITE_OK ){
      /* An error occured while attempting log recovery. */
      sqlite3WalCloseSnapshot(pLog);
    }
  }
  return rc;
}

/*
** Unlock the current snapshot.
*/
void sqlite3WalCloseSnapshot(Log *pLog){
  if( pLog->isLocked ){
    assert( pLog->isLocked==LOG_REGION_A || pLog->isLocked==LOG_REGION_D );
    logLockRegion(pLog, pLog->isLocked, LOG_UNLOCK);
  }
  pLog->isLocked = 0;
}

/* 
** Read a page from the log, if it is present. 
*/
int sqlite3WalRead(Log *pLog, Pgno pgno, int *pInLog, u8 *pOut){
  u32 iRead = 0;
  u32 *aData = pLog->pSummary->aData;
  int iFrame = (pLog->hdr.iLastPg & 0xFFFFFF00);

  assert( pLog->isLocked );

  /* Do a linear search of the unindexed block of page-numbers (if any) 
................................................................................
  return SQLITE_OK;
}


/* 
** Set *pPgno to the size of the database file (or zero, if unknown).
*/
void sqlite3WalDbsize(Log *pLog, Pgno *pPgno){
  assert( pLog->isLocked );
  *pPgno = pLog->hdr.nPage;
}

/* 
** This function returns SQLITE_OK if the caller may write to the database.
** Otherwise, if the caller is operating on a snapshot that has already
** been overwritten by another writer, SQLITE_BUSY is returned.
*/
int sqlite3WalWriteLock(Log *pLog, int op){
  assert( pLog->isLocked );
  if( op ){

    /* Obtain the writer lock */
    int rc = logLockRegion(pLog, LOG_REGION_C|LOG_REGION_D, LOG_WRLOCK);
    if( rc!=SQLITE_OK ){
      return rc;
................................................................................
** to the log since the start of the transaction. If the callback returns
** other than SQLITE_OK, it is not invoked again and the error code is
** returned to the caller.
**
** Otherwise, if the callback function does not return an error, this
** function returns SQLITE_OK.
*/
int sqlite3WalUndo(Log *pLog, int (*xUndo)(void *, Pgno), void *pUndoCtx){
  int rc = SQLITE_OK;
  Pgno iMax = pLog->hdr.iLastPg;
  Pgno iFrame;

  assert( pLog->isWriteLocked );
  logSummaryReadHdr(pLog, 0);
  for(iFrame=pLog->hdr.iLastPg+1; iFrame<=iMax && rc==SQLITE_OK; iFrame++){
................................................................................
  }
  return rc;
}

/* 
** Return true if data has been written but not committed to the log file. 
*/
int sqlite3WalDirty(Log *pLog){
  assert( pLog->isWriteLocked );
  return( pLog->hdr.iLastPg!=((LogSummaryHdr*)pLog->pSummary->aData)->iLastPg );
}

/* 
** Write a set of frames to the log. The caller must hold at least a
** RESERVED lock on the database file.
*/
int sqlite3WalFrames(
  Log *pLog,                      /* Log handle to write to */
  int nPgsz,                      /* Database page-size in bytes */
  PgHdr *pList,                   /* List of dirty pages to write */
  Pgno nTruncate,                 /* Database size after this commit */
  int isCommit,                   /* True if this is a commit */
  int sync_flags                  /* Flags to pass to OsSync() (or 0) */
){
................................................................................
**
**   1. Wait for an EXCLUSIVE lock on regions B and C.
**   2. Wait for an EXCLUSIVE lock on region A.
**   3. Copy the contents of the log into the database file.
**   4. Zero the log-summary header (so new readers will ignore the log).
**   5. Drop the locks obtained in steps 1 and 2.
*/
int sqlite3WalCheckpoint(
  Log *pLog,                      /* Log connection */
  sqlite3_file *pFd,              /* File descriptor open on db file */
  int sync_flags,                 /* Flags to sync db file with (or 0) */
  u8 *zBuf,                       /* Temporary buffer to use */
  int (*xBusyHandler)(void *),    /* Pointer to busy-handler function */
  void *pBusyHandlerArg           /* Argument to pass to xBusyHandler */
){
................................................................................
  }

  /* Release the locks. */
  logLockRegion(pLog, LOG_REGION_A|LOG_REGION_B|LOG_REGION_C, LOG_UNLOCK);
  return rc;
}

int sqlite3WalCallback(Log *pLog){
  u32 ret = 0;
  if( pLog ){
    ret = pLog->iCallback;
    pLog->iCallback = 0;
  }
  return (int)ret;
}

Name change from src/log.h to src/wal.h.

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
**
*************************************************************************
** This header file defines the interface to the write-ahead logging 
** system. Refer to the comments below and the header comment attached to 
** the implementation of each function in log.c for further details.
*/

#ifndef _LOG_H_
#define _LOG_H_

#include "sqliteInt.h"

/* Connection to a log file. There is one object of this type for each pager. */
typedef struct Log Log;

/* Open and close a connection to a log file. */
int sqlite3LogOpen(sqlite3_vfs*, const char *zDb, Log **ppLog);
int sqlite3LogClose(Log *pLog, sqlite3_file *pFd, int sync_flags, u8 *zBuf);

/* Used by readers to open (lock) and close (unlock) a snapshot. */
int sqlite3LogOpenSnapshot(Log *pLog, int *);
void sqlite3LogCloseSnapshot(Log *pLog);

/* Read a page from the log, if it is present. */
int sqlite3LogRead(Log *pLog, Pgno pgno, int *pInLog, u8 *pOut);
void sqlite3LogDbsize(Log *pLog, Pgno *pPgno);

/* Obtain or release the WRITER lock. */
int sqlite3LogWriteLock(Log *pLog, int op);

/* Undo any frames written (but not committed) to the log */
int sqlite3LogUndo(Log *pLog, int (*xUndo)(void *, Pgno), void *pUndoCtx);

/* Return true if data has been written but not committed to the log file. */
int sqlite3LogDirty(Log *pLog);

/* Write a frame or frames to the log. */
int sqlite3LogFrames(Log *pLog, int, PgHdr *, Pgno, int, int);

/* Copy pages from the log to the database file */ 
int sqlite3LogCheckpoint(
  Log *pLog,                      /* Log connection */
  sqlite3_file *pFd,              /* File descriptor open on db file */
  int sync_flags,                 /* Flags to sync db file with (or 0) */
  u8 *zBuf,                       /* Temporary buffer to use */
  int (*xBusyHandler)(void *),    /* Pointer to busy-handler function */
  void *pBusyHandlerArg           /* Argument to pass to xBusyHandler */
);

/* Return the value to pass to a log callback. Or 0 for no callback. */
int sqlite3LogCallback(Log *pLog);

#endif /* _LOG_H_ */







|
|







|
|


|
|


|
|


|


|


|


|


|









|

|
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
**
*************************************************************************
** This header file defines the interface to the write-ahead logging 
** system. Refer to the comments below and the header comment attached to 
** the implementation of each function in log.c for further details.
*/

#ifndef _WAL_H_
#define _WAL_H_

#include "sqliteInt.h"

/* Connection to a log file. There is one object of this type for each pager. */
typedef struct Log Log;

/* Open and close a connection to a log file. */
int sqlite3WalOpen(sqlite3_vfs*, const char *zDb, Log **ppLog);
int sqlite3WalClose(Log *pLog, sqlite3_file *pFd, int sync_flags, u8 *zBuf);

/* Used by readers to open (lock) and close (unlock) a snapshot. */
int sqlite3WalOpenSnapshot(Log *pLog, int *);
void sqlite3WalCloseSnapshot(Log *pLog);

/* Read a page from the log, if it is present. */
int sqlite3WalRead(Log *pLog, Pgno pgno, int *pInLog, u8 *pOut);
void sqlite3WalDbsize(Log *pLog, Pgno *pPgno);

/* Obtain or release the WRITER lock. */
int sqlite3WalWriteLock(Log *pLog, int op);

/* Undo any frames written (but not committed) to the log */
int sqlite3WalUndo(Log *pLog, int (*xUndo)(void *, Pgno), void *pUndoCtx);

/* Return true if data has been written but not committed to the log file. */
int sqlite3WalDirty(Log *pLog);

/* Write a frame or frames to the log. */
int sqlite3WalFrames(Log *pLog, int, PgHdr *, Pgno, int, int);

/* Copy pages from the log to the database file */ 
int sqlite3WalCheckpoint(
  Log *pLog,                      /* Log connection */
  sqlite3_file *pFd,              /* File descriptor open on db file */
  int sync_flags,                 /* Flags to sync db file with (or 0) */
  u8 *zBuf,                       /* Temporary buffer to use */
  int (*xBusyHandler)(void *),    /* Pointer to busy-handler function */
  void *pBusyHandlerArg           /* Argument to pass to xBusyHandler */
);

/* Return the value to pass to a log callback. Or 0 for no callback. */
int sqlite3WalCallback(Log *pLog);

#endif /* _WAL_H_ */

Changes to tool/mksqlite3c.tcl.

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
106
107
108
109
110
111
112

113
114
115
116
117
118
119
...
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
   fts3.h
   fts3Int.h
   fts3_hash.h
   fts3_tokenizer.h
   hash.h
   hwtime.h
   keywordhash.h
   log.h
   mutex.h
   opcodes.h
   os_common.h
   os.h
   os_os2.h
   pager.h
   parse.h
................................................................................
   sqlite3ext.h
   sqlite3.h
   sqliteicu.h
   sqliteInt.h
   sqliteLimit.h
   vdbe.h
   vdbeInt.h

} {
  set available_hdr($hdr) 1
}
set available_hdr(sqliteInt.h) 0

# 78 stars used for comment formatting.
set s78 \
................................................................................
   os_unix.c
   os_win.c

   bitvec.c
   pcache.c
   pcache1.c
   rowset.c
   log.c
   pager.c

   btmutex.c
   btree.c
   backup.c

   vdbemem.c







<







 







>







 







|







89
90
91
92
93
94
95

96
97
98
99
100
101
102
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
   fts3.h
   fts3Int.h
   fts3_hash.h
   fts3_tokenizer.h
   hash.h
   hwtime.h
   keywordhash.h

   mutex.h
   opcodes.h
   os_common.h
   os.h
   os_os2.h
   pager.h
   parse.h
................................................................................
   sqlite3ext.h
   sqlite3.h
   sqliteicu.h
   sqliteInt.h
   sqliteLimit.h
   vdbe.h
   vdbeInt.h
   wal.h
} {
  set available_hdr($hdr) 1
}
set available_hdr(sqliteInt.h) 0

# 78 stars used for comment formatting.
set s78 \
................................................................................
   os_unix.c
   os_win.c

   bitvec.c
   pcache.c
   pcache1.c
   rowset.c
   wal.c
   pager.c

   btmutex.c
   btree.c
   backup.c

   vdbemem.c