/* ** Allocate a new database file block to write data to, either by extending ** the database file or by recycling a free-list entry. The worker snapshot ** must be held in order to call this function. ** ** If successful, *piBlk is set to the block number allocated and LSM_OK is ** returned. Otherwise, *piBlk is zeroed and an lsm error code returned. */ int lsmBlockAllocate(lsm_db *pDb, int *piBlk){ Database *p = pDb->pDatabase; Snapshot *pWorker; /* Worker snapshot */ Freelist *pFree; /* Database free list */ int iRet = 0; /* Block number of allocated block */ pWorker = pDb->pWorker; pFree = &pWorker->freelist; if( pFree->nEntry>0 ){ /* The first block on the free list was freed as part of the work done ** to create the snapshot with id iFree. So, we can reuse this block if ** snapshot iFree or later has been checkpointed and all currently ** active clients are reading from snapshot iFree or later. */ Snapshot *pIter; i64 iFree = pFree->aEntry[0].iId; i64 iInUse; /* Both Database.iCheckpointId and the Database.pClient list are ** protected by the client mutex. So grab it here before determining ** the id of the oldest snapshot still potentially in use. */ lsmMutexEnter(pDb->pEnv, p->pClientMutex); assertSnapshotListOk(p); for(pIter=p->pClient; pIter->pSnapshotNext; pIter=pIter->pSnapshotNext); iInUse = LSM_MIN(pIter->iId, p->iCheckpointId); lsmMutexLeave(pDb->pEnv, p->pClientMutex); if( iFree<=iInUse ){ iRet = pFree->aEntry[0].iBlk; flRemoveEntry0(pFree); assert( iRet!=0 ); if( pWorker->bRecordDelta ){ pWorker->aDelta[0]++; } } } /* If no block was allocated from the free-list, allocate one at the ** end of the file. */ if( iRet==0 ){ pWorker->nBlock++; iRet = pWorker->nBlock; } *piBlk = iRet; return LSM_OK; }
/* ** The default key-compare function. */ static int xCmp(void *p1, int n1, void *p2, int n2){ int res; res = memcmp(p1, p2, LSM_MIN(n1, n2)); if( res==0 ) res = (n1-n2); return res; }