Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch mutexfree-shmlock Excluding Merge-Ins
This is equivalent to a diff from 95a9a39f to 606b1ead
2018-12-24
| ||
15:22 | Copy some extra test infrastructure from the mutexfree-shmlock branch to trunk. (check-in: 883337ff user: dan tags: trunk) | |
15:15 | Merge latest trunk with this branch. (Leaf check-in: 606b1ead user: dan tags: mutexfree-shmlock) | |
13:39 | Change the way a comparison used to detect corrupt databases in fts3 is done to avoid potential pointer overflow in 32-bit builds. Cherrypick of [95a9a39ff7]. (check-in: 27199380 user: dan tags: branch-3.22) | |
13:34 | Change the way a comparison used to detect corrupt databases in fts3 is done to avoid potential pointer overflow in 32-bit builds. (check-in: 95a9a39f user: dan tags: trunk) | |
2018-12-23
| ||
21:27 | Split the code generation for the RHS of IN operators and for SELECT and EXISTS expressions into two separate subroutines, because there is now little commonality between those to functions. This is intended to help make the code easier to read and maintain. (check-in: 2b6494b1 user: drh tags: trunk) | |
2018-12-10
| ||
16:52 | Make SQLITE_MFS_NSHARD a compile time setting. (check-in: b9a74151 user: dan tags: mutexfree-shmlock) | |
Changes to src/os_unix.c.
︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | + + + + + + + + + + | ** * Locking primitives for the proxy uber-locking-method. (MacOSX only) ** * Definitions of sqlite3_vfs objects for all locking methods ** plus implementations of sqlite3_os_init() and sqlite3_os_end(). */ #include "sqliteInt.h" #if SQLITE_OS_UNIX /* This file is used on unix only */ /* Turn this feature on in all builds for now */ #define SQLITE_MUTEXFREE_SHMLOCK 1 #define SQLITE_MFS_EXCLUSIVE 255 #ifndef SQLITE_MFS_NSHARD # define SQLITE_MFS_NSHARD 8 #endif #if SQLITE_MFS_NSHARD<1 # error "SQLITE_MFS_NSHARD must be greater than 0" #endif /* ** There are various methods for file locking used for concurrency ** control: ** ** 1. POSIX locking (the default), ** 2. No locking, ** 3. Dot-file locking, |
︙ | |||
4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 | 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ #ifdef SQLITE_DEBUG u8 exclMask; /* Mask of exclusive locks held */ u8 sharedMask; /* Mask of shared locks held */ u8 nextShmId; /* Next available unixShm.id value */ #endif #ifdef SQLITE_MUTEXFREE_SHMLOCK /* In unix-excl mode, if SQLITE_MUTEXFREE_SHMLOCK is defined, all locks ** are stored in the following 64-bit value. There are in total 8 ** shm-locking slots, each of which are assigned 8-bits from the 64-bit ** value. The least-significant 8 bits correspond to shm-locking slot ** 0, and so on. ** ** If the 8-bits corresponding to a shm-locking locking slot are set to ** 0xFF, then a write-lock is held on the slot. Or, if they are set to ** a non-zero value smaller than 0xFF, then they represent the total ** number of read-locks held on the slot. There is no way to distinguish ** between a write-lock and 255 read-locks. */ struct LockingSlot { u32 nLock; u64 aPadding[7]; } aMFSlot[3 + SQLITE_MFS_NSHARD*5]; #endif }; /* ** Atomic CAS primitive used in multi-process mode. Equivalent to: ** ** int unixCompareAndSwap(u32 *ptr, u32 oldval, u32 newval){ ** if( *ptr==oldval ){ ** *ptr = newval; ** return 1; ** } ** return 0; ** } */ #define unixCompareAndSwap(ptr,oldval,newval) \ __sync_bool_compare_and_swap(ptr,oldval,newval) /* ** Structure used internally by this VFS to record the state of an ** open shared memory connection. ** ** The following fields are initialized when this object is created and ** are read-only thereafter: |
︙ | |||
4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 | 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 | + + + | struct unixShm { unixShmNode *pShmNode; /* The underlying unixShmNode object */ unixShm *pNext; /* Next unixShm with the same unixShmNode */ u8 hasMutex; /* True if holding the unixShmNode->pShmMutex */ u8 id; /* Id of this connection within its unixShmNode */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ #ifdef SQLITE_MUTEXFREE_SHMLOCK u8 aMFCurrent[8]; /* Current slot used for each shared lock */ #endif }; /* ** Constants used for locking */ #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ |
︙ | |||
4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 | 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | *pp = 0; } if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; } #ifdef SQLITE_MUTEXFREE_SHMLOCK static int unixMutexFreeShmlock( unixFile *pFd, /* Database file holding the shared memory */ int ofst, /* First lock to acquire or release */ int n, /* Number of locks to acquire or release */ int flags /* What to do with the lock */ ){ struct LockMapEntry { int iFirst; int nSlot; } aMap[9] = { { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3+0*SQLITE_MFS_NSHARD, SQLITE_MFS_NSHARD }, { 3+1*SQLITE_MFS_NSHARD, SQLITE_MFS_NSHARD }, { 3+2*SQLITE_MFS_NSHARD, SQLITE_MFS_NSHARD }, { 3+3*SQLITE_MFS_NSHARD, SQLITE_MFS_NSHARD }, { 3+4*SQLITE_MFS_NSHARD, SQLITE_MFS_NSHARD }, { 3+5*SQLITE_MFS_NSHARD, 0 }, }; unixShm *p = pFd->pShm; /* The shared memory being locked */ unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ if( flags & SQLITE_SHM_SHARED ){ /* SHARED locks */ u32 iOld, iNew, *ptr; int iIncr = -1; if( (flags & SQLITE_SHM_UNLOCK)==0 ){ p->aMFCurrent[ofst] = (p->aMFCurrent[ofst] + 1) % aMap[ofst].nSlot; iIncr = 1; } ptr = &pShmNode->aMFSlot[aMap[ofst].iFirst + p->aMFCurrent[ofst]].nLock; do { iOld = *ptr; iNew = iOld + iIncr; if( iNew>SQLITE_MFS_EXCLUSIVE ){ return SQLITE_BUSY; } }while( 0==unixCompareAndSwap(ptr, iOld, iNew) ); }else{ /* EXCLUSIVE locks */ int iFirst = aMap[ofst].iFirst; int iLast = aMap[ofst+n].iFirst; int i; for(i=iFirst; i<iLast; i++){ u32 *ptr = &pShmNode->aMFSlot[i].nLock; if( flags & SQLITE_SHM_UNLOCK ){ assert( (*ptr)==SQLITE_MFS_EXCLUSIVE ); *ptr = 0; }else{ u32 iOld; do { iOld = *ptr; if( iOld>0 ){ while( i>iFirst ){ i--; pShmNode->aMFSlot[i].nLock = 0; } return SQLITE_BUSY; } }while( 0==unixCompareAndSwap(ptr, iOld, SQLITE_MFS_EXCLUSIVE) ); } } } return SQLITE_OK; } #else # define unixMutexFreeShmlock(a,b,c,d) SQLITE_OK #endif /* ** Change the lock state for a shared-memory segment. ** ** Note that the relationship between SHAREd and EXCLUSIVE locks is a little ** different here than in posix. In xShmLock(), one can go from unlocked ** to shared and back or from unlocked to exclusive and back. But one may ** not go from shared to exclusive or from exclusive to shared. |
︙ | |||
4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 | 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 | + + + + + + + + + + + + | assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); if( pDbFd->pInode->bProcessLock ){ return unixMutexFreeShmlock(pDbFd, ofst, n, flags); } mask = (1<<(ofst+n)) - (1<<ofst); assert( n>1 || mask==(1<<ofst) ); if( flags & SQLITE_SHM_LOCK ){ assert( !(flags&SQLITE_SHM_SHARED) || (p->sharedMask&mask)==0 ); assert( !(flags&SQLITE_SHM_EXCLUSIVE) || !(p->exclMask&mask) ); }else{ assert( !(flags&SQLITE_SHM_SHARED) || (p->sharedMask&mask)==mask ); assert( !(flags&SQLITE_SHM_EXCLUSIVE) || (p->exclMask&mask)==mask ); } sqlite3_mutex_enter(pShmNode->pShmMutex); if( flags & SQLITE_SHM_UNLOCK ){ u16 allMask = 0; /* Mask of locks held by siblings */ /* See if any siblings hold this same lock */ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ if( pX==p ) continue; |
︙ | |||
4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 | 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 | + + + + | ** All loads and stores begun before the barrier must complete before ** any load or store begun after the barrier. */ static void unixShmBarrier( sqlite3_file *fd /* Database file holding the shared memory */ ){ UNUSED_PARAMETER(fd); #ifdef SQLITE_MUTEXFREE_SHMLOCK __sync_synchronize(); #else sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ assert( fd->pMethods->xLock==nolockLock || unixFileMutexNotheld((unixFile*)fd) ); unixEnterMutex(); /* Also mutex, for redundancy */ unixLeaveMutex(); #endif } /* ** Close a connection to shared-memory. Delete the underlying ** storage if deleteFlag is true. ** ** If there is no shared memory associated with the connection then this |
︙ |
Changes to src/test_superlock.c.
︙ | |||
37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | + + | ** An instance of the following structure is allocated for each active ** superlock. The opaque handle returned by sqlite3demo_superlock() is ** actually a pointer to an instance of this structure. */ struct Superlock { sqlite3 *db; /* Database handle used to lock db */ int bWal; /* True if db is a WAL database */ int bRecoveryLocked; /* True if WAL RECOVERY lock is held */ int bReaderLocked; /* True if WAL READER locks are held */ }; typedef struct Superlock Superlock; /* ** The pCtx pointer passed to this function is actually a pointer to a ** SuperlockBusy structure. Invoke the busy-handler function encapsulated ** by the structure and return the result. |
︙ | |||
103 104 105 106 107 108 109 | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | - + + + + + + + - - + + + + + + + | } /* ** Obtain the extra locks on the database file required for WAL databases. ** Invoke the supplied busy-handler as required. */ static int superlockWalLock( |
︙ | |||
228 229 230 231 232 233 234 | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | - + | ** to drop the WAL read and write locks currently held. Otherwise, the ** new WAL locks may conflict with the old. */ if( rc==SQLITE_OK ){ if( SQLITE_OK==(rc = superlockIsWal(pLock)) && pLock->bWal ){ rc = sqlite3_exec(pLock->db, "COMMIT", 0, 0, 0); if( rc==SQLITE_OK ){ |
︙ |
Changes to src/test_vfs.c.
︙ | |||
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 | 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | return TCL_OK; bad_args: Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-fullshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?"); return TCL_ERROR; } extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); extern const char *sqlite3ErrName(int); /* ** tclcmd: vfs_shmlock DB DBNAME (shared|exclusive) (lock|unlock) OFFSET N */ static int SQLITE_TCLAPI test_vfs_shmlock( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *azArg1[] = {"shared", "exclusive", 0}; const char *azArg2[] = {"lock", "unlock", 0}; sqlite3 *db = 0; int rc = SQLITE_OK; const char *zDbname = 0; int iArg1 = 0; int iArg2 = 0; int iOffset = 0; int n = 0; sqlite3_file *pFd; if( objc!=7 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME (shared|exclusive) (lock|unlock) OFFSET N" ); return TCL_ERROR; } zDbname = Tcl_GetString(objv[2]); if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) || Tcl_GetIndexFromObj(interp, objv[3], azArg1, "ARG", 0, &iArg1) || Tcl_GetIndexFromObj(interp, objv[4], azArg2, "ARG", 0, &iArg2) || Tcl_GetIntFromObj(interp, objv[5], &iOffset) || Tcl_GetIntFromObj(interp, objv[6], &n) ){ return TCL_ERROR; } sqlite3_file_control(db, zDbname, SQLITE_FCNTL_FILE_POINTER, (void*)&pFd); if( pFd==0 ){ return TCL_ERROR; } rc = pFd->pMethods->xShmLock(pFd, iOffset, n, (iArg1==0 ? SQLITE_SHM_SHARED : SQLITE_SHM_EXCLUSIVE) | (iArg2==0 ? SQLITE_SHM_LOCK : SQLITE_SHM_UNLOCK) ); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_OK; } int Sqlitetestvfs_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0); Tcl_CreateObjCommand(interp, "vfs_shmlock", test_vfs_shmlock, 0, 0); return TCL_OK; } #endif |
Changes to src/wal.c.
︙ | |||
2773 2774 2775 2776 2777 2778 2779 | 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 | - - - + + + - - - + + + - - - - - - - | ** checkpoint need not have completed for this to cause problems. */ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 ); assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame ); |
︙ |
Changes to test/lock_common.tcl.
︙ | |||
11 12 13 14 15 16 17 | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | - + - - + - + + + + | # This file contains code used by several different test scripts. The # code in this file allows testfixture to control another process (or # processes) to test locking. # proc do_multiclient_test {varname script} { |
︙ |
Changes to test/permutations.test.
︙ | |||
607 608 609 610 611 612 613 614 615 616 617 618 619 620 | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | + + + + + + + + + + | Run some tests using the "test_onefile.c" demo } -initialize { set ::G(perm:sqlite3_args) [list -vfs fs] } -files { conflict.test insert.test insert2.test insert3.test rollback.test select1.test select2.test select3.test } # Run some tests using the "unix-excl" VFS. # test_suite "unix-excl" -description { Run some tests using the "unix-excl" VFS } -initialize { set ::G(perm:sqlite3_args) [list -vfs unix-excl] } -files { shmlock.test } # Run some tests using UTF-16 databases. # test_suite "utf16" -description { Run tests using UTF-16 databases } -presql { pragma encoding = 'UTF-16' |
︙ |
Added test/shmlock.test.