SQLite

Check-in [b6eb4bf8c7]
Login

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

Overview
Comment:Fix a pager bug that might have made multi-database commits non-atomic if a power failure occurred at just the wrong moment. (CVS 1900)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b6eb4bf8c7763ef73723fc3d3697af435c19bae4
User & Date: drh 2004-08-21 19:20:42.000
Context
2004-08-24
15:23
Fix a bug in the parsing of wildcards that begin with '$'. (CVS 1901) (check-in: 054dd8901d user: drh tags: trunk)
2004-08-21
19:20
Fix a pager bug that might have made multi-database commits non-atomic if a power failure occurred at just the wrong moment. (CVS 1900) (check-in: b6eb4bf8c7 user: drh tags: trunk)
17:54
Optimizations to the code generator. (CVS 1899) (check-in: bd6649c5aa user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/os_test.c.
92
93
94
95
96
97
98
99

100
101
102
103


104
105
106
107
108
109
110
  sqlite3OsEnterMutex();
  n = strlen(zCrashFile);
  if( zCrashFile[n-1]=='*' ){
    n--;
  }else if( strlen(zPath)>n ){
    n = strlen(zPath);
  }
  r = ( 

    iCrashDelay>0 &&
    !strncmp(zPath, zCrashFile, n) &&
    --iCrashDelay==0
  )?1:0;


  sqlite3OsLeaveMutex();
  return r;
}


static OsTestFile *pAllFiles = 0;








|
>
|
<
|
|
>
>







92
93
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
109
110
111
112
  sqlite3OsEnterMutex();
  n = strlen(zCrashFile);
  if( zCrashFile[n-1]=='*' ){
    n--;
  }else if( strlen(zPath)>n ){
    n = strlen(zPath);
  }
  r = 0;
  if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){
    iCrashDelay--;

    if( iCrashDelay<=0 ){
      r = 1;
    }
  }
  sqlite3OsLeaveMutex();
  return r;
}


static OsTestFile *pAllFiles = 0;

153
154
155
156
157
158
159

160
161
162
163
164
165
166

/*
** Load block 'blk' into the cache of pFile.
*/
static int cacheBlock(OsTestFile *pFile, int blk){
  if( blk>=pFile->nBlk ){
    int n = ((pFile->nBlk * 2) + 100 + blk);

    pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*));
    if( !pFile->apBlk ) return SQLITE_NOMEM;
    memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*));
    pFile->nBlk = n;
  }

  if( !pFile->apBlk[blk] ){







>







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

/*
** Load block 'blk' into the cache of pFile.
*/
static int cacheBlock(OsTestFile *pFile, int blk){
  if( blk>=pFile->nBlk ){
    int n = ((pFile->nBlk * 2) + 100 + blk);
    /* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */
    pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*));
    if( !pFile->apBlk ) return SQLITE_NOMEM;
    memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*));
    pFile->nBlk = n;
  }

  if( !pFile->apBlk[blk] ){
279
280
281
282
283
284
285

286
287
288
289
290
291
292

/*
** Close the file.
*/
int sqlite3OsClose(OsFile *id){
  if( !(*id) ) return SQLITE_OK;
  if( (*id)->fd.isOpen ){

    writeCache(*id);
    sqlite3RealClose(&(*id)->fd);
  }
  closeFile(id);
  return SQLITE_OK;
}








>







282
283
284
285
286
287
288
289
290
291
292
293
294
295
296

/*
** Close the file.
*/
int sqlite3OsClose(OsFile *id){
  if( !(*id) ) return SQLITE_OK;
  if( (*id)->fd.isOpen ){
    /* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
    writeCache(*id);
    sqlite3RealClose(&(*id)->fd);
  }
  closeFile(id);
  return SQLITE_OK;
}

382
383
384
385
386
387
388


389
390
391
392
393
394
395
396
}

/*
** Sync the file. First flush the write-cache to disk, then call the
** real sync() function.
*/
int sqlite3OsSync(OsFile *id){


  int rc = writeCache(*id);
  if( rc!=SQLITE_OK ) return rc;
  rc = sqlite3RealSync(&(*id)->fd);
  return rc;
}

/*
** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new







>
>
|







386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
}

/*
** Sync the file. First flush the write-cache to disk, then call the
** real sync() function.
*/
int sqlite3OsSync(OsFile *id){
  int rc;
  /* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
  rc = writeCache(*id);
  if( rc!=SQLITE_OK ) return rc;
  rc = sqlite3RealSync(&(*id)->fd);
  return rc;
}

/*
** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new
Changes to src/pager.c.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** 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.
**
** @(#) $Id: pager.c,v 1.159 2004/08/19 13:29:15 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>








|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** 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.
**
** @(#) $Id: pager.c,v 1.160 2004/08/21 19:20:42 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

218
219
220
221
222
223
224

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  u8 readOnly;                /* True for a read-only database */
  u8 needSync;                /* True if an fsync() is needed on the journal */
  u8 dirtyCache;              /* True if cached pages have changed */
  u8 alwaysRollback;          /* Disable dont_rollback() for all pages */
  u8 memDb;                   /* True to inhibit all file I/O */
  u8 *aInJournal;             /* One bit for each page in the database file */
  u8 *aInStmt;                /* One bit for each page in the database */

  BusyHandler *pBusyHandler;  /* Pointer to sqlite.busyHandler */
  PgHdr *pFirst, *pLast;      /* List of free pages */
  PgHdr *pFirstSynced;        /* First free page with PgHdr.needSync==0 */
  PgHdr *pAll;                /* List of all pages */
  PgHdr *pStmt;               /* List of pages in the statement subjournal */
  PgHdr *aHash[N_PG_HASH];    /* Hash table to map page number to PgHdr */
  off_t journalOff;           /* Current byte offset in the journal file */
  off_t journalHdr;           /* Byte offset to previous journal header */
  off_t stmtHdrOff;           /* First journal header written this statement */
  off_t stmtCksum;            /* cksumInit when statement was started */
  int sectorSize;             /* Assumed sector size during rollback */
  u8 setMaster;               /* True if a m-j name has been written to jrnl */
};

/*
** These are bits that can be set in Pager.errMask.
*/
#define PAGER_ERR_FULL     0x01  /* a write() failed */
#define PAGER_ERR_MEM      0x02  /* malloc() failed */







>











<







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

237
238
239
240
241
242
243
  u8 readOnly;                /* True for a read-only database */
  u8 needSync;                /* True if an fsync() is needed on the journal */
  u8 dirtyCache;              /* True if cached pages have changed */
  u8 alwaysRollback;          /* Disable dont_rollback() for all pages */
  u8 memDb;                   /* True to inhibit all file I/O */
  u8 *aInJournal;             /* One bit for each page in the database file */
  u8 *aInStmt;                /* One bit for each page in the database */
  u8 setMaster;               /* True if a m-j name has been written to jrnl */
  BusyHandler *pBusyHandler;  /* Pointer to sqlite.busyHandler */
  PgHdr *pFirst, *pLast;      /* List of free pages */
  PgHdr *pFirstSynced;        /* First free page with PgHdr.needSync==0 */
  PgHdr *pAll;                /* List of all pages */
  PgHdr *pStmt;               /* List of pages in the statement subjournal */
  PgHdr *aHash[N_PG_HASH];    /* Hash table to map page number to PgHdr */
  off_t journalOff;           /* Current byte offset in the journal file */
  off_t journalHdr;           /* Byte offset to previous journal header */
  off_t stmtHdrOff;           /* First journal header written this statement */
  off_t stmtCksum;            /* cksumInit when statement was started */
  int sectorSize;             /* Assumed sector size during rollback */

};

/*
** These are bits that can be set in Pager.errMask.
*/
#define PAGER_ERR_FULL     0x01  /* a write() failed */
#define PAGER_ERR_MEM      0x02  /* malloc() failed */
656
657
658
659
660
661
662

663
664
665
666
667
668
669
  rc = write32bits(&pPager->jfd, len);
  if( rc!=SQLITE_OK ) return rc;

  rc = write32bits(&pPager->jfd, cksum);
  if( rc!=SQLITE_OK ) return rc;

  rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));

  return rc;
}

/*
** Add or remove a page from the list of all pages that are in the
** statement journal.
**







>







656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
  rc = write32bits(&pPager->jfd, len);
  if( rc!=SQLITE_OK ) return rc;

  rc = write32bits(&pPager->jfd, cksum);
  if( rc!=SQLITE_OK ) return rc;

  rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
  pPager->needSync = 1;
  return rc;
}

/*
** Add or remove a page from the list of all pages that are in the
** statement journal.
**
Changes to test/crash.test.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# module "crashtest" compiled with the special "os_test.c" backend is used.
# The os_test.c simulates the kind of file corruption that can occur
# when writes are happening at the moment of power loss.
# 
# The special crash-test module with its os_test.c backend only works
# on Unix.
#
# $Id: crash.test,v 1.8 2004/08/21 17:54:46 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# set repeats 100
set repeats 10








|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# module "crashtest" compiled with the special "os_test.c" backend is used.
# The os_test.c simulates the kind of file corruption that can occur
# when writes are happening at the moment of power loss.
# 
# The special crash-test module with its os_test.c backend only works
# on Unix.
#
# $Id: crash.test,v 1.9 2004/08/21 19:20:42 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# set repeats 100
set repeats 10

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
    signature
  } $sig
  do_test crash-4.1.$i.3 {
    signature2
  } $sig2
} 
set i 0
set i 55
while {[incr i]} {
  set sig [signature]
  set sig2 [signature2]
  set ::fin 0
  do_test crash-4.2.$i.1 {
     set c [crashsql $i test2.db-journal "
       ATTACH 'test2.db' AS aux;







<







269
270
271
272
273
274
275

276
277
278
279
280
281
282
    signature
  } $sig
  do_test crash-4.1.$i.3 {
    signature2
  } $sig2
} 
set i 0

while {[incr i]} {
  set sig [signature]
  set sig2 [signature2]
  set ::fin 0
  do_test crash-4.2.$i.1 {
     set c [crashsql $i test2.db-journal "
       ATTACH 'test2.db' AS aux;