SQLite

Check-in [8efb7f4ffb]
Login

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

Overview
Comment:In exclusive locking mode, commit by zeroing the first 28 bytes of the journal file, not by truncating the journal. Overwriting is much faster than truncating. (CVS 5023)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8efb7f4ffbfc3ad901a3bb1b4ff9390b8c13760b
User & Date: drh 2008-04-17 14:16:42.000
Context
2008-04-17
17:02
Add the journal_mode pragma. This is currently just syntax - it is not operational. (CVS 5024) (check-in: 8eaa0c7102 user: drh tags: trunk)
14:16
In exclusive locking mode, commit by zeroing the first 28 bytes of the journal file, not by truncating the journal. Overwriting is much faster than truncating. (CVS 5023) (check-in: 8efb7f4ffb user: drh tags: trunk)
2008-04-16
23:50
Add the -overwrite option to speedtest8.c. (CVS 5022) (check-in: 6765ea52b3 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Deleted src/experimental.c.
1
2
3
4
5
6
7
8
9
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
/*
** 2005 January 20
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are not a part of the official
** SQLite API.  These routines are unsupported.
**
** $Id: experimental.c,v 1.4 2006/01/31 20:49:13 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"

/*
** Set all the parameters in the compiled SQL statement to NULL.
*/
int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
  int i;
  int rc = SQLITE_OK;
  for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){
    rc = sqlite3_bind_null(pStmt, i);
  }
  return rc;
}

/*
** Sleep for a little while.  Return the amount of time slept.
*/
int sqlite3_sleep(int ms){
  return sqlite3OsSleep(ms);
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































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.426 2008/04/14 23:13:46 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.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.427 2008/04/17 14:16:42 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include <assert.h>
#include <string.h>

/*
955
956
957
958
959
960
961














962
963
964
965
966
967
968
    offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager);
  }
  assert( offset%JOURNAL_HDR_SZ(pPager)==0 );
  assert( offset>=c );
  assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
  pPager->journalOff = offset;
}















/*
** The journal file must be open when this routine is called. A journal
** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the
** current location.
**
** The format for the journal header is as follows:







>
>
>
>
>
>
>
>
>
>
>
>
>
>







955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
    offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager);
  }
  assert( offset%JOURNAL_HDR_SZ(pPager)==0 );
  assert( offset>=c );
  assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
  pPager->journalOff = offset;
}

/*
** Write zeros over the header of the journal file.  This has the
** effect of invalidating the journal file and committing the
** transaction.
*/
static int zeroJournalHdr(Pager *pPager){
  int rc;
  static const char zeroHdr[28];

  IOTRACE(("JZEROHDR %p\n", pPager))
  rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0);
  return rc;
}

/*
** The journal file must be open when this routine is called. A journal
** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the
** current location.
**
** The format for the journal header is as follows:
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
  }
  sqlite3PagerStmtCommit(pPager);
  if( pPager->stmtOpen && !pPager->exclusiveMode ){
    sqlite3OsClose(pPager->stfd);
    pPager->stmtOpen = 0;
  }
  if( pPager->journalOpen ){
    if( pPager->exclusiveMode 
          && (rc = sqlite3OsTruncate(pPager->jfd, 0))==SQLITE_OK ){;
      pPager->journalOff = 0;
      pPager->journalStarted = 0;
    }else{
      sqlite3OsClose(pPager->jfd);
      pPager->journalOpen = 0;
      if( rc==SQLITE_OK ){
        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);







|
<







1353
1354
1355
1356
1357
1358
1359
1360

1361
1362
1363
1364
1365
1366
1367
  }
  sqlite3PagerStmtCommit(pPager);
  if( pPager->stmtOpen && !pPager->exclusiveMode ){
    sqlite3OsClose(pPager->stfd);
    pPager->stmtOpen = 0;
  }
  if( pPager->journalOpen ){
    if( pPager->exclusiveMode && (rc = zeroJournalHdr(pPager))==SQLITE_OK ){

      pPager->journalOff = 0;
      pPager->journalStarted = 0;
    }else{
      sqlite3OsClose(pPager->jfd);
      pPager->journalOpen = 0;
      if( rc==SQLITE_OK ){
        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
  i64 szJ;                 /* Size of the full journal */
  i64 hdrOff;
  int nRec;                /* Number of Records */
  int i;                   /* Loop counter */
  int rc;

  szJ = pPager->journalOff;
#ifndef NDEBUG 
  {
    i64 os_szJ;
    rc = sqlite3OsFileSize(pPager->jfd, &os_szJ);
    if( rc!=SQLITE_OK ) return rc;
    assert( szJ==os_szJ );
  }
#endif

  /* Set hdrOff to be the offset just after the end of the last journal
  ** page written before the first journal-header for this statement
  ** transaction was written, or the end of the file if no journal
  ** header was written.
  */
  hdrOff = pPager->stmtHdrOff;







<
<
<
<
<
<
<
<







1922
1923
1924
1925
1926
1927
1928








1929
1930
1931
1932
1933
1934
1935
  i64 szJ;                 /* Size of the full journal */
  i64 hdrOff;
  int nRec;                /* Number of Records */
  int i;                   /* Loop counter */
  int rc;

  szJ = pPager->journalOff;









  /* Set hdrOff to be the offset just after the end of the last journal
  ** page written before the first journal-header for this statement
  ** transaction was written, or the end of the file if no journal
  ** header was written.
  */
  hdrOff = pPager->stmtHdrOff;
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
  ** (assuming there is a journal and it needs to be synced.)
  */
  if( pPager->needSync ){
    if( !pPager->tempFile ){
      int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
      assert( pPager->journalOpen );

      /* assert( !pPager->noSync ); // noSync might be set if synchronous
      ** was turned off after the transaction was started.  Ticket #615 */
#ifndef NDEBUG
      {
        /* Make sure the pPager->nRec counter we are keeping agrees
        ** with the nRec computed from the size of the journal file.
        */
        i64 jSz;
        rc = sqlite3OsFileSize(pPager->jfd, &jSz);
        if( rc!=0 ) return rc;
        assert( pPager->journalOff==jSz );
      }
#endif
      if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
        /* Write the nRec value into the journal file header. If in
        ** full-synchronous mode, sync the journal first. This ensures that
        ** all data has really hit the disk before nRec is updated to mark
        ** it as a candidate for rollback.
        **
        ** This is not required if the persistent media supports the







<
<
<
<
<
<
<
<
<
<
<
<
<







2818
2819
2820
2821
2822
2823
2824













2825
2826
2827
2828
2829
2830
2831
  ** (assuming there is a journal and it needs to be synced.)
  */
  if( pPager->needSync ){
    if( !pPager->tempFile ){
      int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
      assert( pPager->journalOpen );














      if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
        /* Write the nRec value into the journal file header. If in
        ** full-synchronous mode, sync the journal first. This ensures that
        ** all data has really hit the disk before nRec is updated to mark
        ** it as a candidate for rollback.
        **
        ** This is not required if the persistent media supports the
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
  assert( pPager->pInStmt==0 );
  pPager->pInStmt = sqlite3BitvecCreate(pPager->dbSize);
  pagerEnter(pPager);
  if( pPager->pInStmt==0 ){
    /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */
    return SQLITE_NOMEM;
  }
#ifndef NDEBUG
  rc = sqlite3OsFileSize(pPager->jfd, &pPager->stmtJSize);
  if( rc ) goto stmt_begin_failed;
  assert( pPager->stmtJSize == pPager->journalOff );
#endif
  pPager->stmtJSize = pPager->journalOff;
  pPager->stmtSize = pPager->dbSize;
  pPager->stmtHdrOff = 0;
  pPager->stmtCksum = pPager->cksumInit;
  if( !pPager->stmtOpen ){
    rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->stfd, pPager->zStmtJrnl,
                              SQLITE_OPEN_SUBJOURNAL);







<
<
<
<
<







4892
4893
4894
4895
4896
4897
4898





4899
4900
4901
4902
4903
4904
4905
  assert( pPager->pInStmt==0 );
  pPager->pInStmt = sqlite3BitvecCreate(pPager->dbSize);
  pagerEnter(pPager);
  if( pPager->pInStmt==0 ){
    /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */
    return SQLITE_NOMEM;
  }





  pPager->stmtJSize = pPager->journalOff;
  pPager->stmtSize = pPager->dbSize;
  pPager->stmtHdrOff = 0;
  pPager->stmtCksum = pPager->cksumInit;
  if( !pPager->stmtOpen ){
    rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->stfd, pPager->zStmtJrnl,
                              SQLITE_OPEN_SUBJOURNAL);
Changes to src/vdbeaux.c.
1386
1387
1388
1389
1390
1391
1392

1393
1394
1395
1396
1397
1398

1399
1400
1401
1402
1403
1404
1405
    ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and
    ** deleting or truncating journals. If something goes wrong while
    ** this is happening we don't really care. The integrity of the
    ** transaction is already guaranteed, but some stray 'cold' journals
    ** may be lying around. Returning an error code won't help matters.
    */
    disable_simulated_io_errors();

    for(i=0; i<db->nDb; i++){ 
      Btree *pBt = db->aDb[i].pBt;
      if( pBt ){
        sqlite3BtreeCommitPhaseTwo(pBt);
      }
    }

    enable_simulated_io_errors();

    sqlite3VtabCommit(db);
  }
#endif

  return rc;







>






>







1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
    ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and
    ** deleting or truncating journals. If something goes wrong while
    ** this is happening we don't really care. The integrity of the
    ** transaction is already guaranteed, but some stray 'cold' journals
    ** may be lying around. Returning an error code won't help matters.
    */
    disable_simulated_io_errors();
    sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 1);
    for(i=0; i<db->nDb; i++){ 
      Btree *pBt = db->aDb[i].pBt;
      if( pBt ){
        sqlite3BtreeCommitPhaseTwo(pBt);
      }
    }
    sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0);
    enable_simulated_io_errors();

    sqlite3VtabCommit(db);
  }
#endif

  return rc;
Changes to test/exclusive.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The focus
# of these tests is exclusive access mode (i.e. the thing activated by 
# "PRAGMA locking_mode = EXCLUSIVE").
#
# $Id: exclusive.test,v 1.7 2007/10/09 08:29:32 danielk1977 Exp $

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

ifcapable {!pager_pragmas} {
  finish_test
  return







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The focus
# of these tests is exclusive access mode (i.e. the thing activated by 
# "PRAGMA locking_mode = EXCLUSIVE").
#
# $Id: exclusive.test,v 1.8 2008/04/17 14:16:42 drh Exp $

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

ifcapable {!pager_pragmas} {
  finish_test
  return
258
259
260
261
262
263
264

265

266
267
268
269
270
271
272
# a transaction.
#
proc filestate {fname} {
  set exists 0
  set content 0
  if {[file exists $fname]} {
    set exists 1

    set content [expr {[file size $fname] > 0}]

  }
  list $exists $content
}
do_test exclusive-3.0 {
  filestate test.db-journal
} {0 0}
do_test exclusive-3.1 {







>
|
>







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# a transaction.
#
proc filestate {fname} {
  set exists 0
  set content 0
  if {[file exists $fname]} {
    set exists 1
    set hdr [hexio_read $fname 0 28]
    set content \
      [expr {$hdr!="00000000000000000000000000000000000000000000000000000000"}]
  }
  list $exists $content
}
do_test exclusive-3.0 {
  filestate test.db-journal
} {0 0}
do_test exclusive-3.1 {
Changes to test/exclusive3.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file runs the tests in the file ioerr.test with 
# exclusive access mode enabled.
#
# $Id: exclusive3.test,v 1.3 2007/03/30 16:01:55 drh Exp $

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

ifcapable {!pager_pragmas} {
  finish_test
  return







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file runs the tests in the file ioerr.test with 
# exclusive access mode enabled.
#
# $Id: exclusive3.test,v 1.4 2008/04/17 14:16:42 drh Exp $

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

ifcapable {!pager_pragmas} {
  finish_test
  return
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
rename do_test really_do_test
proc do_test {args} {
  set sc [concat really_do_test "exclusive-[lindex $args 0]" \
      [lrange $args 1 end]]
  eval $sc
}

#source $testdir/rollback.test
#source $testdir/select1.test
#source $testdir/select2.test

source $testdir/malloc.test
source $testdir/ioerr.test


rename sqlite3 ""
rename real_sqlite3 sqlite3
rename finish_test ""
rename really_finish_test2 finish_test
rename do_test ""
rename really_do_test do_test
finish_test







|
|
|
<











38
39
40
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56
57
58
rename do_test really_do_test
proc do_test {args} {
  set sc [concat really_do_test "exclusive-[lindex $args 0]" \
      [lrange $args 1 end]]
  eval $sc
}

source $testdir/rollback.test
source $testdir/select1.test
source $testdir/select2.test

source $testdir/malloc.test
source $testdir/ioerr.test


rename sqlite3 ""
rename real_sqlite3 sqlite3
rename finish_test ""
rename really_finish_test2 finish_test
rename do_test ""
rename really_do_test do_test
finish_test
Changes to test/malloc.test.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# This file attempts to check the behavior of the SQLite library in 
# an out-of-memory situation. When compiled with -DSQLITE_DEBUG=1, 
# the SQLite library accepts a special command (sqlite3_memdebug_fail N C)
# which causes the N-th malloc to fail.  This special feature is used
# to see what happens in the library if a malloc were to really fail
# due to an out-of-memory situation.
#
# $Id: malloc.test,v 1.60 2008/04/03 10:13:01 danielk1977 Exp $

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

# Only run these tests if memory debugging is turned on.
#
source $testdir/malloc_common.tcl







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# This file attempts to check the behavior of the SQLite library in 
# an out-of-memory situation. When compiled with -DSQLITE_DEBUG=1, 
# the SQLite library accepts a special command (sqlite3_memdebug_fail N C)
# which causes the N-th malloc to fail.  This special feature is used
# to see what happens in the library if a malloc were to really fail
# due to an out-of-memory situation.
#
# $Id: malloc.test,v 1.61 2008/04/17 14:16:42 drh Exp $

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

# Only run these tests if memory debugging is turned on.
#
source $testdir/malloc_common.tcl
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
    }
  }
}

# This block tests that malloc() failures that occur whilst commiting
# a multi-file transaction are handled correctly.
#
breakpoint
do_malloc_test 9 -sqlprep {
  ATTACH 'test2.db' as test2;
  CREATE TABLE abc1(a, b, c);
  CREATE TABLE test2.abc2(a, b, c);
} -sqlbody {
  BEGIN;
  INSERT INTO abc1 VALUES(1, 2, 3);







<







248
249
250
251
252
253
254

255
256
257
258
259
260
261
    }
  }
}

# This block tests that malloc() failures that occur whilst commiting
# a multi-file transaction are handled correctly.
#

do_malloc_test 9 -sqlprep {
  ATTACH 'test2.db' as test2;
  CREATE TABLE abc1(a, b, c);
  CREATE TABLE test2.abc2(a, b, c);
} -sqlbody {
  BEGIN;
  INSERT INTO abc1 VALUES(1, 2, 3);