Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a problem causing a lock to be held past the end of a transaction. Use a blocking lock to take the read-lock on page 1 taken by all transactions. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | server-edition |
Files: | files | file ages | folders |
SHA3-256: |
2584df3d42ece69d37f31f3655cd0d47 |
User & Date: | dan 2017-05-10 16:18:05.140 |
Context
2017-05-12
| ||
18:52 | Require exclusive access to the db to wrap the wal file. Have "PRAGMA wal_checkpoint = restart" block for this. (check-in: cbf44ed975 user: dan tags: server-edition) | |
2017-05-10
| ||
16:18 | Fix a problem causing a lock to be held past the end of a transaction. Use a blocking lock to take the read-lock on page 1 taken by all transactions. (check-in: 2584df3d42 user: dan tags: server-edition) | |
13:46 | Use a blocking call to obtain the wal-mode WRITER lock in some cases. (check-in: 4464ca1d68 user: dan tags: server-edition) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
5389 5390 5391 5392 5393 5394 5395 | #ifdef SQLITE_SERVER_EDITION if( pagerIsServer(pPager) ){ assert( rc==SQLITE_OK ); pager_reset(pPager); rc = sqlite3ServerBegin(pPager->pServer); } #endif | | | 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 | #ifdef SQLITE_SERVER_EDITION if( pagerIsServer(pPager) ){ assert( rc==SQLITE_OK ); pager_reset(pPager); rc = sqlite3ServerBegin(pPager->pServer); } #endif if( rc==SQLITE_OK && pagerUseWal(pPager) ){ assert( rc==SQLITE_OK ); rc = pagerBeginReadTransaction(pPager); } if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ rc = pagerPagecount(pPager, &pPager->dbSize); } |
︙ | ︙ |
Changes to src/server.c.
︙ | ︙ | |||
409 410 411 412 413 414 415 | ** Begin a transaction. */ int sqlite3ServerBegin(Server *p){ #if 1 int rc = posixLock(p->pHma->fd, p->iClient+1, SERVER_WRITE_LOCK, 1); if( rc ) return rc; #endif | | | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | ** Begin a transaction. */ int sqlite3ServerBegin(Server *p){ #if 1 int rc = posixLock(p->pHma->fd, p->iClient+1, SERVER_WRITE_LOCK, 1); if( rc ) return rc; #endif return sqlite3ServerLock(p, 1, 0, 1); } /* ** End a transaction (and release all locks). */ int sqlite3ServerEnd(Server *p){ int i; |
︙ | ︙ | |||
475 476 477 478 479 480 481 | /* Check if the required lock is already held. If so, exit this function ** early. Otherwise, add an entry to the aLock[] array to record the fact ** that the lock may need to be released. */ if( bWrite ){ int iLock = ((int)(v>>HMA_CLIENT_SLOTS)) - 1; if( iLock==p->iClient ) goto server_lock_out; | < < < < > | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | /* Check if the required lock is already held. If so, exit this function ** early. Otherwise, add an entry to the aLock[] array to record the fact ** that the lock may need to be released. */ if( bWrite ){ int iLock = ((int)(v>>HMA_CLIENT_SLOTS)) - 1; if( iLock==p->iClient ) goto server_lock_out; }else{ if( v & (1<<p->iClient) ) goto server_lock_out; } p->aLock[p->nLock++] = pgno; while( 1 ){ u32 n; while( (bWrite && (v & ~(1 << p->iClient))) || (v >> HMA_CLIENT_SLOTS) ){ int bRetry = 0; rc = serverOvercomeLock(p, bWrite, bBlock, v, &bRetry); if( rc!=SQLITE_OK ) goto server_lock_out; |
︙ | ︙ |
Added src/server.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 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 32 33 34 | /* ** 2017 April 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. ** ************************************************************************* */ #ifdef SQLITE_SERVER_EDITION #ifndef SQLITE_SERVER_H #define SQLITE_SERVER_H typedef struct Server Server; int sqlite3ServerConnect(Pager *pPager, Server **ppOut, int *piClient); void sqlite3ServerDisconnect(Server *p, sqlite3_file *dbfd); int sqlite3ServerBegin(Server *p); int sqlite3ServerEnd(Server *p); int sqlite3ServerReleaseWriteLocks(Server *p); int sqlite3ServerLock(Server *p, Pgno pgno, int bWrite, int bBlock); #endif /* SQLITE_SERVER_H */ #endif /* SQLITE_SERVER_EDITION */ |
Changes to src/wal.c.
︙ | ︙ | |||
2606 2607 2608 2609 2610 2611 2612 | u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */ int iHash; /* Used to loop through N hash tables */ int iMinHash; /* This routine is only be called from within a read transaction. */ assert( walIsServer(pWal) || pWal->readLock>=0 || pWal->lockError ); | | | 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 | u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */ int iHash; /* Used to loop through N hash tables */ int iMinHash; /* This routine is only be called from within a read transaction. */ assert( walIsServer(pWal) || pWal->readLock>=0 || pWal->lockError ); if( walIsServer(pWal) && pWal->writeLock==0 ){ /* A server mode connection must read from the most recent snapshot. */ iLast = walIndexHdr(pWal)->mxFrame; } /* If the "last page" field of the wal-index header snapshot is 0, then ** no data will be read from the wal under any circumstances. Return early ** in this case as an optimization. Likewise, if pWal->readLock==0, |
︙ | ︙ | |||
2808 2809 2810 2811 2812 2813 2814 | ** returned to the caller. ** ** Otherwise, if the callback function does not return an error, this ** function returns SQLITE_OK. */ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ int rc = SQLITE_OK; | | | 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 | ** returned to the caller. ** ** Otherwise, if the callback function does not return an error, this ** function returns SQLITE_OK. */ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ int rc = SQLITE_OK; if( pWal->writeLock ){ Pgno iMax = pWal->hdr.mxFrame; Pgno iFrame; /* Restore the clients cache of the wal-index header to the state it ** was in before the client began writing to the database. */ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); |
︙ | ︙ |
Changes to test/serverwal.test.
︙ | ︙ | |||
81 82 83 84 85 86 87 88 89 90 | execsql { PRAGMA wal_checkpoint; INSERT INTO ttt VALUES(11, 12); INSERT INTO ttt VALUES(13, 14); } expr {$N == [file size test.db-wal]} } {1} finish_test | > > > > > > > > > > > > > > > > > > > > > > > | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | execsql { PRAGMA wal_checkpoint; INSERT INTO ttt VALUES(11, 12); INSERT INTO ttt VALUES(13, 14); } expr {$N == [file size test.db-wal]} } {1} #------------------------------------------------------------------------- # That ROLLBACK appears to work. # reset_db do_execsql_test 4.0 { PRAGMA cache_size = 10; CREATE TABLE ttt(a, b); CREATE INDEX yyy ON ttt(b, a); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO ttt SELECT randomblob(100), randomblob(100) FROM s; } {wal} do_execsql_test 4.1 { PRAGMA integrity_check; BEGIN; UPDATE ttt SET b=a; ROLLBACK; PRAGMA integrity_check; } {ok ok} finish_test |