Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add definitions for the extra locks required for read-only clients to detect whether or not a database is live. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | read-only-clients |
Files: | files | file ages | folders |
SHA1: |
69f33cfa1257123be4e88410fb707de4 |
User & Date: | dan 2013-02-09 19:42:47 |
Context
2013-02-17
| ||
14:19 | Merge trunk changes into this branch. check-in: 29390891c5 user: dan tags: read-only-clients | |
2013-02-09
| ||
19:42 | Add definitions for the extra locks required for read-only clients to detect whether or not a database is live. check-in: 69f33cfa12 user: dan tags: read-only-clients | |
16:55 | Have worker clients and writers that discard an old in-memory tree update a read-lock slot before concluding their work or write transaction. This is required for read-only clients - which cannot set the value of their own read-lock slot. check-in: 798d9e23be user: dan tags: trunk | |
Changes
Changes to src/lsmInt.h.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 ... 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 ... 317 318 319 320 321 322 323 324 325 326 327 328 329 330 ... 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
/* The number of bytes reserved at the start of each shm chunk for MM. */ #define LSM_SHM_CHUNK_HDR (sizeof(ShmChunk)) /* The number of available read locks. */ #define LSM_LOCK_NREADER 6 /* Lock definitions */ #define LSM_LOCK_DMS1 1 #define LSM_LOCK_DMS2 2 #define LSM_LOCK_WRITER 3 #define LSM_LOCK_WORKER 4 #define LSM_LOCK_CHECKPOINTER 5 #define LSM_LOCK_READER(i) ((i) + LSM_LOCK_CHECKPOINTER + 1) /* ** Hard limit on the number of free-list entries that may be stored in ** a checkpoint (the remainder are stored as a system record in the LSM). ** See also LSM_CONFIG_MAX_FREELIST. */ #define LSM_MAX_FREELIST_ENTRIES 24 ................................................................................ /* ** Database handle structure. ** ** mLock: ** A bitmask representing the locks currently held by the connection. ** An LSM database supports N distinct locks, where N is some number less ** than or equal to 16. Locks are numbered starting from 1 (see the ** definitions for LSM_LOCK_WRITER and co.). ** ** The least significant 16-bits in mLock represent EXCLUSIVE locks. The ** most significant are SHARED locks. So, if a connection holds a SHARED ** lock on lock region iLock, then the following is true: ** ** (mLock & ((iLock+16-1) << 1)) ** ** Or for an EXCLUSIVE lock: ** ** (mLock & ((iLock-1) << 1)) */ struct lsm_db { ................................................................................ int bMultiProc; /* Configured by L_C_MULTIPLE_PROCESSES */ lsm_compress compress; /* Compression callbacks */ lsm_compress_factory factory; /* Compression callback factory */ /* Sub-system handles */ FileSystem *pFS; /* On-disk portion of database */ Database *pDatabase; /* Database shared data */ /* Client transaction context */ Snapshot *pClient; /* Client snapshot */ int iReader; /* Read lock held (-1 == unlocked) */ MultiCursor *pCsr; /* List of all open cursors */ LogWriter *pLogWriter; /* Context for writing to the log file */ int nTransOpen; /* Number of opened write transactions */ ................................................................................ void (*xLog)(void *, int, const char *); void *pLogCtx; /* Work done notification callback */ void (*xWork)(lsm_db *, void *); void *pWorkCtx; u32 mLock; /* Mask of current locks. See lsmShmLock(). */ lsm_db *pNext; /* Next connection to same database */ int nShm; /* Size of apShm[] array */ void **apShm; /* Shared memory chunks */ ShmHeader *pShmhdr; /* Live shared-memory header */ TreeHeader treehdr; /* Local copy of tree-header */ u32 aSnapshot[LSM_META_PAGE_SIZE / sizeof(u32)]; |
> > > > | | | > | | | > | |
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 ... 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 ... 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 ... 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
/* The number of bytes reserved at the start of each shm chunk for MM. */ #define LSM_SHM_CHUNK_HDR (sizeof(ShmChunk)) /* The number of available read locks. */ #define LSM_LOCK_NREADER 6 /* The number of available read-write client locks. */ #define LSM_LOCK_NRWCLIENT 16 /* Lock definitions */ #define LSM_LOCK_DMS1 1 #define LSM_LOCK_DMS2 2 #define LSM_LOCK_DMS3 3 #define LSM_LOCK_WRITER 4 #define LSM_LOCK_WORKER 5 #define LSM_LOCK_CHECKPOINTER 6 #define LSM_LOCK_READER(i) ((i) + LSM_LOCK_CHECKPOINTER + 1) #define LSM_LOCK_RWCLIENT(i) ((i) + LSM_LOCK_READER(LSM_LOCK_NREADER)) /* ** Hard limit on the number of free-list entries that may be stored in ** a checkpoint (the remainder are stored as a system record in the LSM). ** See also LSM_CONFIG_MAX_FREELIST. */ #define LSM_MAX_FREELIST_ENTRIES 24 ................................................................................ /* ** Database handle structure. ** ** mLock: ** A bitmask representing the locks currently held by the connection. ** An LSM database supports N distinct locks, where N is some number less ** than or equal to 32. Locks are numbered starting from 1 (see the ** definitions for LSM_LOCK_WRITER and co.). ** ** The least significant 32-bits in mLock represent EXCLUSIVE locks. The ** most significant are SHARED locks. So, if a connection holds a SHARED ** lock on lock region iLock, then the following is true: ** ** (mLock & ((iLock+32-1) << 1)) ** ** Or for an EXCLUSIVE lock: ** ** (mLock & ((iLock-1) << 1)) */ struct lsm_db { ................................................................................ int bMultiProc; /* Configured by L_C_MULTIPLE_PROCESSES */ lsm_compress compress; /* Compression callbacks */ lsm_compress_factory factory; /* Compression callback factory */ /* Sub-system handles */ FileSystem *pFS; /* On-disk portion of database */ Database *pDatabase; /* Database shared data */ int iRwclient; /* Read-write client lock held (-1 == none) */ /* Client transaction context */ Snapshot *pClient; /* Client snapshot */ int iReader; /* Read lock held (-1 == unlocked) */ MultiCursor *pCsr; /* List of all open cursors */ LogWriter *pLogWriter; /* Context for writing to the log file */ int nTransOpen; /* Number of opened write transactions */ ................................................................................ void (*xLog)(void *, int, const char *); void *pLogCtx; /* Work done notification callback */ void (*xWork)(lsm_db *, void *); void *pWorkCtx; u64 mLock; /* Mask of current locks. See lsmShmLock(). */ lsm_db *pNext; /* Next connection to same database */ int nShm; /* Size of apShm[] array */ void **apShm; /* Shared memory chunks */ ShmHeader *pShmhdr; /* Live shared-memory header */ TreeHeader treehdr; /* Local copy of tree-header */ u32 aSnapshot[LSM_META_PAGE_SIZE / sizeof(u32)]; |
Changes to src/lsm_main.c.
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
pDb->xCmp = xCmp;
pDb->nDfltPgsz = LSM_DFLT_PAGE_SIZE;
pDb->nDfltBlksz = LSM_DFLT_BLOCK_SIZE;
pDb->nMerge = LSM_DFLT_AUTOMERGE;
pDb->nMaxFreelist = LSM_MAX_FREELIST_ENTRIES;
pDb->bUseLog = LSM_DFLT_USE_LOG;
pDb->iReader = -1;
pDb->bMultiProc = LSM_DFLT_MULTIPLE_PROCESSES;
pDb->bMmap = LSM_DFLT_MMAP;
pDb->xLog = xLog;
pDb->compress.iId = LSM_COMPRESSION_NONE;
return LSM_OK;
}
................................................................................
if( pDb ){
assert_db_state(pDb);
if( pDb->pCsr || pDb->nTransOpen ){
rc = LSM_MISUSE_BKPT;
}else{
lsmFreeSnapshot(pDb->pEnv, pDb->pClient);
pDb->pClient = 0;
lsmDbDatabaseRelease(pDb);
lsmLogClose(pDb);
lsmFsClose(pDb->pFS);
/* Invoke any destructors registered for the compression or
** compression factory callbacks. */
if( pDb->factory.xFree ) pDb->factory.xFree(pDb->factory.pCtx);
if( pDb->compress.xFree ) pDb->compress.xFree(pDb->compress.pCtx);
lsmFree(pDb->pEnv, pDb->rollback.aArray);
|
>
>
>
|
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
pDb->xCmp = xCmp; pDb->nDfltPgsz = LSM_DFLT_PAGE_SIZE; pDb->nDfltBlksz = LSM_DFLT_BLOCK_SIZE; pDb->nMerge = LSM_DFLT_AUTOMERGE; pDb->nMaxFreelist = LSM_MAX_FREELIST_ENTRIES; pDb->bUseLog = LSM_DFLT_USE_LOG; pDb->iReader = -1; pDb->iRwclient = -1; pDb->bMultiProc = LSM_DFLT_MULTIPLE_PROCESSES; pDb->bMmap = LSM_DFLT_MMAP; pDb->xLog = xLog; pDb->compress.iId = LSM_COMPRESSION_NONE; return LSM_OK; } ................................................................................ if( pDb ){ assert_db_state(pDb); if( pDb->pCsr || pDb->nTransOpen ){ rc = LSM_MISUSE_BKPT; }else{ lsmFreeSnapshot(pDb->pEnv, pDb->pClient); pDb->pClient = 0; lsmDbDatabaseRelease(pDb); lsmLogClose(pDb); lsmFsClose(pDb->pFS); assert( pDb->mLock==0 ); /* Invoke any destructors registered for the compression or ** compression factory callbacks. */ if( pDb->factory.xFree ) pDb->factory.xFree(pDb->factory.pCtx); if( pDb->compress.xFree ) pDb->compress.xFree(pDb->compress.pCtx); lsmFree(pDb->pEnv, pDb->rollback.aArray); |
Changes to src/lsm_shared.c.
276 277 278 279 280 281 282 283 284 285 286 287 288 289 ... 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 .... 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 .... 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 |
Database *p = pDb->pDatabase; dbTruncateFile(pDb); lsmFsCloseAndDeleteLog(pDb->pFS); if( p->pFile && p->bMultiProc ) lsmEnvShmUnmap(pDb->pEnv, p->pFile, 1); } } } lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_UNLOCK, 0); lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); pDb->pShmhdr = 0; } static int doDbConnect(lsm_db *pDb){ ................................................................................ ** mode, this operation will fail. In this case, return the error to the ** caller - the attempt to connect to the db has failed. */ if( rc==LSM_OK ){ rc = lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_SHARED, 0); } /* If anything went wrong, unlock DMS2. Unlock DMS1 in any case. */ if( rc!=LSM_OK ){ lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_UNLOCK, 0); pDb->pShmhdr = 0; } lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); return rc; } /* ** Return a reference to the shared Database handle for the database ................................................................................ int lsmShmLock( lsm_db *db, int iLock, int eOp, /* One of LSM_LOCK_UNLOCK, SHARED or EXCL */ int bBlock /* True for a blocking lock */ ){ lsm_db *pIter; const u32 me = (1 << (iLock-1)); const u32 ms = (1 << (iLock+16-1)); int rc = LSM_OK; Database *p = db->pDatabase; assert( iLock>=1 && iLock<=LSM_LOCK_READER(LSM_LOCK_NREADER-1) ); assert( iLock<=16 ); assert( eOp==LSM_LOCK_UNLOCK || eOp==LSM_LOCK_SHARED || eOp==LSM_LOCK_EXCL ); /* Check for a no-op. Proceed only if this is not one of those. */ if( (eOp==LSM_LOCK_UNLOCK && (db->mLock & (me|ms))!=0) || (eOp==LSM_LOCK_SHARED && (db->mLock & (me|ms))!=ms) || (eOp==LSM_LOCK_EXCL && (db->mLock & me)==0) ){ ................................................................................ return rc; } #ifdef LSM_DEBUG int shmLockType(lsm_db *db, int iLock){ const u32 me = (1 << (iLock-1)); const u32 ms = (1 << (iLock+16-1)); if( db->mLock & me ) return LSM_LOCK_EXCL; if( db->mLock & ms ) return LSM_LOCK_SHARED; return LSM_LOCK_UNLOCK; } /* |
> > > > | > > > > > > > > > > > | | | | | | |
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 ... 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 .... 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 .... 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 |
Database *p = pDb->pDatabase; dbTruncateFile(pDb); lsmFsCloseAndDeleteLog(pDb->pFS); if( p->pFile && p->bMultiProc ) lsmEnvShmUnmap(pDb->pEnv, p->pFile, 1); } } } if( pDb->iRwclient>=0 ){ lsmShmLock(pDb, LSM_LOCK_RWCLIENT(pDb->iRwclient), LSM_LOCK_UNLOCK, 0); } lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_UNLOCK, 0); lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); pDb->pShmhdr = 0; } static int doDbConnect(lsm_db *pDb){ ................................................................................ ** mode, this operation will fail. In this case, return the error to the ** caller - the attempt to connect to the db has failed. */ if( rc==LSM_OK ){ rc = lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_SHARED, 0); } /* If anything went wrong, unlock DMS2. Otherwise, try to take an exclusive ** lock on one of the LSM_LOCK_RWCLIENT() locks. Unlock DMS1 in any case. */ if( rc!=LSM_OK ){ lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_UNLOCK, 0); pDb->pShmhdr = 0; }else{ int i; for(i=0; i<LSM_LOCK_NRWCLIENT; i++){ int rc2 = lsmShmLock(pDb, LSM_LOCK_RWCLIENT(i), LSM_LOCK_EXCL, 0); if( rc2==LSM_OK ) pDb->iRwclient = i; if( rc2!=LSM_BUSY ){ rc = rc2; break; } } } lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); return rc; } /* ** Return a reference to the shared Database handle for the database ................................................................................ int lsmShmLock( lsm_db *db, int iLock, int eOp, /* One of LSM_LOCK_UNLOCK, SHARED or EXCL */ int bBlock /* True for a blocking lock */ ){ lsm_db *pIter; const u64 me = ((u64)1 << (iLock-1)); const u64 ms = ((u64)1 << (iLock+32-1)); int rc = LSM_OK; Database *p = db->pDatabase; assert( iLock>=1 && iLock<=LSM_LOCK_RWCLIENT(LSM_LOCK_NRWCLIENT-1) ); assert( LSM_LOCK_RWCLIENT(LSM_LOCK_NRWCLIENT-1)<=32 ); assert( eOp==LSM_LOCK_UNLOCK || eOp==LSM_LOCK_SHARED || eOp==LSM_LOCK_EXCL ); /* Check for a no-op. Proceed only if this is not one of those. */ if( (eOp==LSM_LOCK_UNLOCK && (db->mLock & (me|ms))!=0) || (eOp==LSM_LOCK_SHARED && (db->mLock & (me|ms))!=ms) || (eOp==LSM_LOCK_EXCL && (db->mLock & me)==0) ){ ................................................................................ return rc; } #ifdef LSM_DEBUG int shmLockType(lsm_db *db, int iLock){ const u64 me = ((u64)1 << (iLock-1)); const u64 ms = ((u64)1 << (iLock+32-1)); if( db->mLock & me ) return LSM_LOCK_EXCL; if( db->mLock & ms ) return LSM_LOCK_SHARED; return LSM_LOCK_UNLOCK; } /* |
Changes to src/lsm_unix.c.
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
static const short aType[3] = { F_UNLCK, F_RDLCK, F_WRLCK };
struct flock lock;
assert( aType[LSM_LOCK_UNLOCK]==F_UNLCK );
assert( aType[LSM_LOCK_SHARED]==F_RDLCK );
assert( aType[LSM_LOCK_EXCL]==F_WRLCK );
assert( eType>=0 && eType<array_size(aType) );
assert( iLock>0 && iLock<=16 );
memset(&lock, 0, sizeof(lock));
lock.l_whence = SEEK_SET;
lock.l_len = 1;
lock.l_type = aType[eType];
lock.l_start = (4096-iLock);
|
| |
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
static const short aType[3] = { F_UNLCK, F_RDLCK, F_WRLCK };
struct flock lock;
assert( aType[LSM_LOCK_UNLOCK]==F_UNLCK );
assert( aType[LSM_LOCK_SHARED]==F_RDLCK );
assert( aType[LSM_LOCK_EXCL]==F_WRLCK );
assert( eType>=0 && eType<array_size(aType) );
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 = (4096-iLock);
|