int lsmStructList( lsm_db *pDb, /* Database handle */ char **pzOut /* OUT: Nul-terminated string (tcl list) */ ){ Level *pTopLevel = 0; /* Top level of snapshot to report on */ int rc = LSM_OK; Level *p; LsmString s; Snapshot *pWorker; /* Worker snapshot */ int bUnlock = 0; /* Obtain the worker snapshot */ rc = infoGetWorker(pDb, &pWorker, &bUnlock); if( rc!=LSM_OK ) return rc; /* Format the contents of the snapshot as text */ pTopLevel = lsmDbSnapshotLevel(pWorker); lsmStringInit(&s, pDb->pEnv); for(p=pTopLevel; rc==LSM_OK && p; p=p->pNext){ int i; lsmStringAppendf(&s, "%s{%d", (s.n ? " " : ""), (int)p->iAge); lsmAppendSegmentList(&s, " ", &p->lhs); for(i=0; rc==LSM_OK && i<p->nRight; i++){ lsmAppendSegmentList(&s, " ", &p->aRhs[i]); } lsmStringAppend(&s, "}", 1); } rc = s.n>=0 ? LSM_OK : LSM_NOMEM; /* Release the snapshot and return */ infoFreeWorker(pDb, bUnlock); *pzOut = s.z; return rc; }
/* ** Write into memory obtained from lsm_malloc(). */ char *lsmMallocPrintf(lsm_env *pEnv, const char *zFormat, ...){ LsmString s; va_list ap, ap2; lsmStringInit(&s, pEnv); va_start(ap, zFormat); va_start(ap2, zFormat); lsmStringVAppendf(&s, zFormat, ap, ap2); va_end(ap); va_end(ap2); if( s.n<0 ) return 0; return (char *)lsmReallocOrFree(pEnv, s.z, s.n+1); }
void lsmLogMessage(lsm_db *pDb, int rc, const char *zFormat, ...){ if( pDb->xLog ){ LsmString s; va_list ap, ap2; lsmStringInit(&s, pDb->pEnv); va_start(ap, zFormat); va_start(ap2, zFormat); lsmStringVAppendf(&s, zFormat, ap, ap2); va_end(ap); va_end(ap2); pDb->xLog(pDb->pLogCtx, rc, s.z); lsmStringClear(&s); } }
int lsmInfoFreelist(lsm_db *pDb, char **pzOut){ Snapshot *pWorker; /* Worker snapshot */ int bUnlock = 0; LsmString s; int rc; /* Obtain the worker snapshot */ rc = infoGetWorker(pDb, &pWorker, &bUnlock); if( rc!=LSM_OK ) return rc; lsmStringInit(&s, pDb->pEnv); rc = lsmWalkFreelist(pDb, 0, infoFreelistCb, &s); if( rc!=LSM_OK ){ lsmFree(pDb->pEnv, s.z); }else{ *pzOut = s.z; } /* Release the snapshot and return */ infoFreeWorker(pDb, bUnlock); return rc; }
int lsmStructList( lsm_db *pDb, /* Database handle */ char **pzOut /* OUT: Nul-terminated string (tcl list) */ ){ Level *pTopLevel = 0; /* Top level of snapshot to report on */ int rc = LSM_OK; Level *p; LsmString s; Snapshot *pWorker; /* Worker snapshot */ Snapshot *pRelease = 0; /* Snapshot to release */ /* Obtain the worker snapshot */ pWorker = pDb->pWorker; if( !pWorker ){ pRelease = pWorker = lsmDbSnapshotWorker(pDb); } /* Format the contents of the snapshot as text */ pTopLevel = lsmDbSnapshotLevel(pWorker); lsmStringInit(&s, pDb->pEnv); for(p=pTopLevel; rc==LSM_OK && p; p=p->pNext){ int i; lsmStringAppendf(&s, "%s{", (s.n ? " " : "")); lsmAppendSegmentList(&s, "", &p->lhs); for(i=0; rc==LSM_OK && i<p->nRight; i++){ lsmAppendSegmentList(&s, " ", &p->aRhs[i]); } lsmStringAppend(&s, "}", 1); } rc = s.n>=0 ? LSM_OK : LSM_NOMEM; /* Release the snapshot and return */ lsmDbSnapshotRelease(pDb->pEnv, pRelease); *pzOut = s.z; return rc; }
/* ** Clear an LsmString object, releasing any allocated memory that it holds. ** This also clears the error indication (if any). */ void lsmStringClear(LsmString *pStr){ lsmFree(pStr->pEnv, pStr->z); lsmStringInit(pStr, pStr->pEnv); }
/* ** Return a reference to the shared Database handle for the database ** identified by canonical path zName. If this is the first connection to ** the named database, a new Database object is allocated. Otherwise, a ** pointer to an existing object is returned. ** ** If successful, *ppDatabase is set to point to the shared Database ** structure and LSM_OK returned. Otherwise, *ppDatabase is set to NULL ** and and LSM error code returned. ** ** Each successful call to this function should be (eventually) matched ** by a call to lsmDbDatabaseRelease(). */ int lsmDbDatabaseFind( lsm_db *pDb, /* Database handle */ const char *zName /* Path to db file */ ){ lsm_env *pEnv = pDb->pEnv; int rc; /* Return code */ Database *p = 0; /* Pointer returned via *ppDatabase */ int nId = 0; void *pId = 0; assert( pDb->pDatabase==0 ); rc = lsmFsFileid(pDb, &pId, &nId); if( rc!=LSM_OK ) return rc; rc = enterGlobalMutex(pEnv); if( rc==LSM_OK ){ /* Search the global list for an existing object. TODO: Need something ** better than the strcmp() below to figure out if a given Database ** object represents the requested file. */ for(p=gShared.pDatabase; p; p=p->pDbNext){ if( nId==p->nId && 0==memcmp(pId, p->pId, nId) ) break; } /* If no suitable Database object was found, allocate a new one. */ if( p==0 ){ int nName = strlen(zName); p = (Database *)lsmMallocZeroRc(pEnv, sizeof(Database)+nId+nName+1, &rc); /* Initialize the log handle */ if( rc==LSM_OK ){ p->log.cksum0 = LSM_CKSUM0_INIT; p->log.cksum1 = LSM_CKSUM1_INIT; lsmStringInit(&p->log.buf, pEnv); } /* Allocate the two mutexes */ if( rc==LSM_OK ) rc = lsmMutexNew(pEnv, &p->pWorkerMutex); if( rc==LSM_OK ) rc = lsmMutexNew(pEnv, &p->pClientMutex); /* If no error has occurred, fill in other fields and link the new ** Database structure into the global list starting at ** gShared.pDatabase. Otherwise, if an error has occurred, free any ** resources allocated and return without linking anything new into ** the gShared.pDatabase list. */ if( rc==LSM_OK ){ p->zName = (char *)&p[1]; memcpy((void *)p->zName, zName, nName+1); p->pId = (void *)&p->zName[nName+1]; memcpy(p->pId, pId, nId); p->nId = nId; p->worker.pDatabase = p; p->pDbNext = gShared.pDatabase; gShared.pDatabase = p; p->worker.iLogPg = LSM_INITIAL_LOGPG; p->worker.iId = LSM_INITIAL_SNAPSHOT_ID; p->worker.iSalt1 = LSM_INITIAL_SALT1; p->worker.iSalt2 = LSM_INITIAL_SALT2; p->nPgsz = pDb->nDfltPgsz; p->nBlksz = pDb->nDfltBlksz; }else{ freeDatabase(pEnv, p); p = 0; } } if( p ) p->nDbRef++; leaveGlobalMutex(pEnv); } lsmFree(pEnv, pId); pDb->pDatabase = p; return rc; }