/ Check-in [16f612d6]
Login

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

Overview
Comment:If the sector size is greater than the database page size, SQLite journals all pages that lie within a sector before writing to any of them. This change ensure that a journal sync does not occur halfway through journalling the set of pages that belong to a single sector. (CVS 5605)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 16f612d61e00938f29ecae4ebfe598be7a8709a8
User & Date: danielk1977 2008-08-25 07:12:29
Context
2008-08-25
11:57
Fix a segfault that can occur when running integrity_check on a corrupt db. (CVS 5606) check-in: eae959ed user: danielk1977 tags: trunk
07:12
If the sector size is greater than the database page size, SQLite journals all pages that lie within a sector before writing to any of them. This change ensure that a journal sync does not occur halfway through journalling the set of pages that belong to a single sector. (CVS 5605) check-in: 16f612d6 user: danielk1977 tags: trunk
2008-08-23
18:53
Instead of marking a page as clean when sqlite3PagerDontWrite() is called, set a dedictated flag - PGHDR_DONT_WRITE. (CVS 5604) check-in: a323bd29 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2437
2438
2439
2440
2441
2442
2443




2444
2445
2446
2447
2448
2449
2450
** 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.477 2008/08/23 18:53:08 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
** object. This function attempts to make a single dirty page that has no
** outstanding references (if one exists) clean so that it can be recycled 
** by the pcache layer.
*/
static int pagerStress(void *p, PgHdr *pPg){
  Pager *pPager = (Pager *)p;
  int rc = SQLITE_OK;





  assert( pPg->flags&PGHDR_DIRTY );
  if( pPager->errCode==SQLITE_OK ){
    if( pPg->flags&PGHDR_NEED_SYNC ){
      rc = syncJournal(pPager);
      if( rc==SQLITE_OK && pPager->fullSync && 
        !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)







|







 







>
>
>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
** 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.478 2008/08/25 07:12:29 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
** object. This function attempts to make a single dirty page that has no
** outstanding references (if one exists) clean so that it can be recycled 
** by the pcache layer.
*/
static int pagerStress(void *p, PgHdr *pPg){
  Pager *pPager = (Pager *)p;
  int rc = SQLITE_OK;

  if( pPager->doNotSync ){
    return SQLITE_OK;
  }

  assert( pPg->flags&PGHDR_DIRTY );
  if( pPager->errCode==SQLITE_OK ){
    if( pPg->flags&PGHDR_NEED_SYNC ){
      rc = syncJournal(pPager);
      if( rc==SQLITE_OK && pPager->fullSync && 
        !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)

Changes to src/pcache.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
450
451
452
453
454
455
456

















457
458
459
460
461
462
463
...
465
466
467
468
469
470
471

472



473
474


475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
**    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 implements that page cache.
**
** @(#) $Id: pcache.c,v 1.11 2008/08/23 18:53:08 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** A complete page cache is an instance of this structure.
*/
struct PCache {
................................................................................
  assert( !pcache.pStart );
  assert( p->apSave[0]==0 );
  assert( p->apSave[1]==0 );
  assert( p && p->pCache );
  return sqlite3MallocSize(p);
}
#endif


















/*
** Recycle a page from the global LRU list. If no page can be recycled, 
** return NULL. Otherwise, the pointer returned points to a PgHdr 
** object that has been removed from all lists and hash tables in
** which is was referenced. The caller may reuse the allocation directly
** or may pass it to pcachePageFree() to return the memory to the heap
................................................................................
*/ 
static PgHdr *pcacheRecycle(PCache *pCache){
  PgHdr *p = 0;

  assert( pcache.isInit );
  assert( sqlite3_mutex_held(pcache.mutex_lru) );


  p = pcache.pLruSynced;



  if( !p ){
    p = pcache.pLruTail;


  }
  if( p && (p->flags&PGHDR_DIRTY) ){
    if( SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){
      PCache *pC = p->pCache;
      assert( pC->iInUseMM==0 );
      pC->iInUseMM = 1;
      if( pC->xStress && (pC->iInUseDB==0 || pC==pCache) ){
        pcacheExitGlobal();
        pC->xStress(pC->pStress, p);
        pcacheEnterGlobal();
      }
      pC->iInUseMM = 0;
      sqlite3_mutex_leave(pcache.mutex_mem2);
    }
  }
  if( p && (p->flags&PGHDR_DIRTY) ){
    p = 0;
  }

  if( p ){
    pcacheRemoveFromLruList(p);
    pcacheRemoveFromHash(p);
    pcacheRemoveFromList(&p->pCache->pClean, p);








|







 







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







 







>
|
>
>
>
|
|
>
>
|
<
<
<
<
<
<
<
<
<
|
<
|
<
<
<
<







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
...
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498









499

500




501
502
503
504
505
506
507
**    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 implements that page cache.
**
** @(#) $Id: pcache.c,v 1.12 2008/08/25 07:12:29 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** A complete page cache is an instance of this structure.
*/
struct PCache {
................................................................................
  assert( !pcache.pStart );
  assert( p->apSave[0]==0 );
  assert( p->apSave[1]==0 );
  assert( p && p->pCache );
  return sqlite3MallocSize(p);
}
#endif

static int pcacheRecyclePage(PgHdr *p, PCache *pCache){
  assert( sqlite3_mutex_held(pcache.mutex_lru) );
  assert( sqlite3_mutex_held(pcache.mutex_mem2) );

  PCache *pC = p->pCache;
  assert( pC->iInUseMM==0 );
  pC->iInUseMM = 1;
  if( pC->xStress && (pC->iInUseDB==0 || pC==pCache) ){
    pcacheExitGlobal();
    pC->xStress(pC->pStress, p);
    pcacheEnterGlobal();
  }
  pC->iInUseMM = 0;

  return (p->flags&PGHDR_DIRTY);
}

/*
** Recycle a page from the global LRU list. If no page can be recycled, 
** return NULL. Otherwise, the pointer returned points to a PgHdr 
** object that has been removed from all lists and hash tables in
** which is was referenced. The caller may reuse the allocation directly
** or may pass it to pcachePageFree() to return the memory to the heap
................................................................................
*/ 
static PgHdr *pcacheRecycle(PCache *pCache){
  PgHdr *p = 0;

  assert( pcache.isInit );
  assert( sqlite3_mutex_held(pcache.mutex_lru) );

  if( SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){
    p = pcache.pLruSynced;
    while( p && (p->flags&PGHDR_DIRTY) && pcacheRecyclePage(p, pCache) ){
      do { p = p->pPrevLru; } while( p && (p->flags&PGHDR_NEED_SYNC) );
    }
    if( !p ){
      p = pcache.pLruTail;
      while( p && (p->flags&PGHDR_DIRTY) && pcacheRecyclePage(p, pCache) ){
        do { p = p->pPrevLru; } while( p && 0==(p->flags&PGHDR_NEED_SYNC) );
      }









    }

    sqlite3_mutex_leave(pcache.mutex_mem2);




  }

  if( p ){
    pcacheRemoveFromLruList(p);
    pcacheRemoveFromHash(p);
    pcacheRemoveFromList(&p->pCache->pClean, p);

Changes to test/crash2.test.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
..
89
90
91
92
93
94
95

96
97
98
99
100
101
102
#
# The focus of this file is testing the ability of the database to
# uses its rollback journal to recover intact (no database corruption)
# from a power failure during the middle of a COMMIT. Even more
# specifically, the tests in this file verify this functionality
# for storage mediums with various sector sizes.
#
# $Id: crash2.test,v 1.5 2007/08/24 11:52:29 danielk1977 Exp $

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

ifcapable !crashtest {
  finish_test
  return
................................................................................
} {1}
for {set i 1} {$i < 30} {incr i} {
  set sig [signature]
  set sector [expr 1024 * 1<<($i%4)]
  db close
  do_test crash2-2.$i.1 {
     crashsql -blocksize $sector -delay [expr $i%5 + 1] -file test.db-journal "

       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc SELECT randstr(10,10), 0, 0 FROM abc WHERE random()%2==0;
       DELETE FROM abc WHERE random()%2!=0;
       COMMIT;
     "
  } {1 {child process exited abnormally}}







|







 







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#
# The focus of this file is testing the ability of the database to
# uses its rollback journal to recover intact (no database corruption)
# from a power failure during the middle of a COMMIT. Even more
# specifically, the tests in this file verify this functionality
# for storage mediums with various sector sizes.
#
# $Id: crash2.test,v 1.6 2008/08/25 07:12:29 danielk1977 Exp $

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

ifcapable !crashtest {
  finish_test
  return
................................................................................
} {1}
for {set i 1} {$i < 30} {incr i} {
  set sig [signature]
  set sector [expr 1024 * 1<<($i%4)]
  db close
  do_test crash2-2.$i.1 {
     crashsql -blocksize $sector -delay [expr $i%5 + 1] -file test.db-journal "
       PRAGMA temp_store = memory;
       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc SELECT randstr(10,10), 0, 0 FROM abc WHERE random()%2==0;
       DELETE FROM abc WHERE random()%2!=0;
       COMMIT;
     "
  } {1 {child process exited abnormally}}