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