/ Check-in [8efb7f4f]
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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:8efb7f4ffbfc3ad901a3bb1b4ff9390b8c13760b
User & Date: drh 2008-04-17 14:16:42
Context
2008-04-17
17:02
Add the journal_mode pragma. This is currently just syntax - it is not operational. (CVS 5024) check-in: 8eaa0c71 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: 8efb7f4f user: drh tags: trunk
2008-04-16
23:50
Add the -overwrite option to speedtest8.c. (CVS 5022) check-in: 6765ea52 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs 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
...
955
956
957
958
959
960
961














962
963
964
965
966
967
968
....
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
....
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
....
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
....
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
** 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>

/*
................................................................................
    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:
................................................................................
  }
  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);
................................................................................
  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;
................................................................................
  ** (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
................................................................................
  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);







|







 







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







 







|
<







 







<
<
<
<
<
<
<
<







 







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







 







<
<
<
<
<







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
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
....
1353
1354
1355
1356
1357
1358
1359
1360

1361
1362
1363
1364
1365
1366
1367
....
1922
1923
1924
1925
1926
1927
1928








1929
1930
1931
1932
1933
1934
1935
....
2818
2819
2820
2821
2822
2823
2824













2825
2826
2827
2828
2829
2830
2831
....
4892
4893
4894
4895
4896
4897
4898





4899
4900
4901
4902
4903
4904
4905
** 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>

/*
................................................................................
    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:
................................................................................
  }
  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);
................................................................................
  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;
................................................................................
  ** (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
................................................................................
  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
...
258
259
260
261
262
263
264

265

266
267
268
269
270
271
272
#    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
................................................................................
# 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 {







|







 







>
|
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#    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
................................................................................
# 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
..
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#    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
................................................................................
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







|







 







|
|
|
<











8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
38
39
40
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56
57
58
#    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
................................................................................
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
...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# 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
................................................................................
    }
  }
}

# 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);







|







 







<







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
248
249
250
251
252
253
254

255
256
257
258
259
260
261
# 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
................................................................................
    }
  }
}

# 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);