/ Check-in [bb177e30]
Login

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

Overview
Comment:Add a case to permutations.test to run tests with the test_journal.c backend installed. Also many fixes to test_journal.c and one quite obscure fix to pager.c. (CVS 6052)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: bb177e3072ab61d0af7af91660ebe4dafa487b42
User & Date: danielk1977 2008-12-22 10:58:46
Context
2008-12-22
11:43
Changes to test scripts so that veryquick.test runs with SQLITE_TEMP_STORE=3 defined. Also a fix to stop the same switch causing a crash in the savepoint code. (CVS 6053) check-in: ee0e6eae user: danielk1977 tags: trunk
10:58
Add a case to permutations.test to run tests with the test_journal.c backend installed. Also many fixes to test_journal.c and one quite obscure fix to pager.c. (CVS 6052) check-in: bb177e30 user: danielk1977 tags: trunk
03:37
Fix a variable type to prevent a warning in the proxy-locking code. (CVS 6051) check-in: d9595b96 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

367
368
369
370
371
372
373

374
375
376
377
378
379
380
  $(TOP)/src/test_autoext.c \
  $(TOP)/src/test_async.c \
  $(TOP)/src/test_btree.c \
  $(TOP)/src/test_config.c \
  $(TOP)/src/test_devsym.c \
  $(TOP)/src/test_func.c \
  $(TOP)/src/test_hexio.c \

  $(TOP)/src/test_malloc.c \
  $(TOP)/src/test_md5.c \
  $(TOP)/src/test_mutex.c \
  $(TOP)/src/test_onefile.c \
  $(TOP)/src/test_osinst.c \
  $(TOP)/src/test_pcache.c \
  $(TOP)/src/test_schema.c \







>







367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
  $(TOP)/src/test_autoext.c \
  $(TOP)/src/test_async.c \
  $(TOP)/src/test_btree.c \
  $(TOP)/src/test_config.c \
  $(TOP)/src/test_devsym.c \
  $(TOP)/src/test_func.c \
  $(TOP)/src/test_hexio.c \
  $(TOP)/src/test_journal.c \
  $(TOP)/src/test_malloc.c \
  $(TOP)/src/test_md5.c \
  $(TOP)/src/test_mutex.c \
  $(TOP)/src/test_onefile.c \
  $(TOP)/src/test_osinst.c \
  $(TOP)/src/test_pcache.c \
  $(TOP)/src/test_schema.c \

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
3275
3276
3277
3278
3279
3280
3281











3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
....
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
** 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.519 2008/12/20 08:39:57 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
        }
        IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, 
                 pPager->journalOff, pPager->pageSize));
        PAGER_INCR(sqlite3_pager_writej_count);
        PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n",
             PAGERID(pPager), pPg->pgno, 
             ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg));












        /* An error has occured writing to the journal file. The 
        ** transaction will be rolled back by the layer above.
        */
        if( rc!=SQLITE_OK ){
          return rc;
        }

        pPager->nRec++;
        assert( pPager->pInJournal!=0 );
        sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
        if( !pPager->noSync ){
          pPg->flags |= PGHDR_NEED_SYNC;
        }
        addToSavepointBitvecs(pPager, pPg->pgno);
      }else{
        if( !pPager->journalStarted && !pPager->noSync ){
          pPg->flags |= PGHDR_NEED_SYNC;
        }
        PAGERTRACE4("APPEND %d page %d needSync=%d\n",
                PAGERID(pPager), pPg->pgno,
................................................................................
    int nNew = iSavepoint + (op==SAVEPOINT_ROLLBACK);
    for(ii=nNew; ii<pPager->nSavepoint; ii++){
      sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
    }
    pPager->nSavepoint = nNew;

    if( op==SAVEPOINT_ROLLBACK ){
      PagerSavepoint *pSavepoint = (nNew==0) ? 0 : &pPager->aSavepoint[nNew-1];
      rc = pagerPlaybackSavepoint(pPager, pSavepoint);
      assert(rc!=SQLITE_DONE);
    }

    /* If this is a release of the outermost savepoint, truncate 
    ** the sub-journal. */
    if( nNew==0 && op==SAVEPOINT_RELEASE && pPager->sjfd->pMethods ){
      assert( rc==SQLITE_OK );
      rc = sqlite3OsTruncate(pPager->sjfd, 0);
      pPager->stmtNRec = 0;
    }







|







 







>
>
>
>
>
>
>
>
>
>
>











<
<
<







 







|



|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303



3304
3305
3306
3307
3308
3309
3310
....
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
** 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.520 2008/12/22 10:58:46 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
        }
        IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, 
                 pPager->journalOff, pPager->pageSize));
        PAGER_INCR(sqlite3_pager_writej_count);
        PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n",
             PAGERID(pPager), pPg->pgno, 
             ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg));

        /* Even if an IO or diskfull error occurred while journalling the
        ** page in the block above, set the need-sync flag for the page.
        ** Otherwise, when the transaction is rolled back, the logic in
        ** playback_one_page() will think that the page needs to be restored
        ** in the database file. And if an IO error occurs while doing so,
        ** then corruption may follow.
        */
        if( !pPager->noSync ){
          pPg->flags |= PGHDR_NEED_SYNC;
        }

        /* An error has occured writing to the journal file. The 
        ** transaction will be rolled back by the layer above.
        */
        if( rc!=SQLITE_OK ){
          return rc;
        }

        pPager->nRec++;
        assert( pPager->pInJournal!=0 );
        sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);



        addToSavepointBitvecs(pPager, pPg->pgno);
      }else{
        if( !pPager->journalStarted && !pPager->noSync ){
          pPg->flags |= PGHDR_NEED_SYNC;
        }
        PAGERTRACE4("APPEND %d page %d needSync=%d\n",
                PAGERID(pPager), pPg->pgno,
................................................................................
    int nNew = iSavepoint + (op==SAVEPOINT_ROLLBACK);
    for(ii=nNew; ii<pPager->nSavepoint; ii++){
      sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
    }
    pPager->nSavepoint = nNew;

    if( op==SAVEPOINT_ROLLBACK ){
      PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1];
      rc = pagerPlaybackSavepoint(pPager, pSavepoint);
      assert(rc!=SQLITE_DONE);
    }
  
    /* If this is a release of the outermost savepoint, truncate 
    ** the sub-journal. */
    if( nNew==0 && op==SAVEPOINT_RELEASE && pPager->sjfd->pMethods ){
      assert( rc==SQLITE_OK );
      rc = sqlite3OsTruncate(pPager->sjfd, 0);
      pPager->stmtNRec = 0;
    }

Changes to src/test_journal.c.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
...
129
130
131
132
133
134
135





136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
...
179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
194
195
196
197
198
199

200
201
202
203
204
205
206
207
208
209
210


211
212
213
214
215
216
217
...
245
246
247
248
249
250
251
252
253
254
255
256

257



258



259
260
261
262
263
264
265
266
267
268
269
270
271
272
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291

292
293
294
295
296
297
298
299
300
301

302

303
304
305



306
307
308

309
310
311

312
313
314
315


316
317
318
319
320
321
322
323
324

325
326
327
328
329
330
331
332
333
334
335
336

337




338
339
340
341
342
343
344
...
422
423
424
425
426
427
428

429
430
431
432
433
434
435
...
440
441
442
443
444
445
446
447
448

449
450
451
452
453
454
455
** bug in SQLite - writing data to a database file page when:
**
**   a) the original page data is not stored in a synced portion of the
**      journal file, and
**   b) the page was not a free-list leaf page when the transaction was
**      first opened.
**
** $Id: test_journal.c,v 1.1 2008/12/20 18:33:59 danielk1977 Exp $
*/
#if SQLITE_TEST          /* This file is used for testing only */

#include "sqlite3.h"
#include "sqliteInt.h"

/*
................................................................................
};

struct JtGlobal {
  sqlite3_vfs *pVfs;
  jt_file *pList;
};
static struct JtGlobal g = {0, 0};






/*
** Close an jt-file.
*/
static int jtClose(sqlite3_file *pFile){
  jt_file **pp;
  jt_file *p = (jt_file *)pFile;

  if( p->zName ){
    for(pp=&g.pList; *pp!=p; *pp=(*pp)->pNext);
    *pp = p->pNext;
  }

  return sqlite3OsClose(p->pReal);
}

/*
................................................................................
}


static u32 decodeUint32(const unsigned char *z){
  return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
}

static void readFreelist(jt_file *pMain){

  sqlite3_file *p = pMain->pReal;
  sqlite3_int64 iSize;

  sqlite3OsFileSize(p, &iSize);
  if( iSize>=pMain->nPagesize ){
    unsigned char *zBuf = (unsigned char *)malloc(pMain->nPagesize);
    u32 iTrunk;

    sqlite3OsRead(p, zBuf, pMain->nPagesize, 0);
    iTrunk = decodeUint32(&zBuf[32]);
    while( iTrunk>0 ){
      u32 nLeaf;
      u32 iLeaf;

      sqlite3OsRead(p, zBuf, pMain->nPagesize, (iTrunk-1)*pMain->nPagesize);
      nLeaf = decodeUint32(&zBuf[4]);
      for(iLeaf=0; iLeaf<nLeaf; iLeaf++){
        u32 pgno = decodeUint32(&zBuf[8+4*iLeaf]);
        sqlite3BitvecSet(pMain->pWritable, pgno);
      }
      iTrunk = decodeUint32(zBuf);
    }

    free(zBuf);
  }


}

/*
** The first argument, zBuf, points to a buffer containing a 28 byte
** serialized journal header. This function deserializes four of the
** integer fields contained in the journal header and writes their
** values to the output variables.
................................................................................
  if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && iOfst==0 ){
    jt_file *pMain = locateDatabaseHandle(p->zName);
    assert( pMain );

    if( decodeJournalHdr(zBuf, 0, &pMain->nPage, 0, &pMain->nPagesize) ){
      /* Zeroing the first journal-file header. This is the end of a
      ** transaction. */
      sqlite3BitvecDestroy(pMain->pWritable);
      pMain->pWritable = 0;
    }else{
      /* Writing the first journal header to a journal file. This happens
      ** when a transaction is first started.  */

      pMain->pWritable = sqlite3BitvecCreate(pMain->nPage);



      readFreelist(pMain);



    }
  }

  if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
    u32 pgno;
    assert( iAmt==p->nPagesize );
    pgno = iOfst/p->nPagesize + 1;
    assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) );
  }

  return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}

/*
................................................................................
** Truncate an jt-file.
*/
static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){
  jt_file *p = (jt_file *)pFile;
  if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){
    /* Truncating a journal file. This is the end of a transaction. */
    jt_file *pMain = locateDatabaseHandle(p->zName);
    sqlite3BitvecDestroy(pMain->pWritable);
    pMain->pWritable = 0;
  }
  return sqlite3OsTruncate(p->pReal, size);
}

/*
** The first argument to this function is a handle open on a journal file.
** This function reads the journal file and adds the page number for each
** page in the journal to the Bitvec object passed as the second argument.
*/
static void readJournalFile(jt_file *p, jt_file *pMain){

  unsigned char zBuf[28];
  sqlite3_file *pReal = p->pReal;
  sqlite3_int64 iOff = 0;
  sqlite3_int64 iSize = 0;

  sqlite3OsFileSize(p->pReal, &iSize);
  while( iOff<iSize ){
    u32 nRec, nPage, nSector, nPagesize;
    u32 ii;
    sqlite3OsRead(pReal, zBuf, 28, iOff);

    if( decodeJournalHdr(zBuf, &nRec, &nPage, &nSector, &nPagesize) ){

      return;
    }
    iOff += nSector;



    for(ii=0; ii<nRec && iOff<iSize; ii++){
      u32 pgno;
      sqlite3OsRead(pReal, zBuf, 4, iOff);

      pgno = decodeUint32(zBuf);
      iOff += (8 + pMain->nPagesize);
      sqlite3BitvecSet(pMain->pWritable, pgno);

    }

    iOff = ((iOff + (nSector-1)) / nSector) * nSector;
  }


}

/*
** Sync an jt-file.
*/
static int jtSync(sqlite3_file *pFile, int flags){
  jt_file *p = (jt_file *)pFile;

  if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){

    jt_file *pMain;                   /* The associated database file */

    /* The journal file is being synced. At this point, we inspect the 
    ** contents of the file up to this point and set each bit in the 
    ** jt_file.pWritable bitvec of the main database file associated with
    ** this journal file.
    */
    pMain = locateDatabaseHandle(p->zName);
    assert(pMain);
    assert(pMain->pWritable);

    /* Set the bitvec values */

    readJournalFile(p, pMain);




  }

  return sqlite3OsSync(p->pReal, flags);
}

/*
** Return the current file-size of an jt-file.
................................................................................
  rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
  if( p->pReal->pMethods ){
    pFile->pMethods = &jt_io_methods;
    p->eLock = 0;
    p->zName = zName;
    p->flags = flags;
    p->pNext = 0;

    if( zName ){
      p->pNext = g.pList;
      g.pList = p;
    }
  }
  return rc;
}
................................................................................
** returning.
*/
static int jtDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  int nPath = strlen(zPath);
  if( nPath>8 && 0==strcmp("-journal", &zPath[nPath-8]) ){
    /* Deleting a journal file. The end of a transaction. */
    jt_file *pMain = locateDatabaseHandle(zPath);
    sqlite3BitvecDestroy(pMain->pWritable);
    pMain->pWritable = 0;

  }

  return sqlite3OsDelete(g.pVfs, zPath, dirSync);
}

/*
** Test for access permissions. Return true if the requested permission







|







 







>
>
>
>
>









|







 







|
>



|
|



|

|


>
|

|








>
>







 







|
<



>

>
>
>
|
>
>
>



|
<
<
|







 







|
<









|
>





|
|


|
>
|
>
|


>
>
>
|

|
>
|
|
|
>




>
>









>









<


>
|
>
>
>
>







 







>







 







|
|
>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
...
254
255
256
257
258
259
260
261

262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277


278
279
280
281
282
283
284
285
...
286
287
288
289
290
291
292
293

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
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
...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
...
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
** bug in SQLite - writing data to a database file page when:
**
**   a) the original page data is not stored in a synced portion of the
**      journal file, and
**   b) the page was not a free-list leaf page when the transaction was
**      first opened.
**
** $Id: test_journal.c,v 1.2 2008/12/22 10:58:46 danielk1977 Exp $
*/
#if SQLITE_TEST          /* This file is used for testing only */

#include "sqlite3.h"
#include "sqliteInt.h"

/*
................................................................................
};

struct JtGlobal {
  sqlite3_vfs *pVfs;
  jt_file *pList;
};
static struct JtGlobal g = {0, 0};

static void closeTransaction(jt_file *p){
  sqlite3BitvecDestroy(p->pWritable);
  p->pWritable = 0;
}

/*
** Close an jt-file.
*/
static int jtClose(sqlite3_file *pFile){
  jt_file **pp;
  jt_file *p = (jt_file *)pFile;

  if( p->zName ){
    for(pp=&g.pList; *pp!=p; pp=&(*pp)->pNext);
    *pp = p->pNext;
  }

  return sqlite3OsClose(p->pReal);
}

/*
................................................................................
}


static u32 decodeUint32(const unsigned char *z){
  return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
}

static int readFreelist(jt_file *pMain){
  int rc;
  sqlite3_file *p = pMain->pReal;
  sqlite3_int64 iSize;

  rc = sqlite3OsFileSize(p, &iSize);
  if( rc==SQLITE_OK && iSize>=pMain->nPagesize ){
    unsigned char *zBuf = (unsigned char *)malloc(pMain->nPagesize);
    u32 iTrunk;

    rc = sqlite3OsRead(p, zBuf, pMain->nPagesize, 0);
    iTrunk = decodeUint32(&zBuf[32]);
    while( rc==SQLITE_OK && iTrunk>0 ){
      u32 nLeaf;
      u32 iLeaf;
      sqlite3_int64 iOff = (iTrunk-1)*pMain->nPagesize;
      rc = sqlite3OsRead(p, zBuf, pMain->nPagesize, iOff);
      nLeaf = decodeUint32(&zBuf[4]);
      for(iLeaf=0; rc==SQLITE_OK && iLeaf<nLeaf; iLeaf++){
        u32 pgno = decodeUint32(&zBuf[8+4*iLeaf]);
        sqlite3BitvecSet(pMain->pWritable, pgno);
      }
      iTrunk = decodeUint32(zBuf);
    }

    free(zBuf);
  }

  return rc;
}

/*
** The first argument, zBuf, points to a buffer containing a 28 byte
** serialized journal header. This function deserializes four of the
** integer fields contained in the journal header and writes their
** values to the output variables.
................................................................................
  if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && iOfst==0 ){
    jt_file *pMain = locateDatabaseHandle(p->zName);
    assert( pMain );

    if( decodeJournalHdr(zBuf, 0, &pMain->nPage, 0, &pMain->nPagesize) ){
      /* Zeroing the first journal-file header. This is the end of a
      ** transaction. */
      closeTransaction(pMain);

    }else{
      /* Writing the first journal header to a journal file. This happens
      ** when a transaction is first started.  */
      int rc;
      pMain->pWritable = sqlite3BitvecCreate(pMain->nPage);
      if( !pMain->pWritable ){
	return SQLITE_IOERR_NOMEM;
      }
      rc = readFreelist(pMain);
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }

  if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable && iAmt==p->nPagesize ){


    u32 pgno = iOfst/p->nPagesize + 1;
    assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) );
  }

  return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}

/*
................................................................................
** Truncate an jt-file.
*/
static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){
  jt_file *p = (jt_file *)pFile;
  if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){
    /* Truncating a journal file. This is the end of a transaction. */
    jt_file *pMain = locateDatabaseHandle(p->zName);
    closeTransaction(pMain);

  }
  return sqlite3OsTruncate(p->pReal, size);
}

/*
** The first argument to this function is a handle open on a journal file.
** This function reads the journal file and adds the page number for each
** page in the journal to the Bitvec object passed as the second argument.
*/
static int readJournalFile(jt_file *p, jt_file *pMain){
  int rc;
  unsigned char zBuf[28];
  sqlite3_file *pReal = p->pReal;
  sqlite3_int64 iOff = 0;
  sqlite3_int64 iSize = 0;

  rc = sqlite3OsFileSize(p->pReal, &iSize);
  while( rc==SQLITE_OK && iOff<iSize ){
    u32 nRec, nPage, nSector, nPagesize;
    u32 ii;
    rc = sqlite3OsRead(pReal, zBuf, 28, iOff);
    if( rc!=SQLITE_OK 
     || decodeJournalHdr(zBuf, &nRec, &nPage, &nSector, &nPagesize) 
    ){
      return rc;
    }
    iOff += nSector;
    if( nRec==0 ){
      nRec = (iSize - iOff)/(pMain->nPagesize + 8);
    }
    for(ii=0; rc==SQLITE_OK && ii<nRec && iOff<iSize; ii++){
      u32 pgno;
      rc = sqlite3OsRead(pReal, zBuf, 4, iOff);
      if( rc==SQLITE_OK ){
        pgno = decodeUint32(zBuf);
        iOff += (8 + pMain->nPagesize);
        sqlite3BitvecSet(pMain->pWritable, pgno);
      }
    }

    iOff = ((iOff + (nSector-1)) / nSector) * nSector;
  }

  return rc;
}

/*
** Sync an jt-file.
*/
static int jtSync(sqlite3_file *pFile, int flags){
  jt_file *p = (jt_file *)pFile;

  if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){
    int rc;
    jt_file *pMain;                   /* The associated database file */

    /* The journal file is being synced. At this point, we inspect the 
    ** contents of the file up to this point and set each bit in the 
    ** jt_file.pWritable bitvec of the main database file associated with
    ** this journal file.
    */
    pMain = locateDatabaseHandle(p->zName);
    assert(pMain);


    /* Set the bitvec values */
    if( pMain->pWritable ){
      rc = readJournalFile(p, pMain);
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }

  return sqlite3OsSync(p->pReal, flags);
}

/*
** Return the current file-size of an jt-file.
................................................................................
  rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
  if( p->pReal->pMethods ){
    pFile->pMethods = &jt_io_methods;
    p->eLock = 0;
    p->zName = zName;
    p->flags = flags;
    p->pNext = 0;
    p->pWritable = 0;
    if( zName ){
      p->pNext = g.pList;
      g.pList = p;
    }
  }
  return rc;
}
................................................................................
** returning.
*/
static int jtDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  int nPath = strlen(zPath);
  if( nPath>8 && 0==strcmp("-journal", &zPath[nPath-8]) ){
    /* Deleting a journal file. The end of a transaction. */
    jt_file *pMain = locateDatabaseHandle(zPath);
    if( pMain ){
      closeTransaction(pMain);
    }
  }

  return sqlite3OsDelete(g.pVfs, zPath, dirSync);
}

/*
** Test for access permissions. Return true if the requested permission

Changes to test/permutations.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
...
700
701
702
703
704
705
706















707
708
709
710
711
712
713
#
#    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.
#
#***********************************************************************
#
# $Id: permutations.test,v 1.39 2008/11/19 01:20:26 drh Exp $

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

# Argument processing.
#
#puts "PERM-DEBUG: argv=$argv"
................................................................................
  set ::perm::testmode [list persistent_journal no_journal autovacuum_ioerr]
  set ISQUICK 1
}
if {$::perm::testmode eq "all" || $::perm::testmode eq ""} {
  set ::perm::testmode {
    memsubsys1 memsubsys2 singlethread multithread onefile utf16 exclusive
    persistent_journal persistent_journal_error no_journal no_journal_error
    autovacuum_ioerr no_mutex_try fullmutex
  }
}
if {$::perm::testmode eq "targets"} { 
  puts ""
  puts -nonewline "veryquick            "
  puts "Same as persistent_journal and no_journal"
  puts -nonewline "quick                "
................................................................................
} -shutdown {
  catch {db close}
  sqlite3_reset_auto_extension
  sqlite3_shutdown
  sqlite3_config_alt_pcache 0 0 0
  sqlite3_initialize
} -include ${perm-alt-pcache-testset}
















# End of tests
#############################################################################

if {$::perm::testmode eq "targets"} { puts "" ; exit }

# Restore the [sqlite3] command.







|







 







|







 







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







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
...
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
#
#    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.
#
#***********************************************************************
#
# $Id: permutations.test,v 1.40 2008/12/22 10:58:46 danielk1977 Exp $

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

# Argument processing.
#
#puts "PERM-DEBUG: argv=$argv"
................................................................................
  set ::perm::testmode [list persistent_journal no_journal autovacuum_ioerr]
  set ISQUICK 1
}
if {$::perm::testmode eq "all" || $::perm::testmode eq ""} {
  set ::perm::testmode {
    memsubsys1 memsubsys2 singlethread multithread onefile utf16 exclusive
    persistent_journal persistent_journal_error no_journal no_journal_error
    autovacuum_ioerr no_mutex_try fullmutex journaltest
  }
}
if {$::perm::testmode eq "targets"} { 
  puts ""
  puts -nonewline "veryquick            "
  puts "Same as persistent_journal and no_journal"
  puts -nonewline "quick                "
................................................................................
} -shutdown {
  catch {db close}
  sqlite3_reset_auto_extension
  sqlite3_shutdown
  sqlite3_config_alt_pcache 0 0 0
  sqlite3_initialize
} -include ${perm-alt-pcache-testset}

run_tests "journaltest" -description {
  Check that pages are synced before being written (test_journal.c).
} -initialize {
  set ISQUICK 1
  catch {db close}
  register_jt_vfs -default ""
} -shutdown {
  unregister_jt_vfs
} -exclude [concat $EXCLUDE {
  incrvacuum.test
  ioerr.test
  corrupt4.test 
  io.test 
}]

# End of tests
#############################################################################

if {$::perm::testmode eq "targets"} { puts "" ; exit }

# Restore the [sqlite3] command.

Changes to test/savepoint2.test.

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
...
145
146
147
148
149
150
151
152
153
154
155
#
#    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.
#
#***********************************************************************
#
# $Id: savepoint2.test,v 1.3 2008/12/20 18:33:59 danielk1977 Exp $

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

# Tests in this file are quite similar to those run by trans.test and
# avtrans.test.
#

db close
register_jt_vfs -default ""
sqlite3 db test.db -vfs jt

proc signature {} {
  return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}

do_test savepoint2-1 {
  execsql {
    PRAGMA cache_size=10;
................................................................................
  } {1}
  integrity_check savepoint2-$ii.6.1
}

unset -nocomplain ::sig
unset -nocomplain SQL

unregister_jt_vfs

finish_test








|








<
<
<
<







 







<
<


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20




21
22
23
24
25
26
27
...
141
142
143
144
145
146
147


148
149
#
#    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.
#
#***********************************************************************
#
# $Id: savepoint2.test,v 1.4 2008/12/22 10:58:46 danielk1977 Exp $

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

# Tests in this file are quite similar to those run by trans.test and
# avtrans.test.
#





proc signature {} {
  return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}

do_test savepoint2-1 {
  execsql {
    PRAGMA cache_size=10;
................................................................................
  } {1}
  integrity_check savepoint2-$ii.6.1
}

unset -nocomplain ::sig
unset -nocomplain SQL



finish_test

Changes to test/trans.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is database locks.
#
# $Id: trans.test,v 1.38 2008/04/19 20:34:19 drh Exp $


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


# Create several tables to work with.
#
do_test trans-1.0 {
  execsql {
    CREATE TABLE one(a int PRIMARY KEY, b text);
    INSERT INTO one VALUES(1,'one');







|




<







7
8
9
10
11
12
13
14
15
16
17
18

19
20
21
22
23
24
25
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is database locks.
#
# $Id: trans.test,v 1.39 2008/12/22 10:58:46 danielk1977 Exp $


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


# Create several tables to work with.
#
do_test trans-1.0 {
  execsql {
    CREATE TABLE one(a int PRIMARY KEY, b text);
    INSERT INTO one VALUES(1,'one');