SQLite

Check-in [22a228edad]
Login

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

Overview
Comment:In SQLITE_ENABLE_BATCH_ATOMIC_WRITE builds on F2FS file-systems, invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE if an SQLITE_FCNTL_COMMIT_ATOMIC_WRITE call fails. Also, do not use an atomic transaction to create the initial database. This is because if an error occurs while writing to the db file, any changes to the file-size do not seem to be rolled back automatically. The only time this matters is when the file was 0 bytes in size to start with. Cherrypick of [b3122db154].
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | branch-3.19
Files: files | file ages | folders
SHA3-256: 22a228edad3edf139b4cc78beaffb15a6f1999aa0ff198ee7b4ebe8074b42f48
User & Date: dan 2018-02-02 08:14:21.615
Context
2018-03-06
11:49
Avoid running a couple of tests in crash8.test that depend on the presence of the journal file if running on an F2FS file-system that does not require a journal file. Cherrypick of [797e02e0]. (check-in: eeedfc74d2 user: dan tags: branch-3.19)
2018-02-02
08:14
In SQLITE_ENABLE_BATCH_ATOMIC_WRITE builds on F2FS file-systems, invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE if an SQLITE_FCNTL_COMMIT_ATOMIC_WRITE call fails. Also, do not use an atomic transaction to create the initial database. This is because if an error occurs while writing to the db file, any changes to the file-size do not seem to be rolled back automatically. The only time this matters is when the file was 0 bytes in size to start with. Cherrypick of [b3122db154]. (check-in: 22a228edad user: dan tags: branch-3.19)
08:08
Update a couple of test scripts so that they work on F2FS file-systems that support atomic transactions. Cherrypick of [49e58e645e]. (check-in: 1b39467927 user: dan tags: branch-3.19)
2018-01-23
14:01
In SQLITE_ENABLE_BATCH_ATOMIC_WRITE builds on F2FS file-systems, invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE if an SQLITE_FCNTL_COMMIT_ATOMIC_WRITE call fails. Also, do not use an atomic transaction to create the initial database. This is because if an error occurs while writing to the db file, any changes to the file-size do not seem to be rolled back automatically. The only time this matters is when the file was 0 bytes in size to start with. (check-in: b3122db154 user: dan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
  int dc;                           /* Device characteristics */

  assert( isOpen(pPager->fd) );
  dc = sqlite3OsDeviceCharacteristics(pPager->fd);
#endif

#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
  if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){
    return -1;
  }
#endif

#ifdef SQLITE_ENABLE_ATOMIC_WRITE
  {
    int nSector = pPager->sectorSize;







|







1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
  int dc;                           /* Device characteristics */

  assert( isOpen(pPager->fd) );
  dc = sqlite3OsDeviceCharacteristics(pPager->fd);
#endif

#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
  if( pPager->dbSize>0 && (dc&SQLITE_IOCAP_BATCH_ATOMIC) ){
    return -1;
  }
#endif

#ifdef SQLITE_ENABLE_ATOMIC_WRITE
  {
    int nSector = pPager->sectorSize;
6479
6480
6481
6482
6483
6484
6485
6486


6487
6488
6489
6490
6491
6492
6493
6494
        rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
      }
      rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
      if( bBatch ){
        if( rc==SQLITE_OK ){
          rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
        }else{


          sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
        }
      }

      if( rc!=SQLITE_OK ){
        assert( rc!=SQLITE_IOERR_BLOCKED );
        goto commit_phase_one_exit;
      }







<
>
>
|







6479
6480
6481
6482
6483
6484
6485

6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
        rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
      }
      rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
      if( bBatch ){
        if( rc==SQLITE_OK ){
          rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);

        }
        if( rc!=SQLITE_OK ){
          sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
        }
      }

      if( rc!=SQLITE_OK ){
        assert( rc!=SQLITE_IOERR_BLOCKED );
        goto commit_phase_one_exit;
      }
Changes to test/malloc3.test.
22
23
24
25
26
27
28











29
30
31
32
33
34
35
# Only run these tests if memory debugging is turned on.
#
if {!$MEMDEBUG} {
   puts "Skipping malloc3 tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test
   return
}













# Do not run these tests with an in-memory journal.
#
# In the pager layer, if an IO or OOM error occurs during a ROLLBACK, or
# when flushing a page to disk due to cache-stress, the pager enters an
# "error state". The only way out of the error state is to unlock the







>
>
>
>
>
>
>
>
>
>
>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Only run these tests if memory debugging is turned on.
#
if {!$MEMDEBUG} {
   puts "Skipping malloc3 tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test
   return
}

# Do not run these tests if F2FS batch writes are supported. In this case,
# it is possible for a single DML statement in an implicit transaction
# to fail with SQLITE_NOMEM, but for the transaction to still end up
# committed to disk. Which confuses the tests in this module.
#
if {[atomic_batch_write test.db]} {
   puts "Skipping malloc3 tests: atomic-batch support"
   finish_test
   return
}


# Do not run these tests with an in-memory journal.
#
# In the pager layer, if an IO or OOM error occurs during a ROLLBACK, or
# when flushing a page to disk due to cache-stress, the pager enters an
# "error state". The only way out of the error state is to unlock the
Changes to test/misc7.test.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# $Id: misc7.test,v 1.29 2009/07/16 18:21:18 drh Exp $

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


if {[clang_sanitize_address]==0} {
  do_test misc7-1-misuse {
    c_misuse_test
  } {}
}








>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# $Id: misc7.test,v 1.29 2009/07/16 18:21:18 drh Exp $

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

if {[clang_sanitize_address]==0} {
  do_test misc7-1-misuse {
    c_misuse_test
  } {}
}

38
39
40
41
42
43
44

45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
    sqlite3 db2 ./mydir
  } msg]
  list $rc $msg
} {1 {unable to open database file}}

# Try to open a file with a directory where its journal file should be.
#

do_test misc7-5 {
  delete_file mydir
  file mkdir mydir-journal
  sqlite3 db2 ./mydir
  catchsql {
    CREATE TABLE abc(a, b, c);
  } db2
} {1 {unable to open database file}}
db2 close


#--------------------------------------------------------------------
# The following tests, misc7-6.* test the libraries behaviour when
# it cannot open a file. To force this condition, we use up all the
# file-descriptors before running sqlite. This probably only works
# on unix.
#







>
|
|
|
|
|
|
|
|
|
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    sqlite3 db2 ./mydir
  } msg]
  list $rc $msg
} {1 {unable to open database file}}

# Try to open a file with a directory where its journal file should be.
#
if {[atomic_batch_write test.db]==0} {
  do_test misc7-5 {
    delete_file mydir
    file mkdir mydir-journal
    sqlite3 db2 ./mydir
    catchsql {
      CREATE TABLE abc(a, b, c);
    } db2
  } {1 {unable to open database file}}
  db2 close
}

#--------------------------------------------------------------------
# The following tests, misc7-6.* test the libraries behaviour when
# it cannot open a file. To force this condition, we use up all the
# file-descriptors before running sqlite. This probably only works
# on unix.
#
517
518
519
520
521
522
523







524




























525
} {1 {attempt to write a readonly database}}
do_test misc7-22.4 { 
  sqlite3_extended_errcode db
} SQLITE_READONLY_ROLLBACK

db close
forcedelete test.db




































finish_test







>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
} {1 {attempt to write a readonly database}}
do_test misc7-22.4 { 
  sqlite3_extended_errcode db
} SQLITE_READONLY_ROLLBACK

db close
forcedelete test.db
if {$::tcl_platform(platform)=="unix"
 && [atomic_batch_write test.db]==0
} {
  reset_db
  do_execsql_test 23.0 {
    CREATE TABLE t1(x, y);
    INSERT INTO t1 VALUES(1, 2);
  }
  
  do_test 23.1 {
    db close
    forcedelete tst
    file mkdir tst
    forcecopy test.db tst/test.db
    file attributes tst -permissions r-xr-xr-x
  } {}
  
  sqlite3 db tst/test.db
  do_execsql_test 23.2 {
    SELECT * FROM t1;
  } {1 2}
  
  do_catchsql_test 23.3 {
    INSERT INTO t1 VALUES(3, 4);
  } {1 {unable to open database file}}
  
  do_test 23.4 {
    sqlite3_extended_errcode db
  } {SQLITE_CANTOPEN}
  
  do_test 23.5 {
    db close
    forcedelete tst
  } {}
}

finish_test
Changes to test/pagerfault.test.
1199
1200
1201
1202
1203
1204
1205

1206
1207
1208
1209
1210
1211

1212
1213
1214
1215
1216
1217
1218
  }
} -test {
  faultsim_test_result {0 {}}

  set contents [db eval {SELECT * FROM t1}]
  if {$contents != "1 2"} { error "Bad database contents ($contents)" }


  set sz [file size test.db]
  if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { 
    error "Expected file size to be 3072 or 12288 bytes - actual size $sz bytes"
  }
  if {$testrc==0 && $sz!=4096*3} { 
    error "Expected file size to be 12288 bytes - actual size $sz bytes"

  }
} 

do_test pagerfault-27-pre {
  faultsim_delete_and_reopen
  db func a_string a_string
  execsql {







>
|
|
|
|
|
|
>







1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
  }
} -test {
  faultsim_test_result {0 {}}

  set contents [db eval {SELECT * FROM t1}]
  if {$contents != "1 2"} { error "Bad database contents ($contents)" }

  if {[atomic_batch_write test.db]==0} {
    set sz [file size test.db]
    if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { 
      error "Expected file size 3072 or 12288 bytes - actual size $sz bytes"
    }
    if {$testrc==0 && $sz!=4096*3} { 
      error "Expected file size to be 12288 bytes - actual size $sz bytes"
    }
  }
} 

do_test pagerfault-27-pre {
  faultsim_delete_and_reopen
  db func a_string a_string
  execsql {
Changes to test/walthread.test.
323
324
325
326
327
328
329

330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382

383
384
385
386
387
388
389
# two do "journal_mode = DELETE".
#
# Each client returns a string of the form "W w, R r", where W is the 
# number of write-transactions performed using a WAL journal, and D is
# the number of write-transactions performed using a rollback journal.
# For example, "192 w, 185 r".
#

do_thread_test2 walthread-2 -seconds $seconds(walthread-2) -init {
  execsql { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE) }
} -thread RB 2 {

  db close
  set nRun 0
  set nDel 0
  while {[tt_continue]} {
    sqlite3 db test.db
    db busy busyhandler
    db eval { SELECT * FROM sqlite_master }
    catch { db eval { PRAGMA journal_mode = DELETE } }
    db eval {
      BEGIN;
      INSERT INTO t1 VALUES(NULL, randomblob(100+$E(pid)));
    }
    incr nRun 1
    incr nDel [file exists test.db-journal]
    if {[file exists test.db-journal] + [file exists test.db-wal] != 1} {
      error "File-system looks bad..."
    }
    db eval COMMIT

    integrity_check
    db close
  }
  list $nRun $nDel
  set {} "[expr $nRun-$nDel] w, $nDel r"

} -thread WAL 2 {
  db close
  set nRun 0
  set nDel 0
  while {[tt_continue]} {
    sqlite3 db test.db
    db busy busyhandler
    db eval { SELECT * FROM sqlite_master }
    catch { db eval { PRAGMA journal_mode = WAL } }
    db eval {
      BEGIN;
      INSERT INTO t1 VALUES(NULL, randomblob(110+$E(pid)));
    }
    incr nRun 1
    incr nDel [file exists test.db-journal]
    if {[file exists test.db-journal] + [file exists test.db-wal] != 1} {
      error "File-system looks bad..."
    }
    db eval COMMIT

    integrity_check
    db close
  }
  set {} "[expr $nRun-$nDel] w, $nDel r"

}

do_thread_test walthread-3 -seconds $seconds(walthread-3) -init {
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);
    CREATE INDEX i1 ON t1(sum1);







>
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>







323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# two do "journal_mode = DELETE".
#
# Each client returns a string of the form "W w, R r", where W is the 
# number of write-transactions performed using a WAL journal, and D is
# the number of write-transactions performed using a rollback journal.
# For example, "192 w, 185 r".
#
if {[atomic_batch_write test.db]==0} {
  do_thread_test2 walthread-2 -seconds $seconds(walthread-2) -init {
    execsql { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE) }
  } -thread RB 2 {

    db close
    set nRun 0
    set nDel 0
    while {[tt_continue]} {
      sqlite3 db test.db
      db busy busyhandler
      db eval { SELECT * FROM sqlite_master }
      catch { db eval { PRAGMA journal_mode = DELETE } }
      db eval {
        BEGIN;
        INSERT INTO t1 VALUES(NULL, randomblob(100+$E(pid)));
      }
      incr nRun 1
      incr nDel [file exists test.db-journal]
      if {[file exists test.db-journal] + [file exists test.db-wal] != 1} {
        error "File-system looks bad..."
      }
      db eval COMMIT
  
      integrity_check
      db close
    }
    list $nRun $nDel
    set {} "[expr $nRun-$nDel] w, $nDel r"
  
  } -thread WAL 2 {
    db close
    set nRun 0
    set nDel 0
    while {[tt_continue]} {
      sqlite3 db test.db
      db busy busyhandler
      db eval { SELECT * FROM sqlite_master }
      catch { db eval { PRAGMA journal_mode = WAL } }
      db eval {
        BEGIN;
        INSERT INTO t1 VALUES(NULL, randomblob(110+$E(pid)));
      }
      incr nRun 1
      incr nDel [file exists test.db-journal]
      if {[file exists test.db-journal] + [file exists test.db-wal] != 1} {
        error "File-system looks bad..."
      }
      db eval COMMIT
  
      integrity_check
      db close
    }
    set {} "[expr $nRun-$nDel] w, $nDel r"
  }
}

do_thread_test walthread-3 -seconds $seconds(walthread-3) -init {
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);
    CREATE INDEX i1 ON t1(sum1);