🌐 AI搜索 & 代理 主页
blob: 071521001fa3e7d861ca1f28fc414e3a48f03910 [file] [log] [blame]
dan7c246102010-04-12 19:00:291/*
drh7ed91f22010-04-29 22:34:072** 2010 February 1
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11*************************************************************************
12**
13** This file contains the implementation of a write-ahead log file used in
dan7c246102010-04-12 19:00:2914** "journal_mode=wal" mode.
15*/
dan5cf53532010-05-01 16:40:2016#ifndef SQLITE_OMIT_WAL
17
drh7ed91f22010-04-29 22:34:0718#include "wal.h"
dan7c246102010-04-12 19:00:2919
dan4b64c1e2010-04-27 18:49:5420
dan97a31352010-04-16 13:59:3121/*
drh7ed91f22010-04-29 22:34:0722** WRITE-AHEAD LOG (WAL) FILE FORMAT
dan97a31352010-04-16 13:59:3123**
drh7ed91f22010-04-29 22:34:0724** A wal file consists of a header followed by zero or more "frames".
25** The header is 12 bytes in size and consists of the following three
dan97a31352010-04-16 13:59:3126** big-endian 32-bit unsigned integer values:
27**
dan3de777f2010-04-17 12:31:3728** 0: Database page size,
29** 4: Randomly selected salt value 1,
30** 8: Randomly selected salt value 2.
dan97a31352010-04-16 13:59:3131**
drh7ed91f22010-04-29 22:34:0732** Immediately following the header are zero or more frames. Each
dan97a31352010-04-16 13:59:3133** frame itself consists of a 16-byte header followed by a <page-size> bytes
34** of page data. The header is broken into 4 big-endian 32-bit unsigned
35** integer values, as follows:
36**
dan3de777f2010-04-17 12:31:3737** 0: Page number.
38** 4: For commit records, the size of the database image in pages
dan97a31352010-04-16 13:59:3139** after the commit. For all other records, zero.
dan3de777f2010-04-17 12:31:3740** 8: Checksum value 1.
dan97a31352010-04-16 13:59:3141** 12: Checksum value 2.
42*/
43
44/*
drh7ed91f22010-04-29 22:34:0745** WAL-INDEX FILE FORMAT
dan97a31352010-04-16 13:59:3146**
drh7ed91f22010-04-29 22:34:0747** The wal-index file consists of a 32-byte header region, followed by an
48** 8-byte region that contains no useful data (used to apply byte-range locks
danff207012010-04-24 04:49:1549** to), followed by the data region.
50**
51** The contents of both the header and data region are specified in terms
52** of 1, 2 and 4 byte unsigned integers. All integers are stored in
drh7ed91f22010-04-29 22:34:0753** machine-endian order. The wal-index is not a persistent file and
54** so it does not need to be portable across archtectures.
danff207012010-04-24 04:49:1555**
drh7ed91f22010-04-29 22:34:0756** A wal-index file is essentially a shadow-pager map. It contains a
57** mapping from database page number to the set of locations in the wal
danff207012010-04-24 04:49:1558** file that contain versions of the database page. When a database
drh7ed91f22010-04-29 22:34:0759** client needs to read a page of data, it first queries the wal-index
danff207012010-04-24 04:49:1560** file to determine if the required version of the page is stored in
drh7ed91f22010-04-29 22:34:0761** the wal. If so, the page is read from the wal. If not, the page is
62** read from the database file.
danff207012010-04-24 04:49:1563**
drh7ed91f22010-04-29 22:34:0764** Whenever a transaction is appended to the wal or a checkpoint transfers
65** data from the wal into the database file, the wal-index is
danff207012010-04-24 04:49:1566** updated accordingly.
67**
drh7ed91f22010-04-29 22:34:0768** The fields in the wal-index file header are described in the comment
69** directly above the definition of struct WalIndexHdr (see below).
70** Immediately following the fields in the WalIndexHdr structure is
danff207012010-04-24 04:49:1571** an 8 byte checksum based on the contents of the header. This field is
drh7ed91f22010-04-29 22:34:0772** not the same as the iCheck1 and iCheck2 fields of the WalIndexHdr.
dan97a31352010-04-16 13:59:3173*/
74
drh7ed91f22010-04-29 22:34:0775/* Object declarations */
76typedef struct WalIndexHdr WalIndexHdr;
77typedef struct WalIterator WalIterator;
dan7c246102010-04-12 19:00:2978
79
80/*
drh7ed91f22010-04-29 22:34:0781** The following object stores a copy of the wal-index header.
dan7c246102010-04-12 19:00:2982**
83** Member variables iCheck1 and iCheck2 contain the checksum for the
drh7ed91f22010-04-29 22:34:0784** last frame written to the wal, or 2 and 3 respectively if the log
dan7c246102010-04-12 19:00:2985** is currently empty.
86*/
drh7ed91f22010-04-29 22:34:0787struct WalIndexHdr {
dan7c246102010-04-12 19:00:2988 u32 iChange; /* Counter incremented each transaction */
89 u32 pgsz; /* Database page size in bytes */
90 u32 iLastPg; /* Address of last valid frame in log */
91 u32 nPage; /* Size of database in pages */
92 u32 iCheck1; /* Checkpoint value 1 */
93 u32 iCheck2; /* Checkpoint value 2 */
94};
95
drh7ed91f22010-04-29 22:34:0796/* Size of serialized WalIndexHdr object. */
97#define WALINDEX_HDR_NFIELD (sizeof(WalIndexHdr) / sizeof(u32))
dan7c246102010-04-12 19:00:2998
drh7ed91f22010-04-29 22:34:0799/* A block of 16 bytes beginning at WALINDEX_LOCK_OFFSET is reserved
danff207012010-04-24 04:49:15100** for locks. Since some systems only feature mandatory file-locks, we
101** do not read or write data from the region of the file on which locks
102** are applied.
103*/
drh7ed91f22010-04-29 22:34:07104#define WALINDEX_LOCK_OFFSET ((sizeof(WalIndexHdr))+2*sizeof(u32))
105#define WALINDEX_LOCK_RESERVED 8
dan7c246102010-04-12 19:00:29106
drh7ed91f22010-04-29 22:34:07107/* Size of header before each frame in wal */
108#define WAL_FRAME_HDRSIZE 16
danff207012010-04-24 04:49:15109
drh7ed91f22010-04-29 22:34:07110/* Size of write ahead log header */
111#define WAL_HDRSIZE 12
dan97a31352010-04-16 13:59:31112
113/*
drh7ed91f22010-04-29 22:34:07114** Return the offset of frame iFrame in the write-ahead log file,
115** assuming a database page size of pgsz bytes. The offset returned
116** is to the start of the write-ahead log frame-header.
dan97a31352010-04-16 13:59:31117*/
drh7ed91f22010-04-29 22:34:07118#define walFrameOffset(iFrame, pgsz) ( \
119 WAL_HDRSIZE + ((iFrame)-1)*((pgsz)+WAL_FRAME_HDRSIZE) \
dan97a31352010-04-16 13:59:31120)
dan7c246102010-04-12 19:00:29121
122/*
drh7ed91f22010-04-29 22:34:07123** An open write-ahead log file is represented by an instance of the
124** following object.
dance4f05f2010-04-22 19:14:13125*/
drh7ed91f22010-04-29 22:34:07126struct Wal {
127 sqlite3_vfs *pVfs; /* The VFS used to create pFd */
128 sqlite3_file *pFd; /* File handle for WAL file */
129 u32 iCallback; /* Value to pass to log callback (or 0) */
130 sqlite3_shm *pWIndex; /* The open wal-index file */
drh5530b762010-04-30 14:39:50131 int szWIndex; /* Size of the wal-index that is mapped in mem */
drh7ed91f22010-04-29 22:34:07132 u32 *pWiData; /* Pointer to wal-index content in memory */
133 u8 lockState; /* SQLITE_SHM_xxxx constant showing lock state */
134 u8 readerType; /* SQLITE_SHM_READ or SQLITE_SHM_READ_FULL */
135 WalIndexHdr hdr; /* Wal-index for current snapshot */
drh2d536e12010-05-01 20:17:30136 char *zName; /* Name of underlying storage */
dan7c246102010-04-12 19:00:29137};
138
dan64d039e2010-04-13 19:27:31139
dan7c246102010-04-12 19:00:29140/*
141** This structure is used to implement an iterator that iterates through
142** all frames in the log in database page order. Where two or more frames
143** correspond to the same database page, the iterator visits only the
144** frame most recently written to the log.
145**
146** The internals of this structure are only accessed by:
147**
drh7ed91f22010-04-29 22:34:07148** walIteratorInit() - Create a new iterator,
149** walIteratorNext() - Step an iterator,
150** walIteratorFree() - Free an iterator.
dan7c246102010-04-12 19:00:29151**
drh7ed91f22010-04-29 22:34:07152** This functionality is used by the checkpoint code (see walCheckpoint()).
dan7c246102010-04-12 19:00:29153*/
drh7ed91f22010-04-29 22:34:07154struct WalIterator {
155 int nSegment; /* Size of WalIterator.aSegment[] array */
dan7c246102010-04-12 19:00:29156 int nFinal; /* Elements in segment nSegment-1 */
drh7ed91f22010-04-29 22:34:07157 struct WalSegment {
dan7c246102010-04-12 19:00:29158 int iNext; /* Next aIndex index */
159 u8 *aIndex; /* Pointer to index array */
160 u32 *aDbPage; /* Pointer to db page array */
161 } aSegment[1];
162};
163
dan64d039e2010-04-13 19:27:31164
dan7c246102010-04-12 19:00:29165/*
166** Generate an 8 byte checksum based on the data in array aByte[] and the
167** initial values of aCksum[0] and aCksum[1]. The checksum is written into
168** aCksum[] before returning.
dan56d95912010-04-24 19:07:29169**
170** The range of bytes to checksum is treated as an array of 32-bit
171** little-endian unsigned integers. For each integer X in the array, from
172** start to finish, do the following:
173**
174** aCksum[0] += X;
175** aCksum[1] += aCksum[0];
176**
177** For the calculation above, use 64-bit unsigned accumulators. Before
178** returning, truncate the values to 32-bits as follows:
179**
180** aCksum[0] = (u32)(aCksum[0] + (aCksum[0]>>24));
181** aCksum[1] = (u32)(aCksum[1] + (aCksum[1]>>24));
dan7c246102010-04-12 19:00:29182*/
drh7ed91f22010-04-29 22:34:07183static void walChecksumBytes(u8 *aByte, int nByte, u32 *aCksum){
dan39c79f52010-04-15 10:58:51184 u64 sum1 = aCksum[0];
185 u64 sum2 = aCksum[1];
186 u32 *a32 = (u32 *)aByte;
187 u32 *aEnd = (u32 *)&aByte[nByte];
dan7c246102010-04-12 19:00:29188
dan7c246102010-04-12 19:00:29189 assert( (nByte&0x00000003)==0 );
190
dance4f05f2010-04-22 19:14:13191 if( SQLITE_LITTLEENDIAN ){
192#ifdef SQLITE_DEBUG
193 u8 *a = (u8 *)a32;
194 assert( *a32==(a[0] + (a[1]<<8) + (a[2]<<16) + (a[3]<<24)) );
195#endif
196 do {
197 sum1 += *a32;
198 sum2 += sum1;
199 } while( ++a32<aEnd );
200 }else{
201 do {
202 u8 *a = (u8*)a32;
203 sum1 += a[0] + (a[1]<<8) + (a[2]<<16) + (a[3]<<24);
204 sum2 += sum1;
205 } while( ++a32<aEnd );
206 }
dan7c246102010-04-12 19:00:29207
dan39c79f52010-04-15 10:58:51208 aCksum[0] = sum1 + (sum1>>24);
209 aCksum[1] = sum2 + (sum2>>24);
dan7c246102010-04-12 19:00:29210}
211
212/*
drh7ed91f22010-04-29 22:34:07213** Attempt to change the lock status.
dan7c246102010-04-12 19:00:29214**
drh7ed91f22010-04-29 22:34:07215** When changing the lock status to SQLITE_SHM_READ, store the
216** type of reader lock (either SQLITE_SHM_READ or SQLITE_SHM_READ_FULL)
217** in pWal->readerType.
dan7c246102010-04-12 19:00:29218*/
drh7ed91f22010-04-29 22:34:07219static int walSetLock(Wal *pWal, int desiredStatus){
220 int rc, got;
221 if( pWal->lockState==desiredStatus ) return SQLITE_OK;
222 rc = pWal->pVfs->xShmLock(pWal->pWIndex, desiredStatus, &got);
drh49156b22010-04-30 16:12:04223 pWal->lockState = got;
224 if( got==SQLITE_SHM_READ_FULL || got==SQLITE_SHM_READ ){
225 pWal->readerType = got;
226 pWal->lockState = SQLITE_SHM_READ;
dan7c246102010-04-12 19:00:29227 }
228 return rc;
229}
230
drh7ed91f22010-04-29 22:34:07231/*
232** Update the header of the wal-index file.
233*/
234static void walIndexWriteHdr(Wal *pWal, WalIndexHdr *pHdr){
235 u32 *aHdr = pWal->pWiData; /* Write header here */
236 u32 *aCksum = &aHdr[WALINDEX_HDR_NFIELD]; /* Write header cksum here */
danff207012010-04-24 04:49:15237
drh7ed91f22010-04-29 22:34:07238 assert( WALINDEX_HDR_NFIELD==sizeof(WalIndexHdr)/4 );
239 assert( aHdr!=0 );
240 memcpy(aHdr, pHdr, sizeof(WalIndexHdr));
danff207012010-04-24 04:49:15241 aCksum[0] = aCksum[1] = 1;
drh7ed91f22010-04-29 22:34:07242 walChecksumBytes((u8 *)aHdr, sizeof(WalIndexHdr), aCksum);
dan7c246102010-04-12 19:00:29243}
244
245/*
246** This function encodes a single frame header and writes it to a buffer
drh7ed91f22010-04-29 22:34:07247** supplied by the caller. A frame-header is made up of a series of
dan7c246102010-04-12 19:00:29248** 4-byte big-endian integers, as follows:
249**
250** 0: Database page size in bytes.
251** 4: Page number.
252** 8: New database size (for commit frames, otherwise zero).
253** 12: Frame checksum 1.
254** 16: Frame checksum 2.
255*/
drh7ed91f22010-04-29 22:34:07256static void walEncodeFrame(
dan7c246102010-04-12 19:00:29257 u32 *aCksum, /* IN/OUT: Checksum values */
258 u32 iPage, /* Database page number for frame */
259 u32 nTruncate, /* New db size (or 0 for non-commit frames) */
260 int nData, /* Database page size (size of aData[]) */
261 u8 *aData, /* Pointer to page data (for checksum) */
262 u8 *aFrame /* OUT: Write encoded frame here */
263){
drh7ed91f22010-04-29 22:34:07264 assert( WAL_FRAME_HDRSIZE==16 );
dan7c246102010-04-12 19:00:29265
dan97a31352010-04-16 13:59:31266 sqlite3Put4byte(&aFrame[0], iPage);
267 sqlite3Put4byte(&aFrame[4], nTruncate);
dan7c246102010-04-12 19:00:29268
drh7ed91f22010-04-29 22:34:07269 walChecksumBytes(aFrame, 8, aCksum);
270 walChecksumBytes(aData, nData, aCksum);
dan7c246102010-04-12 19:00:29271
dan97a31352010-04-16 13:59:31272 sqlite3Put4byte(&aFrame[8], aCksum[0]);
273 sqlite3Put4byte(&aFrame[12], aCksum[1]);
dan7c246102010-04-12 19:00:29274}
275
276/*
277** Return 1 and populate *piPage, *pnTruncate and aCksum if the
278** frame checksum looks Ok. Otherwise return 0.
279*/
drh7ed91f22010-04-29 22:34:07280static int walDecodeFrame(
dan7c246102010-04-12 19:00:29281 u32 *aCksum, /* IN/OUT: Checksum values */
282 u32 *piPage, /* OUT: Database page number for frame */
283 u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
284 int nData, /* Database page size (size of aData[]) */
285 u8 *aData, /* Pointer to page data (for checksum) */
286 u8 *aFrame /* Frame data */
287){
drh7ed91f22010-04-29 22:34:07288 assert( WAL_FRAME_HDRSIZE==16 );
dan4a4b01d2010-04-16 11:30:18289
drh7ed91f22010-04-29 22:34:07290 walChecksumBytes(aFrame, 8, aCksum);
291 walChecksumBytes(aData, nData, aCksum);
dan7c246102010-04-12 19:00:29292
dan97a31352010-04-16 13:59:31293 if( aCksum[0]!=sqlite3Get4byte(&aFrame[8])
294 || aCksum[1]!=sqlite3Get4byte(&aFrame[12])
dan7c246102010-04-12 19:00:29295 ){
296 /* Checksum failed. */
297 return 0;
298 }
299
dan97a31352010-04-16 13:59:31300 *piPage = sqlite3Get4byte(&aFrame[0]);
301 *pnTruncate = sqlite3Get4byte(&aFrame[4]);
dan7c246102010-04-12 19:00:29302 return 1;
303}
304
drh7ed91f22010-04-29 22:34:07305static void walMergesort8(
306 Pgno *aContent, /* Pages in wal */
dan7c246102010-04-12 19:00:29307 u8 *aBuffer, /* Buffer of at least *pnList items to use */
308 u8 *aList, /* IN/OUT: List to sort */
309 int *pnList /* IN/OUT: Number of elements in aList[] */
310){
311 int nList = *pnList;
312 if( nList>1 ){
313 int nLeft = nList / 2; /* Elements in left list */
314 int nRight = nList - nLeft; /* Elements in right list */
315 u8 *aLeft = aList; /* Left list */
316 u8 *aRight = &aList[nLeft]; /* Right list */
317 int iLeft = 0; /* Current index in aLeft */
318 int iRight = 0; /* Current index in aright */
319 int iOut = 0; /* Current index in output buffer */
320
321 /* TODO: Change to non-recursive version. */
drh7ed91f22010-04-29 22:34:07322 walMergesort8(aContent, aBuffer, aLeft, &nLeft);
323 walMergesort8(aContent, aBuffer, aRight, &nRight);
dan7c246102010-04-12 19:00:29324
325 while( iRight<nRight || iLeft<nLeft ){
326 u8 logpage;
327 Pgno dbpage;
328
329 if( (iLeft<nLeft)
330 && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
331 ){
332 logpage = aLeft[iLeft++];
333 }else{
334 logpage = aRight[iRight++];
335 }
336 dbpage = aContent[logpage];
337
338 aBuffer[iOut++] = logpage;
339 if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
340
341 assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
342 assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
343 }
344 memcpy(aList, aBuffer, sizeof(aList[0])*iOut);
345 *pnList = iOut;
346 }
347
348#ifdef SQLITE_DEBUG
349 {
350 int i;
351 for(i=1; i<*pnList; i++){
352 assert( aContent[aList[i]] > aContent[aList[i-1]] );
353 }
354 }
355#endif
356}
357
358
359/*
drh7ed91f22010-04-29 22:34:07360** Return the index in the WalIndex.aData array that corresponds to
361** frame iFrame. The wal-index file consists of a header, followed by
dan7c246102010-04-12 19:00:29362** alternating "map" and "index" blocks.
363*/
drh7ed91f22010-04-29 22:34:07364static int walIndexEntry(u32 iFrame){
danff207012010-04-24 04:49:15365 return (
drh7ed91f22010-04-29 22:34:07366 (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)/sizeof(u32)
danff207012010-04-24 04:49:15367 + (((iFrame-1)>>8)<<6) /* Indexes that occur before iFrame */
368 + iFrame-1 /* Db page numbers that occur before iFrame */
369 );
dan7c246102010-04-12 19:00:29370}
371
drh7ed91f22010-04-29 22:34:07372/*
drh5530b762010-04-30 14:39:50373** Release our reference to the wal-index memory map, if we are holding
374** it.
drh7ed91f22010-04-29 22:34:07375*/
376static void walIndexUnmap(Wal *pWal){
377 if( pWal->pWiData ){
378 pWal->pVfs->xShmRelease(pWal->pWIndex);
379 pWal->pWiData = 0;
380 }
381}
dan7c246102010-04-12 19:00:29382
383/*
drh5530b762010-04-30 14:39:50384** Map the wal-index file into memory if it isn't already.
385**
386** The reqSize parameter is the minimum required size of the mapping.
387** A value of -1 means "don't care". The reqSize parameter is ignored
388** if the mapping is already held.
drh7ed91f22010-04-29 22:34:07389*/
drh5530b762010-04-30 14:39:50390static int walIndexMap(Wal *pWal, int reqSize){
391 int rc = SQLITE_OK;
392 if( pWal->pWiData==0 ){
393 rc = pWal->pVfs->xShmGet(pWal->pWIndex, reqSize, &pWal->szWIndex,
394 (void**)(char*)&pWal->pWiData);
395 if( rc==SQLITE_OK && pWal->pWiData==0 ){
396 /* Make sure pWal->pWiData is not NULL while we are holding the
397 ** lock on the mapping. */
398 assert( pWal->szWIndex==0 );
399 pWal->pWiData = &pWal->iCallback;
400 }
drh79e6c782010-04-30 02:13:26401 }
402 return rc;
403}
404
405/*
drh5530b762010-04-30 14:39:50406** Remap the wal-index so that the mapping covers the full size
407** of the underlying file.
408**
409** If enlargeTo is non-negative, then increase the size of the underlying
410** storage to be at least as big as enlargeTo before remapping.
drh79e6c782010-04-30 02:13:26411*/
drh5530b762010-04-30 14:39:50412static int walIndexRemap(Wal *pWal, int enlargeTo){
413 int rc;
414 int sz;
415 rc = pWal->pVfs->xShmSize(pWal->pWIndex, enlargeTo, &sz);
416 if( rc==SQLITE_OK && sz>pWal->szWIndex ){
417 walIndexUnmap(pWal);
418 rc = walIndexMap(pWal, sz);
419 }
drh7ed91f22010-04-29 22:34:07420 return rc;
421}
422
423/*
424** Increment by which to increase the wal-index file size.
425*/
426#define WALINDEX_MMAP_INCREMENT (64*1024)
427
428/*
429** Set an entry in the wal-index map to map log frame iFrame to db
430** page iPage. Values are always appended to the wal-index (i.e. the
dan7c246102010-04-12 19:00:29431** value of iFrame is always exactly one more than the value passed to
432** the previous call), but that restriction is not enforced or asserted
433** here.
434*/
drh7ed91f22010-04-29 22:34:07435static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
436 u32 iSlot = walIndexEntry(iFrame);
437
drh5530b762010-04-30 14:39:50438 walIndexMap(pWal, -1);
danc9d53db2010-04-30 16:50:00439 while( ((iSlot+128)*sizeof(u32))>=pWal->szWIndex ){
dan31f98fc2010-04-27 05:42:32440 int rc;
danc9d53db2010-04-30 16:50:00441 int nByte = pWal->szWIndex + WALINDEX_MMAP_INCREMENT;
dance4f05f2010-04-22 19:14:13442
drh5530b762010-04-30 14:39:50443 /* Enlarge the storage, then remap it. */
drh7ed91f22010-04-29 22:34:07444 rc = walIndexRemap(pWal, nByte);
dan31f98fc2010-04-27 05:42:32445 if( rc!=SQLITE_OK ){
446 return rc;
447 }
dance4f05f2010-04-22 19:14:13448 }
449
drh7ed91f22010-04-29 22:34:07450 /* Set the wal-index entry itself */
451 pWal->pWiData[iSlot] = iPage;
dan7c246102010-04-12 19:00:29452
453 /* If the frame number is a multiple of 256 (frames are numbered starting
454 ** at 1), build an index of the most recently added 256 frames.
455 */
456 if( (iFrame&0x000000FF)==0 ){
457 int i; /* Iterator used while initializing aIndex */
458 u32 *aFrame; /* Pointer to array of 256 frames */
459 int nIndex; /* Number of entries in index */
460 u8 *aIndex; /* 256 bytes to build index in */
461 u8 *aTmp; /* Scratch space to use while sorting */
462
drh7ed91f22010-04-29 22:34:07463 aFrame = &pWal->pWiData[iSlot-255];
464 aIndex = (u8 *)&pWal->pWiData[iSlot+1];
dan7c246102010-04-12 19:00:29465 aTmp = &aIndex[256];
466
467 nIndex = 256;
468 for(i=0; i<256; i++) aIndex[i] = (u8)i;
drh7ed91f22010-04-29 22:34:07469 walMergesort8(aFrame, aTmp, aIndex, &nIndex);
dan7c246102010-04-12 19:00:29470 memset(&aIndex[nIndex], aIndex[nIndex-1], 256-nIndex);
471 }
dan31f98fc2010-04-27 05:42:32472
473 return SQLITE_OK;
dan7c246102010-04-12 19:00:29474}
475
476
477/*
drh7ed91f22010-04-29 22:34:07478** Recover the wal-index by reading the write-ahead log file.
479** The caller must hold RECOVER lock on the wal-index file.
dan7c246102010-04-12 19:00:29480*/
drh7ed91f22010-04-29 22:34:07481static int walIndexRecover(Wal *pWal){
dan7c246102010-04-12 19:00:29482 int rc; /* Return Code */
483 i64 nSize; /* Size of log file */
drh7ed91f22010-04-29 22:34:07484 WalIndexHdr hdr; /* Recovered wal-index header */
dan7c246102010-04-12 19:00:29485
drh7ed91f22010-04-29 22:34:07486 assert( pWal->lockState==SQLITE_SHM_RECOVER );
dan7c246102010-04-12 19:00:29487 memset(&hdr, 0, sizeof(hdr));
488
drh7ed91f22010-04-29 22:34:07489 rc = sqlite3OsFileSize(pWal->pFd, &nSize);
dan7c246102010-04-12 19:00:29490 if( rc!=SQLITE_OK ){
491 return rc;
492 }
493
drh7ed91f22010-04-29 22:34:07494 if( nSize>WAL_FRAME_HDRSIZE ){
495 u8 aBuf[WAL_FRAME_HDRSIZE]; /* Buffer to load first frame header into */
dan7c246102010-04-12 19:00:29496 u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
497 int nFrame; /* Number of bytes at aFrame */
498 u8 *aData; /* Pointer to data part of aFrame buffer */
499 int iFrame; /* Index of last frame read */
500 i64 iOffset; /* Next offset to read from log file */
501 int nPgsz; /* Page size according to the log */
dan97a31352010-04-16 13:59:31502 u32 aCksum[2]; /* Running checksum */
dan7c246102010-04-12 19:00:29503
504 /* Read in the first frame header in the file (to determine the
505 ** database page size).
506 */
drh7ed91f22010-04-29 22:34:07507 rc = sqlite3OsRead(pWal->pFd, aBuf, WAL_HDRSIZE, 0);
dan7c246102010-04-12 19:00:29508 if( rc!=SQLITE_OK ){
509 return rc;
510 }
511
512 /* If the database page size is not a power of two, or is greater than
513 ** SQLITE_MAX_PAGE_SIZE, conclude that the log file contains no valid data.
514 */
515 nPgsz = sqlite3Get4byte(&aBuf[0]);
dance4f05f2010-04-22 19:14:13516 if( nPgsz&(nPgsz-1) || nPgsz>SQLITE_MAX_PAGE_SIZE || nPgsz<512 ){
dan7c246102010-04-12 19:00:29517 goto finished;
518 }
dan97a31352010-04-16 13:59:31519 aCksum[0] = sqlite3Get4byte(&aBuf[4]);
520 aCksum[1] = sqlite3Get4byte(&aBuf[8]);
dan7c246102010-04-12 19:00:29521
522 /* Malloc a buffer to read frames into. */
drh7ed91f22010-04-29 22:34:07523 nFrame = nPgsz + WAL_FRAME_HDRSIZE;
dan7c246102010-04-12 19:00:29524 aFrame = (u8 *)sqlite3_malloc(nFrame);
525 if( !aFrame ){
526 return SQLITE_NOMEM;
527 }
drh7ed91f22010-04-29 22:34:07528 aData = &aFrame[WAL_FRAME_HDRSIZE];
dan7c246102010-04-12 19:00:29529
530 /* Read all frames from the log file. */
531 iFrame = 0;
drh7ed91f22010-04-29 22:34:07532 for(iOffset=WAL_HDRSIZE; (iOffset+nFrame)<=nSize; iOffset+=nFrame){
dan7c246102010-04-12 19:00:29533 u32 pgno; /* Database page number for frame */
534 u32 nTruncate; /* dbsize field from frame header */
535 int isValid; /* True if this frame is valid */
536
537 /* Read and decode the next log frame. */
drh7ed91f22010-04-29 22:34:07538 rc = sqlite3OsRead(pWal->pFd, aFrame, nFrame, iOffset);
dan7c246102010-04-12 19:00:29539 if( rc!=SQLITE_OK ) break;
drh7ed91f22010-04-29 22:34:07540 isValid = walDecodeFrame(aCksum, &pgno, &nTruncate, nPgsz, aData, aFrame);
dan7c246102010-04-12 19:00:29541 if( !isValid ) break;
drh7ed91f22010-04-29 22:34:07542 walIndexAppend(pWal, ++iFrame, pgno);
dan7c246102010-04-12 19:00:29543
544 /* If nTruncate is non-zero, this is a commit record. */
545 if( nTruncate ){
546 hdr.iCheck1 = aCksum[0];
547 hdr.iCheck2 = aCksum[1];
548 hdr.iLastPg = iFrame;
549 hdr.nPage = nTruncate;
550 hdr.pgsz = nPgsz;
551 }
552 }
553
554 sqlite3_free(aFrame);
555 }else{
556 hdr.iCheck1 = 2;
557 hdr.iCheck2 = 3;
558 }
559
560finished:
drh7ed91f22010-04-29 22:34:07561 walIndexWriteHdr(pWal, &hdr);
dan7c246102010-04-12 19:00:29562 return rc;
563}
564
565/*
566** Open a connection to the log file associated with database zDb. The
567** database file does not actually have to exist. zDb is used only to
568** figure out the name of the log file to open. If the log file does not
569** exist it is created by this call.
dan3de777f2010-04-17 12:31:37570**
571** A SHARED lock should be held on the database file when this function
572** is called. The purpose of this SHARED lock is to prevent any other
drh7ed91f22010-04-29 22:34:07573** client from unlinking the log or wal-index file. If another process
dan3de777f2010-04-17 12:31:37574** were to do this just after this client opened one of these files, the
575** system would be badly broken.
dan7c246102010-04-12 19:00:29576*/
drhc438efd2010-04-26 00:19:45577int sqlite3WalOpen(
drh7ed91f22010-04-29 22:34:07578 sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
dan7c246102010-04-12 19:00:29579 const char *zDb, /* Name of database file */
drh7ed91f22010-04-29 22:34:07580 Wal **ppWal /* OUT: Allocated Wal handle */
dan7c246102010-04-12 19:00:29581){
danb9bf16b2010-04-14 11:23:30582 int rc = SQLITE_OK; /* Return Code */
drh7ed91f22010-04-29 22:34:07583 Wal *pRet; /* Object to allocate and return */
dan7c246102010-04-12 19:00:29584 int flags; /* Flags passed to OsOpen() */
585 char *zWal = 0; /* Path to WAL file */
586 int nWal; /* Length of zWal in bytes */
587
dan7c246102010-04-12 19:00:29588 assert( zDb );
dan87bfb512010-04-30 11:43:28589 if( pVfs->xShmOpen==0 ) return SQLITE_CANTOPEN_BKPT;
dan7c246102010-04-12 19:00:29590
drh7ed91f22010-04-29 22:34:07591 /* Allocate an instance of struct Wal to return. */
592 *ppWal = 0;
593 nWal = strlen(zDb);
drh2d536e12010-05-01 20:17:30594 pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile + nWal+5);
drh7ed91f22010-04-29 22:34:07595 if( !pRet ) goto wal_open_out;
dan7c246102010-04-12 19:00:29596 pRet->pVfs = pVfs;
597 pRet->pFd = (sqlite3_file *)&pRet[1];
drh2d536e12010-05-01 20:17:30598 pRet->zName = zWal = pVfs->szOsFile + (char*)pRet->pFd;
599 sqlite3_snprintf(nWal+5, zWal, "%s-wal", zDb);
drh7ed91f22010-04-29 22:34:07600 rc = pVfs->xShmOpen(pVfs, zWal, &pRet->pWIndex);
601 if( rc ) goto wal_open_out;
dan7c246102010-04-12 19:00:29602
drh7ed91f22010-04-29 22:34:07603 /* Open file handle on the write-ahead log file. */
dan67032392010-04-17 15:42:43604 flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MAIN_JOURNAL);
drh7ed91f22010-04-29 22:34:07605 rc = sqlite3OsOpen(pVfs, zWal, pRet->pFd, flags, &flags);
dan7c246102010-04-12 19:00:29606
drh7ed91f22010-04-29 22:34:07607wal_open_out:
dan7c246102010-04-12 19:00:29608 if( rc!=SQLITE_OK ){
dan7c246102010-04-12 19:00:29609 if( pRet ){
drh2d536e12010-05-01 20:17:30610 pVfs->xShmClose(pRet->pWIndex, 0);
dan7c246102010-04-12 19:00:29611 sqlite3OsClose(pRet->pFd);
612 sqlite3_free(pRet);
613 }
dan7c246102010-04-12 19:00:29614 }
drh7ed91f22010-04-29 22:34:07615 *ppWal = pRet;
dan7c246102010-04-12 19:00:29616 return rc;
617}
618
drh7ed91f22010-04-29 22:34:07619static int walIteratorNext(
620 WalIterator *p, /* Iterator */
621 u32 *piPage, /* OUT: Next db page to write */
622 u32 *piFrame /* OUT: Wal frame to read from */
dan7c246102010-04-12 19:00:29623){
624 u32 iMin = *piPage;
625 u32 iRet = 0xFFFFFFFF;
626 int i;
627 int nBlock = p->nFinal;
628
629 for(i=p->nSegment-1; i>=0; i--){
drh7ed91f22010-04-29 22:34:07630 struct WalSegment *pSegment = &p->aSegment[i];
dan7c246102010-04-12 19:00:29631 while( pSegment->iNext<nBlock ){
632 u32 iPg = pSegment->aDbPage[pSegment->aIndex[pSegment->iNext]];
633 if( iPg>iMin ){
634 if( iPg<iRet ){
635 iRet = iPg;
636 *piFrame = i*256 + 1 + pSegment->aIndex[pSegment->iNext];
637 }
638 break;
639 }
640 pSegment->iNext++;
641 }
642
643 nBlock = 256;
644 }
645
646 *piPage = iRet;
647 return (iRet==0xFFFFFFFF);
648}
649
drh7ed91f22010-04-29 22:34:07650static WalIterator *walIteratorInit(Wal *pWal){
651 u32 *aData; /* Content of the wal-index file */
652 WalIterator *p; /* Return value */
dan7c246102010-04-12 19:00:29653 int nSegment; /* Number of segments to merge */
654 u32 iLast; /* Last frame in log */
655 int nByte; /* Number of bytes to allocate */
656 int i; /* Iterator variable */
657 int nFinal; /* Number of unindexed entries */
drh7ed91f22010-04-29 22:34:07658 struct WalSegment *pFinal; /* Final (unindexed) segment */
dan7c246102010-04-12 19:00:29659 u8 *aTmp; /* Temp space used by merge-sort */
660
drh5530b762010-04-30 14:39:50661 walIndexMap(pWal, -1);
drh7ed91f22010-04-29 22:34:07662 aData = pWal->pWiData;
663 iLast = pWal->hdr.iLastPg;
dan7c246102010-04-12 19:00:29664 nSegment = (iLast >> 8) + 1;
665 nFinal = (iLast & 0x000000FF);
666
drh7ed91f22010-04-29 22:34:07667 nByte = sizeof(WalIterator) + (nSegment-1)*sizeof(struct WalSegment) + 512;
668 p = (WalIterator *)sqlite3_malloc(nByte);
dan7c246102010-04-12 19:00:29669 if( p ){
670 memset(p, 0, nByte);
671 p->nSegment = nSegment;
672 p->nFinal = nFinal;
673 }
674
675 for(i=0; i<nSegment-1; i++){
drh7ed91f22010-04-29 22:34:07676 p->aSegment[i].aDbPage = &aData[walIndexEntry(i*256+1)];
677 p->aSegment[i].aIndex = (u8 *)&aData[walIndexEntry(i*256+1)+256];
dan7c246102010-04-12 19:00:29678 }
679 pFinal = &p->aSegment[nSegment-1];
680
drh7ed91f22010-04-29 22:34:07681 pFinal->aDbPage = &aData[walIndexEntry((nSegment-1)*256+1)];
dan7c246102010-04-12 19:00:29682 pFinal->aIndex = (u8 *)&pFinal[1];
683 aTmp = &pFinal->aIndex[256];
684 for(i=0; i<nFinal; i++){
685 pFinal->aIndex[i] = i;
686 }
drh7ed91f22010-04-29 22:34:07687 walMergesort8(pFinal->aDbPage, aTmp, pFinal->aIndex, &nFinal);
dan7c246102010-04-12 19:00:29688 p->nFinal = nFinal;
689
690 return p;
691}
692
693/*
drh7ed91f22010-04-29 22:34:07694** Free a log iterator allocated by walIteratorInit().
dan7c246102010-04-12 19:00:29695*/
drh7ed91f22010-04-29 22:34:07696static void walIteratorFree(WalIterator *p){
dan7c246102010-04-12 19:00:29697 sqlite3_free(p);
698}
699
700/*
701** Checkpoint the contents of the log file.
702*/
drh7ed91f22010-04-29 22:34:07703static int walCheckpoint(
704 Wal *pWal, /* Wal connection */
dan7c246102010-04-12 19:00:29705 sqlite3_file *pFd, /* File descriptor open on db file */
danc5118782010-04-17 17:34:41706 int sync_flags, /* Flags for OsSync() (or 0) */
dan7c246102010-04-12 19:00:29707 u8 *zBuf /* Temporary buffer to use */
708){
709 int rc; /* Return code */
drh7ed91f22010-04-29 22:34:07710 int pgsz = pWal->hdr.pgsz; /* Database page-size */
711 WalIterator *pIter = 0; /* Wal iterator context */
dan7c246102010-04-12 19:00:29712 u32 iDbpage = 0; /* Next database page to write */
drh7ed91f22010-04-29 22:34:07713 u32 iFrame = 0; /* Wal frame containing data for iDbpage */
dan7c246102010-04-12 19:00:29714
drh7ed91f22010-04-29 22:34:07715 if( pWal->hdr.iLastPg==0 ){
danbb2e9c92010-04-15 13:33:18716 return SQLITE_OK;
717 }
718
dan7c246102010-04-12 19:00:29719 /* Allocate the iterator */
drh7ed91f22010-04-29 22:34:07720 pIter = walIteratorInit(pWal);
dan7c246102010-04-12 19:00:29721 if( !pIter ) return SQLITE_NOMEM;
722
723 /* Sync the log file to disk */
danc5118782010-04-17 17:34:41724 if( sync_flags ){
drh7ed91f22010-04-29 22:34:07725 rc = sqlite3OsSync(pWal->pFd, sync_flags);
danc5118782010-04-17 17:34:41726 if( rc!=SQLITE_OK ) goto out;
727 }
dan7c246102010-04-12 19:00:29728
729 /* Iterate through the contents of the log, copying data to the db file. */
drh7ed91f22010-04-29 22:34:07730 while( 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
731 rc = sqlite3OsRead(pWal->pFd, zBuf, pgsz,
732 walFrameOffset(iFrame, pgsz) + WAL_FRAME_HDRSIZE
dan7c246102010-04-12 19:00:29733 );
734 if( rc!=SQLITE_OK ) goto out;
735 rc = sqlite3OsWrite(pFd, zBuf, pgsz, (iDbpage-1)*pgsz);
736 if( rc!=SQLITE_OK ) goto out;
737 }
738
739 /* Truncate the database file */
drh7ed91f22010-04-29 22:34:07740 rc = sqlite3OsTruncate(pFd, ((i64)pWal->hdr.nPage*(i64)pgsz));
dan7c246102010-04-12 19:00:29741 if( rc!=SQLITE_OK ) goto out;
742
drh7ed91f22010-04-29 22:34:07743 /* Sync the database file. If successful, update the wal-index. */
danc5118782010-04-17 17:34:41744 if( sync_flags ){
745 rc = sqlite3OsSync(pFd, sync_flags);
746 if( rc!=SQLITE_OK ) goto out;
747 }
drh7ed91f22010-04-29 22:34:07748 pWal->hdr.iLastPg = 0;
749 pWal->hdr.iCheck1 = 2;
750 pWal->hdr.iCheck2 = 3;
751 walIndexWriteHdr(pWal, &pWal->hdr);
dan7c246102010-04-12 19:00:29752
753 /* TODO: If a crash occurs and the current log is copied into the
754 ** database there is no problem. However, if a crash occurs while
755 ** writing the next transaction into the start of the log, such that:
756 **
757 ** * The first transaction currently in the log is left intact, but
758 ** * The second (or subsequent) transaction is damaged,
759 **
760 ** then the database could become corrupt.
761 **
762 ** The easiest thing to do would be to write and sync a dummy header
763 ** into the log at this point. Unfortunately, that turns out to be
764 ** an unwelcome performance hit. Alternatives are...
765 */
766#if 0
drh7ed91f22010-04-29 22:34:07767 memset(zBuf, 0, WAL_FRAME_HDRSIZE);
768 rc = sqlite3OsWrite(pWal->pFd, zBuf, WAL_FRAME_HDRSIZE, 0);
dan7c246102010-04-12 19:00:29769 if( rc!=SQLITE_OK ) goto out;
drh7ed91f22010-04-29 22:34:07770 rc = sqlite3OsSync(pWal->pFd, pWal->sync_flags);
dan7c246102010-04-12 19:00:29771#endif
772
773 out:
drh7ed91f22010-04-29 22:34:07774 walIteratorFree(pIter);
dan7c246102010-04-12 19:00:29775 return rc;
776}
777
778/*
779** Close a connection to a log file.
780*/
drhc438efd2010-04-26 00:19:45781int sqlite3WalClose(
drh7ed91f22010-04-29 22:34:07782 Wal *pWal, /* Wal to close */
dan7c246102010-04-12 19:00:29783 sqlite3_file *pFd, /* Database file */
danc5118782010-04-17 17:34:41784 int sync_flags, /* Flags to pass to OsSync() (or 0) */
dan7c246102010-04-12 19:00:29785 u8 *zBuf /* Buffer of at least page-size bytes */
786){
787 int rc = SQLITE_OK;
drh7ed91f22010-04-29 22:34:07788 if( pWal ){
dan30c86292010-04-30 16:24:46789 int isDelete = 0; /* True to unlink wal and wal-index files */
790
791 /* If an EXCLUSIVE lock can be obtained on the database file (using the
792 ** ordinary, rollback-mode locking methods, this guarantees that the
793 ** connection associated with this log file is the only connection to
794 ** the database. In this case checkpoint the database and unlink both
795 ** the wal and wal-index files.
796 **
797 ** The EXCLUSIVE lock is not released before returning.
798 */
799 rc = sqlite3OsLock(pFd, SQLITE_LOCK_EXCLUSIVE);
800 if( rc==SQLITE_OK ){
801 rc = walCheckpoint(pWal, pFd, sync_flags, zBuf);
802 if( rc==SQLITE_OK ){
803 isDelete = 1;
804 }
805 walIndexUnmap(pWal);
806 }
807
drh2d536e12010-05-01 20:17:30808 pWal->pVfs->xShmClose(pWal->pWIndex, isDelete);
drh7ed91f22010-04-29 22:34:07809 sqlite3OsClose(pWal->pFd);
dan30c86292010-04-30 16:24:46810 if( isDelete ){
drh2d536e12010-05-01 20:17:30811 sqlite3OsDelete(pWal->pVfs, pWal->zName, 0);
dan30c86292010-04-30 16:24:46812 }
drh7ed91f22010-04-29 22:34:07813 sqlite3_free(pWal);
dan7c246102010-04-12 19:00:29814 }
815 return rc;
816}
817
818/*
drh7ed91f22010-04-29 22:34:07819** Try to read the wal-index header. Attempt to verify the header
820** checksum. If the checksum can be verified, copy the wal-index
821** header into structure pWal->hdr. If the contents of pWal->hdr are
danb9bf16b2010-04-14 11:23:30822** modified by this and pChanged is not NULL, set *pChanged to 1.
823** Otherwise leave *pChanged unmodified.
824**
825** If the checksum cannot be verified return SQLITE_ERROR.
826*/
drh7ed91f22010-04-29 22:34:07827int walIndexTryHdr(Wal *pWal, int *pChanged){
danb9bf16b2010-04-14 11:23:30828 u32 aCksum[2] = {1, 1};
drh7ed91f22010-04-29 22:34:07829 u32 aHdr[WALINDEX_HDR_NFIELD+2];
danb9bf16b2010-04-14 11:23:30830
drh79e6c782010-04-30 02:13:26831 if( pWal->szWIndex==0 ){
drh5530b762010-04-30 14:39:50832 int rc;
833 rc = walIndexRemap(pWal, WALINDEX_MMAP_INCREMENT);
drh79e6c782010-04-30 02:13:26834 if( rc ) return rc;
835 }
836
drh7ed91f22010-04-29 22:34:07837 /* Read the header. The caller may or may not have locked the wal-index
dancd11fb22010-04-26 10:40:52838 ** file, meaning it is possible that an inconsistent snapshot is read
839 ** from the file. If this happens, return SQLITE_ERROR. The caller will
840 ** retry. Or, if the caller has already locked the file and the header
841 ** still looks inconsistent, it will run recovery.
drh79e6c782010-04-30 02:13:26842 **
843 ** FIX-ME: It is no longer possible to have not locked the wal-index.
danb9bf16b2010-04-14 11:23:30844 */
drh7ed91f22010-04-29 22:34:07845 memcpy(aHdr, pWal->pWiData, sizeof(aHdr));
846 walChecksumBytes((u8*)aHdr, sizeof(u32)*WALINDEX_HDR_NFIELD, aCksum);
847 if( aCksum[0]!=aHdr[WALINDEX_HDR_NFIELD]
848 || aCksum[1]!=aHdr[WALINDEX_HDR_NFIELD+1]
danb9bf16b2010-04-14 11:23:30849 ){
850 return SQLITE_ERROR;
851 }
852
drh7ed91f22010-04-29 22:34:07853 if( memcmp(&pWal->hdr, aHdr, sizeof(WalIndexHdr)) ){
danb9bf16b2010-04-14 11:23:30854 if( pChanged ){
855 *pChanged = 1;
856 }
drh7ed91f22010-04-29 22:34:07857 memcpy(&pWal->hdr, aHdr, sizeof(WalIndexHdr));
danb9bf16b2010-04-14 11:23:30858 }
859 return SQLITE_OK;
860}
861
862/*
drh7ed91f22010-04-29 22:34:07863** Read the wal-index header from the wal-index file into structure
864** pWal->hdr. If attempting to verify the header checksum fails, try
danb9bf16b2010-04-14 11:23:30865** to recover the log before returning.
866**
drh7ed91f22010-04-29 22:34:07867** If the wal-index header is successfully read, return SQLITE_OK.
danb9bf16b2010-04-14 11:23:30868** Otherwise an SQLite error code.
869*/
drh7ed91f22010-04-29 22:34:07870static int walIndexReadHdr(Wal *pWal, int *pChanged){
danb9bf16b2010-04-14 11:23:30871 int rc;
872
dan4c97b532010-04-30 09:52:17873 assert( pWal->lockState>=SQLITE_SHM_READ );
drh5530b762010-04-30 14:39:50874 walIndexMap(pWal, -1);
drh7ed91f22010-04-29 22:34:07875
danb9bf16b2010-04-14 11:23:30876 /* First try to read the header without a lock. Verify the checksum
877 ** before returning. This will almost always work.
878 */
drh7ed91f22010-04-29 22:34:07879 if( SQLITE_OK==walIndexTryHdr(pWal, pChanged) ){
danb9bf16b2010-04-14 11:23:30880 return SQLITE_OK;
881 }
882
drh7ed91f22010-04-29 22:34:07883 /* If the first attempt to read the header failed, lock the wal-index
danb9bf16b2010-04-14 11:23:30884 ** file and try again. If the header checksum verification fails this
885 ** time as well, run log recovery.
886 */
drh7ed91f22010-04-29 22:34:07887 if( SQLITE_OK==(rc = walSetLock(pWal, SQLITE_SHM_RECOVER)) ){
888 if( SQLITE_OK!=walIndexTryHdr(pWal, pChanged) ){
danb9bf16b2010-04-14 11:23:30889 if( pChanged ){
890 *pChanged = 1;
891 }
drh7ed91f22010-04-29 22:34:07892 rc = walIndexRecover(pWal);
danb9bf16b2010-04-14 11:23:30893 if( rc==SQLITE_OK ){
drh7ed91f22010-04-29 22:34:07894 rc = walIndexTryHdr(pWal, 0);
danb9bf16b2010-04-14 11:23:30895 }
896 }
drh7ed91f22010-04-29 22:34:07897 walSetLock(pWal, SQLITE_SHM_READ);
danb9bf16b2010-04-14 11:23:30898 }
899
900 return rc;
901}
902
903/*
dan64d039e2010-04-13 19:27:31904** Lock a snapshot.
dan7c246102010-04-12 19:00:29905**
906** If this call obtains a new read-lock and the database contents have been
drh7ed91f22010-04-29 22:34:07907** modified since the most recent call to WalCloseSnapshot() on this Wal
dan7c246102010-04-12 19:00:29908** connection, then *pChanged is set to 1 before returning. Otherwise, it
909** is left unmodified. This is used by the pager layer to determine whether
910** or not any cached pages may be safely reused.
911*/
drh7ed91f22010-04-29 22:34:07912int sqlite3WalOpenSnapshot(Wal *pWal, int *pChanged){
913 int rc;
dan64d039e2010-04-13 19:27:31914
drh7ed91f22010-04-29 22:34:07915 rc = walSetLock(pWal, SQLITE_SHM_READ);
916 if( rc==SQLITE_OK ){
917 pWal->lockState = SQLITE_SHM_READ;
dan64d039e2010-04-13 19:27:31918
drh7ed91f22010-04-29 22:34:07919 rc = walIndexReadHdr(pWal, pChanged);
dan64d039e2010-04-13 19:27:31920 if( rc!=SQLITE_OK ){
921 /* An error occured while attempting log recovery. */
drh7ed91f22010-04-29 22:34:07922 sqlite3WalCloseSnapshot(pWal);
dan31f98fc2010-04-27 05:42:32923 }else{
924 /* Check if the mapping needs to grow. */
drh5530b762010-04-30 14:39:50925 if( pWal->hdr.iLastPg
danfe05aa12010-04-30 17:05:23926 && walIndexEntry(pWal->hdr.iLastPg)*sizeof(u32)>=pWal->szWIndex
drh5530b762010-04-30 14:39:50927 ){
928 walIndexRemap(pWal, -1);
dan31f98fc2010-04-27 05:42:32929 }
dan64d039e2010-04-13 19:27:31930 }
dan7c246102010-04-12 19:00:29931 }
danba515902010-04-30 09:32:06932
933 walIndexUnmap(pWal);
dan7c246102010-04-12 19:00:29934 return rc;
935}
936
937/*
938** Unlock the current snapshot.
939*/
drh7ed91f22010-04-29 22:34:07940void sqlite3WalCloseSnapshot(Wal *pWal){
941 if( pWal->lockState!=SQLITE_SHM_UNLOCK ){
942 assert( pWal->lockState==SQLITE_SHM_READ );
943 walSetLock(pWal, SQLITE_SHM_UNLOCK);
dan64d039e2010-04-13 19:27:31944 }
dan7c246102010-04-12 19:00:29945}
946
dan5e0ce872010-04-28 17:48:44947/*
dan7c246102010-04-12 19:00:29948** Read a page from the log, if it is present.
949*/
drh7ed91f22010-04-29 22:34:07950int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, u8 *pOut){
dan7c246102010-04-12 19:00:29951 u32 iRead = 0;
dancd11fb22010-04-26 10:40:52952 u32 *aData;
drh7ed91f22010-04-29 22:34:07953 int iFrame = (pWal->hdr.iLastPg & 0xFFFFFF00);
dan7c246102010-04-12 19:00:29954
dan1bc61712010-04-30 10:24:54955 assert( pWal->lockState==SQLITE_SHM_READ||pWal->lockState==SQLITE_SHM_WRITE );
drh5530b762010-04-30 14:39:50956 walIndexMap(pWal, -1);
dancd11fb22010-04-26 10:40:52957
dan7c246102010-04-12 19:00:29958 /* Do a linear search of the unindexed block of page-numbers (if any)
drh7ed91f22010-04-29 22:34:07959 ** at the end of the wal-index. An alternative to this would be to
dan7c246102010-04-12 19:00:29960 ** build an index in private memory each time a read transaction is
961 ** opened on a new snapshot.
962 */
drh7ed91f22010-04-29 22:34:07963 aData = pWal->pWiData;
964 if( pWal->hdr.iLastPg ){
965 u32 *pi = &aData[walIndexEntry(pWal->hdr.iLastPg)];
966 u32 *piStop = pi - (pWal->hdr.iLastPg & 0xFF);
dan7c246102010-04-12 19:00:29967 while( *pi!=pgno && pi!=piStop ) pi--;
968 if( pi!=piStop ){
969 iRead = (pi-piStop) + iFrame;
970 }
971 }
drh7ed91f22010-04-29 22:34:07972 assert( iRead==0 || aData[walIndexEntry(iRead)]==pgno );
dan7c246102010-04-12 19:00:29973
974 while( iRead==0 && iFrame>0 ){
975 int iLow = 0;
976 int iHigh = 255;
977 u32 *aFrame;
978 u8 *aIndex;
979
980 iFrame -= 256;
drh7ed91f22010-04-29 22:34:07981 aFrame = &aData[walIndexEntry(iFrame+1)];
dan7c246102010-04-12 19:00:29982 aIndex = (u8 *)&aFrame[256];
983
984 while( iLow<=iHigh ){
985 int iTest = (iLow+iHigh)>>1;
986 u32 iPg = aFrame[aIndex[iTest]];
987
988 if( iPg==pgno ){
989 iRead = iFrame + 1 + aIndex[iTest];
990 break;
991 }
992 else if( iPg<pgno ){
993 iLow = iTest+1;
994 }else{
995 iHigh = iTest-1;
996 }
997 }
998 }
drh7ed91f22010-04-29 22:34:07999 assert( iRead==0 || aData[walIndexEntry(iRead)]==pgno );
1000 walIndexUnmap(pWal);
dancd11fb22010-04-26 10:40:521001
dan7c246102010-04-12 19:00:291002 /* If iRead is non-zero, then it is the log frame number that contains the
1003 ** required page. Read and return data from the log file.
1004 */
1005 if( iRead ){
drh7ed91f22010-04-29 22:34:071006 i64 iOffset = walFrameOffset(iRead, pWal->hdr.pgsz) + WAL_FRAME_HDRSIZE;
1007 *pInWal = 1;
1008 return sqlite3OsRead(pWal->pFd, pOut, pWal->hdr.pgsz, iOffset);
dan7c246102010-04-12 19:00:291009 }
1010
drh7ed91f22010-04-29 22:34:071011 *pInWal = 0;
dan7c246102010-04-12 19:00:291012 return SQLITE_OK;
1013}
1014
1015
1016/*
1017** Set *pPgno to the size of the database file (or zero, if unknown).
1018*/
drh7ed91f22010-04-29 22:34:071019void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno){
1020 assert( pWal->lockState==SQLITE_SHM_READ
1021 || pWal->lockState==SQLITE_SHM_WRITE );
1022 *pPgno = pWal->hdr.nPage;
dan7c246102010-04-12 19:00:291023}
1024
1025/*
dan7c246102010-04-12 19:00:291026** This function returns SQLITE_OK if the caller may write to the database.
1027** Otherwise, if the caller is operating on a snapshot that has already
dan49320f82010-04-14 18:50:081028** been overwritten by another writer, SQLITE_BUSY is returned.
dan7c246102010-04-12 19:00:291029*/
drh7ed91f22010-04-29 22:34:071030int sqlite3WalWriteLock(Wal *pWal, int op){
1031 int rc;
dan7c246102010-04-12 19:00:291032 if( op ){
drh7ed91f22010-04-29 22:34:071033 assert( pWal->lockState == SQLITE_SHM_READ );
1034 rc = walSetLock(pWal, SQLITE_SHM_WRITE);
dan30c86292010-04-30 16:24:461035
1036 /* If this connection is not reading the most recent database snapshot,
1037 ** it is not possible to write to the database. In this case release
1038 ** the write locks and return SQLITE_BUSY.
1039 */
1040 if( rc==SQLITE_OK ){
1041 rc = walIndexMap(pWal, -1);
1042 if( rc==SQLITE_OK
1043 && memcmp(&pWal->hdr, pWal->pWiData, sizeof(WalIndexHdr))
1044 ){
1045 rc = SQLITE_BUSY;
1046 }
1047 walIndexUnmap(pWal);
1048 if( rc!=SQLITE_OK ){
1049 walSetLock(pWal, SQLITE_SHM_READ);
1050 }
1051 }
drh7ed91f22010-04-29 22:34:071052 }else if( pWal->lockState==SQLITE_SHM_WRITE ){
1053 rc = walSetLock(pWal, SQLITE_SHM_READ);
dan7c246102010-04-12 19:00:291054 }
drh7ed91f22010-04-29 22:34:071055 return rc;
dan7c246102010-04-12 19:00:291056}
1057
dan74d6cd82010-04-24 18:44:051058/*
drh7ed91f22010-04-29 22:34:071059** The Wal object passed to this function must be holding the write-lock.
dan74d6cd82010-04-24 18:44:051060**
1061** If any data has been written (but not committed) to the log file, this
1062** function moves the write-pointer back to the start of the transaction.
1063**
1064** Additionally, the callback function is invoked for each frame written
1065** to the log since the start of the transaction. If the callback returns
1066** other than SQLITE_OK, it is not invoked again and the error code is
1067** returned to the caller.
1068**
1069** Otherwise, if the callback function does not return an error, this
1070** function returns SQLITE_OK.
1071*/
drh7ed91f22010-04-29 22:34:071072int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
dan74d6cd82010-04-24 18:44:051073 int rc = SQLITE_OK;
drh7ed91f22010-04-29 22:34:071074 Pgno iMax = pWal->hdr.iLastPg;
dan74d6cd82010-04-24 18:44:051075 Pgno iFrame;
1076
drh7ed91f22010-04-29 22:34:071077 assert( pWal->lockState==SQLITE_SHM_WRITE );
1078 walIndexReadHdr(pWal, 0);
1079 for(iFrame=pWal->hdr.iLastPg+1; iFrame<=iMax && rc==SQLITE_OK; iFrame++){
1080 rc = xUndo(pUndoCtx, pWal->pWiData[walIndexEntry(iFrame)]);
dan74d6cd82010-04-24 18:44:051081 }
drh7ed91f22010-04-29 22:34:071082 walIndexUnmap(pWal);
dan74d6cd82010-04-24 18:44:051083 return rc;
1084}
1085
drh7ed91f22010-04-29 22:34:071086/* Return an integer that records the current (uncommitted) write
1087** position in the WAL
1088*/
1089u32 sqlite3WalSavepoint(Wal *pWal){
1090 assert( pWal->lockState==SQLITE_SHM_WRITE );
1091 return pWal->hdr.iLastPg;
dan4cd78b42010-04-26 16:57:101092}
1093
drh7ed91f22010-04-29 22:34:071094/* Move the write position of the WAL back to iFrame. Called in
1095** response to a ROLLBACK TO command.
1096*/
1097int sqlite3WalSavepointUndo(Wal *pWal, u32 iFrame){
dan4cd78b42010-04-26 16:57:101098 int rc = SQLITE_OK;
1099 u8 aCksum[8];
drh7ed91f22010-04-29 22:34:071100 assert( pWal->lockState==SQLITE_SHM_WRITE );
dan4cd78b42010-04-26 16:57:101101
drh7ed91f22010-04-29 22:34:071102 pWal->hdr.iLastPg = iFrame;
dan4cd78b42010-04-26 16:57:101103 if( iFrame>0 ){
drh7ed91f22010-04-29 22:34:071104 i64 iOffset = walFrameOffset(iFrame, pWal->hdr.pgsz) + sizeof(u32)*2;
1105 rc = sqlite3OsRead(pWal->pFd, aCksum, sizeof(aCksum), iOffset);
1106 pWal->hdr.iCheck1 = sqlite3Get4byte(&aCksum[0]);
1107 pWal->hdr.iCheck2 = sqlite3Get4byte(&aCksum[4]);
dan4cd78b42010-04-26 16:57:101108 }
1109
1110 return rc;
1111}
1112
dan7c246102010-04-12 19:00:291113/*
dan4cd78b42010-04-26 16:57:101114** Write a set of frames to the log. The caller must hold the write-lock
1115** on the log file (obtained using sqlite3WalWriteLock()).
dan7c246102010-04-12 19:00:291116*/
drhc438efd2010-04-26 00:19:451117int sqlite3WalFrames(
drh7ed91f22010-04-29 22:34:071118 Wal *pWal, /* Wal handle to write to */
dan7c246102010-04-12 19:00:291119 int nPgsz, /* Database page-size in bytes */
1120 PgHdr *pList, /* List of dirty pages to write */
1121 Pgno nTruncate, /* Database size after this commit */
1122 int isCommit, /* True if this is a commit */
danc5118782010-04-17 17:34:411123 int sync_flags /* Flags to pass to OsSync() (or 0) */
dan7c246102010-04-12 19:00:291124){
dan7c246102010-04-12 19:00:291125 int rc; /* Used to catch return codes */
1126 u32 iFrame; /* Next frame address */
drh7ed91f22010-04-29 22:34:071127 u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
dan7c246102010-04-12 19:00:291128 PgHdr *p; /* Iterator to run through pList with. */
dan97a31352010-04-16 13:59:311129 u32 aCksum[2]; /* Checksums */
dan7c246102010-04-12 19:00:291130 PgHdr *pLast; /* Last frame in list */
1131 int nLast = 0; /* Number of extra copies of last page */
1132
drh7ed91f22010-04-29 22:34:071133 assert( WAL_FRAME_HDRSIZE==(4 * 2 + 2*sizeof(u32)) );
dan7c246102010-04-12 19:00:291134 assert( pList );
drh7ed91f22010-04-29 22:34:071135 assert( pWal->lockState==SQLITE_SHM_WRITE );
danba515902010-04-30 09:32:061136 assert( pWal->pWiData==0 );
dan7c246102010-04-12 19:00:291137
dan97a31352010-04-16 13:59:311138 /* If this is the first frame written into the log, write the log
1139 ** header to the start of the log file. See comments at the top of
1140 ** this file for a description of the log-header format.
1141 */
drh7ed91f22010-04-29 22:34:071142 assert( WAL_FRAME_HDRSIZE>=WAL_HDRSIZE );
1143 iFrame = pWal->hdr.iLastPg;
dan97a31352010-04-16 13:59:311144 if( iFrame==0 ){
1145 sqlite3Put4byte(aFrame, nPgsz);
1146 sqlite3_randomness(8, &aFrame[4]);
drh7ed91f22010-04-29 22:34:071147 pWal->hdr.iCheck1 = sqlite3Get4byte(&aFrame[4]);
1148 pWal->hdr.iCheck2 = sqlite3Get4byte(&aFrame[8]);
1149 rc = sqlite3OsWrite(pWal->pFd, aFrame, WAL_HDRSIZE, 0);
dan97a31352010-04-16 13:59:311150 if( rc!=SQLITE_OK ){
1151 return rc;
1152 }
1153 }
1154
drh7ed91f22010-04-29 22:34:071155 aCksum[0] = pWal->hdr.iCheck1;
1156 aCksum[1] = pWal->hdr.iCheck2;
dan7c246102010-04-12 19:00:291157
1158 /* Write the log file. */
dan7c246102010-04-12 19:00:291159 for(p=pList; p; p=p->pDirty){
1160 u32 nDbsize; /* Db-size field for frame header */
1161 i64 iOffset; /* Write offset in log file */
1162
drh7ed91f22010-04-29 22:34:071163 iOffset = walFrameOffset(++iFrame, nPgsz);
dan7c246102010-04-12 19:00:291164
1165 /* Populate and write the frame header */
1166 nDbsize = (isCommit && p->pDirty==0) ? nTruncate : 0;
drh7ed91f22010-04-29 22:34:071167 walEncodeFrame(aCksum, p->pgno, nDbsize, nPgsz, p->pData, aFrame);
1168 rc = sqlite3OsWrite(pWal->pFd, aFrame, sizeof(aFrame), iOffset);
dan7c246102010-04-12 19:00:291169 if( rc!=SQLITE_OK ){
1170 return rc;
1171 }
1172
1173 /* Write the page data */
drh7ed91f22010-04-29 22:34:071174 rc = sqlite3OsWrite(pWal->pFd, p->pData, nPgsz, iOffset + sizeof(aFrame));
dan7c246102010-04-12 19:00:291175 if( rc!=SQLITE_OK ){
1176 return rc;
1177 }
1178 pLast = p;
1179 }
1180
1181 /* Sync the log file if the 'isSync' flag was specified. */
danc5118782010-04-17 17:34:411182 if( sync_flags ){
drh7ed91f22010-04-29 22:34:071183 i64 iSegment = sqlite3OsSectorSize(pWal->pFd);
1184 i64 iOffset = walFrameOffset(iFrame+1, nPgsz);
dan67032392010-04-17 15:42:431185
1186 assert( isCommit );
dan7c246102010-04-12 19:00:291187
1188 if( iSegment<SQLITE_DEFAULT_SECTOR_SIZE ){
1189 iSegment = SQLITE_DEFAULT_SECTOR_SIZE;
1190 }
1191 iSegment = (((iOffset+iSegment-1)/iSegment) * iSegment);
1192 while( iOffset<iSegment ){
drh7ed91f22010-04-29 22:34:071193 walEncodeFrame(aCksum,pLast->pgno,nTruncate,nPgsz,pLast->pData,aFrame);
1194 rc = sqlite3OsWrite(pWal->pFd, aFrame, sizeof(aFrame), iOffset);
dan7c246102010-04-12 19:00:291195 if( rc!=SQLITE_OK ){
1196 return rc;
1197 }
1198
drh7ed91f22010-04-29 22:34:071199 iOffset += WAL_FRAME_HDRSIZE;
1200 rc = sqlite3OsWrite(pWal->pFd, pLast->pData, nPgsz, iOffset);
dan7c246102010-04-12 19:00:291201 if( rc!=SQLITE_OK ){
1202 return rc;
1203 }
1204 nLast++;
1205 iOffset += nPgsz;
1206 }
dan7c246102010-04-12 19:00:291207
drh7ed91f22010-04-29 22:34:071208 rc = sqlite3OsSync(pWal->pFd, sync_flags);
dan7c246102010-04-12 19:00:291209 if( rc!=SQLITE_OK ){
1210 return rc;
1211 }
1212 }
danba515902010-04-30 09:32:061213 assert( pWal->pWiData==0 );
dan7c246102010-04-12 19:00:291214
1215 /* Append data to the log summary. It is not necessary to lock the
drh7ed91f22010-04-29 22:34:071216 ** wal-index to do this as the RESERVED lock held on the db file
dan7c246102010-04-12 19:00:291217 ** guarantees that there are no other writers, and no data that may
1218 ** be in use by existing readers is being overwritten.
1219 */
drh7ed91f22010-04-29 22:34:071220 iFrame = pWal->hdr.iLastPg;
dan7c246102010-04-12 19:00:291221 for(p=pList; p; p=p->pDirty){
1222 iFrame++;
drh7ed91f22010-04-29 22:34:071223 walIndexAppend(pWal, iFrame, p->pgno);
dan7c246102010-04-12 19:00:291224 }
1225 while( nLast>0 ){
1226 iFrame++;
1227 nLast--;
drh7ed91f22010-04-29 22:34:071228 walIndexAppend(pWal, iFrame, pLast->pgno);
dan7c246102010-04-12 19:00:291229 }
1230
1231 /* Update the private copy of the header. */
drh7ed91f22010-04-29 22:34:071232 pWal->hdr.pgsz = nPgsz;
1233 pWal->hdr.iLastPg = iFrame;
dan7c246102010-04-12 19:00:291234 if( isCommit ){
drh7ed91f22010-04-29 22:34:071235 pWal->hdr.iChange++;
1236 pWal->hdr.nPage = nTruncate;
dan7c246102010-04-12 19:00:291237 }
drh7ed91f22010-04-29 22:34:071238 pWal->hdr.iCheck1 = aCksum[0];
1239 pWal->hdr.iCheck2 = aCksum[1];
dan7c246102010-04-12 19:00:291240
drh7ed91f22010-04-29 22:34:071241 /* If this is a commit, update the wal-index header too. */
1242 if( isCommit ){
1243 walIndexWriteHdr(pWal, &pWal->hdr);
1244 pWal->iCallback = iFrame;
dan7c246102010-04-12 19:00:291245 }
drh7ed91f22010-04-29 22:34:071246 walIndexUnmap(pWal);
dan7c246102010-04-12 19:00:291247
dan8d22a172010-04-19 18:03:511248 return rc;
dan7c246102010-04-12 19:00:291249}
1250
1251/*
danb9bf16b2010-04-14 11:23:301252** Checkpoint the database:
1253**
drh7ed91f22010-04-29 22:34:071254** 1. Acquire a CHECKPOINT lock
1255** 2. Copy the contents of the log into the database file.
1256** 3. Zero the wal-index header (so new readers will ignore the log).
1257** 4. Drop the CHECKPOINT lock.
dan7c246102010-04-12 19:00:291258*/
drhc438efd2010-04-26 00:19:451259int sqlite3WalCheckpoint(
drh7ed91f22010-04-29 22:34:071260 Wal *pWal, /* Wal connection */
dan7c246102010-04-12 19:00:291261 sqlite3_file *pFd, /* File descriptor open on db file */
danc5118782010-04-17 17:34:411262 int sync_flags, /* Flags to sync db file with (or 0) */
dan64d039e2010-04-13 19:27:311263 u8 *zBuf, /* Temporary buffer to use */
1264 int (*xBusyHandler)(void *), /* Pointer to busy-handler function */
1265 void *pBusyHandlerArg /* Argument to pass to xBusyHandler */
dan7c246102010-04-12 19:00:291266){
danb9bf16b2010-04-14 11:23:301267 int rc; /* Return code */
dan31c03902010-04-29 14:51:331268 int isChanged = 0; /* True if a new wal-index header is loaded */
dan7c246102010-04-12 19:00:291269
drh7ed91f22010-04-29 22:34:071270 assert( pWal->lockState==SQLITE_SHM_UNLOCK );
dan5cf53532010-05-01 16:40:201271 assert( pWal->pWiData==0 );
dan39c79f52010-04-15 10:58:511272
drh7ed91f22010-04-29 22:34:071273 /* Get the CHECKPOINT lock */
dan64d039e2010-04-13 19:27:311274 do {
drh7ed91f22010-04-29 22:34:071275 rc = walSetLock(pWal, SQLITE_SHM_CHECKPOINT);
dan64d039e2010-04-13 19:27:311276 }while( rc==SQLITE_BUSY && xBusyHandler(pBusyHandlerArg) );
danb9bf16b2010-04-14 11:23:301277 if( rc!=SQLITE_OK ){
drh7ed91f22010-04-29 22:34:071278 walSetLock(pWal, SQLITE_SHM_UNLOCK);
danb9bf16b2010-04-14 11:23:301279 return rc;
1280 }
dan64d039e2010-04-13 19:27:311281
danb9bf16b2010-04-14 11:23:301282 /* Copy data from the log to the database file. */
drh7ed91f22010-04-29 22:34:071283 rc = walIndexReadHdr(pWal, &isChanged);
danb9bf16b2010-04-14 11:23:301284 if( rc==SQLITE_OK ){
drh7ed91f22010-04-29 22:34:071285 rc = walCheckpoint(pWal, pFd, sync_flags, zBuf);
danb9bf16b2010-04-14 11:23:301286 }
dan31c03902010-04-29 14:51:331287 if( isChanged ){
1288 /* If a new wal-index header was loaded before the checkpoint was
drh7ed91f22010-04-29 22:34:071289 ** performed, then the pager-cache associated with log pWal is now
dan31c03902010-04-29 14:51:331290 ** out of date. So zero the cached wal-index header to ensure that
1291 ** next time the pager opens a snapshot on this database it knows that
1292 ** the cache needs to be reset.
1293 */
drh7ed91f22010-04-29 22:34:071294 memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
dan31c03902010-04-29 14:51:331295 }
danb9bf16b2010-04-14 11:23:301296
1297 /* Release the locks. */
dan87bfb512010-04-30 11:43:281298 walIndexUnmap(pWal);
drh7ed91f22010-04-29 22:34:071299 walSetLock(pWal, SQLITE_SHM_UNLOCK);
dan64d039e2010-04-13 19:27:311300 return rc;
dan7c246102010-04-12 19:00:291301}
1302
drh7ed91f22010-04-29 22:34:071303/* Return the value to pass to a sqlite3_wal_hook callback, the
1304** number of frames in the WAL at the point of the last commit since
1305** sqlite3WalCallback() was called. If no commits have occurred since
1306** the last call, then return 0.
1307*/
1308int sqlite3WalCallback(Wal *pWal){
dan8d22a172010-04-19 18:03:511309 u32 ret = 0;
drh7ed91f22010-04-29 22:34:071310 if( pWal ){
1311 ret = pWal->iCallback;
1312 pWal->iCallback = 0;
dan8d22a172010-04-19 18:03:511313 }
1314 return (int)ret;
1315}
dan5cf53532010-05-01 16:40:201316#endif /* #ifndef SQLITE_OMIT_WAL */