Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add experimental new API sqlite3_wal_info(). |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | begin-concurrent |
Files: | files | file ages | folders |
SHA3-256: |
5b9d498f6e9de6ee2ab86370c02c28a2 |
User & Date: | dan 2017-05-23 19:23:45.315 |
Context
2017-05-25
| ||
21:02 | Fix a problem with the deferred page allocation on this branch that could occur when the database file is just slightly smaller than the PENDING_BYTE page offset. (check-in: 47a7dd9235 user: dan tags: begin-concurrent) | |
2017-05-23
| ||
19:23 | Add experimental new API sqlite3_wal_info(). (check-in: 5b9d498f6e user: dan tags: begin-concurrent) | |
2017-05-19
| ||
19:57 | Invoke sqlite3_log() in response to irregularities surrounding the Pager.pAllRead bit-vector. (check-in: 9527089b7a user: dan tags: begin-concurrent) | |
Changes
Changes to src/main.c.
︙ | ︙ | |||
4091 4092 4093 4094 4095 4096 4097 | /* ** Free a snapshot handle obtained from sqlite3_snapshot_get(). */ void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ sqlite3_free(pSnapshot); } #endif /* SQLITE_ENABLE_SNAPSHOT */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 | /* ** Free a snapshot handle obtained from sqlite3_snapshot_get(). */ void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ sqlite3_free(pSnapshot); } #endif /* SQLITE_ENABLE_SNAPSHOT */ SQLITE_EXPERIMENTAL int sqlite3_wal_info( sqlite3 *db, const char *zDb, unsigned int *pnPrior, unsigned int *pnFrame ){ int rc = SQLITE_OK; #ifndef SQLITE_OMIT_WAL Btree *pBt; int iDb; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); iDb = sqlite3FindDbName(db, zDb); if( iDb<0 ){ return SQLITE_ERROR; } pBt = db->aDb[iDb].pBt; rc = sqlite3PagerWalInfo(sqlite3BtreePager(pBt), pnPrior, pnFrame); sqlite3_mutex_leave(db->mutex); #endif /* SQLITE_OMIT_WAL */ return rc; } |
Changes to src/pager.c.
︙ | ︙ | |||
7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 | rc = sqlite3WalSnapshotRecover(pPager->pWal); }else{ rc = SQLITE_ERROR; } return rc; } #endif /* SQLITE_ENABLE_SNAPSHOT */ #endif /* !SQLITE_OMIT_WAL */ #ifdef SQLITE_ENABLE_ZIPVFS /* ** A read-lock must be held on the pager when this function is called. If ** the pager is in WAL mode and the WAL file currently contains one or more ** frames, return the size in bytes of the page images stored within the | > > > > > | 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 | rc = sqlite3WalSnapshotRecover(pPager->pWal); }else{ rc = SQLITE_ERROR; } return rc; } #endif /* SQLITE_ENABLE_SNAPSHOT */ int sqlite3PagerWalInfo(Pager *pPager, u32 *pnPrior, u32 *pnFrame){ return sqlite3WalInfo(pPager->pWal, pnPrior, pnFrame); } #endif /* !SQLITE_OMIT_WAL */ #ifdef SQLITE_ENABLE_ZIPVFS /* ** A read-lock must be held on the pager when this function is called. If ** the pager is in WAL mode and the WAL file currently contains one or more ** frames, return the size in bytes of the page images stored within the |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
226 227 228 229 230 231 232 233 234 235 236 237 238 239 | void sqlite3PagerSetDbsize(Pager *pPager, Pgno); int sqlite3PagerIsWal(Pager*); #else # define sqlite3PagerEndConcurrent(x) #endif int sqlite3PagerIswriteable(DbPage*); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) | > > | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | void sqlite3PagerSetDbsize(Pager *pPager, Pgno); int sqlite3PagerIsWal(Pager*); #else # define sqlite3PagerEndConcurrent(x) #endif int sqlite3PagerIswriteable(DbPage*); int sqlite3PagerWalInfo(Pager*, u32 *pnPrior, u32 *pnFrame); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 | ** sqlite3_snapshot_open(). It is an error if there is already a read ** transaction open on the database, or if the database is not a wal mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double | > > > > > > > > > > > > > > > > > > > > > > > > > | 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 | ** sqlite3_snapshot_open(). It is an error if there is already a read ** transaction open on the database, or if the database is not a wal mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Wal related information regarding the most recent COMMIT ** EXPERIMENTAL ** ** This function reports on the state of the wal file (if any) for database ** zDb, which should be "main", "temp", or the name of the attached database. ** Its results - the values written to the output parameters - are only ** defined if the most recent SQL command on the connection was a successful ** COMMIT that wrote data to wal-mode database zDb. ** ** Assuming the above conditions are met, output parameter (*pnFrame) is set ** to the total number of frames in the wal file. Parameter (*pnPrior) is ** set to the number of frames that were present in the wal file before the ** most recent transaction was committed. So that the number of frames written ** by the most recent transaction is (*pnFrame)-(*pnPrior). ** ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. It ** is not an error if this function is called at a time when the results ** are undefined. */ SQLITE_EXPERIMENTAL int sqlite3_wal_info( sqlite3 *db, const char *zDb, unsigned int *pnPrior, unsigned int *pnFrame ); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 | }else{ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "icecube"); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_found_count; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 | }else{ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "icecube"); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } } /* ** Usage: sqlite3_wal_info DB DBNAME */ static int SQLITE_TCLAPI test_wal_info( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; sqlite3 *db; char *zName; unsigned int nPrior; unsigned int nFrame; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zName = Tcl_GetString(objv[2]); rc = sqlite3_wal_info(db, zName, &nPrior, &nFrame); if( rc!=SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_ERROR; }else{ Tcl_Obj *pNew = Tcl_NewObj(); Tcl_ListObjAppendElement(interp, pNew, Tcl_NewWideIntObj((i64)nPrior)); Tcl_ListObjAppendElement(interp, pNew, Tcl_NewWideIntObj((i64)nFrame)); Tcl_SetObjResult(interp, pNew); } return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_found_count; |
︙ | ︙ | |||
7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 | { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 }, { "sqlite3_snapshot_recover", test_snapshot_recover, 0 }, { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 }, { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 }, { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 }, #endif { "sqlite3_delete_database", test_delete_database, 0 }, }; static int bitmask_size = sizeof(Bitmask)*8; static int longdouble_size = sizeof(LONGDOUBLE_TYPE); int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; | > | 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 | { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 }, { "sqlite3_snapshot_recover", test_snapshot_recover, 0 }, { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 }, { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 }, { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 }, #endif { "sqlite3_delete_database", test_delete_database, 0 }, { "sqlite3_wal_info", test_wal_info, 0 }, }; static int bitmask_size = sizeof(Bitmask)*8; static int longdouble_size = sizeof(LONGDOUBLE_TYPE); int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
442 443 444 445 446 447 448 449 450 451 452 453 454 455 | u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */ u8 truncateOnCommit; /* True to truncate WAL file on commit */ u8 syncHeader; /* Fsync the WAL header if true */ u8 padToSectorBoundary; /* Pad transactions out to the next sector */ WalIndexHdr hdr; /* Wal-index header for current transaction */ u32 minFrame; /* Ignore wal frames before this one */ u32 iReCksum; /* On commit, recalculate checksums from here */ const char *zWalName; /* Name of WAL file */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ #ifdef SQLITE_DEBUG u8 lockError; /* True if a locking error has occurred */ #endif #ifdef SQLITE_ENABLE_SNAPSHOT WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ | > | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */ u8 truncateOnCommit; /* True to truncate WAL file on commit */ u8 syncHeader; /* Fsync the WAL header if true */ u8 padToSectorBoundary; /* Pad transactions out to the next sector */ WalIndexHdr hdr; /* Wal-index header for current transaction */ u32 minFrame; /* Ignore wal frames before this one */ u32 iReCksum; /* On commit, recalculate checksums from here */ u32 nPriorFrame; /* For sqlite3WalInfo() */ const char *zWalName; /* Name of WAL file */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ #ifdef SQLITE_DEBUG u8 lockError; /* True if a locking error has occurred */ #endif #ifdef SQLITE_ENABLE_SNAPSHOT WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ |
︙ | ︙ | |||
2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 | rc = walTryBeginRead(pWal, pChanged, 0, ++cnt); }while( rc==WAL_RETRY ); testcase( (rc&0xff)==SQLITE_BUSY ); testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); #ifdef SQLITE_ENABLE_SNAPSHOT if( rc==SQLITE_OK ){ if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ /* At this point the client has a lock on an aReadMark[] slot holding ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr ** is populated with the wal-index header corresponding to the head ** of the wal file. Verify that pSnapshot is still valid before | > | 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 | rc = walTryBeginRead(pWal, pChanged, 0, ++cnt); }while( rc==WAL_RETRY ); testcase( (rc&0xff)==SQLITE_BUSY ); testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); pWal->nPriorFrame = pWal->hdr.mxFrame; #ifdef SQLITE_ENABLE_SNAPSHOT if( rc==SQLITE_OK ){ if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ /* At this point the client has a lock on an aReadMark[] slot holding ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr ** is populated with the wal-index header corresponding to the head ** of the wal file. Verify that pSnapshot is still valid before |
︙ | ︙ | |||
2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 | } } if( rc!=SQLITE_OK ) break; } } } return rc; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** This function is called as part of committing an CONCURRENT transaction. ** It is assumed that sqlite3WalLockForCommit() has already been successfully | > | 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 | } } if( rc!=SQLITE_OK ) break; } } } pWal->nPriorFrame = pWal->hdr.mxFrame; return rc; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** This function is called as part of committing an CONCURRENT transaction. ** It is assumed that sqlite3WalLockForCommit() has already been successfully |
︙ | ︙ | |||
3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 | ** ** In theory it would be Ok to update the cache of the header only ** at this point. But updating the actual wal-index header is also ** safe and means there is no special case for sqlite3WalUndo() ** to handle if this transaction is rolled back. */ walRestartHdr(pWal, salt1); walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); }else if( rc!=SQLITE_BUSY ){ return rc; } } /* Regardless of whether or not the wal file was restarted, change the ** read-lock held by this client to a slot other than aReadmark[0]. | > | 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 | ** ** In theory it would be Ok to update the cache of the header only ** at this point. But updating the actual wal-index header is also ** safe and means there is no special case for sqlite3WalUndo() ** to handle if this transaction is rolled back. */ walRestartHdr(pWal, salt1); walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); pWal->nPriorFrame = 0; }else if( rc!=SQLITE_BUSY ){ return rc; } } /* Regardless of whether or not the wal file was restarted, change the ** read-lock held by this client to a slot other than aReadmark[0]. |
︙ | ︙ | |||
3754 3755 3756 3757 3758 3759 3760 3761 3762 | #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal){ return pWal->pWalFd; } #endif /* #ifndef SQLITE_OMIT_WAL */ | > > > > > > > > > > > > | 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 | #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal){ return pWal->pWalFd; } /* ** Return the values required by sqlite3_wal_info(). */ int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame){ int rc = SQLITE_OK; if( pWal ){ *pnFrame = pWal->hdr.mxFrame; *pnPrior = pWal->nPriorFrame; } return rc; } #endif /* #ifndef SQLITE_OMIT_WAL */ |
Changes to src/wal.h.
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 | */ int sqlite3WalFramesize(Wal *pWal); #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal); #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ | > > > | 149 150 151 152 153 154 155 156 157 158 159 160 | */ int sqlite3WalFramesize(Wal *pWal); #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal); /* sqlite3_wal_info() data */ int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame); #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ |
Changes to test/concurrent2.test.
︙ | ︙ | |||
543 544 545 546 547 548 549 550 551 552 | code1 { sqlite3_finalize $::stmt } sql1 { INSERT INTO t2 VALUES(8); COMMIT; } } {} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | code1 { sqlite3_finalize $::stmt } sql1 { INSERT INTO t2 VALUES(8); COMMIT; } } {} } do_multiclient_test tn { do_test 11.$tn.1 { sql1 { PRAGMA journal_mode = wal; CREATE TABLE t1(a); } } {wal} do_test 11.$tn.2 { code1 { sqlite3_wal_info db main } } {0 2} do_test 11.$tn.3 { sql1 { INSERT INTO t1 VALUES(1) } code1 { sqlite3_wal_info db main } } {2 3} do_test 11.$tn.4 { sql2 { INSERT INTO t1 VALUES(2) } code2 { sqlite3_wal_info db2 main } } {3 4} do_test 11.$tn.5 { sql1 { PRAGMA wal_checkpoint } sql2 { INSERT INTO t1 VALUES(3) } code2 { sqlite3_wal_info db2 main } } {0 1} } finish_test |