1 /* 2 ** 2012-01-23 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ************************************************************************* 12 ** 13 ** Utilities used to help multiple LSM clients to coexist within the 14 ** same process space. 15 */ 16 #include "lsmInt.h" 17 18 /* 19 ** Global data. All global variables used by code in this file are grouped 20 ** into the following structure instance. 21 ** 22 ** pDatabase: 23 ** Linked list of all Database objects allocated within this process. 24 ** This list may not be traversed without holding the global mutex (see 25 ** functions enterGlobalMutex() and leaveGlobalMutex()). 26 */ 27 static struct SharedData { 28 Database *pDatabase; /* Linked list of all Database objects */ 29 } gShared; 30 31 /* 32 ** Database structure. There is one such structure for each distinct 33 ** database accessed by this process. They are stored in the singly linked 34 ** list starting at global variable gShared.pDatabase. Database objects are 35 ** reference counted. Once the number of connections to the associated 36 ** database drops to zero, they are removed from the linked list and deleted. 37 ** 38 ** pFile: 39 ** In multi-process mode, this file descriptor is used to obtain locks 40 ** and to access shared-memory. In single process mode, its only job is 41 ** to hold the exclusive lock on the file. 42 ** 43 */ 44 struct Database { 45 /* Protected by the global mutex (enterGlobalMutex/leaveGlobalMutex): */ 46 char *zName; /* Canonical path to database file */ 47 int nName; /* strlen(zName) */ 48 int nDbRef; /* Number of associated lsm_db handles */ 49 Database *pDbNext; /* Next Database structure in global list */ 50 51 /* Protected by the local mutex (pClientMutex) */ 52 int bReadonly; /* True if Database.pFile is read-only */ 53 int bMultiProc; /* True if running in multi-process mode */ 54 lsm_file *pFile; /* Used for locks/shm in multi-proc mode */ 55 LsmFile *pLsmFile; /* List of deferred closes */ 56 lsm_mutex *pClientMutex; /* Protects the apShmChunk[] and pConn */ 57 int nShmChunk; /* Number of entries in apShmChunk[] array */ 58 void **apShmChunk; /* Array of "shared" memory regions */ 59 lsm_db *pConn; /* List of connections to this db. */ 60 }; 61 62 /* 63 ** Functions to enter and leave the global mutex. This mutex is used 64 ** to protect the global linked-list headed at gShared.pDatabase. 65 */ 66 static int enterGlobalMutex(lsm_env *pEnv){ 67 lsm_mutex *p; 68 int rc = lsmMutexStatic(pEnv, LSM_MUTEX_GLOBAL, &p); 69 if( rc==LSM_OK ) lsmMutexEnter(pEnv, p); 70 return rc; 71 } 72 static void leaveGlobalMutex(lsm_env *pEnv){ 73 lsm_mutex *p; 74 lsmMutexStatic(pEnv, LSM_MUTEX_GLOBAL, &p); 75 lsmMutexLeave(pEnv, p); 76 } 77 78 #ifdef LSM_DEBUG 79 static int holdingGlobalMutex(lsm_env *pEnv){ 80 lsm_mutex *p; 81 lsmMutexStatic(pEnv, LSM_MUTEX_GLOBAL, &p); 82 return lsmMutexHeld(pEnv, p); 83 } 84 #endif 85 86 #if 0 87 static void assertNotInFreelist(Freelist *p, int iBlk){ 88 int i; 89 for(i=0; i<p->nEntry; i++){ 90 assert( p->aEntry[i].iBlk!=iBlk ); 91 } 92 } 93 #else 94 # define assertNotInFreelist(x,y) 95 #endif 96 97 /* 98 ** Append an entry to the free-list. If (iId==-1), this is a delete. 99 */ 100 int freelistAppend(lsm_db *db, u32 iBlk, i64 iId){ 101 lsm_env *pEnv = db->pEnv; 102 Freelist *p; 103 int i; 104 105 assert( iId==-1 || iId>=0 ); 106 p = db->bUseFreelist ? db->pFreelist : &db->pWorker->freelist; 107 108 /* Extend the space allocated for the freelist, if required */ 109 assert( p->nAlloc>=p->nEntry ); 110 if( p->nAlloc==p->nEntry ){ 111 int nNew; 112 int nByte; 113 FreelistEntry *aNew; 114 115 nNew = (p->nAlloc==0 ? 4 : p->nAlloc*2); 116 nByte = sizeof(FreelistEntry) * nNew; 117 aNew = (FreelistEntry *)lsmRealloc(pEnv, p->aEntry, nByte); 118 if( !aNew ) return LSM_NOMEM_BKPT; 119 p->nAlloc = nNew; 120 p->aEntry = aNew; 121 } 122 123 for(i=0; i<p->nEntry; i++){ 124 assert( i==0 || p->aEntry[i].iBlk > p->aEntry[i-1].iBlk ); 125 if( p->aEntry[i].iBlk>=iBlk ) break; 126 } 127 128 if( i<p->nEntry && p->aEntry[i].iBlk==iBlk ){ 129 /* Clobber an existing entry */ 130 p->aEntry[i].iId = iId; 131 }else{ 132 /* Insert a new entry into the list */ 133 int nByte = sizeof(FreelistEntry)*(p->nEntry-i); 134 memmove(&p->aEntry[i+1], &p->aEntry[i], nByte); 135 p->aEntry[i].iBlk = iBlk; 136 p->aEntry[i].iId = iId; 137 p->nEntry++; 138 } 139 140 return LSM_OK; 141 } 142 143 /* 144 ** This function frees all resources held by the Database structure passed 145 ** as the only argument. 146 */ 147 static void freeDatabase(lsm_env *pEnv, Database *p){ 148 assert( holdingGlobalMutex(pEnv) ); 149 if( p ){ 150 /* Free the mutexes */ 151 lsmMutexDel(pEnv, p->pClientMutex); 152 153 if( p->pFile ){ 154 lsmEnvClose(pEnv, p->pFile); 155 } 156 157 /* Free the array of shm pointers */ 158 lsmFree(pEnv, p->apShmChunk); 159 160 /* Free the memory allocated for the Database struct itself */ 161 lsmFree(pEnv, p); 162 } 163 } 164 165 typedef struct DbTruncateCtx DbTruncateCtx; 166 struct DbTruncateCtx { 167 int nBlock; 168 i64 iInUse; 169 }; 170 171 static int dbTruncateCb(void *pCtx, int iBlk, i64 iSnapshot){ 172 DbTruncateCtx *p = (DbTruncateCtx *)pCtx; 173 if( iBlk!=p->nBlock || (p->iInUse>=0 && iSnapshot>=p->iInUse) ) return 1; 174 p->nBlock--; 175 return 0; 176 } 177 178 static int dbTruncate(lsm_db *pDb, i64 iInUse){ 179 int rc = LSM_OK; 180 #if 0 181 int i; 182 DbTruncateCtx ctx; 183 184 assert( pDb->pWorker ); 185 ctx.nBlock = pDb->pWorker->nBlock; 186 ctx.iInUse = iInUse; 187 188 rc = lsmWalkFreelist(pDb, 1, dbTruncateCb, (void *)&ctx); 189 for(i=ctx.nBlock+1; rc==LSM_OK && i<=pDb->pWorker->nBlock; i++){ 190 rc = freelistAppend(pDb, i, -1); 191 } 192 193 if( rc==LSM_OK ){ 194 #ifdef LSM_LOG_FREELIST 195 if( ctx.nBlock!=pDb->pWorker->nBlock ){ 196 lsmLogMessage(pDb, 0, 197 "dbTruncate(): truncated db to %d blocks",ctx.nBlock 198 ); 199 } 200 #endif 201 pDb->pWorker->nBlock = ctx.nBlock; 202 } 203 #endif 204 return rc; 205 } 206 207 208 /* 209 ** This function is called during database shutdown (when the number of 210 ** connections drops from one to zero). It truncates the database file 211 ** to as small a size as possible without truncating away any blocks that 212 ** contain data. 213 */ 214 static int dbTruncateFile(lsm_db *pDb){ 215 int rc; 216 217 assert( pDb->pWorker==0 ); 218 assert( lsmShmAssertLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_EXCL) ); 219 rc = lsmCheckpointLoadWorker(pDb); 220 221 if( rc==LSM_OK ){ 222 DbTruncateCtx ctx; 223 224 /* Walk the database free-block-list in reverse order. Set ctx.nBlock 225 ** to the block number of the last block in the database that actually 226 ** contains data. */ 227 ctx.nBlock = pDb->pWorker->nBlock; 228 ctx.iInUse = -1; 229 rc = lsmWalkFreelist(pDb, 1, dbTruncateCb, (void *)&ctx); 230 231 /* If the last block that contains data is not already the last block in 232 ** the database file, truncate the database file so that it is. */ 233 if( rc==LSM_OK ){ 234 rc = lsmFsTruncateDb( 235 pDb->pFS, (i64)ctx.nBlock*lsmFsBlockSize(pDb->pFS) 236 ); 237 } 238 } 239 240 lsmFreeSnapshot(pDb->pEnv, pDb->pWorker); 241 pDb->pWorker = 0; 242 return rc; 243 } 244 245 static void doDbDisconnect(lsm_db *pDb){ 246 int rc; 247 248 if( pDb->bReadonly ){ 249 lsmShmLock(pDb, LSM_LOCK_DMS3, LSM_LOCK_UNLOCK, 0); 250 }else{ 251 /* Block for an exclusive lock on DMS1. This lock serializes all calls 252 ** to doDbConnect() and doDbDisconnect() across all processes. */ 253 rc = lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_EXCL, 1); 254 if( rc==LSM_OK ){ 255 256 lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_UNLOCK, 0); 257 258 /* Try an exclusive lock on DMS2. If successful, this is the last 259 ** connection to the database. In this case flush the contents of the 260 ** in-memory tree to disk and write a checkpoint. */ 261 rc = lsmShmTestLock(pDb, LSM_LOCK_DMS2, 1, LSM_LOCK_EXCL); 262 if( rc==LSM_OK ){ 263 rc = lsmShmTestLock(pDb, LSM_LOCK_CHECKPOINTER, 1, LSM_LOCK_EXCL); 264 } 265 if( rc==LSM_OK ){ 266 int bReadonly = 0; /* True if there exist read-only conns. */ 267 268 /* Flush the in-memory tree, if required. If there is data to flush, 269 ** this will create a new client snapshot in Database.pClient. The 270 ** checkpoint (serialization) of this snapshot may be written to disk 271 ** by the following block. 272 ** 273 ** There is no need to take a WRITER lock here. That there are no 274 ** other locks on DMS2 guarantees that there are no other read-write 275 ** connections at this time (and the lock on DMS1 guarantees that 276 ** no new ones may appear). 277 */ 278 rc = lsmTreeLoadHeader(pDb, 0); 279 if( rc==LSM_OK && (lsmTreeHasOld(pDb) || lsmTreeSize(pDb)>0) ){ 280 rc = lsmFlushTreeToDisk(pDb); 281 } 282 283 /* Now check if there are any read-only connections. If there are, 284 ** then do not truncate the db file or unlink the shared-memory 285 ** region. */ 286 if( rc==LSM_OK ){ 287 rc = lsmShmTestLock(pDb, LSM_LOCK_DMS3, 1, LSM_LOCK_EXCL); 288 if( rc==LSM_BUSY ){ 289 bReadonly = 1; 290 rc = LSM_OK; 291 } 292 } 293 294 /* Write a checkpoint to disk. */ 295 if( rc==LSM_OK ){ 296 rc = lsmCheckpointWrite(pDb, 0); 297 } 298 299 /* If the checkpoint was written successfully, delete the log file 300 ** and, if possible, truncate the database file. */ 301 if( rc==LSM_OK ){ 302 int bRotrans = 0; 303 Database *p = pDb->pDatabase; 304 305 /* The log file may only be deleted if there are no clients 306 ** read-only clients running rotrans transactions. */ 307 rc = lsmDetectRoTrans(pDb, &bRotrans); 308 if( rc==LSM_OK && bRotrans==0 ){ 309 lsmFsCloseAndDeleteLog(pDb->pFS); 310 } 311 312 /* The database may only be truncated if there exist no read-only 313 ** clients - either connected or running rotrans transactions. */ 314 if( bReadonly==0 && bRotrans==0 ){ 315 lsmFsUnmap(pDb->pFS); 316 dbTruncateFile(pDb); 317 if( p->pFile && p->bMultiProc ){ 318 lsmEnvShmUnmap(pDb->pEnv, p->pFile, 1); 319 } 320 } 321 } 322 } 323 } 324 325 if( pDb->iRwclient>=0 ){ 326 lsmShmLock(pDb, LSM_LOCK_RWCLIENT(pDb->iRwclient), LSM_LOCK_UNLOCK, 0); 327 pDb->iRwclient = -1; 328 } 329 330 lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); 331 } 332 pDb->pShmhdr = 0; 333 } 334 335 static int doDbConnect(lsm_db *pDb){ 336 const int nUsMax = 100000; /* Max value for nUs */ 337 int nUs = 1000; /* us to wait between DMS1 attempts */ 338 int rc; 339 340 /* Obtain a pointer to the shared-memory header */ 341 assert( pDb->pShmhdr==0 ); 342 assert( pDb->bReadonly==0 ); 343 rc = lsmShmCacheChunks(pDb, 1); 344 if( rc!=LSM_OK ) return rc; 345 pDb->pShmhdr = (ShmHeader *)pDb->apShm[0]; 346 347 /* Block for an exclusive lock on DMS1. This lock serializes all calls 348 ** to doDbConnect() and doDbDisconnect() across all processes. */ 349 while( 1 ){ 350 rc = lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_EXCL, 1); 351 if( rc!=LSM_BUSY ) break; 352 lsmEnvSleep(pDb->pEnv, nUs); 353 nUs = nUs * 2; 354 if( nUs>nUsMax ) nUs = nUsMax; 355 } 356 if( rc!=LSM_OK ){ 357 pDb->pShmhdr = 0; 358 return rc; 359 } 360 361 /* Try an exclusive lock on DMS2/DMS3. If successful, this is the first 362 ** and only connection to the database. In this case initialize the 363 ** shared-memory and run log file recovery. */ 364 assert( LSM_LOCK_DMS3==1+LSM_LOCK_DMS2 ); 365 rc = lsmShmTestLock(pDb, LSM_LOCK_DMS2, 2, LSM_LOCK_EXCL); 366 if( rc==LSM_OK ){ 367 memset(pDb->pShmhdr, 0, sizeof(ShmHeader)); 368 rc = lsmCheckpointRecover(pDb); 369 if( rc==LSM_OK ){ 370 rc = lsmLogRecover(pDb); 371 } 372 if( rc==LSM_OK ){ 373 ShmHeader *pShm = pDb->pShmhdr; 374 pShm->aReader[0].iLsmId = lsmCheckpointId(pShm->aSnap1, 0); 375 pShm->aReader[0].iTreeId = pDb->treehdr.iUsedShmid; 376 } 377 }else if( rc==LSM_BUSY ){ 378 rc = LSM_OK; 379 } 380 381 /* Take a shared lock on DMS2. In multi-process mode this lock "cannot" 382 ** fail, as connections may only hold an exclusive lock on DMS2 if they 383 ** first hold an exclusive lock on DMS1. And this connection is currently 384 ** holding the exclusive lock on DSM1. 385 ** 386 ** However, if some other connection has the database open in single-process 387 ** mode, this operation will fail. In this case, return the error to the 388 ** caller - the attempt to connect to the db has failed. 389 */ 390 if( rc==LSM_OK ){ 391 rc = lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_SHARED, 0); 392 } 393 394 /* If anything went wrong, unlock DMS2. Otherwise, try to take an exclusive 395 ** lock on one of the LSM_LOCK_RWCLIENT() locks. Unlock DMS1 in any case. */ 396 if( rc!=LSM_OK ){ 397 pDb->pShmhdr = 0; 398 }else{ 399 int i; 400 for(i=0; i<LSM_LOCK_NRWCLIENT; i++){ 401 int rc2 = lsmShmLock(pDb, LSM_LOCK_RWCLIENT(i), LSM_LOCK_EXCL, 0); 402 if( rc2==LSM_OK ) pDb->iRwclient = i; 403 if( rc2!=LSM_BUSY ){ 404 rc = rc2; 405 break; 406 } 407 } 408 } 409 lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); 410 411 return rc; 412 } 413 414 static int dbOpenSharedFd(lsm_env *pEnv, Database *p, int bRoOk){ 415 int rc; 416 417 rc = lsmEnvOpen(pEnv, p->zName, 0, &p->pFile); 418 if( rc==LSM_IOERR && bRoOk ){ 419 rc = lsmEnvOpen(pEnv, p->zName, LSM_OPEN_READONLY, &p->pFile); 420 p->bReadonly = 1; 421 } 422 423 return rc; 424 } 425 426 /* 427 ** Return a reference to the shared Database handle for the database 428 ** identified by canonical path zName. If this is the first connection to 429 ** the named database, a new Database object is allocated. Otherwise, a 430 ** pointer to an existing object is returned. 431 ** 432 ** If successful, *ppDatabase is set to point to the shared Database 433 ** structure and LSM_OK returned. Otherwise, *ppDatabase is set to NULL 434 ** and and LSM error code returned. 435 ** 436 ** Each successful call to this function should be (eventually) matched 437 ** by a call to lsmDbDatabaseRelease(). 438 */ 439 int lsmDbDatabaseConnect( 440 lsm_db *pDb, /* Database handle */ 441 const char *zName /* Full-path to db file */ 442 ){ 443 lsm_env *pEnv = pDb->pEnv; 444 int rc; /* Return code */ 445 Database *p = 0; /* Pointer returned via *ppDatabase */ 446 int nName = lsmStrlen(zName); 447 448 assert( pDb->pDatabase==0 ); 449 rc = enterGlobalMutex(pEnv); 450 if( rc==LSM_OK ){ 451 452 /* Search the global list for an existing object. TODO: Need something 453 ** better than the memcmp() below to figure out if a given Database 454 ** object represents the requested file. */ 455 for(p=gShared.pDatabase; p; p=p->pDbNext){ 456 if( nName==p->nName && 0==memcmp(zName, p->zName, nName) ) break; 457 } 458 459 /* If no suitable Database object was found, allocate a new one. */ 460 if( p==0 ){ 461 p = (Database *)lsmMallocZeroRc(pEnv, sizeof(Database)+nName+1, &rc); 462 463 /* If the allocation was successful, fill in other fields and 464 ** allocate the client mutex. */ 465 if( rc==LSM_OK ){ 466 p->bMultiProc = pDb->bMultiProc; 467 p->zName = (char *)&p[1]; 468 p->nName = nName; 469 memcpy((void *)p->zName, zName, nName+1); 470 rc = lsmMutexNew(pEnv, &p->pClientMutex); 471 } 472 473 /* If nothing has gone wrong so far, open the shared fd. And if that 474 ** succeeds and this connection requested single-process mode, 475 ** attempt to take the exclusive lock on DMS2. */ 476 if( rc==LSM_OK ){ 477 int bReadonly = (pDb->bReadonly && pDb->bMultiProc); 478 rc = dbOpenSharedFd(pDb->pEnv, p, bReadonly); 479 } 480 481 if( rc==LSM_OK && p->bMultiProc==0 ){ 482 /* Hold an exclusive lock DMS1 while grabbing DMS2. This ensures 483 ** that any ongoing call to doDbDisconnect() (even one in another 484 ** process) is finished before proceeding. */ 485 assert( p->bReadonly==0 ); 486 rc = lsmEnvLock(pDb->pEnv, p->pFile, LSM_LOCK_DMS1, LSM_LOCK_EXCL); 487 if( rc==LSM_OK ){ 488 rc = lsmEnvLock(pDb->pEnv, p->pFile, LSM_LOCK_DMS2, LSM_LOCK_EXCL); 489 lsmEnvLock(pDb->pEnv, p->pFile, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK); 490 } 491 } 492 493 if( rc==LSM_OK ){ 494 p->pDbNext = gShared.pDatabase; 495 gShared.pDatabase = p; 496 }else{ 497 freeDatabase(pEnv, p); 498 p = 0; 499 } 500 } 501 502 if( p ){ 503 p->nDbRef++; 504 } 505 leaveGlobalMutex(pEnv); 506 507 if( p ){ 508 lsmMutexEnter(pDb->pEnv, p->pClientMutex); 509 pDb->pNext = p->pConn; 510 p->pConn = pDb; 511 lsmMutexLeave(pDb->pEnv, p->pClientMutex); 512 } 513 } 514 515 pDb->pDatabase = p; 516 if( rc==LSM_OK ){ 517 assert( p ); 518 rc = lsmFsOpen(pDb, zName, p->bReadonly); 519 } 520 521 /* If the db handle is read-write, then connect to the system now. Run 522 ** recovery as necessary. Or, if this is a read-only database handle, 523 ** defer attempting to connect to the system until a read-transaction 524 ** is opened. */ 525 if( pDb->bReadonly==0 ){ 526 if( rc==LSM_OK ){ 527 rc = lsmFsConfigure(pDb); 528 } 529 if( rc==LSM_OK ){ 530 rc = doDbConnect(pDb); 531 } 532 } 533 534 return rc; 535 } 536 537 static void dbDeferClose(lsm_db *pDb){ 538 if( pDb->pFS ){ 539 LsmFile *pLsmFile; 540 Database *p = pDb->pDatabase; 541 pLsmFile = lsmFsDeferClose(pDb->pFS); 542 pLsmFile->pNext = p->pLsmFile; 543 p->pLsmFile = pLsmFile; 544 } 545 } 546 547 LsmFile *lsmDbRecycleFd(lsm_db *db){ 548 LsmFile *pRet; 549 Database *p = db->pDatabase; 550 lsmMutexEnter(db->pEnv, p->pClientMutex); 551 if( (pRet = p->pLsmFile)!=0 ){ 552 p->pLsmFile = pRet->pNext; 553 } 554 lsmMutexLeave(db->pEnv, p->pClientMutex); 555 return pRet; 556 } 557 558 /* 559 ** Release a reference to a Database object obtained from 560 ** lsmDbDatabaseConnect(). There should be exactly one call to this function 561 ** for each successful call to Find(). 562 */ 563 void lsmDbDatabaseRelease(lsm_db *pDb){ 564 Database *p = pDb->pDatabase; 565 if( p ){ 566 lsm_db **ppDb; 567 568 if( pDb->pShmhdr ){ 569 doDbDisconnect(pDb); 570 } 571 572 lsmFsUnmap(pDb->pFS); 573 lsmMutexEnter(pDb->pEnv, p->pClientMutex); 574 for(ppDb=&p->pConn; *ppDb!=pDb; ppDb=&((*ppDb)->pNext)); 575 *ppDb = pDb->pNext; 576 dbDeferClose(pDb); 577 lsmMutexLeave(pDb->pEnv, p->pClientMutex); 578 579 enterGlobalMutex(pDb->pEnv); 580 p->nDbRef--; 581 if( p->nDbRef==0 ){ 582 LsmFile *pIter; 583 LsmFile *pNext; 584 Database **pp; 585 586 /* Remove the Database structure from the linked list. */ 587 for(pp=&gShared.pDatabase; *pp!=p; pp=&((*pp)->pDbNext)); 588 *pp = p->pDbNext; 589 590 /* If they were allocated from the heap, free the shared memory chunks */ 591 if( p->bMultiProc==0 ){ 592 int i; 593 for(i=0; i<p->nShmChunk; i++){ 594 lsmFree(pDb->pEnv, p->apShmChunk[i]); 595 } 596 } 597 598 /* Close any outstanding file descriptors */ 599 for(pIter=p->pLsmFile; pIter; pIter=pNext){ 600 pNext = pIter->pNext; 601 lsmEnvClose(pDb->pEnv, pIter->pFile); 602 lsmFree(pDb->pEnv, pIter); 603 } 604 freeDatabase(pDb->pEnv, p); 605 } 606 leaveGlobalMutex(pDb->pEnv); 607 } 608 } 609 610 Level *lsmDbSnapshotLevel(Snapshot *pSnapshot){ 611 return pSnapshot->pLevel; 612 } 613 614 void lsmDbSnapshotSetLevel(Snapshot *pSnap, Level *pLevel){ 615 pSnap->pLevel = pLevel; 616 } 617 618 /* TODO: Shuffle things around to get rid of this */ 619 static int firstSnapshotInUse(lsm_db *, i64 *); 620 621 /* 622 ** Context object used by the lsmWalkFreelist() utility. 623 */ 624 typedef struct WalkFreelistCtx WalkFreelistCtx; 625 struct WalkFreelistCtx { 626 lsm_db *pDb; 627 int bReverse; 628 Freelist *pFreelist; 629 int iFree; 630 int (*xUsr)(void *, int, i64); /* User callback function */ 631 void *pUsrctx; /* User callback context */ 632 int bDone; /* Set to true after xUsr() returns true */ 633 }; 634 635 /* 636 ** Callback used by lsmWalkFreelist(). 637 */ 638 static int walkFreelistCb(void *pCtx, int iBlk, i64 iSnapshot){ 639 WalkFreelistCtx *p = (WalkFreelistCtx *)pCtx; 640 const int iDir = (p->bReverse ? -1 : 1); 641 Freelist *pFree = p->pFreelist; 642 643 assert( p->bDone==0 ); 644 assert( iBlk>=0 ); 645 if( pFree ){ 646 while( (p->iFree < pFree->nEntry) && p->iFree>=0 ){ 647 FreelistEntry *pEntry = &pFree->aEntry[p->iFree]; 648 if( (p->bReverse==0 && pEntry->iBlk>(u32)iBlk) 649 || (p->bReverse!=0 && pEntry->iBlk<(u32)iBlk) 650 ){ 651 break; 652 }else{ 653 p->iFree += iDir; 654 if( pEntry->iId>=0 655 && p->xUsr(p->pUsrctx, pEntry->iBlk, pEntry->iId) 656 ){ 657 p->bDone = 1; 658 return 1; 659 } 660 if( pEntry->iBlk==(u32)iBlk ) return 0; 661 } 662 } 663 } 664 665 if( p->xUsr(p->pUsrctx, iBlk, iSnapshot) ){ 666 p->bDone = 1; 667 return 1; 668 } 669 return 0; 670 } 671 672 /* 673 ** The database handle passed as the first argument must be the worker 674 ** connection. This function iterates through the contents of the current 675 ** free block list, invoking the supplied callback once for each list 676 ** element. 677 ** 678 ** The difference between this function and lsmSortedWalkFreelist() is 679 ** that lsmSortedWalkFreelist() only considers those free-list elements 680 ** stored within the LSM. This function also merges in any in-memory 681 ** elements. 682 */ 683 int lsmWalkFreelist( 684 lsm_db *pDb, /* Database handle (must be worker) */ 685 int bReverse, /* True to iterate from largest to smallest */ 686 int (*x)(void *, int, i64), /* Callback function */ 687 void *pCtx /* First argument to pass to callback */ 688 ){ 689 const int iDir = (bReverse ? -1 : 1); 690 int rc; 691 int iCtx; 692 693 WalkFreelistCtx ctx[2]; 694 695 ctx[0].pDb = pDb; 696 ctx[0].bReverse = bReverse; 697 ctx[0].pFreelist = &pDb->pWorker->freelist; 698 if( ctx[0].pFreelist && bReverse ){ 699 ctx[0].iFree = ctx[0].pFreelist->nEntry-1; 700 }else{ 701 ctx[0].iFree = 0; 702 } 703 ctx[0].xUsr = walkFreelistCb; 704 ctx[0].pUsrctx = (void *)&ctx[1]; 705 ctx[0].bDone = 0; 706 707 ctx[1].pDb = pDb; 708 ctx[1].bReverse = bReverse; 709 ctx[1].pFreelist = pDb->pFreelist; 710 if( ctx[1].pFreelist && bReverse ){ 711 ctx[1].iFree = ctx[1].pFreelist->nEntry-1; 712 }else{ 713 ctx[1].iFree = 0; 714 } 715 ctx[1].xUsr = x; 716 ctx[1].pUsrctx = pCtx; 717 ctx[1].bDone = 0; 718 719 rc = lsmSortedWalkFreelist(pDb, bReverse, walkFreelistCb, (void *)&ctx[0]); 720 721 if( ctx[0].bDone==0 ){ 722 for(iCtx=0; iCtx<2; iCtx++){ 723 int i; 724 WalkFreelistCtx *p = &ctx[iCtx]; 725 for(i=p->iFree; 726 p->pFreelist && rc==LSM_OK && i<p->pFreelist->nEntry && i>=0; 727 i += iDir 728 ){ 729 FreelistEntry *pEntry = &p->pFreelist->aEntry[i]; 730 if( pEntry->iId>=0 && p->xUsr(p->pUsrctx, pEntry->iBlk, pEntry->iId) ){ 731 return LSM_OK; 732 } 733 } 734 } 735 } 736 737 return rc; 738 } 739 740 741 typedef struct FindFreeblockCtx FindFreeblockCtx; 742 struct FindFreeblockCtx { 743 i64 iInUse; 744 int iRet; 745 int bNotOne; 746 }; 747 748 static int findFreeblockCb(void *pCtx, int iBlk, i64 iSnapshot){ 749 FindFreeblockCtx *p = (FindFreeblockCtx *)pCtx; 750 if( iSnapshot<p->iInUse && (iBlk!=1 || p->bNotOne==0) ){ 751 p->iRet = iBlk; 752 return 1; 753 } 754 return 0; 755 } 756 757 static int findFreeblock(lsm_db *pDb, i64 iInUse, int bNotOne, int *piRet){ 758 int rc; /* Return code */ 759 FindFreeblockCtx ctx; /* Context object */ 760 761 ctx.iInUse = iInUse; 762 ctx.iRet = 0; 763 ctx.bNotOne = bNotOne; 764 rc = lsmWalkFreelist(pDb, 0, findFreeblockCb, (void *)&ctx); 765 *piRet = ctx.iRet; 766 767 return rc; 768 } 769 770 /* 771 ** Allocate a new database file block to write data to, either by extending 772 ** the database file or by recycling a free-list entry. The worker snapshot 773 ** must be held in order to call this function. 774 ** 775 ** If successful, *piBlk is set to the block number allocated and LSM_OK is 776 ** returned. Otherwise, *piBlk is zeroed and an lsm error code returned. 777 */ 778 int lsmBlockAllocate(lsm_db *pDb, int iBefore, int *piBlk){ 779 Snapshot *p = pDb->pWorker; 780 int iRet = 0; /* Block number of allocated block */ 781 int rc = LSM_OK; 782 i64 iInUse = 0; /* Snapshot id still in use */ 783 i64 iSynced = 0; /* Snapshot id synced to disk */ 784 785 assert( p ); 786 787 #ifdef LSM_LOG_FREELIST 788 { 789 static int nCall = 0; 790 char *zFree = 0; 791 nCall++; 792 rc = lsmInfoFreelist(pDb, &zFree); 793 if( rc!=LSM_OK ) return rc; 794 lsmLogMessage(pDb, 0, "lsmBlockAllocate(): %d freelist: %s", nCall, zFree); 795 lsmFree(pDb->pEnv, zFree); 796 } 797 #endif 798 799 /* Set iInUse to the smallest snapshot id that is either: 800 ** 801 ** * Currently in use by a database client, 802 ** * May be used by a database client in the future, or 803 ** * Is the most recently checkpointed snapshot (i.e. the one that will 804 ** be used following recovery if a failure occurs at this point). 805 */ 806 rc = lsmCheckpointSynced(pDb, &iSynced, 0, 0); 807 if( rc==LSM_OK && iSynced==0 ) iSynced = p->iId; 808 iInUse = iSynced; 809 if( rc==LSM_OK && pDb->iReader>=0 ){ 810 assert( pDb->pClient ); 811 iInUse = LSM_MIN(iInUse, pDb->pClient->iId); 812 } 813 if( rc==LSM_OK ) rc = firstSnapshotInUse(pDb, &iInUse); 814 815 #ifdef LSM_LOG_FREELIST 816 { 817 lsmLogMessage(pDb, 0, "lsmBlockAllocate(): " 818 "snapshot-in-use: %lld (iSynced=%lld) (client-id=%lld)", 819 iInUse, iSynced, (pDb->iReader>=0 ? pDb->pClient->iId : 0) 820 ); 821 } 822 #endif 823 824 825 /* Unless there exists a read-only transaction (which prevents us from 826 ** recycling any blocks regardless, query the free block list for a 827 ** suitable block to reuse. 828 ** 829 ** It might seem more natural to check for a read-only transaction at 830 ** the start of this function. However, it is better do wait until after 831 ** the call to lsmCheckpointSynced() to do so. 832 */ 833 if( rc==LSM_OK ){ 834 int bRotrans; 835 rc = lsmDetectRoTrans(pDb, &bRotrans); 836 837 if( rc==LSM_OK && bRotrans==0 ){ 838 rc = findFreeblock(pDb, iInUse, (iBefore>0), &iRet); 839 } 840 } 841 842 if( iBefore>0 && (iRet<=0 || iRet>=iBefore) ){ 843 iRet = 0; 844 845 }else if( rc==LSM_OK ){ 846 /* If a block was found in the free block list, use it and remove it from 847 ** the list. Otherwise, if no suitable block was found, allocate one from 848 ** the end of the file. */ 849 if( iRet>0 ){ 850 #ifdef LSM_LOG_FREELIST 851 lsmLogMessage(pDb, 0, 852 "reusing block %d (snapshot-in-use=%lld)", iRet, iInUse); 853 #endif 854 rc = freelistAppend(pDb, iRet, -1); 855 if( rc==LSM_OK ){ 856 rc = dbTruncate(pDb, iInUse); 857 } 858 }else{ 859 iRet = ++(p->nBlock); 860 #ifdef LSM_LOG_FREELIST 861 lsmLogMessage(pDb, 0, "extending file to %d blocks", iRet); 862 #endif 863 } 864 } 865 866 assert( iBefore>0 || iRet>0 || rc!=LSM_OK ); 867 *piBlk = iRet; 868 return rc; 869 } 870 871 /* 872 ** Free a database block. The worker snapshot must be held in order to call 873 ** this function. 874 ** 875 ** If successful, LSM_OK is returned. Otherwise, an lsm error code (e.g. 876 ** LSM_NOMEM). 877 */ 878 int lsmBlockFree(lsm_db *pDb, int iBlk){ 879 Snapshot *p = pDb->pWorker; 880 assert( lsmShmAssertWorker(pDb) ); 881 882 #ifdef LSM_LOG_FREELIST 883 lsmLogMessage(pDb, LSM_OK, "lsmBlockFree(): Free block %d", iBlk); 884 #endif 885 886 return freelistAppend(pDb, iBlk, p->iId); 887 } 888 889 /* 890 ** Refree a database block. The worker snapshot must be held in order to call 891 ** this function. 892 ** 893 ** Refreeing is required when a block is allocated using lsmBlockAllocate() 894 ** but then not used. This function is used to push the block back onto 895 ** the freelist. Refreeing a block is different from freeing is, as a refreed 896 ** block may be reused immediately. Whereas a freed block can not be reused 897 ** until (at least) after the next checkpoint. 898 */ 899 int lsmBlockRefree(lsm_db *pDb, int iBlk){ 900 int rc = LSM_OK; /* Return code */ 901 902 #ifdef LSM_LOG_FREELIST 903 lsmLogMessage(pDb, LSM_OK, "lsmBlockRefree(): Refree block %d", iBlk); 904 #endif 905 906 rc = freelistAppend(pDb, iBlk, 0); 907 return rc; 908 } 909 910 /* 911 ** If required, copy a database checkpoint from shared memory into the 912 ** database itself. 913 ** 914 ** The WORKER lock must not be held when this is called. This is because 915 ** this function may indirectly call fsync(). And the WORKER lock should 916 ** not be held that long (in case it is required by a client flushing an 917 ** in-memory tree to disk). 918 */ 919 int lsmCheckpointWrite(lsm_db *pDb, u32 *pnWrite){ 920 int rc; /* Return Code */ 921 u32 nWrite = 0; 922 923 assert( pDb->pWorker==0 ); 924 assert( 1 || pDb->pClient==0 ); 925 assert( lsmShmAssertLock(pDb, LSM_LOCK_WORKER, LSM_LOCK_UNLOCK) ); 926 927 rc = lsmShmLock(pDb, LSM_LOCK_CHECKPOINTER, LSM_LOCK_EXCL, 0); 928 if( rc!=LSM_OK ) return rc; 929 930 rc = lsmCheckpointLoad(pDb, 0); 931 if( rc==LSM_OK ){ 932 int nBlock = lsmCheckpointNBlock(pDb->aSnapshot); 933 ShmHeader *pShm = pDb->pShmhdr; 934 int bDone = 0; /* True if checkpoint is already stored */ 935 936 /* Check if this checkpoint has already been written to the database 937 ** file. If so, set variable bDone to true. */ 938 if( pShm->iMetaPage ){ 939 MetaPage *pPg; /* Meta page */ 940 u8 *aData; /* Meta-page data buffer */ 941 int nData; /* Size of aData[] in bytes */ 942 i64 iCkpt; /* Id of checkpoint just loaded */ 943 i64 iDisk = 0; /* Id of checkpoint already stored in db */ 944 iCkpt = lsmCheckpointId(pDb->aSnapshot, 0); 945 rc = lsmFsMetaPageGet(pDb->pFS, 0, pShm->iMetaPage, &pPg); 946 if( rc==LSM_OK ){ 947 aData = lsmFsMetaPageData(pPg, &nData); 948 iDisk = lsmCheckpointId((u32 *)aData, 1); 949 nWrite = lsmCheckpointNWrite((u32 *)aData, 1); 950 lsmFsMetaPageRelease(pPg); 951 } 952 bDone = (iDisk>=iCkpt); 953 } 954 955 if( rc==LSM_OK && bDone==0 ){ 956 int iMeta = (pShm->iMetaPage % 2) + 1; 957 if( pDb->eSafety!=LSM_SAFETY_OFF ){ 958 rc = lsmFsSyncDb(pDb->pFS, nBlock); 959 } 960 if( rc==LSM_OK ) rc = lsmCheckpointStore(pDb, iMeta); 961 if( rc==LSM_OK && pDb->eSafety!=LSM_SAFETY_OFF){ 962 rc = lsmFsSyncDb(pDb->pFS, 0); 963 } 964 if( rc==LSM_OK ){ 965 pShm->iMetaPage = iMeta; 966 nWrite = lsmCheckpointNWrite(pDb->aSnapshot, 0) - nWrite; 967 } 968 #ifdef LSM_LOG_WORK 969 lsmLogMessage(pDb, 0, "finish checkpoint %d", 970 (int)lsmCheckpointId(pDb->aSnapshot, 0) 971 ); 972 #endif 973 } 974 } 975 976 lsmShmLock(pDb, LSM_LOCK_CHECKPOINTER, LSM_LOCK_UNLOCK, 0); 977 if( pnWrite && rc==LSM_OK ) *pnWrite = nWrite; 978 return rc; 979 } 980 981 int lsmBeginWork(lsm_db *pDb){ 982 int rc; 983 984 /* Attempt to take the WORKER lock */ 985 rc = lsmShmLock(pDb, LSM_LOCK_WORKER, LSM_LOCK_EXCL, 0); 986 987 /* Deserialize the current worker snapshot */ 988 if( rc==LSM_OK ){ 989 rc = lsmCheckpointLoadWorker(pDb); 990 } 991 return rc; 992 } 993 994 void lsmFreeSnapshot(lsm_env *pEnv, Snapshot *p){ 995 if( p ){ 996 lsmSortedFreeLevel(pEnv, p->pLevel); 997 lsmFree(pEnv, p->freelist.aEntry); 998 lsmFree(pEnv, p->redirect.a); 999 lsmFree(pEnv, p); 1000 } 1001 } 1002 1003 /* 1004 ** Attempt to populate one of the read-lock slots to contain lock values 1005 ** iLsm/iShm. Or, if such a slot exists already, this function is a no-op. 1006 ** 1007 ** It is not an error if no slot can be populated because the write-lock 1008 ** cannot be obtained. If any other error occurs, return an LSM error code. 1009 ** Otherwise, LSM_OK. 1010 ** 1011 ** This function is called at various points to try to ensure that there 1012 ** always exists at least one read-lock slot that can be used by a read-only 1013 ** client. And so that, in the usual case, there is an "exact match" available 1014 ** whenever a read transaction is opened by any client. At present this 1015 ** function is called when: 1016 ** 1017 ** * A write transaction that called lsmTreeDiscardOld() is committed, and 1018 ** * Whenever the working snapshot is updated (i.e. lsmFinishWork()). 1019 */ 1020 static int dbSetReadLock(lsm_db *db, i64 iLsm, u32 iShm){ 1021 int rc = LSM_OK; 1022 ShmHeader *pShm = db->pShmhdr; 1023 int i; 1024 1025 /* Check if there is already a slot containing the required values. */ 1026 for(i=0; i<LSM_LOCK_NREADER; i++){ 1027 ShmReader *p = &pShm->aReader[i]; 1028 if( p->iLsmId==iLsm && p->iTreeId==iShm ) return LSM_OK; 1029 } 1030 1031 /* Iterate through all read-lock slots, attempting to take a write-lock 1032 ** on each of them. If a write-lock succeeds, populate the locked slot 1033 ** with the required values and break out of the loop. */ 1034 for(i=0; rc==LSM_OK && i<LSM_LOCK_NREADER; i++){ 1035 rc = lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_EXCL, 0); 1036 if( rc==LSM_BUSY ){ 1037 rc = LSM_OK; 1038 }else{ 1039 ShmReader *p = &pShm->aReader[i]; 1040 p->iLsmId = iLsm; 1041 p->iTreeId = iShm; 1042 lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_UNLOCK, 0); 1043 break; 1044 } 1045 } 1046 1047 return rc; 1048 } 1049 1050 /* 1051 ** Release the read-lock currently held by connection db. 1052 */ 1053 int dbReleaseReadlock(lsm_db *db){ 1054 int rc = LSM_OK; 1055 if( db->iReader>=0 ){ 1056 rc = lsmShmLock(db, LSM_LOCK_READER(db->iReader), LSM_LOCK_UNLOCK, 0); 1057 db->iReader = -1; 1058 } 1059 db->bRoTrans = 0; 1060 return rc; 1061 } 1062 1063 1064 /* 1065 ** Argument bFlush is true if the contents of the in-memory tree has just 1066 ** been flushed to disk. The significance of this is that once the snapshot 1067 ** created to hold the updated state of the database is synced to disk, log 1068 ** file space can be recycled. 1069 */ 1070 void lsmFinishWork(lsm_db *pDb, int bFlush, int *pRc){ 1071 int rc = *pRc; 1072 assert( rc!=0 || pDb->pWorker ); 1073 if( pDb->pWorker ){ 1074 /* If no error has occurred, serialize the worker snapshot and write 1075 ** it to shared memory. */ 1076 if( rc==LSM_OK ){ 1077 rc = lsmSaveWorker(pDb, bFlush); 1078 } 1079 1080 /* Assuming no error has occurred, update a read lock slot with the 1081 ** new snapshot id (see comments above function dbSetReadLock()). */ 1082 if( rc==LSM_OK ){ 1083 if( pDb->iReader<0 ){ 1084 rc = lsmTreeLoadHeader(pDb, 0); 1085 } 1086 if( rc==LSM_OK ){ 1087 rc = dbSetReadLock(pDb, pDb->pWorker->iId, pDb->treehdr.iUsedShmid); 1088 } 1089 } 1090 1091 /* Free the snapshot object. */ 1092 lsmFreeSnapshot(pDb->pEnv, pDb->pWorker); 1093 pDb->pWorker = 0; 1094 } 1095 1096 lsmShmLock(pDb, LSM_LOCK_WORKER, LSM_LOCK_UNLOCK, 0); 1097 *pRc = rc; 1098 } 1099 1100 /* 1101 ** Called when recovery is finished. 1102 */ 1103 int lsmFinishRecovery(lsm_db *pDb){ 1104 lsmTreeEndTransaction(pDb, 1); 1105 return LSM_OK; 1106 } 1107 1108 /* 1109 ** Check if the currently configured compression functions 1110 ** (LSM_CONFIG_SET_COMPRESSION) are compatible with a database that has its 1111 ** compression id set to iReq. Compression routines are compatible if iReq 1112 ** is zero (indicating the database is empty), or if it is equal to the 1113 ** compression id of the configured compression routines. 1114 ** 1115 ** If the check shows that the current compression are incompatible and there 1116 ** is a compression factory registered, give it a chance to install new 1117 ** compression routines. 1118 ** 1119 ** If, after any registered factory is invoked, the compression functions 1120 ** are still incompatible, return LSM_MISMATCH. Otherwise, LSM_OK. 1121 */ 1122 int lsmCheckCompressionId(lsm_db *pDb, u32 iReq){ 1123 if( iReq!=LSM_COMPRESSION_EMPTY && pDb->compress.iId!=iReq ){ 1124 if( pDb->factory.xFactory ){ 1125 pDb->bInFactory = 1; 1126 pDb->factory.xFactory(pDb->factory.pCtx, pDb, iReq); 1127 pDb->bInFactory = 0; 1128 } 1129 if( pDb->compress.iId!=iReq ){ 1130 /* Incompatible */ 1131 return LSM_MISMATCH; 1132 } 1133 } 1134 /* Compatible */ 1135 return LSM_OK; 1136 } 1137 1138 /* 1139 ** Begin a read transaction. This function is a no-op if the connection 1140 ** passed as the only argument already has an open read transaction. 1141 */ 1142 int lsmBeginReadTrans(lsm_db *pDb){ 1143 const int MAX_READLOCK_ATTEMPTS = 10; 1144 const int nMaxAttempt = (pDb->bRoTrans ? 1 : MAX_READLOCK_ATTEMPTS); 1145 1146 int rc = LSM_OK; /* Return code */ 1147 int iAttempt = 0; 1148 1149 assert( pDb->pWorker==0 ); 1150 1151 while( rc==LSM_OK && pDb->iReader<0 && (iAttempt++)<nMaxAttempt ){ 1152 int iTreehdr = 0; 1153 int iSnap = 0; 1154 assert( pDb->pCsr==0 && pDb->nTransOpen==0 ); 1155 1156 /* Load the in-memory tree header. */ 1157 rc = lsmTreeLoadHeader(pDb, &iTreehdr); 1158 1159 /* Load the database snapshot */ 1160 if( rc==LSM_OK ){ 1161 if( lsmCheckpointClientCacheOk(pDb)==0 ){ 1162 lsmFreeSnapshot(pDb->pEnv, pDb->pClient); 1163 pDb->pClient = 0; 1164 lsmMCursorFreeCache(pDb); 1165 lsmFsPurgeCache(pDb->pFS); 1166 rc = lsmCheckpointLoad(pDb, &iSnap); 1167 }else{ 1168 iSnap = 1; 1169 } 1170 } 1171 1172 /* Take a read-lock on the tree and snapshot just loaded. Then check 1173 ** that the shared-memory still contains the same values. If so, proceed. 1174 ** Otherwise, relinquish the read-lock and retry the whole procedure 1175 ** (starting with loading the in-memory tree header). */ 1176 if( rc==LSM_OK ){ 1177 u32 iShmMax = pDb->treehdr.iUsedShmid; 1178 u32 iShmMin = pDb->treehdr.iNextShmid+1-LSM_MAX_SHMCHUNKS; 1179 rc = lsmReadlock( 1180 pDb, lsmCheckpointId(pDb->aSnapshot, 0), iShmMin, iShmMax 1181 ); 1182 if( rc==LSM_OK ){ 1183 if( lsmTreeLoadHeaderOk(pDb, iTreehdr) 1184 && lsmCheckpointLoadOk(pDb, iSnap) 1185 ){ 1186 /* Read lock has been successfully obtained. Deserialize the 1187 ** checkpoint just loaded. TODO: This will be removed after 1188 ** lsm_sorted.c is changed to work directly from the serialized 1189 ** version of the snapshot. */ 1190 if( pDb->pClient==0 ){ 1191 rc = lsmCheckpointDeserialize(pDb, 0, pDb->aSnapshot,&pDb->pClient); 1192 } 1193 assert( (rc==LSM_OK)==(pDb->pClient!=0) ); 1194 assert( pDb->iReader>=0 ); 1195 1196 /* Check that the client has the right compression hooks loaded. 1197 ** If not, set rc to LSM_MISMATCH. */ 1198 if( rc==LSM_OK ){ 1199 rc = lsmCheckCompressionId(pDb, pDb->pClient->iCmpId); 1200 } 1201 }else{ 1202 rc = dbReleaseReadlock(pDb); 1203 } 1204 } 1205 1206 if( rc==LSM_BUSY ){ 1207 rc = LSM_OK; 1208 } 1209 } 1210 #if 0 1211 if( rc==LSM_OK && pDb->pClient ){ 1212 fprintf(stderr, 1213 "reading %p: snapshot:%d used-shmid:%d trans-id:%d iOldShmid=%d\n", 1214 (void *)pDb, 1215 (int)pDb->pClient->iId, (int)pDb->treehdr.iUsedShmid, 1216 (int)pDb->treehdr.root.iTransId, 1217 (int)pDb->treehdr.iOldShmid 1218 ); 1219 } 1220 #endif 1221 } 1222 1223 if( rc==LSM_OK ){ 1224 rc = lsmShmCacheChunks(pDb, pDb->treehdr.nChunk); 1225 } 1226 if( rc!=LSM_OK ){ 1227 dbReleaseReadlock(pDb); 1228 } 1229 if( pDb->pClient==0 && rc==LSM_OK ) rc = LSM_BUSY; 1230 return rc; 1231 } 1232 1233 /* 1234 ** This function is used by a read-write connection to determine if there 1235 ** are currently one or more read-only transactions open on the database 1236 ** (in this context a read-only transaction is one opened by a read-only 1237 ** connection on a non-live database). 1238 ** 1239 ** If no error occurs, LSM_OK is returned and *pbExists is set to true if 1240 ** some other connection has a read-only transaction open, or false 1241 ** otherwise. If an error occurs an LSM error code is returned and the final 1242 ** value of *pbExist is undefined. 1243 */ 1244 int lsmDetectRoTrans(lsm_db *db, int *pbExist){ 1245 int rc; 1246 1247 /* Only a read-write connection may use this function. */ 1248 assert( db->bReadonly==0 ); 1249 1250 rc = lsmShmTestLock(db, LSM_LOCK_ROTRANS, 1, LSM_LOCK_EXCL); 1251 if( rc==LSM_BUSY ){ 1252 *pbExist = 1; 1253 rc = LSM_OK; 1254 }else{ 1255 *pbExist = 0; 1256 } 1257 1258 return rc; 1259 } 1260 1261 /* 1262 ** db is a read-only database handle in the disconnected state. This function 1263 ** attempts to open a read-transaction on the database. This may involve 1264 ** connecting to the database system (opening shared memory etc.). 1265 */ 1266 int lsmBeginRoTrans(lsm_db *db){ 1267 int rc = LSM_OK; 1268 1269 assert( db->bReadonly && db->pShmhdr==0 ); 1270 assert( db->iReader<0 ); 1271 1272 if( db->bRoTrans==0 ){ 1273 1274 /* Attempt a shared-lock on DMS1. */ 1275 rc = lsmShmLock(db, LSM_LOCK_DMS1, LSM_LOCK_SHARED, 0); 1276 if( rc!=LSM_OK ) return rc; 1277 1278 rc = lsmShmTestLock( 1279 db, LSM_LOCK_RWCLIENT(0), LSM_LOCK_NREADER, LSM_LOCK_SHARED 1280 ); 1281 if( rc==LSM_OK ){ 1282 /* System is not live. Take a SHARED lock on the ROTRANS byte and 1283 ** release DMS1. Locking ROTRANS tells all read-write clients that they 1284 ** may not recycle any disk space from within the database or log files, 1285 ** as a read-only client may be using it. */ 1286 rc = lsmShmLock(db, LSM_LOCK_ROTRANS, LSM_LOCK_SHARED, 0); 1287 lsmShmLock(db, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); 1288 1289 if( rc==LSM_OK ){ 1290 db->bRoTrans = 1; 1291 rc = lsmShmCacheChunks(db, 1); 1292 if( rc==LSM_OK ){ 1293 db->pShmhdr = (ShmHeader *)db->apShm[0]; 1294 memset(db->pShmhdr, 0, sizeof(ShmHeader)); 1295 rc = lsmCheckpointRecover(db); 1296 if( rc==LSM_OK ){ 1297 rc = lsmLogRecover(db); 1298 } 1299 } 1300 } 1301 }else if( rc==LSM_BUSY ){ 1302 /* System is live! */ 1303 rc = lsmShmLock(db, LSM_LOCK_DMS3, LSM_LOCK_SHARED, 0); 1304 lsmShmLock(db, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); 1305 if( rc==LSM_OK ){ 1306 rc = lsmShmCacheChunks(db, 1); 1307 if( rc==LSM_OK ){ 1308 db->pShmhdr = (ShmHeader *)db->apShm[0]; 1309 } 1310 } 1311 } 1312 1313 if( rc==LSM_OK ){ 1314 rc = lsmBeginReadTrans(db); 1315 } 1316 } 1317 1318 return rc; 1319 } 1320 1321 /* 1322 ** Close the currently open read transaction. 1323 */ 1324 void lsmFinishReadTrans(lsm_db *pDb){ 1325 1326 /* Worker connections should not be closing read transactions. And 1327 ** read transactions should only be closed after all cursors and write 1328 ** transactions have been closed. Finally pClient should be non-NULL 1329 ** only iff pDb->iReader>=0. */ 1330 assert( pDb->pWorker==0 ); 1331 assert( pDb->pCsr==0 && pDb->nTransOpen==0 ); 1332 1333 if( pDb->bRoTrans ){ 1334 int i; 1335 for(i=0; i<pDb->nShm; i++){ 1336 lsmFree(pDb->pEnv, pDb->apShm[i]); 1337 } 1338 lsmFree(pDb->pEnv, pDb->apShm); 1339 pDb->apShm = 0; 1340 pDb->nShm = 0; 1341 pDb->pShmhdr = 0; 1342 1343 lsmShmLock(pDb, LSM_LOCK_ROTRANS, LSM_LOCK_UNLOCK, 0); 1344 } 1345 dbReleaseReadlock(pDb); 1346 } 1347 1348 /* 1349 ** Open a write transaction. 1350 */ 1351 int lsmBeginWriteTrans(lsm_db *pDb){ 1352 int rc = LSM_OK; /* Return code */ 1353 ShmHeader *pShm = pDb->pShmhdr; /* Shared memory header */ 1354 1355 assert( pDb->nTransOpen==0 ); 1356 assert( pDb->bDiscardOld==0 ); 1357 assert( pDb->bReadonly==0 ); 1358 1359 /* If there is no read-transaction open, open one now. */ 1360 if( pDb->iReader<0 ){ 1361 rc = lsmBeginReadTrans(pDb); 1362 } 1363 1364 /* Attempt to take the WRITER lock */ 1365 if( rc==LSM_OK ){ 1366 rc = lsmShmLock(pDb, LSM_LOCK_WRITER, LSM_LOCK_EXCL, 0); 1367 } 1368 1369 /* If the previous writer failed mid-transaction, run emergency rollback. */ 1370 if( rc==LSM_OK && pShm->bWriter ){ 1371 rc = lsmTreeRepair(pDb); 1372 if( rc==LSM_OK ) pShm->bWriter = 0; 1373 } 1374 1375 /* Check that this connection is currently reading from the most recent 1376 ** version of the database. If not, return LSM_BUSY. */ 1377 if( rc==LSM_OK && memcmp(&pShm->hdr1, &pDb->treehdr, sizeof(TreeHeader)) ){ 1378 rc = LSM_BUSY; 1379 } 1380 1381 if( rc==LSM_OK ){ 1382 rc = lsmLogBegin(pDb); 1383 } 1384 1385 /* If everything was successful, set the "transaction-in-progress" flag 1386 ** and return LSM_OK. Otherwise, if some error occurred, relinquish the 1387 ** WRITER lock and return an error code. */ 1388 if( rc==LSM_OK ){ 1389 TreeHeader *p = &pDb->treehdr; 1390 pShm->bWriter = 1; 1391 p->root.iTransId++; 1392 if( lsmTreeHasOld(pDb) && p->iOldLog==pDb->pClient->iLogOff ){ 1393 lsmTreeDiscardOld(pDb); 1394 pDb->bDiscardOld = 1; 1395 } 1396 }else{ 1397 lsmShmLock(pDb, LSM_LOCK_WRITER, LSM_LOCK_UNLOCK, 0); 1398 if( pDb->pCsr==0 ) lsmFinishReadTrans(pDb); 1399 } 1400 return rc; 1401 } 1402 1403 /* 1404 ** End the current write transaction. The connection is left with an open 1405 ** read transaction. It is an error to call this if there is no open write 1406 ** transaction. 1407 ** 1408 ** If the transaction was committed, then a commit record has already been 1409 ** written into the log file when this function is called. Or, if the 1410 ** transaction was rolled back, both the log file and in-memory tree 1411 ** structure have already been restored. In either case, this function 1412 ** merely releases locks and other resources held by the write-transaction. 1413 ** 1414 ** LSM_OK is returned if successful, or an LSM error code otherwise. 1415 */ 1416 int lsmFinishWriteTrans(lsm_db *pDb, int bCommit){ 1417 int rc = LSM_OK; 1418 int bFlush = 0; 1419 1420 lsmLogEnd(pDb, bCommit); 1421 if( rc==LSM_OK && bCommit && lsmTreeSize(pDb)>pDb->nTreeLimit ){ 1422 bFlush = 1; 1423 lsmTreeMakeOld(pDb); 1424 } 1425 lsmTreeEndTransaction(pDb, bCommit); 1426 1427 if( rc==LSM_OK ){ 1428 if( bFlush && pDb->bAutowork ){ 1429 rc = lsmSortedAutoWork(pDb, 1); 1430 }else if( bCommit && pDb->bDiscardOld ){ 1431 rc = dbSetReadLock(pDb, pDb->pClient->iId, pDb->treehdr.iUsedShmid); 1432 } 1433 } 1434 pDb->bDiscardOld = 0; 1435 lsmShmLock(pDb, LSM_LOCK_WRITER, LSM_LOCK_UNLOCK, 0); 1436 1437 if( bFlush && pDb->bAutowork==0 && pDb->xWork ){ 1438 pDb->xWork(pDb, pDb->pWorkCtx); 1439 } 1440 return rc; 1441 } 1442 1443 1444 /* 1445 ** Return non-zero if the caller is holding the client mutex. 1446 */ 1447 #ifdef LSM_DEBUG 1448 int lsmHoldingClientMutex(lsm_db *pDb){ 1449 return lsmMutexHeld(pDb->pEnv, pDb->pDatabase->pClientMutex); 1450 } 1451 #endif 1452 1453 static int slotIsUsable(ShmReader *p, i64 iLsm, u32 iShmMin, u32 iShmMax){ 1454 return( 1455 p->iLsmId && p->iLsmId<=iLsm 1456 && shm_sequence_ge(iShmMax, p->iTreeId) 1457 && shm_sequence_ge(p->iTreeId, iShmMin) 1458 ); 1459 } 1460 1461 /* 1462 ** Obtain a read-lock on database version identified by the combination 1463 ** of snapshot iLsm and tree iTree. Return LSM_OK if successful, or 1464 ** an LSM error code otherwise. 1465 */ 1466 int lsmReadlock(lsm_db *db, i64 iLsm, u32 iShmMin, u32 iShmMax){ 1467 int rc = LSM_OK; 1468 ShmHeader *pShm = db->pShmhdr; 1469 int i; 1470 1471 assert( db->iReader<0 ); 1472 assert( shm_sequence_ge(iShmMax, iShmMin) ); 1473 1474 /* This is a no-op if the read-only transaction flag is set. */ 1475 if( db->bRoTrans ){ 1476 db->iReader = 0; 1477 return LSM_OK; 1478 } 1479 1480 /* Search for an exact match. */ 1481 for(i=0; db->iReader<0 && rc==LSM_OK && i<LSM_LOCK_NREADER; i++){ 1482 ShmReader *p = &pShm->aReader[i]; 1483 if( p->iLsmId==iLsm && p->iTreeId==iShmMax ){ 1484 rc = lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_SHARED, 0); 1485 if( rc==LSM_OK && p->iLsmId==iLsm && p->iTreeId==iShmMax ){ 1486 db->iReader = i; 1487 }else if( rc==LSM_BUSY ){ 1488 rc = LSM_OK; 1489 } 1490 } 1491 } 1492 1493 /* Try to obtain a write-lock on each slot, in order. If successful, set 1494 ** the slot values to iLsm/iTree. */ 1495 for(i=0; db->iReader<0 && rc==LSM_OK && i<LSM_LOCK_NREADER; i++){ 1496 rc = lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_EXCL, 0); 1497 if( rc==LSM_BUSY ){ 1498 rc = LSM_OK; 1499 }else{ 1500 ShmReader *p = &pShm->aReader[i]; 1501 p->iLsmId = iLsm; 1502 p->iTreeId = iShmMax; 1503 rc = lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_SHARED, 0); 1504 assert( rc!=LSM_BUSY ); 1505 if( rc==LSM_OK ) db->iReader = i; 1506 } 1507 } 1508 1509 /* Search for any usable slot */ 1510 for(i=0; db->iReader<0 && rc==LSM_OK && i<LSM_LOCK_NREADER; i++){ 1511 ShmReader *p = &pShm->aReader[i]; 1512 if( slotIsUsable(p, iLsm, iShmMin, iShmMax) ){ 1513 rc = lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_SHARED, 0); 1514 if( rc==LSM_OK && slotIsUsable(p, iLsm, iShmMin, iShmMax) ){ 1515 db->iReader = i; 1516 }else if( rc==LSM_BUSY ){ 1517 rc = LSM_OK; 1518 } 1519 } 1520 } 1521 1522 if( rc==LSM_OK && db->iReader<0 ){ 1523 rc = LSM_BUSY; 1524 } 1525 return rc; 1526 } 1527 1528 /* 1529 ** This is used to check if there exists a read-lock locking a particular 1530 ** version of either the in-memory tree or database file. 1531 ** 1532 ** If iLsmId is non-zero, then it is a snapshot id. If there exists a 1533 ** read-lock using this snapshot or newer, set *pbInUse to true. Or, 1534 ** if there is no such read-lock, set it to false. 1535 ** 1536 ** Or, if iLsmId is zero, then iShmid is a shared-memory sequence id. 1537 ** Search for a read-lock using this sequence id or newer. etc. 1538 */ 1539 static int isInUse(lsm_db *db, i64 iLsmId, u32 iShmid, int *pbInUse){ 1540 ShmHeader *pShm = db->pShmhdr; 1541 int i; 1542 int rc = LSM_OK; 1543 1544 for(i=0; rc==LSM_OK && i<LSM_LOCK_NREADER; i++){ 1545 ShmReader *p = &pShm->aReader[i]; 1546 if( p->iLsmId ){ 1547 if( (iLsmId!=0 && p->iLsmId!=0 && iLsmId>=p->iLsmId) 1548 || (iLsmId==0 && shm_sequence_ge(p->iTreeId, iShmid)) 1549 ){ 1550 rc = lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_EXCL, 0); 1551 if( rc==LSM_OK ){ 1552 p->iLsmId = 0; 1553 lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_UNLOCK, 0); 1554 } 1555 } 1556 } 1557 } 1558 1559 if( rc==LSM_BUSY ){ 1560 *pbInUse = 1; 1561 return LSM_OK; 1562 } 1563 *pbInUse = 0; 1564 return rc; 1565 } 1566 1567 /* 1568 ** This function is called by worker connections to determine the smallest 1569 ** snapshot id that is currently in use by a database client. The worker 1570 ** connection uses this result to determine whether or not it is safe to 1571 ** recycle a database block. 1572 */ 1573 static int firstSnapshotInUse( 1574 lsm_db *db, /* Database handle */ 1575 i64 *piInUse /* IN/OUT: Smallest snapshot id in use */ 1576 ){ 1577 ShmHeader *pShm = db->pShmhdr; 1578 i64 iInUse = *piInUse; 1579 int i; 1580 1581 assert( iInUse>0 ); 1582 for(i=0; i<LSM_LOCK_NREADER; i++){ 1583 ShmReader *p = &pShm->aReader[i]; 1584 if( p->iLsmId ){ 1585 i64 iThis = p->iLsmId; 1586 if( iThis!=0 && iInUse>iThis ){ 1587 int rc = lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_EXCL, 0); 1588 if( rc==LSM_OK ){ 1589 p->iLsmId = 0; 1590 lsmShmLock(db, LSM_LOCK_READER(i), LSM_LOCK_UNLOCK, 0); 1591 }else if( rc==LSM_BUSY ){ 1592 iInUse = iThis; 1593 }else{ 1594 /* Some error other than LSM_BUSY. Return the error code to 1595 ** the caller in this case. */ 1596 return rc; 1597 } 1598 } 1599 } 1600 } 1601 1602 *piInUse = iInUse; 1603 return LSM_OK; 1604 } 1605 1606 int lsmTreeInUse(lsm_db *db, u32 iShmid, int *pbInUse){ 1607 if( db->treehdr.iUsedShmid==iShmid ){ 1608 *pbInUse = 1; 1609 return LSM_OK; 1610 } 1611 return isInUse(db, 0, iShmid, pbInUse); 1612 } 1613 1614 int lsmLsmInUse(lsm_db *db, i64 iLsmId, int *pbInUse){ 1615 if( db->pClient && db->pClient->iId<=iLsmId ){ 1616 *pbInUse = 1; 1617 return LSM_OK; 1618 } 1619 return isInUse(db, iLsmId, 0, pbInUse); 1620 } 1621 1622 /* 1623 ** This function may only be called after a successful call to 1624 ** lsmDbDatabaseConnect(). It returns true if the connection is in 1625 ** multi-process mode, or false otherwise. 1626 */ 1627 int lsmDbMultiProc(lsm_db *pDb){ 1628 return pDb->pDatabase && pDb->pDatabase->bMultiProc; 1629 } 1630 1631 1632 /************************************************************************* 1633 ************************************************************************** 1634 ************************************************************************** 1635 ************************************************************************** 1636 ************************************************************************** 1637 *************************************************************************/ 1638 1639 /* 1640 ** Ensure that database connection db has cached pointers to at least the 1641 ** first nChunk chunks of shared memory. 1642 */ 1643 int lsmShmCacheChunks(lsm_db *db, int nChunk){ 1644 int rc = LSM_OK; 1645 if( nChunk>db->nShm ){ 1646 static const int NINCR = 16; 1647 Database *p = db->pDatabase; 1648 lsm_env *pEnv = db->pEnv; 1649 int nAlloc; 1650 int i; 1651 1652 /* Ensure that the db->apShm[] array is large enough. If an attempt to 1653 ** allocate memory fails, return LSM_NOMEM immediately. The apShm[] array 1654 ** is always extended in multiples of 16 entries - so the actual allocated 1655 ** size can be inferred from nShm. */ 1656 nAlloc = ((db->nShm + NINCR - 1) / NINCR) * NINCR; 1657 while( nChunk>=nAlloc ){ 1658 void **apShm; 1659 nAlloc += NINCR; 1660 apShm = lsmRealloc(pEnv, db->apShm, sizeof(void*)*nAlloc); 1661 if( !apShm ) return LSM_NOMEM_BKPT; 1662 db->apShm = apShm; 1663 } 1664 1665 if( db->bRoTrans ){ 1666 for(i=db->nShm; rc==LSM_OK && i<nChunk; i++){ 1667 db->apShm[i] = lsmMallocZeroRc(pEnv, LSM_SHM_CHUNK_SIZE, &rc); 1668 db->nShm++; 1669 } 1670 1671 }else{ 1672 1673 /* Enter the client mutex */ 1674 lsmMutexEnter(pEnv, p->pClientMutex); 1675 1676 /* Extend the Database objects apShmChunk[] array if necessary. Using the 1677 ** same pattern as for the lsm_db.apShm[] array above. */ 1678 nAlloc = ((p->nShmChunk + NINCR - 1) / NINCR) * NINCR; 1679 while( nChunk>=nAlloc ){ 1680 void **apShm; 1681 nAlloc += NINCR; 1682 apShm = lsmRealloc(pEnv, p->apShmChunk, sizeof(void*)*nAlloc); 1683 if( !apShm ){ 1684 rc = LSM_NOMEM_BKPT; 1685 break; 1686 } 1687 p->apShmChunk = apShm; 1688 } 1689 1690 for(i=db->nShm; rc==LSM_OK && i<nChunk; i++){ 1691 if( i>=p->nShmChunk ){ 1692 void *pChunk = 0; 1693 if( p->bMultiProc==0 ){ 1694 /* Single process mode */ 1695 pChunk = lsmMallocZeroRc(pEnv, LSM_SHM_CHUNK_SIZE, &rc); 1696 }else{ 1697 /* Multi-process mode */ 1698 rc = lsmEnvShmMap(pEnv, p->pFile, i, LSM_SHM_CHUNK_SIZE, &pChunk); 1699 } 1700 if( rc==LSM_OK ){ 1701 p->apShmChunk[i] = pChunk; 1702 p->nShmChunk++; 1703 } 1704 } 1705 if( rc==LSM_OK ){ 1706 db->apShm[i] = p->apShmChunk[i]; 1707 db->nShm++; 1708 } 1709 } 1710 1711 /* Release the client mutex */ 1712 lsmMutexLeave(pEnv, p->pClientMutex); 1713 } 1714 } 1715 1716 return rc; 1717 } 1718 1719 static int lockSharedFile(lsm_env *pEnv, Database *p, int iLock, int eOp){ 1720 int rc = LSM_OK; 1721 if( p->bMultiProc ){ 1722 rc = lsmEnvLock(pEnv, p->pFile, iLock, eOp); 1723 } 1724 return rc; 1725 } 1726 1727 /* 1728 ** Test if it would be possible for connection db to obtain a lock of type 1729 ** eType on the nLock locks starting at iLock. If so, return LSM_OK. If it 1730 ** would not be possible to obtain the lock due to a lock held by another 1731 ** connection, return LSM_BUSY. If an IO or other error occurs (i.e. in the 1732 ** lsm_env.xTestLock function), return some other LSM error code. 1733 ** 1734 ** Note that this function never actually locks the database - it merely 1735 ** queries the system to see if there exists a lock that would prevent 1736 ** it from doing so. 1737 */ 1738 int lsmShmTestLock( 1739 lsm_db *db, 1740 int iLock, 1741 int nLock, 1742 int eOp 1743 ){ 1744 int rc = LSM_OK; 1745 lsm_db *pIter; 1746 Database *p = db->pDatabase; 1747 int i; 1748 u64 mask = 0; 1749 1750 for(i=iLock; i<(iLock+nLock); i++){ 1751 mask |= ((u64)1 << (iLock-1)); 1752 if( eOp==LSM_LOCK_EXCL ) mask |= ((u64)1 << (iLock+32-1)); 1753 } 1754 1755 lsmMutexEnter(db->pEnv, p->pClientMutex); 1756 for(pIter=p->pConn; pIter; pIter=pIter->pNext){ 1757 if( pIter!=db && (pIter->mLock & mask) ){ 1758 assert( pIter!=db ); 1759 break; 1760 } 1761 } 1762 1763 if( pIter ){ 1764 rc = LSM_BUSY; 1765 }else if( p->bMultiProc ){ 1766 rc = lsmEnvTestLock(db->pEnv, p->pFile, iLock, nLock, eOp); 1767 } 1768 1769 lsmMutexLeave(db->pEnv, p->pClientMutex); 1770 return rc; 1771 } 1772 1773 /* 1774 ** Attempt to obtain the lock identified by the iLock and bExcl parameters. 1775 ** If successful, return LSM_OK. If the lock cannot be obtained because 1776 ** there exists some other conflicting lock, return LSM_BUSY. If some other 1777 ** error occurs, return an LSM error code. 1778 ** 1779 ** Parameter iLock must be one of LSM_LOCK_WRITER, WORKER or CHECKPOINTER, 1780 ** or else a value returned by the LSM_LOCK_READER macro. 1781 */ 1782 int lsmShmLock( 1783 lsm_db *db, 1784 int iLock, 1785 int eOp, /* One of LSM_LOCK_UNLOCK, SHARED or EXCL */ 1786 int bBlock /* True for a blocking lock */ 1787 ){ 1788 lsm_db *pIter; 1789 const u64 me = ((u64)1 << (iLock-1)); 1790 const u64 ms = ((u64)1 << (iLock+32-1)); 1791 int rc = LSM_OK; 1792 Database *p = db->pDatabase; 1793 1794 assert( eOp!=LSM_LOCK_EXCL || p->bReadonly==0 ); 1795 assert( iLock>=1 && iLock<=LSM_LOCK_RWCLIENT(LSM_LOCK_NRWCLIENT-1) ); 1796 assert( LSM_LOCK_RWCLIENT(LSM_LOCK_NRWCLIENT-1)<=32 ); 1797 assert( eOp==LSM_LOCK_UNLOCK || eOp==LSM_LOCK_SHARED || eOp==LSM_LOCK_EXCL ); 1798 1799 /* Check for a no-op. Proceed only if this is not one of those. */ 1800 if( (eOp==LSM_LOCK_UNLOCK && (db->mLock & (me|ms))!=0) 1801 || (eOp==LSM_LOCK_SHARED && (db->mLock & (me|ms))!=ms) 1802 || (eOp==LSM_LOCK_EXCL && (db->mLock & me)==0) 1803 ){ 1804 int nExcl = 0; /* Number of connections holding EXCLUSIVE */ 1805 int nShared = 0; /* Number of connections holding SHARED */ 1806 lsmMutexEnter(db->pEnv, p->pClientMutex); 1807 1808 /* Figure out the locks currently held by this process on iLock, not 1809 ** including any held by connection db. */ 1810 for(pIter=p->pConn; pIter; pIter=pIter->pNext){ 1811 assert( (pIter->mLock & me)==0 || (pIter->mLock & ms)!=0 ); 1812 if( pIter!=db ){ 1813 if( pIter->mLock & me ){ 1814 nExcl++; 1815 }else if( pIter->mLock & ms ){ 1816 nShared++; 1817 } 1818 } 1819 } 1820 assert( nExcl==0 || nExcl==1 ); 1821 assert( nExcl==0 || nShared==0 ); 1822 assert( nExcl==0 || (db->mLock & (me|ms))==0 ); 1823 1824 switch( eOp ){ 1825 case LSM_LOCK_UNLOCK: 1826 if( nShared==0 ){ 1827 lockSharedFile(db->pEnv, p, iLock, LSM_LOCK_UNLOCK); 1828 } 1829 db->mLock &= ~(me|ms); 1830 break; 1831 1832 case LSM_LOCK_SHARED: 1833 if( nExcl ){ 1834 rc = LSM_BUSY; 1835 }else{ 1836 if( nShared==0 ){ 1837 rc = lockSharedFile(db->pEnv, p, iLock, LSM_LOCK_SHARED); 1838 } 1839 if( rc==LSM_OK ){ 1840 db->mLock |= ms; 1841 db->mLock &= ~me; 1842 } 1843 } 1844 break; 1845 1846 default: 1847 assert( eOp==LSM_LOCK_EXCL ); 1848 if( nExcl || nShared ){ 1849 rc = LSM_BUSY; 1850 }else{ 1851 rc = lockSharedFile(db->pEnv, p, iLock, LSM_LOCK_EXCL); 1852 if( rc==LSM_OK ){ 1853 db->mLock |= (me|ms); 1854 } 1855 } 1856 break; 1857 } 1858 1859 lsmMutexLeave(db->pEnv, p->pClientMutex); 1860 } 1861 1862 return rc; 1863 } 1864 1865 #ifdef LSM_DEBUG 1866 1867 int shmLockType(lsm_db *db, int iLock){ 1868 const u64 me = ((u64)1 << (iLock-1)); 1869 const u64 ms = ((u64)1 << (iLock+32-1)); 1870 1871 if( db->mLock & me ) return LSM_LOCK_EXCL; 1872 if( db->mLock & ms ) return LSM_LOCK_SHARED; 1873 return LSM_LOCK_UNLOCK; 1874 } 1875 1876 /* 1877 ** The arguments passed to this function are similar to those passed to 1878 ** the lsmShmLock() function. However, instead of obtaining a new lock 1879 ** this function returns true if the specified connection already holds 1880 ** (or does not hold) such a lock, depending on the value of eOp. As 1881 ** follows: 1882 ** 1883 ** (eOp==LSM_LOCK_UNLOCK) -> true if db has no lock on iLock 1884 ** (eOp==LSM_LOCK_SHARED) -> true if db has at least a SHARED lock on iLock. 1885 ** (eOp==LSM_LOCK_EXCL) -> true if db has an EXCLUSIVE lock on iLock. 1886 */ 1887 int lsmShmAssertLock(lsm_db *db, int iLock, int eOp){ 1888 int ret = 0; 1889 int eHave; 1890 1891 assert( iLock>=1 && iLock<=LSM_LOCK_READER(LSM_LOCK_NREADER-1) ); 1892 assert( iLock<=16 ); 1893 assert( eOp==LSM_LOCK_UNLOCK || eOp==LSM_LOCK_SHARED || eOp==LSM_LOCK_EXCL ); 1894 1895 eHave = shmLockType(db, iLock); 1896 1897 switch( eOp ){ 1898 case LSM_LOCK_UNLOCK: 1899 ret = (eHave==LSM_LOCK_UNLOCK); 1900 break; 1901 case LSM_LOCK_SHARED: 1902 ret = (eHave!=LSM_LOCK_UNLOCK); 1903 break; 1904 case LSM_LOCK_EXCL: 1905 ret = (eHave==LSM_LOCK_EXCL); 1906 break; 1907 default: 1908 assert( !"bad eOp value passed to lsmShmAssertLock()" ); 1909 break; 1910 } 1911 1912 return ret; 1913 } 1914 1915 int lsmShmAssertWorker(lsm_db *db){ 1916 return lsmShmAssertLock(db, LSM_LOCK_WORKER, LSM_LOCK_EXCL) && db->pWorker; 1917 } 1918 1919 /* 1920 ** This function does not contribute to library functionality, and is not 1921 ** included in release builds. It is intended to be called from within 1922 ** an interactive debugger. 1923 ** 1924 ** When called, this function prints a single line of human readable output 1925 ** to stdout describing the locks currently held by the connection. For 1926 ** example: 1927 ** 1928 ** (gdb) call print_db_locks(pDb) 1929 ** (shared on dms2) (exclusive on writer) 1930 */ 1931 void print_db_locks(lsm_db *db){ 1932 int iLock; 1933 for(iLock=0; iLock<16; iLock++){ 1934 int bOne = 0; 1935 const char *azLock[] = {0, "shared", "exclusive"}; 1936 const char *azName[] = { 1937 0, "dms1", "dms2", "writer", "worker", "checkpointer", 1938 "reader0", "reader1", "reader2", "reader3", "reader4", "reader5" 1939 }; 1940 int eHave = shmLockType(db, iLock); 1941 if( azLock[eHave] ){ 1942 printf("%s(%s on %s)", (bOne?" ":""), azLock[eHave], azName[iLock]); 1943 bOne = 1; 1944 } 1945 } 1946 printf("\n"); 1947 } 1948 void print_all_db_locks(lsm_db *db){ 1949 lsm_db *p; 1950 for(p=db->pDatabase->pConn; p; p=p->pNext){ 1951 printf("%s connection %p ", ((p==db)?"*":""), p); 1952 print_db_locks(p); 1953 } 1954 } 1955 #endif 1956 1957 void lsmShmBarrier(lsm_db *db){ 1958 lsmEnvShmBarrier(db->pEnv); 1959 } 1960 1961 int lsm_checkpoint(lsm_db *pDb, int *pnKB){ 1962 int rc; /* Return code */ 1963 u32 nWrite = 0; /* Number of pages checkpointed */ 1964 1965 /* Attempt the checkpoint. If successful, nWrite is set to the number of 1966 ** pages written between this and the previous checkpoint. */ 1967 rc = lsmCheckpointWrite(pDb, &nWrite); 1968 1969 /* If required, calculate the output variable (KB of data checkpointed). 1970 ** Set it to zero if an error occured. */ 1971 if( pnKB ){ 1972 int nKB = 0; 1973 if( rc==LSM_OK && nWrite ){ 1974 nKB = (((i64)nWrite * lsmFsPageSize(pDb->pFS)) + 1023) / 1024; 1975 } 1976 *pnKB = nKB; 1977 } 1978 1979 return rc; 1980 } 1981