Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Ensure that write-locks on pages are dropped at the end of each write transaction, even if there is still a read transaction open. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | server-process-edition |
Files: | files | file ages | folders |
SHA3-256: |
2dd36ade9ea948de27b217b83cbf704e |
User & Date: | dan 2017-08-19 15:50:45.975 |
Context
2017-08-29
| ||
17:52 | Add a Tcl script to run the performance tests described in README-server-edition.html. (check-in: 1b3df8ffc5 user: dan tags: server-process-edition) | |
2017-08-19
| ||
15:50 | Ensure that write-locks on pages are dropped at the end of each write transaction, even if there is still a read transaction open. (check-in: 2dd36ade9e user: dan tags: server-process-edition) | |
2017-08-18
| ||
18:55 | Add tests to this branch. (check-in: abb6e076c8 user: dan tags: server-process-edition) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
2155 2156 2157 2158 2159 2160 2161 | if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } #ifdef SQLITE_SERVER_EDITION if( pagerIsServer(pPager) ){ | | | 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 | if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } #ifdef SQLITE_SERVER_EDITION if( pagerIsServer(pPager) ){ rc2 = sqlite3ServerEndWrite(pPager->pServer); }else #endif if( !pPager->exclusiveMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); pPager->changeCountDone = 0; |
︙ | ︙ |
Changes to src/server.c.
︙ | ︙ | |||
619 620 621 622 623 624 625 | if( serverCompareAndSwap(pSlot, o, n) ) break; } } p->nLock = 0; } | < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < | | | > | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | if( serverCompareAndSwap(pSlot, o, n) ) break; } } p->nLock = 0; } static void serverRecycleBuffers(ServerDb *pDb){ assert( pDb->pServerShm==0 ); assert( sqlite3_mutex_held(pDb->mutex) ); /* See if it is possible to free any ServerPage records. If so, remove ** them from the linked list and hash table, and add them to the pFree ** list. */ if( pDb->pPgFirst ){ ServerPage *pPg; Server *pIter; ServerPage *pLast = 0; int iOldest = 0x7FFFFFFF; for(pIter=pDb->pReader; pIter; pIter=pIter->pNext){ iOldest = MIN(iOldest, pIter->iCommitId); } for(pIter=pDb->pCommit; pIter; pIter=pIter->pNext){ iOldest = MIN(iOldest, pIter->iCommitId); } |
︙ | ︙ | |||
692 693 694 695 696 697 698 | if( pPg==0 ){ pDb->pPgFirst = pDb->pPgLast = 0; }else{ pDb->pPgFirst = pPg; } } | | > > > > > > > > > > > > > > > > > > > > > > > > > > < | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 | if( pPg==0 ){ pDb->pPgFirst = pDb->pPgLast = 0; }else{ pDb->pPgFirst = pPg; } } } /* ** End a transaction (and release all locks). This version runs in ** single process mode only. */ static void serverEndSingle(Server *p){ Server **pp; ServerDb *pDb = p->pDb; assert( p->eTrans!=SERVER_TRANS_NONE ); assert( pDb->pServerShm==0 ); sqlite3_mutex_enter(pDb->mutex); if( p->eTrans==SERVER_TRANS_READONLY ){ /* Remove the connection from the readers list */ for(pp=&pDb->pReader; *pp!=p; pp = &((*pp)->pNext)); *pp = p->pNext; }else{ serverReleaseLocks(p); /* Clear the bit in the transaction mask. */ pDb->transmask &= ~((u32)1 << p->iTransId); } serverRecycleBuffers(pDb); sqlite3_mutex_leave(pDb->mutex); p->pNext = 0; p->iTransId = -1; } /* ** End a transaction (and release all locks). */ int sqlite3ServerEnd(Server *p){ if( p->eTrans!=SERVER_TRANS_NONE ){ |
︙ | ︙ | |||
782 783 784 785 786 787 788 | sqlite3_mutex_leave(pDb->mutex); return rc; } /* ** Release all write-locks. */ | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | sqlite3_mutex_leave(pDb->mutex); return rc; } /* ** Release all write-locks. */ int sqlite3ServerEndWrite(Server *p){ ServerDb *pDb = p->pDb; int i; if( pDb->pServerShm==0 ) sqlite3_mutex_enter(pDb->mutex); for(i=0; i<p->nLock; i++){ while( 1 ){ u32 *pSlot = serverLockingSlot(pDb, p->aLock[i]); u32 o = *pSlot; u32 n = o & ~((u32)1 << p->iTransId); if( slotGetWriter(n)==p->iTransId ){ n -= ((p->iTransId + 1) << HMA_MAX_TRANSACTIONID); n |= ((u32)1 << p->iTransId); } if( o==n || serverCompareAndSwap(pSlot, o, n) ) break; } } if( pDb->pServerShm==0 ){ ServerDb **pp; /* If this connection is in the committers list, remove it. */ for(pp=&pDb->pCommit; *pp; pp = &((*pp)->pNext)){ if( *pp==p ){ *pp = p->pNext; break; } } p->iCommitId = 0; sqlite3_mutex_leave(pDb->mutex); } return SQLITE_OK; } static int serverCheckClient(Server *p, int iClient){ ServerDb *pDb = p->pDb; int rc = SQLITE_BUSY_DEADLOCK; if( pDb->pServerShm && 0==(pDb->transmask & (1 << iClient)) ){ |
︙ | ︙ | |||
894 895 896 897 898 899 900 | p->aLock[p->nLock++] = pgno; } } return rc; } | < < < < < | 919 920 921 922 923 924 925 926 927 928 929 930 931 932 | p->aLock[p->nLock++] = pgno; } } return rc; } static void serverIncrSlowReader(u32 *pSlot, int n){ assert( n==1 || n==-1 ); *pSlot += (n * (1 << HMA_SLOT_RLWL_BITS)); } void sqlite3ServerReadPage(Server *p, Pgno pgno, u8 **ppData){ if( p->eTrans==SERVER_TRANS_READONLY ){ |
︙ | ︙ |
Changes to src/server.h.
︙ | ︙ | |||
34 35 36 37 38 39 40 | int sqlite3ServerConnect(Pager *pPager, int eServer, Server **ppOut); void sqlite3ServerDisconnect(Server *p, sqlite3_file *dbfd); int sqlite3ServerBegin(Server *p, int bReadonly); int sqlite3ServerPreCommit(Server*, ServerPage*); int sqlite3ServerEnd(Server *p); | | < < | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | int sqlite3ServerConnect(Pager *pPager, int eServer, Server **ppOut); void sqlite3ServerDisconnect(Server *p, sqlite3_file *dbfd); int sqlite3ServerBegin(Server *p, int bReadonly); int sqlite3ServerPreCommit(Server*, ServerPage*); int sqlite3ServerEnd(Server *p); int sqlite3ServerEndWrite(Server *p); int sqlite3ServerLock(Server *p, Pgno pgno, int bWrite, int bBlock); ServerPage *sqlite3ServerBuffer(Server*); int sqlite3ServerIsSingleProcess(Server*); /* For "BEGIN READONLY" clients. */ int sqlite3ServerIsReadonly(Server*); void sqlite3ServerReadPage(Server*, Pgno, u8**); |
︙ | ︙ |
Changes to test/server2.test.
︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 147 148 | lsort [glob -nocomplain test.db-journal/*-journal] } {test.db-journal/0-journal} do_test $tn.3.2 { db close lsort [glob -nocomplain test.db-journal/*-journal] } {} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | lsort [glob -nocomplain test.db-journal/*-journal] } {test.db-journal/0-journal} do_test $tn.3.2 { db close lsort [glob -nocomplain test.db-journal/*-journal] } {} #----------------------------------------------------------------------- # Test that write-locks are downgraded when a transaction is ended, # even if the connection holds an open read statement. # do_test $tn.4.1 { server_sqlite3 db test.db server_sqlite3 db2 test.db db eval { CREATE TABLE t2(a); INSERT INTO t2 VALUES('one'); INSERT INTO t2 VALUES('two'); INSERT INTO t2 VALUES('three'); CREATE TABLE t3(k INTEGER PRIMARY KEY, val); } set res [list] db eval { SELECT a FROM t2 ORDER BY rowid } { db eval { REPLACE INTO t3 VALUES(1, $a) } lappend res [db2 one { SELECT val FROM t3 }] } set res } {one two three} catch { db close } catch { db2 close } } finish_test |