Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add support for multiple processes to bt. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
1336c5d00a9e09a41851447de72883ac |
User & Date: | dan 2013-11-11 20:06:20.107 |
Context
2013-11-11
| ||
20:27 | Add the BT_CONTROL_MULTIPROC option. check-in: 7343be21c9 user: dan tags: trunk | |
20:06 | Add support for multiple processes to bt. check-in: 1336c5d00a user: dan tags: trunk | |
2013-11-09
| ||
17:32 | Add BT_CONTROL directives to configure the safety-level and auto-checkpoint parameter. Fix bugs. check-in: 15856cf080 user: dan tags: trunk | |
Changes
Changes to lsm-test/lsmtest_tdb4.c.
︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 49 50 51 52 53 | bt_db *pBt; /* bt database handle */ sqlite4_env *pEnv; /* SQLite environment (for malloc/free) */ bt_env *pVfs; /* Underlying VFS */ /* Space for bt_fetch() results */ u8 *aBuffer; /* Space to store results */ int nBuffer; /* Allocated size of aBuffer[] in bytes */ /* Stuff used for crash test simulation */ BtFile *apFile[2]; /* Database and log files used by pBt */ bt_env env; /* Private VFS for this object */ int nCrashSync; /* Number of syncs until crash (see above) */ int bCrash; /* True once a crash has been simulated */ }; | > > | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | bt_db *pBt; /* bt database handle */ sqlite4_env *pEnv; /* SQLite environment (for malloc/free) */ bt_env *pVfs; /* Underlying VFS */ /* Space for bt_fetch() results */ u8 *aBuffer; /* Space to store results */ int nBuffer; /* Allocated size of aBuffer[] in bytes */ int nRef; /* Stuff used for crash test simulation */ BtFile *apFile[2]; /* Database and log files used by pBt */ bt_env env; /* Private VFS for this object */ int nCrashSync; /* Number of syncs until crash (see above) */ int bCrash; /* True once a crash has been simulated */ }; |
︙ | ︙ | |||
73 74 75 76 77 78 79 | BtDb *pBt = (BtDb*)pVfs->pVfsCtx; int rc; if( pBt->bCrash ) return SQLITE4_IOERR; p = (BtFile*)testMalloc(sizeof(BtFile)); if( !p ) return SQLITE4_NOMEM; | > | > | | > > | > > | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | BtDb *pBt = (BtDb*)pVfs->pVfsCtx; int rc; if( pBt->bCrash ) return SQLITE4_IOERR; p = (BtFile*)testMalloc(sizeof(BtFile)); if( !p ) return SQLITE4_NOMEM; if( flags & BT_OPEN_DATABASE ){ pBt->apFile[0] = p; }else if( flags & BT_OPEN_LOG ){ pBt->apFile[1] = p; } p->pBt = pBt; rc = pBt->pVfs->xOpen(pEnv, pVfs, zFile, flags, &p->pFile); if( rc!=SQLITE4_OK ){ testFree(p); p = 0; }else{ pBt->nRef++; } *ppFile = (bt_file*)p; return rc; } static int btVfsSize(bt_file *pFile, sqlite4_int64 *piRes){ |
︙ | ︙ | |||
232 233 234 235 236 237 238 239 240 241 242 | return rc; } static int btVfsSectorSize(bt_file *pFile){ BtFile *p = (BtFile*)pFile; return p->pBt->pVfs->xSectorSize(p->pFile); } static int btVfsClose(bt_file *pFile){ BtFile *p = (BtFile*)pFile; int rc; | > > > > > > < > | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | return rc; } static int btVfsSectorSize(bt_file *pFile){ BtFile *p = (BtFile*)pFile; return p->pBt->pVfs->xSectorSize(p->pFile); } static void btDeref(BtDb *p){ p->nRef--; assert( p->nRef>=0 ); if( p->nRef<=0 ) testFree(p); } static int btVfsClose(bt_file *pFile){ BtFile *p = (BtFile*)pFile; int rc; btFlushSectors(p, 0); testFree(p->apSector); rc = p->pBt->pVfs->xClose(p->pFile); btDeref(p->pBt); testFree(p); return rc; } static int btVfsUnlink(sqlite4_env *pEnv, bt_env *pVfs, const char *zFile){ BtDb *pBt = (BtDb*)pVfs->pVfsCtx; if( pBt->bCrash ) return SQLITE4_IOERR; |
︙ | ︙ | |||
281 282 283 284 285 286 287 288 | BtFile *p = (BtFile*)pFile; if( p->pBt->bCrash ) return SQLITE4_IOERR; return p->pBt->pVfs->xShmUnmap(p->pFile, bDelete); } static int bt_close(TestDb *pTestDb){ BtDb *p = (BtDb*)pTestDb; free(p->aBuffer); | > > | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | BtFile *p = (BtFile*)pFile; if( p->pBt->bCrash ) return SQLITE4_IOERR; return p->pBt->pVfs->xShmUnmap(p->pFile, bDelete); } static int bt_close(TestDb *pTestDb){ BtDb *p = (BtDb*)pTestDb; int rc = sqlite4BtClose(p->pBt); free(p->aBuffer); btDeref(p); return rc; } static int btMinTransaction(BtDb *p, int iMin, int *piLevel){ int iLevel; int rc = SQLITE4_OK; iLevel = sqlite4BtTransactionLevel(p->pBt); |
︙ | ︙ | |||
641 642 643 644 645 646 647 | if( bClear && zFilename && zFilename[0] ){ char *zLog = sqlite3_mprintf("%s-wal", zFilename); unlink(zFilename); unlink(zLog); sqlite3_free(zLog); } | | | > | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 | if( bClear && zFilename && zFilename[0] ){ char *zLog = sqlite3_mprintf("%s-wal", zFilename); unlink(zFilename); unlink(zLog); sqlite3_free(zLog); } rc = sqlite4BtNew(pEnv, 0, &pBt); if( rc==SQLITE4_OK ){ p = (BtDb*)testMalloc(sizeof(BtDb)); p->base.pMethods = &SqlMethods; p->pBt = pBt; p->pEnv = pEnv; p->nRef = 1; p->env.pVfsCtx = (void*)p; p->env.xFullpath = btVfsFullpath; p->env.xOpen = btVfsOpen; p->env.xSize = btVfsSize; p->env.xRead = btVfsRead; p->env.xWrite = btVfsWrite; |
︙ | ︙ |
Changes to src/bt.h.
︙ | ︙ | |||
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | ** BT_CONTROL_SAFETY: ** The third argument is interpreted as a pointer to type (int). If ** the value stored in the (int) location is 0, 1 or 2, then the current ** b-tree safety level is set to 0, 1 or 2, respectively. Otherwise, the ** integer value is set to the current safety level. ** ** BT_CONTROL_AUTOCKPT: */ #define BT_CONTROL_INFO 7706389 #define BT_CONTROL_SETVFS 7706390 #define BT_CONTROL_GETVFS 7706391 #define BT_CONTROL_SAFETY 7706392 #define BT_CONTROL_AUTOCKPT 7706393 int sqlite4BtControl(bt_db*, int op, void *pArg); #define BT_SAFETY_OFF 0 #define BT_SAFETY_NORMAL 1 #define BT_SAFETY_FULL 2 | > > > > > > > > > > > > > | 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 | ** BT_CONTROL_SAFETY: ** The third argument is interpreted as a pointer to type (int). If ** the value stored in the (int) location is 0, 1 or 2, then the current ** b-tree safety level is set to 0, 1 or 2, respectively. Otherwise, the ** integer value is set to the current safety level. ** ** BT_CONTROL_AUTOCKPT: ** The third argument is interpreted as a pointer to type (int). If ** the indicated value is greater than or equal to zero, then the ** database connection auto-checkpoint value is set accordingly. If ** the indicated value is less than zero, it is set to the current ** auto-checkpoint value before returning. ** ** BT_CONTROL_LOGSIZE: ** The third argument is interpreted as a pointer to type (int). The ** value pointer to is set to the number of uncheckpointed frames ** that stored in the log file according to the snapshot used by the ** most recently completed transaction or checkpoint operation. ** */ #define BT_CONTROL_INFO 7706389 #define BT_CONTROL_SETVFS 7706390 #define BT_CONTROL_GETVFS 7706391 #define BT_CONTROL_SAFETY 7706392 #define BT_CONTROL_AUTOCKPT 7706393 #define BT_CONTROL_LOGSIZE 7706394 int sqlite4BtControl(bt_db*, int op, void *pArg); #define BT_SAFETY_OFF 0 #define BT_SAFETY_NORMAL 1 #define BT_SAFETY_FULL 2 |
︙ | ︙ | |||
195 196 197 198 199 200 201 202 | int (*xUnlink)(sqlite4_env*,bt_env*, const char *); int (*xLock)(bt_file*, int, int); int (*xTestLock)(bt_file*, int, int, int); int (*xShmMap)(bt_file*, int, int, void **); void (*xShmBarrier)(bt_file*); int (*xShmUnmap)(bt_file*, int); }; | > > > > > > > > | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | int (*xUnlink)(sqlite4_env*,bt_env*, const char *); int (*xLock)(bt_file*, int, int); int (*xTestLock)(bt_file*, int, int, int); int (*xShmMap)(bt_file*, int, int, void **); void (*xShmBarrier)(bt_file*); int (*xShmUnmap)(bt_file*, int); }; /* ** Flags for xOpen */ #define BT_OPEN_DATABASE 0x0001 #define BT_OPEN_LOG 0x0002 #define BT_OPEN_READONLY 0x0004 |
Changes to src/btInt.h.
︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | bt_env *sqlite4BtPagerGetEnv(BtPager*); void sqlite4BtPagerSetEnv(BtPager*, bt_env*); void sqlite4BtPagerSetSafety(BtPager*, int*); void sqlite4BtPagerSetAutockpt(BtPager*, int*); /* ** End of bt_pager.c interface. *************************************************************************/ /************************************************************************* ** File-system interface. */ | > > < < < | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | bt_env *sqlite4BtPagerGetEnv(BtPager*); void sqlite4BtPagerSetEnv(BtPager*, bt_env*); void sqlite4BtPagerSetSafety(BtPager*, int*); void sqlite4BtPagerSetAutockpt(BtPager*, int*); void sqlite4BtPagerLogsize(BtPager*, int*); /* ** End of bt_pager.c interface. *************************************************************************/ /************************************************************************* ** File-system interface. */ /* Candidate values for the 3rd argument to bt_env.xLock() */ #define BT_LOCK_UNLOCK 0 #define BT_LOCK_SHARED 1 #define BT_LOCK_EXCL 2 /* Size of shared-memory chunks - 48KB. */ #define BT_SHM_CHUNK_SIZE (48*1024) |
︙ | ︙ | |||
206 207 208 209 210 211 212 213 214 215 216 217 218 219 | /************************************************************************* ** Interface to bt_lock.c functionality. */ typedef struct BtShared BtShared; typedef struct BtLock BtLock; typedef struct BtReadSlot BtReadSlot; struct BtLock { /* These three are set by the bt_pager module and thereafter used by ** the bt_lock, bt_pager and bt_log modules. */ sqlite4_env *pEnv; /* SQLite environment */ bt_env *pVfs; /* Bt environment */ bt_file *pFd; /* Database file descriptor */ int iDebugId; /* Sometimes useful when debugging */ | > > | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | /************************************************************************* ** Interface to bt_lock.c functionality. */ typedef struct BtShared BtShared; typedef struct BtLock BtLock; typedef struct BtReadSlot BtReadSlot; typedef struct BtFile BtFile; struct BtLock { /* These three are set by the bt_pager module and thereafter used by ** the bt_lock, bt_pager and bt_log modules. */ sqlite4_env *pEnv; /* SQLite environment */ bt_env *pVfs; /* Bt environment */ bt_file *pFd; /* Database file descriptor */ int iDebugId; /* Sometimes useful when debugging */ |
︙ | ︙ | |||
231 232 233 234 235 236 237 238 239 240 241 242 243 244 | int nAutoCkpt; /* Auto-checkpoint when log is this large */ /* These are used only by the bt_lock module. */ BtShared *pShared; /* Shared by all handles on this file */ BtLock *pNext; /* Next connection using pShared */ u32 mExclLock; /* Mask of exclusive locks held */ u32 mSharedLock; /* Mask of shared locks held */ }; struct BtReadSlot { u32 iFirst; u32 iLast; }; | > | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | int nAutoCkpt; /* Auto-checkpoint when log is this large */ /* These are used only by the bt_lock module. */ BtShared *pShared; /* Shared by all handles on this file */ BtLock *pNext; /* Next connection using pShared */ u32 mExclLock; /* Mask of exclusive locks held */ u32 mSharedLock; /* Mask of shared locks held */ BtFile *pBtFile; /* Used to defer close if necessary */ }; struct BtReadSlot { u32 iFirst; u32 iLast; }; |
︙ | ︙ |
Changes to src/bt_lock.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 | #define BT_LOCK_READER_DBONLY 5 /* Reading the db file only */ #define BT_LOCK_READER0 6 /* Array of BT_NREADER locks */ #define BT_LOCK_UNLOCK 0 #define BT_LOCK_SHARED 1 #define BT_LOCK_EXCL 2 | < < | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #define BT_LOCK_READER_DBONLY 5 /* Reading the db file only */ #define BT_LOCK_READER0 6 /* Array of BT_NREADER locks */ #define BT_LOCK_UNLOCK 0 #define BT_LOCK_SHARED 1 #define BT_LOCK_EXCL 2 /* ** Global data. All global variables used by code in this file are grouped ** into the following structure instance. ** ** pDatabase: ** Linked list of all Database objects allocated within this process. ** This list may not be traversed without holding the global mutex (see |
︙ | ︙ | |||
87 88 89 90 91 92 93 94 95 96 97 98 99 100 | /* ** Relinquish the mutex obtained by calling btLockMutexEnter(). */ static void btLockMutexLeave(sqlite4_env *pEnv){ sqlite4_mutex_leave(sqlite4_mutex_alloc(pEnv, SQLITE4_MUTEX_STATIC_KV)); } static int btLockLockopNonblocking( BtLock *p, /* BtLock handle */ int iLock, /* Slot to lock */ int eOp /* One of BT_LOCK_UNLOCK, SHARED or EXCL */ ){ const u32 mask = ((u32)1 << iLock); | > > > > > > > > > > > > > > > > | 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 114 | /* ** Relinquish the mutex obtained by calling btLockMutexEnter(). */ static void btLockMutexLeave(sqlite4_env *pEnv){ sqlite4_mutex_leave(sqlite4_mutex_alloc(pEnv, SQLITE4_MUTEX_STATIC_KV)); } /* ** Take the specified lock on the shared file-handle associated with ** the connection passed as the first argument. */ static int btLockSharedFile(BtLock *p, int iLock, int eOp){ int rc = SQLITE4_OK; BtShared *pShared = p->pShared; /* This is a no-op in single process mode */ assert( (pShared->bMultiProc==0)==(pShared->pFile==0) ); if( pShared->pFile ){ rc = p->pVfs->xLock(pShared->pFile, iLock, eOp); } return rc; } static int btLockLockopNonblocking( BtLock *p, /* BtLock handle */ int iLock, /* Slot to lock */ int eOp /* One of BT_LOCK_UNLOCK, SHARED or EXCL */ ){ const u32 mask = ((u32)1 << iLock); |
︙ | ︙ | |||
131 132 133 134 135 136 137 | } assert( nExcl==0 || nExcl==1 ); assert( nExcl==0 || nShared==0 ); switch( eOp ){ case BT_LOCK_UNLOCK: if( nShared==0 ){ | < | < < | < < | < | 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 181 182 183 184 | } assert( nExcl==0 || nExcl==1 ); assert( nExcl==0 || nShared==0 ); switch( eOp ){ case BT_LOCK_UNLOCK: if( nShared==0 ){ btLockSharedFile(p, iLock, BT_LOCK_UNLOCK); } p->mExclLock &= ~mask; p->mSharedLock &= ~mask; break; case BT_LOCK_SHARED: if( nExcl ){ rc = SQLITE4_BUSY; }else{ if( nShared==0 ){ rc = btLockSharedFile(p, iLock, BT_LOCK_SHARED); } if( rc==SQLITE4_OK ){ p->mSharedLock |= mask; p->mExclLock &= ~mask; } } break; default: assert( eOp==BT_LOCK_EXCL ); if( nExcl || nShared ){ rc = SQLITE4_BUSY; }else{ rc = btLockSharedFile(p, iLock, BT_LOCK_EXCL); if( rc==SQLITE4_OK ){ p->mSharedLock &= ~mask; p->mExclLock |= mask; } } break; } |
︙ | ︙ | |||
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | if( rc!=SQLITE4_BUSY || bBlock==0 ) break; /* todo: Fix blocking locks */ btLockDelay(); } return rc; } /* ** Connect to the database as a read/write connection. If recovery ** is required (i.e. if this is the first connection to the db), invoke ** the xRecover() method. ** ** Return SQLITE4_OK if successful, or an SQLite4 error code if an ** error occurs. */ int sqlite4BtLockConnect(BtLock *p, int (*xRecover)(BtLock*)){ sqlite4_env *pEnv = p->pEnv; int rc = SQLITE4_OK; const char *zName; int nName; BtShared *pShared; zName = sqlite4BtPagerFilename((BtPager*)p, BT_PAGERFILE_DATABASE); nName = strlen(zName); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | if( rc!=SQLITE4_BUSY || bBlock==0 ) break; /* todo: Fix blocking locks */ btLockDelay(); } return rc; } static void btLockSharedDeref( sqlite4_env *pEnv, bt_env *pVfs, BtShared *pShared ){ btLockMutexEnter(pEnv); pShared->nRef--; if( pShared->nRef==0 ){ BtShared **ppS; for(ppS=&gBtShared.pDatabase; *ppS!=pShared; ppS=&(*ppS)->pNext); *ppS = (*ppS)->pNext; while( pShared->pBtFile ){ BtFile *p = pShared->pBtFile; pShared->pBtFile = p->pNext; pVfs->xClose(p->pFd); sqlite4_free(pEnv, p); } sqlite4_mutex_free(pShared->pClientMutex); /* If they were allocated in heap space, free all "shared" memory chunks */ if( pShared->pFile==0 ){ int i; for(i=0; i<pShared->nShmChunk; i++){ sqlite4_free(pEnv, pShared->apShmChunk[i]); } }else{ pVfs->xClose(pShared->pFile); } sqlite4_free(pEnv, pShared->apShmChunk); sqlite4_free(pEnv, pShared); } btLockMutexLeave(pEnv); } /* ** Connect to the database as a read/write connection. If recovery ** is required (i.e. if this is the first connection to the db), invoke ** the xRecover() method. ** ** Return SQLITE4_OK if successful, or an SQLite4 error code if an ** error occurs. */ int sqlite4BtLockConnect(BtLock *p, int (*xRecover)(BtLock*)){ sqlite4_env *pEnv = p->pEnv; bt_env *pVfs = p->pVfs; int rc = SQLITE4_OK; const char *zName; int nName; BtShared *pShared; zName = sqlite4BtPagerFilename((BtPager*)p, BT_PAGERFILE_DATABASE); nName = strlen(zName); |
︙ | ︙ | |||
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | sqlite4_free(pEnv, pShared); sqlite4_mutex_free(pMutex); pShared = 0; pMutex = 0; rc = btErrorBkpt(SQLITE4_NOMEM); }else{ memset(pShared, 0, sizeof(BtShared)); pShared->nName = nName; pShared->zName = (char *)&pShared[1]; memcpy(pShared->zName, zName, nName+1); pShared->pNext = gBtShared.pDatabase; pShared->pClientMutex = pMutex; gBtShared.pDatabase = pShared; } } | > < > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > | > | 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 | sqlite4_free(pEnv, pShared); sqlite4_mutex_free(pMutex); pShared = 0; pMutex = 0; rc = btErrorBkpt(SQLITE4_NOMEM); }else{ memset(pShared, 0, sizeof(BtShared)); pShared->bMultiProc = 1; pShared->nName = nName; pShared->zName = (char *)&pShared[1]; memcpy(pShared->zName, zName, nName+1); pShared->pNext = gBtShared.pDatabase; pShared->pClientMutex = pMutex; gBtShared.pDatabase = pShared; } } if( rc==SQLITE4_OK ){ pShared->nRef++; } btLockMutexLeave(p->pEnv); /* Add this connection to the linked list at BtShared.pLock */ if( rc==SQLITE4_OK ){ sqlite4_mutex_enter(pShared->pClientMutex); /* If this is a multi-process connection and the shared file-handle ** has not yet been opened, open it now. Under the cover of the ** client-mutex. */ if( pShared->pFile==0 && pShared->bMultiProc ){ rc = pVfs->xOpen(pEnv, pVfs, pShared->zName, 0, &pShared->pFile); } if( rc==SQLITE4_OK ){ if( pShared->pBtFile ){ p->pBtFile = pShared->pBtFile; pShared->pBtFile = p->pBtFile->pNext; p->pBtFile->pNext = 0; p->pFd = p->pBtFile->pFd; }else{ p->pBtFile = (BtFile*)sqlite4_malloc(pEnv, sizeof(BtFile)); if( p->pBtFile ){ int flags = BT_OPEN_DATABASE; p->pBtFile->pNext = 0; rc = pVfs->xOpen(pEnv, pVfs, pShared->zName, flags, &p->pFd); p->pBtFile->pFd = p->pFd; }else{ rc = btErrorBkpt(SQLITE4_NOMEM); } } } if( rc==SQLITE4_OK ){ p->pNext = pShared->pLock; pShared->pLock = p; p->pShared = pShared; } sqlite4_mutex_leave(pShared->pClientMutex); if( rc!=SQLITE4_OK ){ btLockSharedDeref(pEnv, pVfs, pShared); } } if( rc==SQLITE4_OK ){ rc = btLockLockop(p, BT_LOCK_DMS1, BT_LOCK_EXCL, 1); if( rc==SQLITE4_OK ){ rc = btLockLockop(p, BT_LOCK_DMS2_RW, BT_LOCK_EXCL, 0); if( rc==SQLITE4_OK ){ |
︙ | ︙ | |||
344 345 346 347 348 349 350 | } if( rc==SQLITE4_BUSY ) rc = SQLITE4_OK; btLockLockop(p, BT_LOCK_DMS2_RW, BT_LOCK_UNLOCK, 0); btLockLockop(p, BT_LOCK_DMS2_RO, BT_LOCK_UNLOCK, 0); btLockLockop(p, BT_LOCK_DMS1, BT_LOCK_UNLOCK, 0); } | < | | < < < | | | < < | < | < < | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | } if( rc==SQLITE4_BUSY ) rc = SQLITE4_OK; btLockLockop(p, BT_LOCK_DMS2_RW, BT_LOCK_UNLOCK, 0); btLockLockop(p, BT_LOCK_DMS2_RO, BT_LOCK_UNLOCK, 0); btLockLockop(p, BT_LOCK_DMS1, BT_LOCK_UNLOCK, 0); } sqlite4_mutex_enter(pShared->pClientMutex); assert( p->pBtFile->pNext==0 ); p->pBtFile->pNext = pShared->pBtFile; pShared->pBtFile = p->pBtFile; sqlite4_mutex_leave(pShared->pClientMutex); btLockSharedDeref(p->pEnv, p->pVfs, pShared); return rc; } #ifndef NDEBUG static void assertNoLockedSlots(BtLock *pLock){ u32 mask = (1 << (BT_LOCK_READER0+BT_NREADER+1)) - (1 << BT_LOCK_READER0); assert( (pLock->mExclLock & mask)==0 ); |
︙ | ︙ | |||
404 405 406 407 408 409 410 | if( (iFirst<aLog[0] || iFirst>aLog[1]) && (iFirst<aLog[2] || iFirst>aLog[3]) && (iFirst<aLog[4] || iFirst>aLog[5]) ){ iLast = 0; } | < < < < < | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | if( (iFirst<aLog[0] || iFirst>aLog[1]) && (iFirst<aLog[2] || iFirst>aLog[3]) && (iFirst<aLog[4] || iFirst>aLog[5]) ){ iLast = 0; } if( iLast==0 ){ rc = btLockLockop(pLock, BT_LOCK_READER_DBONLY, BT_LOCK_SHARED, 0); }else{ const int nMaxRetry = 100; int nAttempt = 100; /* Remaining lock attempts */ for(nAttempt=0; rc==SQLITE4_BUSY && nAttempt<nMaxRetry; nAttempt++){ int iIdxFirst = sqlite4BtLogFrameToIdx(aLog, iFirst); int iIdxLast = sqlite4BtLogFrameToIdx(aLog, iLast); assert( iIdxFirst>=0 && iIdxLast>=0 ); /* Try to find a slot populated with the values required. */ for(i=0; i<BT_NREADER; i++){ if( aSlot[i].iFirst==iFirst && aSlot[i].iLast==iLast ){ break; } } /* Or, if there is no slot with the required values - try to create one */ if( i==BT_NREADER ){ for(i=0; i<BT_NREADER; i++){ |
︙ | ︙ | |||
567 568 569 570 571 572 573 | } int sqlite4BtLockShmMap(BtLock *pLock, int iChunk, int nByte, u8 **ppOut){ int rc = SQLITE4_OK; BtShared *pShared = pLock->pShared; u8 *pOut = 0; | | > > > > | | > | | > > | > > > > > | < < > > > | 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | } int sqlite4BtLockShmMap(BtLock *pLock, int iChunk, int nByte, u8 **ppOut){ int rc = SQLITE4_OK; BtShared *pShared = pLock->pShared; u8 *pOut = 0; assert( pShared->bReadonly==0 ); sqlite4_mutex_enter(pShared->pClientMutex); if( pShared->nShmChunk<=iChunk ){ u8 **apNew; int nNew = iChunk+1; int nByte = sizeof(u8*)*nNew; apNew = (u8**)sqlite4_realloc(pLock->pEnv, pShared->apShmChunk, nByte); if( apNew==0 ){ rc = btErrorBkpt(SQLITE4_NOMEM); }else{ memset(&apNew[pShared->nShmChunk],0,nByte-sizeof(u8*)*pShared->nShmChunk); pShared->nShmChunk = nNew; pShared->apShmChunk = apNew; } } if( rc==SQLITE4_OK ){ assert( (pShared->bMultiProc==0)==(pShared->pFile==0) ); if( pShared->pFile==0 ){ /* Single process mode. Allocate memory from the heap. */ if( pShared->apShmChunk[iChunk]==0 ){ u8 *p = (u8*)sqlite4_malloc(pLock->pEnv, nByte); if( p ){ memset(p, 0, nByte); pShared->apShmChunk[iChunk] = p; }else{ rc = btErrorBkpt(SQLITE4_NOMEM); } } }else{ /* Multi-process mode. Request shared memory from VFS */ void *pShm = 0; rc = pLock->pVfs->xShmMap(pShared->pFile, iChunk, nByte, &pShm); pShared->apShmChunk[iChunk] = (u8*)pShm; } pOut = pShared->apShmChunk[iChunk]; assert( pOut || rc!=SQLITE4_OK ); } sqlite4_mutex_leave(pShared->pClientMutex); *ppOut = pOut; return rc; } |
︙ | ︙ |
Changes to src/bt_log.c.
︙ | ︙ | |||
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | int sqlite4BtLogOpen(BtPager *pPager, int bRecover, BtLog **ppLog){ BtLock *pLock = (BtLock*)pPager; bt_env *pVfs = pLock->pVfs; sqlite4_env *pEnv = pLock->pEnv; int rc; /* Return code */ const char *zWal; /* Name of log file to open */ BtLog *pLog; /* Log handle to return */ pLog = sqlite4_malloc(pEnv, sizeof(BtLog)); if( pLog==0 ){ rc = SQLITE4_NOMEM; goto open_out; } memset(pLog, 0, sizeof(BtLog)); pLog->pLock = (BtLock*)pPager; pLog->nWrapLog = BT_NWRAPLOG; zWal = sqlite4BtPagerFilename(pPager, BT_PAGERFILE_LOG); | > | | 921 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 | int sqlite4BtLogOpen(BtPager *pPager, int bRecover, BtLog **ppLog){ BtLock *pLock = (BtLock*)pPager; bt_env *pVfs = pLock->pVfs; sqlite4_env *pEnv = pLock->pEnv; int rc; /* Return code */ const char *zWal; /* Name of log file to open */ BtLog *pLog; /* Log handle to return */ int flags = BT_OPEN_LOG; pLog = sqlite4_malloc(pEnv, sizeof(BtLog)); if( pLog==0 ){ rc = SQLITE4_NOMEM; goto open_out; } memset(pLog, 0, sizeof(BtLog)); pLog->pLock = (BtLock*)pPager; pLog->nWrapLog = BT_NWRAPLOG; zWal = sqlite4BtPagerFilename(pPager, BT_PAGERFILE_LOG); rc = pVfs->xOpen(pEnv, pVfs, zWal, flags, &pLog->pFd); if( rc==SQLITE4_OK && bRecover ){ rc = btLogMapShm(pLog, 0); if( rc==SQLITE4_OK ){ BtShm *pShm = btLogShm(pLog); memset(pShm, 0, sizeof(BtShm)); pShm->ckpt.iFirstRead = 1; |
︙ | ︙ |
Changes to src/bt_main.c.
︙ | ︙ | |||
2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 | } case BT_CONTROL_AUTOCKPT: { int *pInt = (int*)pArg; sqlite4BtPagerSetAutockpt(db->pPager, pInt); break; } } return rc; } | > > > > > > | 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 | } case BT_CONTROL_AUTOCKPT: { int *pInt = (int*)pArg; sqlite4BtPagerSetAutockpt(db->pPager, pInt); break; } case BT_CONTROL_LOGSIZE: { int *pInt = (int*)pArg; sqlite4BtPagerLogsize(db->pPager, pInt); break; } } return rc; } |
Changes to src/bt_pager.c.
︙ | ︙ | |||
364 365 366 367 368 369 370 | ** Close a pager database handle. */ int sqlite4BtPagerClose(BtPager *p){ int rc; rc = sqlite4BtLockDisconnect((BtLock*)p, btCheckpoint, btCleanup); | < < < < | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | ** Close a pager database handle. */ int sqlite4BtPagerClose(BtPager *p){ int rc; rc = sqlite4BtLockDisconnect((BtLock*)p, btCheckpoint, btCleanup); p->iTransactionLevel = 0; btCloseSavepoints(p, 0); btPurgeCache(p); sqlite4BtLogClose(p->pLog, 0); sqlite4_free(p->btl.pEnv, p->zFile); sqlite4_free(p->btl.pEnv, p->aSavepoint); sqlite4_free(p->btl.pEnv, p); |
︙ | ︙ | |||
407 408 409 410 411 412 413 | ** fails, the BtPager is rendered unusable (and must be closed by the ** caller using BtPagerClose()). ** ** If successful, SQLITE4_OK is returned. Otherwise, an SQLite error code. */ int sqlite4BtPagerOpen(BtPager *p, const char *zFilename){ int rc; /* Return code */ | < < < < < < < | 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | ** fails, the BtPager is rendered unusable (and must be closed by the ** caller using BtPagerClose()). ** ** If successful, SQLITE4_OK is returned. Otherwise, an SQLite error code. */ int sqlite4BtPagerOpen(BtPager *p, const char *zFilename){ int rc; /* Return code */ sqlite4_env *pEnv = p->btl.pEnv; bt_env *pVfs = p->btl.pVfs; assert( p->btl.pFd==0 && p->zFile==0 ); rc = pVfs->xFullpath(pEnv, pVfs, zFilename, &p->zFile); if( rc==SQLITE4_OK ){ p->nFile = strlen(p->zFile); rc = sqlite4BtLockConnect((BtLock*)p, btRecover); if( rc==SQLITE4_OK && p->pLog==0 ){ rc = sqlite4BtLogOpen(p, 0, &p->pLog); } } assert( (rc==SQLITE4_OK)==(p->btl.pFd!=0 && p->pLog!=0) ); |
︙ | ︙ | |||
928 929 930 931 932 933 934 935 936 937 938 939 940 941 | void sqlite4BtPagerSetAutockpt(BtPager *pPager, int *piVal){ int iVal = *piVal; if( iVal>=0 ){ pPager->btl.nAutoCkpt = iVal; } *piVal = pPager->btl.nAutoCkpt; } #ifndef NDEBUG int sqlite4BtPagerRefcount(BtPager *p){ return p->nTotalRef; } #endif | > > > > | 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 | void sqlite4BtPagerSetAutockpt(BtPager *pPager, int *piVal){ int iVal = *piVal; if( iVal>=0 ){ pPager->btl.nAutoCkpt = iVal; } *piVal = pPager->btl.nAutoCkpt; } void sqlite4BtPagerLogsize(BtPager *pPager, int *pnFrame){ *pnFrame = sqlite4BtLogSize(pPager->pLog); } #ifndef NDEBUG int sqlite4BtPagerRefcount(BtPager *p){ return p->nTotalRef; } #endif |
Changes to src/bt_unix.c.
︙ | ︙ | |||
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | return rc; } static int btPosixOsUnlink(sqlite4_env *pEnv, bt_env *pVfs, const char *zFile){ int prc = unlink(zFile); return prc ? btErrorBkpt(SQLITE4_IOERR) : SQLITE4_OK; } int btPosixOsLock(bt_file *pFile, int iLock, int eType){ int rc = SQLITE4_OK; PosixFile *p = (PosixFile *)pFile; static const short aType[3] = { F_UNLCK, F_RDLCK, F_WRLCK }; struct flock lock; assert( aType[BT_LOCK_UNLOCK]==F_UNLCK ); assert( aType[BT_LOCK_SHARED]==F_RDLCK ); assert( aType[BT_LOCK_EXCL]==F_WRLCK ); assert( eType>=0 && eType<(sizeof(aType)/sizeof(aType[0])) ); | > > | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | return rc; } static int btPosixOsUnlink(sqlite4_env *pEnv, bt_env *pVfs, const char *zFile){ int prc = unlink(zFile); return prc ? btErrorBkpt(SQLITE4_IOERR) : SQLITE4_OK; } #define btPosixLockToByte(iLock) (100 + (iLock)) int btPosixOsLock(bt_file *pFile, int iLock, int eType){ int rc = SQLITE4_OK; PosixFile *p = (PosixFile *)pFile; static const short aType[3] = { F_UNLCK, F_RDLCK, F_WRLCK }; struct flock lock; assert( aType[BT_LOCK_UNLOCK]==F_UNLCK ); assert( aType[BT_LOCK_SHARED]==F_RDLCK ); assert( aType[BT_LOCK_EXCL]==F_WRLCK ); assert( eType>=0 && eType<(sizeof(aType)/sizeof(aType[0])) ); assert( iLock>=0 && iLock<=32 ); memset(&lock, 0, sizeof(lock)); lock.l_whence = SEEK_SET; lock.l_len = 1; lock.l_type = aType[eType]; lock.l_start = btPosixLockToByte(iLock); if( fcntl(p->fd, F_SETLK, &lock) ){ int e = errno; if( e==EACCES || e==EAGAIN ){ rc = SQLITE4_BUSY; }else{ rc = btErrorBkpt(SQLITE4_IOERR); |
︙ | ︙ | |||
296 297 298 299 300 301 302 | static const short aType[3] = { 0, F_RDLCK, F_WRLCK }; struct flock lock; assert( eType==BT_LOCK_SHARED || eType==BT_LOCK_EXCL ); assert( aType[BT_LOCK_SHARED]==F_RDLCK ); assert( aType[BT_LOCK_EXCL]==F_WRLCK ); assert( eType>=0 && eType<(sizeof(aType)/sizeof(aType[0])) ); | | | | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | static const short aType[3] = { 0, F_RDLCK, F_WRLCK }; struct flock lock; assert( eType==BT_LOCK_SHARED || eType==BT_LOCK_EXCL ); assert( aType[BT_LOCK_SHARED]==F_RDLCK ); assert( aType[BT_LOCK_EXCL]==F_WRLCK ); assert( eType>=0 && eType<(sizeof(aType)/sizeof(aType[0])) ); assert( iLock>=0 && iLock<=32 ); memset(&lock, 0, sizeof(lock)); lock.l_whence = SEEK_SET; lock.l_len = nLock; lock.l_type = aType[eType]; lock.l_start = btPosixLockToByte(iLock); if( fcntl(p->fd, F_GETLK, &lock) ){ rc = btErrorBkpt(SQLITE4_IOERR); }else if( lock.l_type!=F_UNLCK ){ rc = SQLITE4_BUSY; } |
︙ | ︙ |