Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Some fixes and test cases for exclusive access mode. (CVS 3714) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
899e60707bea0fabab2ff3ac8a3fbb67 |
User & Date: | danielk1977 2007-03-26 08:05:12.000 |
Context
2007-03-26
| ||
08:41 | Add some documentation for pragma locking_mode. (CVS 3715) (check-in: 394b174e59 user: danielk1977 tags: trunk) | |
08:05 | Some fixes and test cases for exclusive access mode. (CVS 3714) (check-in: 899e60707b user: danielk1977 tags: trunk) | |
2007-03-25
| ||
19:08 | Add the sqlite3_prepare_v2 and sqlite3_prepare16_v2 APIs to the loadable extension interface. (CVS 3713) (check-in: f02ba56d5c user: drh tags: trunk) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** 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. ** | | | 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.295 2007/03/26 08:05:12 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
868 869 870 871 872 873 874 | } /* ** Execute a rollback if a transaction is active and unlock the ** database file. This is a no-op if the pager has already entered ** the error-state. */ | | | | | | > > | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 | } /* ** Execute a rollback if a transaction is active and unlock the ** database file. This is a no-op if the pager has already entered ** the error-state. */ static void pagerUnlockAndRollback(Pager *p){ if( p->errCode ) return; if( p->state>=PAGER_RESERVED ){ sqlite3PagerRollback(p); } pager_unlock(p); assert( p->errCode || !p->journalOpen || (p->exclusiveMode&&!p->journalOff) ); assert( p->errCode || !p->stmtOpen || p->exclusiveMode ); } /* ** Unlock the database and clear the in-memory cache. This routine ** sets the state of the pager back to what it was when it was first ** opened. Any outstanding pages are invalidated and subsequent attempts |
︙ | ︙ | |||
920 921 922 923 924 925 926 | PgHdr *pPg; int rc = SQLITE_OK; assert( !MEMDB ); if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } sqlite3PagerStmtCommit(pPager); | | > > > > > | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 | PgHdr *pPg; int rc = SQLITE_OK; assert( !MEMDB ); if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } sqlite3PagerStmtCommit(pPager); if( pPager->stmtOpen && !pPager->exclusiveMode ){ if( pPager->exclusiveMode ){ sqlite3OsClose(&pPager->stfd); pPager->stmtOpen = 0; }else{ sqlite3OsTruncate(pPager->stfd, 0); } } if( pPager->journalOpen ){ if( pPager->exclusiveMode ){ sqlite3OsTruncate(pPager->jfd, 0); sqlite3OsSeek(pPager->jfd, 0); pPager->journalOff = 0; pPager->journalStarted = 0; }else{ sqlite3OsClose(&pPager->jfd); pPager->journalOpen = 0; sqlite3OsDelete(pPager->zJournal); } sqliteFree( pPager->aInJournal ); pPager->aInJournal = 0; |
︙ | ︙ | |||
955 956 957 958 959 960 961 | }else{ assert( pPager->aInJournal==0 ); assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } if( !pPager->exclusiveMode ){ rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; | | < < < < | < < > | 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 | }else{ assert( pPager->aInJournal==0 ); assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } if( !pPager->exclusiveMode ){ rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; }else if( pPager->state==PAGER_SYNCED ){ pPager->state = PAGER_EXCLUSIVE; } pPager->origDbSize = 0; pPager->setMaster = 0; pPager->needSync = 0; pPager->pFirstSynced = pPager->pFirst; pPager->dbSize = -1; return rc; } |
︙ | ︙ | |||
1319 1320 1321 1322 1323 1324 1325 | char *zMaster = 0; /* Name of master journal file if any */ /* Figure out how many records are in the journal. Abort early if ** the journal is empty. */ assert( pPager->journalOpen ); rc = sqlite3OsFileSize(pPager->jfd, &szJ); | | | 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 | char *zMaster = 0; /* Name of master journal file if any */ /* Figure out how many records are in the journal. Abort early if ** the journal is empty. */ assert( pPager->journalOpen ); rc = sqlite3OsFileSize(pPager->jfd, &szJ); if( rc!=SQLITE_OK || szJ==0 ){ goto end_playback; } /* Read the master journal name from the journal, if it is present. ** If a master journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. |
︙ | ︙ | |||
2797 2798 2799 2800 2801 2802 2803 | assert( pPager!=0 ); *ppPage = 0; if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ return pPager->errCode; } /* If this is the first page accessed, then get a SHARED lock | | > | 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 | assert( pPager!=0 ); *ppPage = 0; if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ return pPager->errCode; } /* If this is the first page accessed, then get a SHARED lock ** on the database file. pagerSharedLock() is a no-op if ** a database lock is already held. */ rc = pagerSharedLock(pPager); if( rc!=SQLITE_OK ){ return rc; } assert( pPager->state!=PAGER_UNLOCK ); |
︙ | ︙ | |||
2944 2945 2946 2947 2948 2949 2950 2951 2952 | DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ PgHdr *pPg; assert( pPager!=0 ); assert( pgno!=0 ); if( pPager->state==PAGER_UNLOCK ){ return 0; } | > | | 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 | DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ PgHdr *pPg; assert( pPager!=0 ); assert( pgno!=0 ); if( pPager->state==PAGER_UNLOCK ){ assert( !pPager->pAll || pPager->exclusiveMode ); return 0; } if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ return 0; } pPg = pager_lookup(pPager, pgno); if( pPg==0 ) return 0; page_ref(pPg); return pPg; } |
︙ | ︙ | |||
3000 3001 3002 3003 3004 3005 3006 | /* When all pages reach the freelist, drop the read lock from ** the database file. */ pPager->nRef--; assert( pPager->nRef>=0 ); if( pPager->nRef==0 ){ | < | 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 | /* When all pages reach the freelist, drop the read lock from ** the database file. */ pPager->nRef--; assert( pPager->nRef>=0 ); if( pPager->nRef==0 ){ pagerUnlockAndRollback(pPager); } } return SQLITE_OK; } /* |
︙ | ︙ | |||
3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 | } pPager->dirtyCache = 0; TRACE2("TRANSACTION %d\n", PAGERID(pPager)); if( pPager->useJournal && !pPager->tempFile ){ rc = pager_open_journal(pPager); } } } return rc; } /* ** Make a page dirty. Set its dirty flag and add it to the dirty ** page list. */ | > > > > > > > > > > > > > > > > > | 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 | } pPager->dirtyCache = 0; TRACE2("TRANSACTION %d\n", PAGERID(pPager)); if( pPager->useJournal && !pPager->tempFile ){ rc = pager_open_journal(pPager); } } }else if( pPager->journalOpen && pPager->journalOff==0 ){ /* This happens when the pager was in exclusive-access mode last ** time a (read or write) transaction was successfully concluded ** by this connection. Instead of deleting the journal file it was ** kept open and truncated to 0 bytes. */ assert( pPager->nRec==0 ); assert( pPager->origDbSize==0 ); sqlite3PagerPagecount(pPager); pPager->origDbSize = pPager->dbSize; pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( !pPager->aInJournal ){ rc = SQLITE_NOMEM; }else{ rc = writeJournalHdr(pPager); } } assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK ); return rc; } /* ** Make a page dirty. Set its dirty flag and add it to the dirty ** page list. */ |
︙ | ︙ | |||
3610 3611 3612 3613 3614 3615 3616 | TRACE2("ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ PgHdr *p; for(p=pPager->pAll; p; p=p->pNextAll){ PgHistory *pHist; assert( !p->alwaysRollback ); if( !p->dirty ){ | < < | 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 | TRACE2("ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ PgHdr *p; for(p=pPager->pAll; p; p=p->pNextAll){ PgHistory *pHist; assert( !p->alwaysRollback ); if( !p->dirty ){ assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig ); assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt ); continue; } pHist = PGHDR_TO_HIST(p, pPager); if( pHist->pOrig ){ |
︙ | ︙ | |||
3655 3656 3657 3658 3659 3660 3661 | if( pPager->state>=PAGER_EXCLUSIVE ){ pager_playback(pPager, 0); } return pPager->errCode; } if( pPager->state==PAGER_RESERVED ){ int rc2; | < | 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 | if( pPager->state>=PAGER_EXCLUSIVE ){ pager_playback(pPager, 0); } return pPager->errCode; } if( pPager->state==PAGER_RESERVED ){ int rc2; rc = pager_playback(pPager, 0); rc2 = pager_unwritelock(pPager); if( rc==SQLITE_OK ){ rc = rc2; } }else{ rc = pager_playback(pPager, 0); |
︙ | ︙ |
Changes to test/exclusive.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2007 March 24 # # 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 implements regression tests for SQLite library. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2007 March 24 # # 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 implements regression tests for SQLite library. # # $Id: exclusive.test,v 1.2 2007/03/26 08:05:12 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!pager_pragmas} { finish_test return |
︙ | ︙ | |||
270 271 272 273 274 275 276 | do_test exclusive-3.4 { execsql { BEGIN; UPDATE abc SET a = 1, b = 2, c = 3; ROLLBACK; SELECT * FROM abc; } | | > > > > > < < < < < > < < < < < > | > | < | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | do_test exclusive-3.4 { execsql { BEGIN; UPDATE abc SET a = 1, b = 2, c = 3; ROLLBACK; SELECT * FROM abc; } } {A B C} do_test exclusive-3.5 { filestate test.db-journal } {1 0} do_test exclusive-3.6 { execsql { PRAGMA locking_mode = normal; SELECT * FROM abc; } filestate test.db-journal } {0 0} #---------------------------------------------------------------------- # Tests exclusive-4.X - test that rollback works correctly when # in exclusive-access mode. # # The following procedure computes a "signature" for table "t3". If # T3 changes in any way, the signature should change. # # This is used to test ROLLBACK. We gather a signature for t3, then # make lots of changes to t3, then rollback and take another signature. # The two signatures should be the same. # proc signature {} { return [db eval {SELECT count(*), md5sum(x) FROM t3}] } do_test exclusive-4.0 { execsql { PRAGMA locking_mode = exclusive; } execsql { PRAGMA default_cache_size = 10; } execsql { BEGIN; CREATE TABLE t3(x TEXT); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; COMMIT; } execsql {SELECT count(*) FROM t3;} } {32} set ::X [signature] do_test exclusive-4.1 { execsql { BEGIN; DELETE FROM t3 WHERE random()%10!=0; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; SELECT count(*) FROM t3; ROLLBACK; } signature } $::X do_test exclusive-4.2 { execsql { BEGIN; DELETE FROM t3 WHERE random()%10!=0; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; DELETE FROM t3 WHERE random()%10!=0; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; ROLLBACK; } signature } $::X do_test exclusive-4.3 { execsql { INSERT INTO t3 SELECT randstr(10,400) FROM t3 WHERE random()%10==0; } } {} do_test exclusive-4.4 { catch {set ::X [signature]} } {0} do_test exclusive-4.5 { execsql { PRAGMA locking_mode = NORMAL; DROP TABLE t3; DROP TABLE abc; } } {normal} #---------------------------------------------------------------------- # Tests exclusive-5.X - test that statement journals are truncated # instead of deleted when in exclusive access mode. # #set sqlite_os_trace 1 do_test exclusive-5.0 { execsql { CREATE TABLE abc(a UNIQUE, b UNIQUE, c UNIQUE); BEGIN; INSERT INTO abc VALUES(1, 2, 3); INSERT INTO abc SELECT a+1, b+1, c+1 FROM abc; } } {} do_test exclusive-5.1 { # Three files are open: The db, journal and statement-journal. set sqlite_open_file_count } {3} do_test exclusive-5.2 { execsql { COMMIT; } # One file open: the db. set sqlite_open_file_count } {1} do_test exclusive-5.3 { execsql { PRAGMA locking_mode = exclusive; BEGIN; INSERT INTO abc VALUES(5, 6, 7); } # Two files open: the db and journal. set sqlite_open_file_count } {2} do_test exclusive-5.4 { execsql { INSERT INTO abc SELECT a+10, b+10, c+10 FROM abc; } # Three files are open: The db, journal and statement-journal. set sqlite_open_file_count } {3} do_test exclusive-5.5 { execsql { COMMIT; } # Three files are still open: The db, journal and statement-journal. set sqlite_open_file_count } {3} do_test exclusive-5.6 { execsql { PRAGMA locking_mode = normal; SELECT * FROM abc; } } {normal 1 2 3 2 3 4 5 6 7 11 12 13 12 13 14 15 16 17} do_test exclusive-5.7 { # Just the db open. set sqlite_open_file_count } {1} finish_test |
Changes to test/trans.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # 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 implements regression tests for SQLite library. The # focus of this script is database locks. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # 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 implements regression tests for SQLite library. The # focus of this script is database locks. # # $Id: trans.test,v 1.34 2007/03/26 08:05:12 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create several tables to work with. |
︙ | ︙ | |||
811 812 813 814 815 816 817 | # do_test trans-9.1 { execsql { PRAGMA default_cache_size=10; } db close sqlite3 db test.db | < | 811 812 813 814 815 816 817 818 819 820 821 822 823 824 | # do_test trans-9.1 { execsql { PRAGMA default_cache_size=10; } db close sqlite3 db test.db execsql { BEGIN; CREATE TABLE t3(x TEXT); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; |
︙ | ︙ |