#endif
/* A page number is a 64-bit integer. */
-typedef i64 Pgno;
+typedef i64 LsmPgno;
#ifdef LSM_DEBUG
int lsmErrorBkpt(int);
};
struct Segment {
- Pgno iFirst; /* First page of this run */
- Pgno iLastPg; /* Last page of this run */
- Pgno iRoot; /* Root page number (if any) */
+ LsmPgno iFirst; /* First page of this run */
+ LsmPgno iLastPg; /* Last page of this run */
+ LsmPgno iRoot; /* Root page number (if any) */
int nSize; /* Size of this run in pages */
Redirect *pRedirect; /* Block redirects (or NULL) */
** output segment.
*/
struct MergeInput {
- Pgno iPg; /* Page on which next input is stored */
+ LsmPgno iPg; /* Page on which next input is stored */
int iCell; /* Cell containing next input to merge */
};
struct Merge {
MergeInput splitkey; /* Location in file of current splitkey */
int nSkip; /* Number of separators entries to skip */
int iOutputOff; /* Write offset on output page */
- Pgno iCurrentPtr; /* Current pointer value */
+ LsmPgno iCurrentPtr; /* Current pointer value */
};
/*
Redirect redirect; /* Block redirection array */
/* Used by worker snapshots only */
- int nBlock; /* Number of blocks in database file */
- Pgno aiAppend[LSM_APPLIST_SZ]; /* Append point list */
- Freelist freelist; /* Free block list */
- u32 nWrite; /* Total number of pages written to disk */
+ int nBlock; /* Number of blocks in database file */
+ LsmPgno aiAppend[LSM_APPLIST_SZ]; /* Append point list */
+ Freelist freelist; /* Free block list */
+ u32 nWrite; /* Total number of pages written to disk */
};
#define LSM_INITIAL_SNAPSHOT_ID 11
int lsmFsFileid(lsm_db *pDb, void **ppId, int *pnId);
/* Creating, populating, gobbling and deleting sorted runs. */
-void lsmFsGobble(lsm_db *, Segment *, Pgno *, int);
+void lsmFsGobble(lsm_db *, Segment *, LsmPgno *, int);
int lsmFsSortedDelete(FileSystem *, Snapshot *, int, Segment *);
int lsmFsSortedFinish(FileSystem *, Segment *);
int lsmFsSortedAppend(FileSystem *, Snapshot *, Level *, int, Page **);
/* Reading sorted run content. */
int lsmFsDbPageLast(FileSystem *pFS, Segment *pSeg, Page **ppPg);
-int lsmFsDbPageGet(FileSystem *, Segment *, Pgno, Page **);
+int lsmFsDbPageGet(FileSystem *, Segment *, LsmPgno, Page **);
int lsmFsDbPageNext(Segment *, Page *, int eDir, Page **);
u8 *lsmFsPageData(Page *, int *);
int lsmFsPageRelease(Page *);
int lsmFsPagePersist(Page *);
void lsmFsPageRef(Page *);
-Pgno lsmFsPageNumber(Page *);
+LsmPgno lsmFsPageNumber(Page *);
int lsmFsNRead(FileSystem *);
int lsmFsNWrite(FileSystem *);
int lsmFsIntegrityCheck(lsm_db *);
#endif
-Pgno lsmFsRedirectPage(FileSystem *, Redirect *, Pgno);
+LsmPgno lsmFsRedirectPage(FileSystem *, Redirect *, LsmPgno);
int lsmFsPageWritable(Page *);
void lsmFsFlushWaiting(FileSystem *, int *);
/* Used by lsm_info(ARRAY_STRUCTURE) and lsm_config(MMAP) */
-int lsmInfoArrayStructure(lsm_db *pDb, int bBlock, Pgno iFirst, char **pzOut);
-int lsmInfoArrayPages(lsm_db *pDb, Pgno iFirst, char **pzOut);
+int lsmInfoArrayStructure(lsm_db *pDb, int bBlock, LsmPgno iFirst, char **pz);
+int lsmInfoArrayPages(lsm_db *pDb, LsmPgno iFirst, char **pzOut);
int lsmConfigMmap(lsm_db *pDb, int *piParam);
int lsmEnvOpen(lsm_env *, const char *, int, lsm_file **);
int lsmFsReadSyncedId(lsm_db *db, int, i64 *piVal);
-int lsmFsSegmentContainsPg(FileSystem *pFS, Segment *, Pgno, int *);
+int lsmFsSegmentContainsPg(FileSystem *pFS, Segment *, LsmPgno, int *);
void lsmFsPurgeCache(FileSystem *);
/*
** Functions from file "lsm_sorted.c".
*/
-int lsmInfoPageDump(lsm_db *, Pgno, int, char **);
+int lsmInfoPageDump(lsm_db *, LsmPgno, int, char **);
void lsmSortedCleanup(lsm_db *);
int lsmSortedAutoWork(lsm_db *, int nUnit);
int *pRc /* IN/OUT: Error code */
){
int i;
- Pgno *aiAppend = db->pWorker->aiAppend;
+ LsmPgno *aiAppend = db->pWorker->aiAppend;
for(i=0; i<LSM_APPLIST_SZ; i++){
ckptAppend64(p, piOut, aiAppend[i], pRc);
struct Page {
u8 *aData; /* Buffer containing page data */
int nData; /* Bytes of usable data at aData[] */
- Pgno iPg; /* Page number */
+ LsmPgno iPg; /* Page number */
int nRef; /* Number of outstanding references */
int flags; /* Combination of PAGE_XXX flags */
Page *pHashNext; /* Next page in hash table slot */
#ifdef NDEBUG
# define assert_lists_are_ok(x)
#else
-static Page *fsPageFindInHash(FileSystem *pFS, Pgno iPg, int *piHash);
+static Page *fsPageFindInHash(FileSystem *pFS, LsmPgno iPg, int *piHash);
static void assert_lists_are_ok(FileSystem *pFS){
#if 0
** Return true if page iReal of the database should be accessed using mmap.
** False otherwise.
*/
-static int fsMmapPage(FileSystem *pFS, Pgno iReal){
+static int fsMmapPage(FileSystem *pFS, LsmPgno iReal){
return ((i64)iReal*pFS->nPagesize <= pFS->nMapLimit);
}
** Given that there are currently nHash slots in the hash table, return
** the hash key for file iFile, page iPg.
*/
-static int fsHashKey(int nHash, Pgno iPg){
+static int fsHashKey(int nHash, LsmPgno iPg){
return (iPg % nHash);
}
** page on each block is the byte offset immediately following the 4-byte
** "previous block" pointer at the start of each block.
*/
-static Pgno fsFirstPageOnBlock(FileSystem *pFS, int iBlock){
- Pgno iPg;
+static LsmPgno fsFirstPageOnBlock(FileSystem *pFS, int iBlock){
+ LsmPgno iPg;
if( pFS->pCompress ){
if( iBlock==1 ){
iPg = pFS->nMetasize * 2 + 4;
}else{
- iPg = pFS->nBlocksize * (Pgno)(iBlock-1) + 4;
+ iPg = pFS->nBlocksize * (LsmPgno)(iBlock-1) + 4;
}
}else{
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
** page on each block is the byte offset of the byte immediately before
** the 4-byte "next block" pointer at the end of each block.
*/
-static Pgno fsLastPageOnBlock(FileSystem *pFS, int iBlock){
+static LsmPgno fsLastPageOnBlock(FileSystem *pFS, int iBlock){
if( pFS->pCompress ){
- return pFS->nBlocksize * (Pgno)iBlock - 1 - 4;
+ return pFS->nBlocksize * (LsmPgno)iBlock - 1 - 4;
}else{
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
return iBlock * nPagePerBlock;
** Return the block number of the block that page iPg is located on.
** Blocks are numbered starting from 1.
*/
-static int fsPageToBlock(FileSystem *pFS, Pgno iPg){
+static int fsPageToBlock(FileSystem *pFS, LsmPgno iPg){
if( pFS->pCompress ){
return (int)((iPg / pFS->nBlocksize) + 1);
}else{
**
** This function is only called in non-compressed database mode.
*/
-static int fsIsLast(FileSystem *pFS, Pgno iPg){
+static int fsIsLast(FileSystem *pFS, LsmPgno iPg){
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
assert( !pFS->pCompress );
return ( iPg && (iPg % nPagePerBlock)==0 );
**
** This function is only called in non-compressed database mode.
*/
-static int fsIsFirst(FileSystem *pFS, Pgno iPg){
+static int fsIsFirst(FileSystem *pFS, LsmPgno iPg){
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
assert( !pFS->pCompress );
return ( (iPg % nPagePerBlock)==1
/*
** Return the page number of a page.
*/
-Pgno lsmFsPageNumber(Page *pPage){
+LsmPgno lsmFsPageNumber(Page *pPage){
/* assert( (pPage->flags & PAGE_DIRTY)==0 ); */
return pPage ? pPage->iPg : 0;
}
** Either way, if argument piHash is not NULL set *piHash to the hash slot
** number that page iPg would be stored in before returning.
*/
-static Page *fsPageFindInHash(FileSystem *pFS, Pgno iPg, int *piHash){
+static Page *fsPageFindInHash(FileSystem *pFS, LsmPgno iPg, int *piHash){
Page *p; /* Return value */
int iHash = fsHashKey(pFS->nHash, iPg);
** object passed as the second argument, return the destination page to
** which it is redirected. Otherwise, return a copy of iPg.
*/
-Pgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, Pgno iPg){
- Pgno iReal = iPg;
+LsmPgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, LsmPgno iPg){
+ LsmPgno iReal = iPg;
if( pRedir ){
const int nPagePerBlock = (
if( iFrom>iBlk ) break;
if( iFrom==iBlk ){
int iTo = pRedir->a[i].iTo;
- iReal = iPg - (Pgno)(iFrom - iTo) * nPagePerBlock;
+ iReal = iPg - (LsmPgno)(iFrom - iTo) * nPagePerBlock;
if( iTo==1 ){
iReal += (fsFirstPageOnBlock(pFS, 1)-1);
}
}
/* Required by the circular fsBlockNext<->fsPageGet dependency. */
-static int fsPageGet(FileSystem *, Segment *, Pgno, int, Page **, int *);
+static int fsPageGet(FileSystem *, Segment *, LsmPgno, int, Page **, int *);
/*
** Parameter iBlock is a database file block. This function reads the value
/*
** Return the page number of the last page on the same block as page iPg.
*/
-Pgno fsLastPageOnPagesBlock(FileSystem *pFS, Pgno iPg){
+LsmPgno fsLastPageOnPagesBlock(FileSystem *pFS, LsmPgno iPg){
return fsLastPageOnBlock(pFS, fsPageToBlock(pFS, iPg));
}
static int fsPageGet(
FileSystem *pFS, /* File-system handle */
Segment *pSeg, /* Block redirection to use (or NULL) */
- Pgno iPg, /* Page id */
+ LsmPgno iPg, /* Page id */
int noContent, /* True to not load content from disk */
Page **ppPg, /* OUT: New page handle */
int *pnSpace /* OUT: Bytes of free space */
/* In most cases iReal is the same as iPg. Except, if pSeg->pRedirect is
** not NULL, and the block containing iPg has been redirected, then iReal
** is the page number after redirection. */
- Pgno iReal = lsmFsRedirectPage(pFS, (pSeg ? pSeg->pRedirect : 0), iPg);
+ LsmPgno iReal = lsmFsRedirectPage(pFS, (pSeg ? pSeg->pRedirect : 0), iPg);
assert_lists_are_ok(pFS);
assert( iPg>=fsFirstPageOnBlock(pFS, 1) );
static int fsRunEndsBetween(
Segment *pRun,
Segment *pIgnore,
- Pgno iFirst,
- Pgno iLast
+ LsmPgno iFirst,
+ LsmPgno iLast
){
return (pRun!=pIgnore && (
(pRun->iFirst>=iFirst && pRun->iFirst<=iLast)
static int fsLevelEndsBetween(
Level *pLevel,
Segment *pIgnore,
- Pgno iFirst,
- Pgno iLast
+ LsmPgno iFirst,
+ LsmPgno iLast
){
int i;
int iBlk /* Block number of block to free */
){
int rc = LSM_OK; /* Return code */
- Pgno iFirst; /* First page on block iBlk */
- Pgno iLast; /* Last page on block iBlk */
+ LsmPgno iFirst; /* First page on block iBlk */
+ LsmPgno iLast; /* Last page on block iBlk */
Level *pLevel; /* Used to iterate through levels */
int iIn; /* Used to iterate through append points */
int iOut = 0; /* Used to output append points */
- Pgno *aApp = pSnapshot->aiAppend;
+ LsmPgno *aApp = pSnapshot->aiAppend;
iFirst = fsFirstPageOnBlock(pFS, iBlk);
iLast = fsLastPageOnBlock(pFS, iBlk);
** number from the array that falls on block iBlk. Or, if none of the pages
** in aPgno[] fall on block iBlk, return 0.
*/
-static Pgno firstOnBlock(FileSystem *pFS, int iBlk, Pgno *aPgno, int nPgno){
- Pgno iRet = 0;
+static LsmPgno firstOnBlock(
+ FileSystem *pFS,
+ int iBlk,
+ LsmPgno *aPgno,
+ int nPgno
+){
+ LsmPgno iRet = 0;
int i;
for(i=0; i<nPgno; i++){
- Pgno iPg = aPgno[i];
+ LsmPgno iPg = aPgno[i];
if( fsPageToBlock(pFS, iPg)==iBlk && (iRet==0 || iPg<iRet) ){
iRet = iPg;
}
** Return true if page iPg, which is a part of segment p, lies on
** a redirected block.
*/
-static int fsPageRedirects(FileSystem *pFS, Segment *p, Pgno iPg){
+static int fsPageRedirects(FileSystem *pFS, Segment *p, LsmPgno iPg){
return (iPg!=0 && iPg!=lsmFsRedirectPage(pFS, p->pRedirect, iPg));
}
void lsmFsGobble(
lsm_db *pDb,
Segment *pRun,
- Pgno *aPgno,
+ LsmPgno *aPgno,
int nPgno
){
int rc = LSM_OK;
while( rc==LSM_OK ){
int iNext = 0;
- Pgno iFirst = firstOnBlock(pFS, iBlk, aPgno, nPgno);
+ LsmPgno iFirst = firstOnBlock(pFS, iBlk, aPgno, nPgno);
if( iFirst ){
pRun->iFirst = iFirst;
break;
static int fsNextPageOffset(
FileSystem *pFS, /* File system object */
Segment *pSeg, /* Segment to move within */
- Pgno iPg, /* Offset of current page */
+ LsmPgno iPg, /* Offset of current page */
int nByte, /* Size of current page including headers */
- Pgno *piNext /* OUT: Offset of next page. Or zero (EOF) */
+ LsmPgno *piNext /* OUT: Offset of next page. Or zero (EOF) */
){
- Pgno iNext;
+ LsmPgno iNext;
int rc;
assert( pFS->pCompress );
static int fsGetPageBefore(
FileSystem *pFS,
Segment *pSeg,
- Pgno iPg,
- Pgno *piPrev
+ LsmPgno iPg,
+ LsmPgno *piPrev
){
u8 aSz[3];
int rc;
int lsmFsDbPageNext(Segment *pRun, Page *pPg, int eDir, Page **ppNext){
int rc = LSM_OK;
FileSystem *pFS = pPg->pFS;
- Pgno iPg = pPg->iPg;
+ LsmPgno iPg = pPg->iPg;
assert( 0==fsSegmentRedirects(pFS, pRun) );
if( pFS->pCompress ){
** start the new segment immediately following any segment that is part
** of the right-hand-side of pLvl.
*/
-static Pgno findAppendPoint(FileSystem *pFS, Level *pLvl){
+static LsmPgno findAppendPoint(FileSystem *pFS, Level *pLvl){
int i;
- Pgno *aiAppend = pFS->pDb->pWorker->aiAppend;
- Pgno iRet = 0;
+ LsmPgno *aiAppend = pFS->pDb->pWorker->aiAppend;
+ LsmPgno iRet = 0;
for(i=LSM_APPLIST_SZ-1; iRet==0 && i>=0; i--){
if( (iRet = aiAppend[i]) ){
){
int rc = LSM_OK;
Page *pPg = 0;
- Pgno iApp = 0;
- Pgno iNext = 0;
+ LsmPgno iApp = 0;
+ LsmPgno iNext = 0;
Segment *p = &pLvl->lhs;
- Pgno iPrev = p->iLastPg;
+ LsmPgno iPrev = p->iLastPg;
*ppOut = 0;
assert( p->pRedirect==0 );
*/
if( fsLastPageOnPagesBlock(pFS, p->iLastPg)!=p->iLastPg ){
int i;
- Pgno *aiAppend = pFS->pDb->pWorker->aiAppend;
+ LsmPgno *aiAppend = pFS->pDb->pWorker->aiAppend;
for(i=0; i<LSM_APPLIST_SZ; i++){
if( aiAppend[i]==0 ){
aiAppend[i] = p->iLastPg+1;
**
** Return LSM_OK if successful, or an lsm error code if an error occurs.
*/
-int lsmFsDbPageGet(FileSystem *pFS, Segment *pSeg, Pgno iPg, Page **ppPg){
+int lsmFsDbPageGet(FileSystem *pFS, Segment *pSeg, LsmPgno iPg, Page **ppPg){
return fsPageGet(pFS, pSeg, iPg, 0, ppPg, 0);
}
*/
int lsmFsDbPageLast(FileSystem *pFS, Segment *pSeg, Page **ppPg){
int rc;
- Pgno iPg = pSeg->iLastPg;
+ LsmPgno iPg = pSeg->iLastPg;
if( pFS->pCompress ){
int nSpace;
iPg++;
FileSystem *pFS, /* File system object */
int iTo, /* Destination block */
int iFrom, /* Source block */
- Pgno *piPg /* IN/OUT: Page number */
+ LsmPgno *piPg /* IN/OUT: Page number */
){
- Pgno iPg = *piPg;
+ LsmPgno iPg = *piPg;
if( iFrom==fsPageToBlock(pFS, iPg) ){
const int nPagePerBlock = (
pFS->pCompress ? pFS ->nBlocksize : (pFS->nBlocksize / pFS->nPagesize)
);
- *piPg = iPg - (Pgno)(iFrom - iTo) * nPagePerBlock;
+ *piPg = iPg - (LsmPgno)(iFrom - iTo) * nPagePerBlock;
}
}
**
** This function is only used in compressed database mode.
*/
-static Pgno fsAppendData(
+static LsmPgno fsAppendData(
FileSystem *pFS, /* File-system handle */
Segment *pSeg, /* Segment to append to */
const u8 *aData, /* Buffer containing data to write */
int nData, /* Size of buffer aData[] in bytes */
int *pRc /* IN/OUT: Error code */
){
- Pgno iRet = 0;
+ LsmPgno iRet = 0;
int rc = *pRc;
assert( pFS->pCompress );
if( rc==LSM_OK ){
int nRem = 0;
int nWrite = 0;
- Pgno iLastOnBlock;
- Pgno iApp = pSeg->iLastPg+1;
+ LsmPgno iLastOnBlock;
+ LsmPgno iApp = pSeg->iLastPg+1;
/* If this is the first data written into the segment, find an append-point
** or allocate a new block. */
/* Set the "prev" pointer on the new block */
if( rc==LSM_OK ){
- Pgno iWrite;
+ LsmPgno iWrite;
lsmPutU32(aPtr, fsPageToBlock(pFS, iApp));
iWrite = fsFirstPageOnBlock(pFS, iBlk);
rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iWrite-4, aPtr, sizeof(aPtr));
static int fsAppendPage(
FileSystem *pFS,
Segment *pSeg,
- Pgno *piNew,
+ LsmPgno *piNew,
int *piPrev,
int *piNext
){
- Pgno iPrev = pSeg->iLastPg;
+ LsmPgno iPrev = pSeg->iLastPg;
int rc;
assert( iPrev!=0 );
/*
** If there exists a hash-table entry associated with page iPg, remove it.
*/
-static void fsRemoveHashEntry(FileSystem *pFS, Pgno iPg){
+static void fsRemoveHashEntry(FileSystem *pFS, LsmPgno iPg){
Page *p;
int iHash = fsHashKey(pFS->nHash, iPg);
){
int rc = LSM_OK;
if( pFS->pCompress && pSeg->iFirst ){
- Pgno iLast2;
- Pgno iLast = pSeg->iLastPg; /* Current last page of segment */
+ LsmPgno iLast2;
+ LsmPgno iLast = pSeg->iLastPg; /* Current last page of segment */
int nPad; /* Bytes of padding required */
u8 aSz[3];
/*
** Helper function for lsmInfoArrayStructure().
*/
-static Segment *startsWith(Segment *pRun, Pgno iFirst){
+static Segment *startsWith(Segment *pRun, LsmPgno iFirst){
return (iFirst==pRun->iFirst) ? pRun : 0;
}
** Return the segment that starts with page iFirst, if any. If no such segment
** can be found, return NULL.
*/
-static Segment *findSegment(Snapshot *pWorker, Pgno iFirst){
+static Segment *findSegment(Snapshot *pWorker, LsmPgno iFirst){
Level *pLvl; /* Used to iterate through db levels */
Segment *pSeg = 0; /* Pointer to segment to return */
int lsmInfoArrayStructure(
lsm_db *pDb,
int bBlock, /* True for block numbers only */
- Pgno iFirst,
+ LsmPgno iFirst,
char **pzOut
){
int rc = LSM_OK;
int lsmFsSegmentContainsPg(
FileSystem *pFS,
Segment *pSeg,
- Pgno iPg,
+ LsmPgno iPg,
int *pbRes
){
Redirect *pRedir = pSeg->pRedirect;
**
** If an error occurs, *pzOut is set to NULL and an LSM error code returned.
*/
-int lsmInfoArrayPages(lsm_db *pDb, Pgno iFirst, char **pzOut){
+int lsmInfoArrayPages(lsm_db *pDb, LsmPgno iFirst, char **pzOut){
int rc = LSM_OK;
Snapshot *pWorker; /* Worker snapshot */
Segment *pSeg = 0; /* Array to report on */
*/
int lsmFsDbPageIsLast(Segment *pSeg, Page *pPg){
if( pPg->pFS->pCompress ){
- Pgno iNext = 0;
+ LsmPgno iNext = 0;
int rc;
rc = fsNextPageOffset(pPg->pFS, pSeg, pPg->iPg, pPg->nCompress+6, &iNext);
return (rc!=LSM_OK || iNext==0);
}
case LSM_INFO_ARRAY_STRUCTURE: {
- Pgno pgno = va_arg(ap, Pgno);
+ LsmPgno pgno = va_arg(ap, LsmPgno);
char **pzVal = va_arg(ap, char **);
rc = lsmInfoArrayStructure(pDb, 0, pgno, pzVal);
break;
}
case LSM_INFO_ARRAY_PAGES: {
- Pgno pgno = va_arg(ap, Pgno);
+ LsmPgno pgno = va_arg(ap, LsmPgno);
char **pzVal = va_arg(ap, char **);
rc = lsmInfoArrayPages(pDb, pgno, pzVal);
break;
case LSM_INFO_PAGE_HEX_DUMP:
case LSM_INFO_PAGE_ASCII_DUMP: {
- Pgno pgno = va_arg(ap, Pgno);
+ LsmPgno pgno = va_arg(ap, LsmPgno);
char **pzVal = va_arg(ap, char **);
int bUnlock = 0;
rc = infoGetWorker(pDb, 0, &bUnlock);
#endif
typedef struct SegmentPtr SegmentPtr;
-typedef struct Blob Blob;
+typedef struct LsmBlob LsmBlob;
-struct Blob {
+struct LsmBlob {
lsm_env *pEnv;
void *pData;
int nData;
Page *pPg; /* Current page */
u16 flags; /* Copy of page flags field */
int nCell; /* Number of cells on pPg */
- Pgno iPtr; /* Base cascade pointer */
+ LsmPgno iPtr; /* Base cascade pointer */
/* Current cell. See segmentPtrLoadCell() */
int iCell; /* Current record within page pPg */
int eType; /* Type of current record */
- Pgno iPgPtr; /* Cascade pointer offset */
+ LsmPgno iPgPtr; /* Cascade pointer offset */
void *pKey; int nKey; /* Key associated with current record */
void *pVal; int nVal; /* Current record value (eType==WRITE only) */
/* Blobs used to allocate buffers for pKey and pVal as required */
- Blob blob1;
- Blob blob2;
+ LsmBlob blob1;
+ LsmBlob blob2;
};
/*
void *pKey;
int nKey;
int eType;
- Pgno iPtr;
+ LsmPgno iPtr;
/* Storage for key, if not local */
- Blob blob;
+ LsmBlob blob;
};
int flags; /* Mask of CURSOR_XXX flags */
int eType; /* Cache of current key type */
- Blob key; /* Cache of current key (or NULL) */
- Blob val; /* Cache of current value */
+ LsmBlob key; /* Cache of current key (or NULL) */
+ LsmBlob val; /* Cache of current value */
/* All the component cursors: */
TreeCursor *apTreeCsr[2]; /* Up to two tree cursors */
void *pSystemVal; /* Pointer to buffer to free */
/* Used by worker cursors only */
- Pgno *pPrevMergePtr;
+ LsmPgno *pPrevMergePtr;
};
/*
Hierarchy hier; /* B-tree hierarchy under construction */
Page *pPage; /* Current output page */
int nWork; /* Number of calls to mergeWorkerNextPage() */
- Pgno *aGobble; /* Gobble point for each input segment */
+ LsmPgno *aGobble; /* Gobble point for each input segment */
- Pgno iIndirect;
+ LsmPgno iIndirect;
struct SavedPgno {
- Pgno iPgno;
+ LsmPgno iPgno;
int bStore;
} aSave[2];
};
aOut[7] = (u8)((nVal ) & 0xFF);
}
-static int sortedBlobGrow(lsm_env *pEnv, Blob *pBlob, int nData){
+static int sortedBlobGrow(lsm_env *pEnv, LsmBlob *pBlob, int nData){
assert( pBlob->pEnv==pEnv || (pBlob->pEnv==0 && pBlob->pData==0) );
if( pBlob->nAlloc<nData ){
pBlob->pData = lsmReallocOrFree(pEnv, pBlob->pData, nData);
return LSM_OK;
}
-static int sortedBlobSet(lsm_env *pEnv, Blob *pBlob, void *pData, int nData){
+static int sortedBlobSet(lsm_env *pEnv, LsmBlob *pBlob, void *pData, int nData){
if( sortedBlobGrow(pEnv, pBlob, nData) ) return LSM_NOMEM;
memcpy(pBlob->pData, pData, nData);
pBlob->nData = nData;
}
#if 0
-static int sortedBlobCopy(Blob *pDest, Blob *pSrc){
+static int sortedBlobCopy(LsmBlob *pDest, LsmBlob *pSrc){
return sortedBlobSet(pDest, pSrc->pData, pSrc->nData);
}
#endif
-static void sortedBlobFree(Blob *pBlob){
+static void sortedBlobFree(LsmBlob *pBlob){
assert( pBlob->pEnv || pBlob->pData==0 );
if( pBlob->pData ) lsmFree(pBlob->pEnv, pBlob->pData);
- memset(pBlob, 0, sizeof(Blob));
+ memset(pBlob, 0, sizeof(LsmBlob));
}
static int sortedReadData(
int iOff,
int nByte,
void **ppData,
- Blob *pBlob
+ LsmBlob *pBlob
){
int rc = LSM_OK;
int iEnd;
return (int)lsmGetU16(&aData[SEGMENT_NRECORD_OFFSET(nData)]);
}
-static Pgno pageGetPtr(u8 *aData, int nData){
- return (Pgno)lsmGetU64(&aData[SEGMENT_POINTER_OFFSET(nData)]);
+static LsmPgno pageGetPtr(u8 *aData, int nData){
+ return (LsmPgno)lsmGetU64(&aData[SEGMENT_POINTER_OFFSET(nData)]);
}
static int pageGetFlags(u8 *aData, int nData){
** Return the decoded (possibly relative) pointer value stored in cell
** iCell from page aData/nData.
*/
-static Pgno pageGetRecordPtr(u8 *aData, int nData, int iCell){
- Pgno iRet; /* Return value */
+static LsmPgno pageGetRecordPtr(u8 *aData, int nData, int iCell){
+ LsmPgno iRet; /* Return value */
u8 *aCell; /* Pointer to cell iCell */
assert( iCell<pageGetNRec(aData, nData) && iCell>=0 );
int iCell, /* Index of cell on page to read */
int *piTopic, /* OUT: Topic associated with this key */
int *pnKey, /* OUT: Size of key in bytes */
- Blob *pBlob /* If required, use this for dynamic memory */
+ LsmBlob *pBlob /* If required, use this for dynamic memory */
){
u8 *pKey;
int nDummy;
Page *pPg, /* Page to read from */
int iCell, /* Index of cell on page to read */
int *piTopic, /* OUT: Topic associated with this key */
- Blob *pBlob /* If required, use this for dynamic memory */
+ LsmBlob *pBlob /* If required, use this for dynamic memory */
){
int rc = LSM_OK;
int nKey;
return rc;
}
-static Pgno pageGetBtreeRef(Page *pPg, int iKey){
- Pgno iRef;
+static LsmPgno pageGetBtreeRef(Page *pPg, int iKey){
+ LsmPgno iRef;
u8 *aData;
int nData;
u8 *aCell;
Segment *pSeg, /* Segment page pPg belongs to */
Page *pPg,
int iKey,
- Pgno *piPtr,
+ LsmPgno *piPtr,
int *piTopic,
void **ppKey,
int *pnKey,
- Blob *pBlob
+ LsmBlob *pBlob
){
u8 *aData;
int nData;
if( eType==0 ){
int rc;
- Pgno iRef; /* Page number of referenced page */
+ LsmPgno iRef; /* Page number of referenced page */
Page *pRef;
aCell += GETVARINT64(aCell, iRef);
rc = lsmFsDbPageGet(lsmPageFS(pPg), pSeg, iRef, &pRef);
pCsr->nKey = 0;
pCsr->eType = 0;
}else{
- Pgno dummy;
+ LsmPgno dummy;
int iPg = pCsr->iPg;
int iCell = pCsr->aPg[iPg].iCell;
while( iCell<0 && (--iPg)>=0 ){
assert( pPg->iCell<=nCell );
pPg->iCell++;
if( pPg->iCell==nCell ){
- Pgno iLoad;
+ LsmPgno iLoad;
/* Up to parent. */
lsmFsPageRelease(pPg->pPage);
if( p->iPg ){
lsm_env *pEnv = lsmFsEnv(pCsr->pFS);
int iCell; /* Current cell number on leaf page */
- Pgno iLeaf; /* Page number of current leaf page */
+ LsmPgno iLeaf; /* Page number of current leaf page */
int nDepth; /* Depth of b-tree structure */
Segment *pSeg = pCsr->pSeg;
/* Populate any other aPg[] array entries */
if( rc==LSM_OK && nDepth>1 ){
- Blob blob = {0,0,0};
+ LsmBlob blob = {0,0,0};
void *pSeek;
int nSeek;
int iTopicSeek;
pSeek = 0;
nSeek = 0;
}else{
- Pgno dummy;
+ LsmPgno dummy;
rc = pageGetBtreeKey(pSeg, pPg,
0, &dummy, &iTopicSeek, &pSeek, &nSeek, &pCsr->blob
);
int iTry = (iMin+iMax)/2;
void *pKey; int nKey; /* Key for cell iTry */
int iTopic; /* Topic for key pKeyT/nKeyT */
- Pgno iPtr; /* Pointer for cell iTry */
+ LsmPgno iPtr; /* Pointer for cell iTry */
int res; /* (pSeek - pKeyT) */
rc = pageGetBtreeKey(
aData = fsPageData(pBtreePg->pPage, &nData);
pCsr->iPtr = btreeCursorPtr(aData, nData, pBtreePg->iCell+1);
if( pBtreePg->iCell<0 ){
- Pgno dummy;
+ LsmPgno dummy;
int i;
for(i=pCsr->iPg-1; i>=0; i--){
if( pCsr->aPg[i].iCell>0 ) break;
int iOff,
int nByte,
void **ppData,
- Blob *pBlob
+ LsmBlob *pBlob
){
return sortedReadData(pPtr->pSeg, pPtr->pPg, iOff, nByte, ppData, pBlob);
}
}
if( rc==LSM_OK ){
int iTopic;
- Blob blob = {0, 0, 0, 0};
+ LsmBlob blob = {0, 0, 0, 0};
u8 *aData;
int nData;
if( pageGetFlags(aData, nData) & SEGMENT_BTREE_FLAG ){
void *pKey;
int nKey;
- Pgno dummy;
+ LsmPgno dummy;
rc = pageGetBtreeKey(pSeg,
pPg, pMerge->splitkey.iCell, &dummy, &iTopic, &pKey, &nKey, &blob
);
void *pKey, int nKey
){
lsm_env *pEnv = lsmFsEnv(pCsr->pDb->pFS);
- Blob blob = {0, 0, 0};
+ LsmBlob blob = {0, 0, 0};
int eDir;
int iTopic = 0; /* TODO: Fix me */
Page *pPage,
int iCell,
Segment *pSeg,
- Pgno *piPtr,
+ LsmPgno *piPtr,
int *pbFound
){
Page *pPg = pPage;
static int segmentPtrFwdPointer(
MultiCursor *pCsr, /* Multi-cursor pPtr belongs to */
SegmentPtr *pPtr, /* Segment-pointer to extract FC ptr from */
- Pgno *piPtr /* OUT: FC pointer value */
+ LsmPgno *piPtr /* OUT: FC pointer value */
){
Level *pLvl = pPtr->pLevel;
Level *pNext = pLvl->pNext;
Page *pPg = pPtr->pPg;
int rc;
int bFound;
- Pgno iOut = 0;
+ LsmPgno iOut = 0;
if( pPtr->pSeg==&pLvl->lhs || pPtr->pSeg==&pLvl->aRhs[pLvl->nRight-1] ){
if( pNext==0
int rc = LSM_OK;
int iMin;
int iMax;
- Pgno iPtrOut = 0;
+ LsmPgno iPtrOut = 0;
/* If the current page contains an oversized entry, then there are no
** pointers to one or more of the subsequent pages in the sorted run.
Segment *pSeg, /* Seek within this segment */
int iTopic,
void *pKey, int nKey, /* Key to seek to */
- Pgno *aPg, /* OUT: Page numbers */
+ LsmPgno *aPg, /* OUT: Page numbers */
Page **ppPg /* OUT: Leaf (sorted-run) page reference */
){
int i = 0;
int rc;
int iPg;
Page *pPg = 0;
- Blob blob = {0, 0, 0};
+ LsmBlob blob = {0, 0, 0};
iPg = (int)pSeg->iRoot;
do {
- Pgno *piFirst = 0;
+ LsmPgno *piFirst = 0;
if( aPg ){
aPg[i++] = iPg;
piFirst = &aPg[i];
int iTry = (iMin+iMax)/2;
void *pKeyT; int nKeyT; /* Key for cell iTry */
int iTopicT; /* Topic for key pKeyT/nKeyT */
- Pgno iPtr; /* Pointer associated with cell iTry */
+ LsmPgno iPtr; /* Pointer associated with cell iTry */
int res; /* (pKey - pKeyT) */
rc = pageGetBtreeKey(
int eSeek, /* Search bias - see above */
int iTopic, /* Key topic to search for */
void *pKey, int nKey, /* Key to search for */
- Pgno *piPgno, /* IN/OUT: fraction cascade pointer (or 0) */
+ LsmPgno *piPgno, /* IN/OUT: fraction cascade pointer (or 0) */
int *pbStop /* OUT: See above */
){
Level *pLvl = aPtr[0].pLevel; /* Level to seek within */
int bStop = 0; /* Set to true to halt search operation */
int rc = LSM_OK; /* Return code */
int iPtr = 0; /* Used to iterate through pCsr->aPtr[] */
- Pgno iPgno = 0; /* FC pointer value */
+ LsmPgno iPgno = 0; /* FC pointer value */
assert( pCsr->apTreeCsr[0]==0 || iTopic==0 );
assert( pCsr->apTreeCsr[1]==0 || iTopic==0 );
** + Type byte (always SORTED_SEPARATOR or SORTED_SYSTEM_SEPARATOR),
** + Absolute pointer value (varint),
** + Number of bytes in key (varint),
-** + Blob containing key data.
+** + LsmBlob containing key data.
**
** 2. All pointer values are stored as absolute values (not offsets
** relative to the footer pointer value).
static int mergeWorkerBtreeWrite(
MergeWorker *pMW,
u8 eType,
- Pgno iPtr,
- Pgno iKeyPg,
+ LsmPgno iPtr,
+ LsmPgno iKeyPg,
void *pKey,
int nKey
){
static int mergeWorkerBtreeIndirect(MergeWorker *pMW){
int rc = LSM_OK;
if( pMW->iIndirect ){
- Pgno iKeyPg = pMW->aSave[1].iPgno;
+ LsmPgno iKeyPg = pMW->aSave[1].iPgno;
rc = mergeWorkerBtreeWrite(pMW, 0, pMW->iIndirect, iKeyPg, 0, 0);
pMW->iIndirect = 0;
}
int nKey /* Size of pKey buffer in bytes */
){
int rc = LSM_OK; /* Return Code */
- Pgno iPtr; /* Pointer value to accompany pKey/nKey */
+ LsmPgno iPtr; /* Pointer value to accompany pKey/nKey */
assert( pMW->aSave[0].bStore==0 );
assert( pMW->aSave[1].bStore==0 );
){
int i; /* Used to loop through apHier[] */
int rc = LSM_OK; /* Return code */
- Pgno iPtr; /* New right-hand-child pointer value */
+ LsmPgno iPtr; /* New right-hand-child pointer value */
iPtr = pMW->aSave[0].iPgno;
for(i=0; i<pMW->hier.nHier && rc==LSM_OK; i++){
*/
static int mergeWorkerNextPage(
MergeWorker *pMW, /* Merge worker object to append page to */
- Pgno iFPtr /* Pointer value for footer of new page */
+ LsmPgno iFPtr /* Pointer value for footer of new page */
){
int rc = LSM_OK; /* Return code */
Page *pNext = 0; /* New page appended to run */
int rc = LSM_OK; /* Return code */
int eType; /* SORTED_SEPARATOR, WRITE or DELETE */
void *pKey; int nKey; /* Key */
- Pgno iPtr;
+ LsmPgno iPtr;
int iVal;
pCsr = pMW->pCsr;
if( rc!=LSM_OK ){
lsmMCursorClose(pCsr, 0);
}else{
- Pgno iLeftPtr = 0;
+ LsmPgno iLeftPtr = 0;
Merge merge; /* Merge object used to create new level */
MergeWorker mergeworker; /* MergeWorker object for the same purpose */
memset(pMW, 0, sizeof(MergeWorker));
pMW->pDb = pDb;
pMW->pLevel = pLevel;
- pMW->aGobble = lsmMallocZeroRc(pDb->pEnv, sizeof(Pgno) * pLevel->nRight, &rc);
+ pMW->aGobble = lsmMallocZeroRc(pDb->pEnv, sizeof(LsmPgno)*pLevel->nRight,&rc);
/* Create a multi-cursor to read the data to write to the new
** segment. The new segment contains:
int rc = LSM_OK;
if( rtTopic(pCsr->eType)==0 ){
Segment *pSeg = pCsr->aPtr[iGobble].pSeg;
- Pgno *aPg;
+ LsmPgno *aPg;
int nPg;
/* Seek from the root of the b-tree to the segment leaf that may contain
** gobbled up to (but not including) the first of these page numbers.
*/
assert( pSeg->iRoot>0 );
- aPg = lsmMallocZeroRc(pDb->pEnv, sizeof(Pgno)*32, &rc);
+ aPg = lsmMallocZeroRc(pDb->pEnv, sizeof(LsmPgno)*32, &rc);
if( rc==LSM_OK ){
rc = seekInBtree(pCsr, pSeg,
rtTopic(pCsr->eType), pCsr->key.pData, pCsr->key.nData, aPg, 0
*/
static char *segToString(lsm_env *pEnv, Segment *pSeg, int nMin){
int nSize = pSeg->nSize;
- Pgno iRoot = pSeg->iRoot;
- Pgno iFirst = pSeg->iFirst;
- Pgno iLast = pSeg->iLastPg;
+ LsmPgno iRoot = pSeg->iRoot;
+ LsmPgno iFirst = pSeg->iFirst;
+ LsmPgno iLast = pSeg->iLastPg;
char *z;
char *z1;
}
void sortedDumpPage(lsm_db *pDb, Segment *pRun, Page *pPg, int bVals){
- Blob blob = {0, 0, 0}; /* Blob used for keys */
+ LsmBlob blob = {0, 0, 0}; /* LsmBlob used for keys */
LsmString s;
int i;
aCell += lsmVarintGet32(aCell, &iPgPtr);
if( eType==0 ){
- Pgno iRef; /* Page number of referenced page */
+ LsmPgno iRef; /* Page number of referenced page */
aCell += lsmVarintGet64(aCell, &iRef);
lsmFsDbPageGet(pDb->pFS, pRun, iRef, &pRef);
aKey = pageGetKey(pRun, pRef, 0, &iTopic, &nKey, &blob);
int *piPgPtr,
u8 **paKey, int *pnKey,
u8 **paVal, int *pnVal,
- Blob *pBlob
+ LsmBlob *pBlob
){
u8 *aData; int nData; /* Page data */
u8 *aKey; int nKey = 0; /* Key */
if( eType==0 ){
int dummy;
- Pgno iRef; /* Page number of referenced page */
+ LsmPgno iRef; /* Page number of referenced page */
aCell += lsmVarintGet64(aCell, &iRef);
if( bIndirect ){
lsmFsDbPageGet(pDb->pFS, pSeg, iRef, &pRef);
static int infoPageDump(
lsm_db *pDb, /* Database handle */
- Pgno iPg, /* Page number of page to dump */
+ LsmPgno iPg, /* Page number of page to dump */
int flags,
char **pzOut /* OUT: lsmMalloc'd string */
){
}
if( rc==LSM_OK ){
- Blob blob = {0, 0, 0, 0};
+ LsmBlob blob = {0, 0, 0, 0};
int nKeyWidth = 0;
LsmString str;
int nRec;
u8 *aVal; int nVal = 0; /* Value */
int iPgPtr;
int eType;
- Pgno iAbsPtr;
+ LsmPgno iAbsPtr;
char zFlags[8];
infoCellDump(pDb, pSeg, bIndirect, pPg, iCell, &eType, &iPgPtr,
int lsmInfoPageDump(
lsm_db *pDb, /* Database handle */
- Pgno iPg, /* Page number of page to dump */
+ LsmPgno iPg, /* Page number of page to dump */
int bHex, /* True to output key/value in hex form */
char **pzOut /* OUT: lsmMalloc'd string */
){
#ifdef LSM_DEBUG_EXPENSIVE
static void assertRunInOrder(lsm_db *pDb, Segment *pSeg){
Page *pPg = 0;
- Blob blob1 = {0, 0, 0, 0};
- Blob blob2 = {0, 0, 0, 0};
+ LsmBlob blob1 = {0, 0, 0, 0};
+ LsmBlob blob2 = {0, 0, 0, 0};
lsmFsDbPageGet(pDb->pFS, pSeg, pSeg->iFirst, &pPg);
while( pPg ){
int rc = LSM_OK; /* Error code */
SegmentPtr ptr1; /* Iterates through pOne */
SegmentPtr ptr2; /* Iterates through pTwo */
- Pgno iPrev;
+ LsmPgno iPrev;
assert( pOne && pTwo );
}
while( rc==LSM_OK && ptr2.pPg ){
- Pgno iThis;
+ LsmPgno iThis;
/* Advance to the next page of segment pTwo that contains at least
** one cell. Break out of the loop if the iterator reaches EOF. */
){
int rc = LSM_OK; /* Return code */
if( pSeg->iRoot ){
- Blob blob = {0, 0, 0}; /* Buffer used to cache overflow keys */
+ LsmBlob blob = {0, 0, 0}; /* Buffer used to cache overflow keys */
FileSystem *pFS = pDb->pFS; /* File system to read from */
Page *pPg = 0; /* Main run page */
BtreeCursor *pCsr = 0; /* Btree cursor */
-C Add\sscript\sto\samalgamate\sall\sLSM\sfiles\sinto\s"lsm1.c".
-D 2017-12-13T14:22:48.449
+C Change\ssome\sLSM\scode\sinternal\stypenames\sfrom\s"Blob"\sand\s"Pgno"\sto\s"LsmBlob"\nand\s"LsmPgno".\sThis\sallows\sthe\sLSM\scode\sto\sbe\scompiled\sas\sa\ssingle\sunit\swith\nsqlite3.c.
+D 2017-12-13T15:32:33.291
F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc e5d7606238f55816da99f719969598df5b091aa2e9a6935c9412fcae8f53fc44
F ext/lsm1/lsm-test/lsmtest_util.c 241622db5a332a09c8e6e7606b617d288a37b557f7d3bce0bb97809f67cc2806
F ext/lsm1/lsm-test/lsmtest_win32.c 0e0a224674c4d3170631c41b026b56c7e1672b151f5261e1b4cc19068641da2d
F ext/lsm1/lsm.h 0f6f64ff071471cb87bf98beb8386566f30ea001
-F ext/lsm1/lsmInt.h e9e5c5f08e35a104086102b3def94ee69cbc0d39002f6596f5c80a640439628e
-F ext/lsm1/lsm_ckpt.c ac6fb4581983291c2e0be6fbb68f12b26f0c08d606835c05417be1323d0fdd03
-F ext/lsm1/lsm_file.c 4b3fb56336fbc9d941e1b2042e809d986feebdc41e73dc7fc4fdc0dd1bd4274d
+F ext/lsm1/lsmInt.h 5983690e05e83653cc01ba9d8fbf8455e534ddf8349ed9adedbf46a7549760b0
+F ext/lsm1/lsm_ckpt.c 0eabfaf812ddb4ea43add38f05e430694cd054eb622c3e35af4c43118a2d5321
+F ext/lsm1/lsm_file.c 3c51841d5b3e7da162693cbac9a9f47eeedf6bcbbe2969a4d25e30c428c9fe36
F ext/lsm1/lsm_log.c a8bf334532109bba05b09a504ee45fc393828b0d034ca61ab45e3940709d9a7c
-F ext/lsm1/lsm_main.c 15e73ccdafdd44ddeefc29e332079d88ba8f00c12c797b3c2b63d3171b5afce8
+F ext/lsm1/lsm_main.c 801295038b548ae2e5fae93f08c3f945154f40848a03ff26b16eab5d04ba573a
F ext/lsm1/lsm_mem.c 4c51ea9fa285ee6e35301b33491642d071740a0a
F ext/lsm1/lsm_mutex.c 378edf0a2b142b4f7640ee982df06d50b98788ea
F ext/lsm1/lsm_shared.c 76adfc1ed9ffebaf92746dde4b370ccc48143ca8b05b563816eadd2aadf1c525
-F ext/lsm1/lsm_sorted.c 8f899fb64a4c736ff3c27d5126c7ce181129ddffde947fe5fb657a7a413f470b
+F ext/lsm1/lsm_sorted.c d07ff7c28758542b8b4da4b5a1fb67b22a4d33e50e7f684cffe1f6c45cf5182c
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
F ext/lsm1/lsm_tree.c 682679d7ef2b8b6f2fe77aeb532c8d29695bca671c220b0abac77069de5fb9fb
F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 9cede8a83ca4cd88d504050115e1e89e7b3d3cd3cb2ffb5b8961e311a23ff5e2
-R 0bb1b86efd302c3523a2137056206a8a
+P e32b69d73062e233b0ac853611d10b24546a346a603289ab0e339a3604ae2af4
+R 3d8a0d79c82564334f201ac883edd045
U dan
-Z 0df44b61ec124ac51afd1eb16b579be7
+Z 7a59c9677684f4709aed2e3a45c7d151
-e32b69d73062e233b0ac853611d10b24546a346a603289ab0e339a3604ae2af4
\ No newline at end of file
+30bf38d589adf0b2eb613e184ffb03ed7e625736cb04fd5c341328f72bc5ef4d
\ No newline at end of file