Merge branch 'feature/tdb' into feature/tdb-merge
This commit is contained in:
commit
b646052fb6
|
@ -8,7 +8,6 @@ target_sources(tdb
|
||||||
"src/db/tdbBtree.c"
|
"src/db/tdbBtree.c"
|
||||||
"src/db/tdbDb.c"
|
"src/db/tdbDb.c"
|
||||||
"src/db/tdbEnv.c"
|
"src/db/tdbEnv.c"
|
||||||
# "src/db/tdbPage.c"
|
|
||||||
"src/page/tdbPage.c"
|
"src/page/tdbPage.c"
|
||||||
"src/page/tdbPageL.c"
|
"src/page/tdbPageL.c"
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TDB_BTREE_INT_H_
|
||||||
|
#define _TDB_BTREE_INT_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TDB_BTREE_INT_H_*/
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
File diff suppressed because it is too large
Load Diff
|
@ -15,13 +15,17 @@
|
||||||
|
|
||||||
#include "tdbInt.h"
|
#include "tdbInt.h"
|
||||||
|
|
||||||
struct STDb {
|
struct STDB {
|
||||||
STEnv *pEnv;
|
STEnv *pEnv;
|
||||||
SBTree *pBt;
|
SBTree *pBt;
|
||||||
};
|
};
|
||||||
|
|
||||||
int tdbDbOpen(const char *fname, int keyLen, int valLen, FKeyComparator keyCmprFn, STEnv *pEnv, STDb **ppDb) {
|
struct STDBC {
|
||||||
STDb *pDb;
|
SBTC btc;
|
||||||
|
};
|
||||||
|
|
||||||
|
int tdbDbOpen(const char *fname, int keyLen, int valLen, FKeyComparator keyCmprFn, STEnv *pEnv, STDB **ppDb) {
|
||||||
|
STDB *pDb;
|
||||||
SPager *pPager;
|
SPager *pPager;
|
||||||
int ret;
|
int ret;
|
||||||
char fFullName[TDB_FILENAME_LEN];
|
char fFullName[TDB_FILENAME_LEN];
|
||||||
|
@ -30,7 +34,7 @@ int tdbDbOpen(const char *fname, int keyLen, int valLen, FKeyComparator keyCmprF
|
||||||
|
|
||||||
*ppDb = NULL;
|
*ppDb = NULL;
|
||||||
|
|
||||||
pDb = (STDb *)calloc(1, sizeof(*pDb));
|
pDb = (STDB *)calloc(1, sizeof(*pDb));
|
||||||
if (pDb == NULL) {
|
if (pDb == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -59,23 +63,23 @@ int tdbDbOpen(const char *fname, int keyLen, int valLen, FKeyComparator keyCmprF
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tdbDbClose(STDb *pDb) {
|
int tdbDbClose(STDB *pDb) {
|
||||||
// TODO
|
// TODO
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tdbDbDrop(STDb *pDb) {
|
int tdbDbDrop(STDB *pDb) {
|
||||||
// TODO
|
// TODO
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tdbDbInsert(STDb *pDb, const void *pKey, int keyLen, const void *pVal, int valLen) {
|
int tdbDbInsert(STDB *pDb, const void *pKey, int keyLen, const void *pVal, int valLen) {
|
||||||
SBtCursor btc;
|
SBTC btc;
|
||||||
SBtCursor *pCur;
|
SBTC *pCur;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pCur = &btc;
|
pCur = &btc;
|
||||||
ret = tdbBtreeCursor(pCur, pDb->pBt);
|
ret = tdbBtcOpen(pCur, pDb->pBt);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -87,3 +91,43 @@ int tdbDbInsert(STDb *pDb, const void *pKey, int keyLen, const void *pVal, int v
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tdbDbGet(STDB *pDb, const void *pKey, int kLen, void **ppVal, int *vLen) {
|
||||||
|
return tdbBtreeGet(pDb->pBt, pKey, kLen, ppVal, vLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tdbDbcOpen(STDB *pDb, STDBC **ppDbc) {
|
||||||
|
int ret;
|
||||||
|
STDBC *pDbc = NULL;
|
||||||
|
|
||||||
|
*ppDbc = NULL;
|
||||||
|
pDbc = malloc(sizeof(*pDbc));
|
||||||
|
if (pDbc == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdbBtcOpen(&pDbc->btc, pDb->pBt);
|
||||||
|
|
||||||
|
// TODO: move to first now, we can move to any key-value
|
||||||
|
// and in any direction, design new APIs.
|
||||||
|
ret = tdbBtcMoveToFirst(&pDbc->btc);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppDbc = pDbc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tdbDbNext(STDBC *pDbc, void **ppKey, int *kLen, void **ppVal, int *vLen) {
|
||||||
|
return tdbBtreeNext(&pDbc->btc, ppKey, kLen, ppVal, vLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tdbDbcClose(STDBC *pDbc) {
|
||||||
|
if (pDbc) {
|
||||||
|
free(pDbc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -53,12 +53,10 @@ static void tdbPCacheLock(SPCache *pCache);
|
||||||
static void tdbPCacheUnlock(SPCache *pCache);
|
static void tdbPCacheUnlock(SPCache *pCache);
|
||||||
static bool tdbPCacheLocked(SPCache *pCache);
|
static bool tdbPCacheLocked(SPCache *pCache);
|
||||||
static SPage *tdbPCacheFetchImpl(SPCache *pCache, const SPgid *pPgid, bool alcNewPage);
|
static SPage *tdbPCacheFetchImpl(SPCache *pCache, const SPgid *pPgid, bool alcNewPage);
|
||||||
static void tdbPCachePinPage(SPage *pPage);
|
static void tdbPCachePinPage(SPCache *pCache, SPage *pPage);
|
||||||
static void tdbPCacheRemovePageFromHash(SPage *pPage);
|
static void tdbPCacheRemovePageFromHash(SPCache *pCache, SPage *pPage);
|
||||||
static void tdbPCacheAddPageToHash(SPage *pPage);
|
static void tdbPCacheAddPageToHash(SPCache *pCache, SPage *pPage);
|
||||||
static void tdbPCacheUnpinPage(SPage *pPage);
|
static void tdbPCacheUnpinPage(SPCache *pCache, SPage *pPage);
|
||||||
static void *tdbOsMalloc(void *arg, size_t size);
|
|
||||||
static void tdbOsFree(void *arg, void *ptr);
|
|
||||||
|
|
||||||
int tdbPCacheOpen(int pageSize, int cacheSize, SPCache **ppCache) {
|
int tdbPCacheOpen(int pageSize, int cacheSize, SPCache **ppCache) {
|
||||||
SPCache *pCache;
|
SPCache *pCache;
|
||||||
|
@ -102,7 +100,7 @@ SPage *tdbPCacheFetch(SPCache *pCache, const SPgid *pPgid, bool alcNewPage) {
|
||||||
return pPage;
|
return pPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tdbPCacheRelease(SPage *pPage) {
|
void tdbPCacheRelease(SPCache *pCache, SPage *pPage) {
|
||||||
i32 nRef;
|
i32 nRef;
|
||||||
|
|
||||||
nRef = TDB_UNREF_PAGE(pPage);
|
nRef = TDB_UNREF_PAGE(pPage);
|
||||||
|
@ -110,7 +108,7 @@ void tdbPCacheRelease(SPage *pPage) {
|
||||||
|
|
||||||
if (nRef == 0) {
|
if (nRef == 0) {
|
||||||
if (1 /*TODO: page still clean*/) {
|
if (1 /*TODO: page still clean*/) {
|
||||||
tdbPCacheUnpinPage(pPage);
|
tdbPCacheUnpinPage(pCache, pPage);
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
// TODO
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
|
@ -144,7 +142,7 @@ static SPage *tdbPCacheFetchImpl(SPCache *pCache, const SPgid *pPgid, bool alcNe
|
||||||
|
|
||||||
if (pPage || !alcNewPage) {
|
if (pPage || !alcNewPage) {
|
||||||
if (pPage) {
|
if (pPage) {
|
||||||
tdbPCachePinPage(pPage);
|
tdbPCachePinPage(pCache, pPage);
|
||||||
}
|
}
|
||||||
return pPage;
|
return pPage;
|
||||||
}
|
}
|
||||||
|
@ -160,8 +158,8 @@ static SPage *tdbPCacheFetchImpl(SPCache *pCache, const SPgid *pPgid, bool alcNe
|
||||||
// 3. Try to Recycle a page
|
// 3. Try to Recycle a page
|
||||||
if (!pPage && !pCache->lru.pLruPrev->isAnchor) {
|
if (!pPage && !pCache->lru.pLruPrev->isAnchor) {
|
||||||
pPage = pCache->lru.pLruPrev;
|
pPage = pCache->lru.pLruPrev;
|
||||||
tdbPCacheRemovePageFromHash(pPage);
|
tdbPCacheRemovePageFromHash(pCache, pPage);
|
||||||
tdbPCachePinPage(pPage);
|
tdbPCachePinPage(pCache, pPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Try a stress allocation (TODO)
|
// 4. Try a stress allocation (TODO)
|
||||||
|
@ -173,16 +171,13 @@ static SPage *tdbPCacheFetchImpl(SPCache *pCache, const SPgid *pPgid, bool alcNe
|
||||||
memcpy(&(pPage->pgid), pPgid, sizeof(*pPgid));
|
memcpy(&(pPage->pgid), pPgid, sizeof(*pPgid));
|
||||||
pPage->pLruNext = NULL;
|
pPage->pLruNext = NULL;
|
||||||
pPage->pPager = NULL;
|
pPage->pPager = NULL;
|
||||||
tdbPCacheAddPageToHash(pPage);
|
tdbPCacheAddPageToHash(pCache, pPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pPage;
|
return pPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tdbPCachePinPage(SPage *pPage) {
|
static void tdbPCachePinPage(SPCache *pCache, SPage *pPage) {
|
||||||
SPCache *pCache;
|
|
||||||
|
|
||||||
pCache = pPage->pCache;
|
|
||||||
if (!PAGE_IS_PINNED(pPage)) {
|
if (!PAGE_IS_PINNED(pPage)) {
|
||||||
pPage->pLruPrev->pLruNext = pPage->pLruNext;
|
pPage->pLruPrev->pLruNext = pPage->pLruNext;
|
||||||
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
|
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
|
||||||
|
@ -192,12 +187,9 @@ static void tdbPCachePinPage(SPage *pPage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tdbPCacheUnpinPage(SPage *pPage) {
|
static void tdbPCacheUnpinPage(SPCache *pCache, SPage *pPage) {
|
||||||
SPCache *pCache;
|
|
||||||
i32 nRef;
|
i32 nRef;
|
||||||
|
|
||||||
pCache = pPage->pCache;
|
|
||||||
|
|
||||||
tdbPCacheLock(pCache);
|
tdbPCacheLock(pCache);
|
||||||
|
|
||||||
nRef = TDB_GET_PAGE_REF(pPage);
|
nRef = TDB_GET_PAGE_REF(pPage);
|
||||||
|
@ -217,12 +209,10 @@ static void tdbPCacheUnpinPage(SPage *pPage) {
|
||||||
tdbPCacheUnlock(pCache);
|
tdbPCacheUnlock(pCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tdbPCacheRemovePageFromHash(SPage *pPage) {
|
static void tdbPCacheRemovePageFromHash(SPCache *pCache, SPage *pPage) {
|
||||||
SPCache *pCache;
|
|
||||||
SPage **ppPage;
|
SPage **ppPage;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
pCache = pPage->pCache;
|
|
||||||
h = PCACHE_PAGE_HASH(&(pPage->pgid));
|
h = PCACHE_PAGE_HASH(&(pPage->pgid));
|
||||||
for (ppPage = &(pCache->pgHash[h % pCache->nHash]); *ppPage != pPage; ppPage = &((*ppPage)->pHashNext))
|
for (ppPage = &(pCache->pgHash[h % pCache->nHash]); *ppPage != pPage; ppPage = &((*ppPage)->pHashNext))
|
||||||
;
|
;
|
||||||
|
@ -232,11 +222,9 @@ static void tdbPCacheRemovePageFromHash(SPage *pPage) {
|
||||||
pCache->nPage--;
|
pCache->nPage--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tdbPCacheAddPageToHash(SPage *pPage) {
|
static void tdbPCacheAddPageToHash(SPCache *pCache, SPage *pPage) {
|
||||||
SPCache *pCache;
|
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
pCache = pPage->pCache;
|
|
||||||
h = PCACHE_PAGE_HASH(&(pPage->pgid)) % pCache->nHash;
|
h = PCACHE_PAGE_HASH(&(pPage->pgid)) % pCache->nHash;
|
||||||
|
|
||||||
pPage->pHashNext = pCache->pgHash[h];
|
pPage->pHashNext = pCache->pgHash[h];
|
||||||
|
@ -257,7 +245,7 @@ static int tdbPCacheOpenImpl(SPCache *pCache) {
|
||||||
pCache->nFree = 0;
|
pCache->nFree = 0;
|
||||||
pCache->pFree = NULL;
|
pCache->pFree = NULL;
|
||||||
for (int i = 0; i < pCache->cacheSize; i++) {
|
for (int i = 0; i < pCache->cacheSize; i++) {
|
||||||
ret = tdbPageCreate(pCache->pageSize, &pPage, tdbOsMalloc, NULL);
|
ret = tdbPageCreate(pCache->pageSize, &pPage, NULL, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
// TODO: handle error
|
// TODO: handle error
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -266,7 +254,6 @@ static int tdbPCacheOpenImpl(SPCache *pCache) {
|
||||||
// pPage->pgid = 0;
|
// pPage->pgid = 0;
|
||||||
pPage->isAnchor = 0;
|
pPage->isAnchor = 0;
|
||||||
pPage->isLocalPage = 1;
|
pPage->isLocalPage = 1;
|
||||||
pPage->pCache = pCache;
|
|
||||||
TDB_INIT_PAGE_REF(pPage);
|
TDB_INIT_PAGE_REF(pPage);
|
||||||
pPage->pHashNext = NULL;
|
pPage->pHashNext = NULL;
|
||||||
pPage->pLruNext = NULL;
|
pPage->pLruNext = NULL;
|
||||||
|
@ -297,13 +284,3 @@ static int tdbPCacheOpenImpl(SPCache *pCache) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int tdbPCacheGetPageSize(SPCache *pCache) { return pCache->pageSize; }
|
int tdbPCacheGetPageSize(SPCache *pCache) { return pCache->pageSize; }
|
||||||
|
|
||||||
static void *tdbOsMalloc(void *arg, size_t size) {
|
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
ptr = malloc(size);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tdbOsFree(void *arg, void *ptr) { free(ptr); }
|
|
|
@ -1,253 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tdbInt.h"
|
|
||||||
|
|
||||||
typedef struct __attribute__((__packed__)) {
|
|
||||||
u8 szCell[2];
|
|
||||||
u8 nxOffset[2];
|
|
||||||
} SFreeCell;
|
|
||||||
|
|
||||||
typedef struct __attribute__((__packed__)) {
|
|
||||||
u8 szCell[3];
|
|
||||||
u8 nxOffset[3];
|
|
||||||
} SFreeCellL;
|
|
||||||
|
|
||||||
/* For small page */
|
|
||||||
#define TDB_SPAGE_FREE_CELL_SIZE_PTR(PCELL) (((SFreeCell *)(PCELL))->szCell)
|
|
||||||
#define TDB_SPAGE_FREE_CELL_NXOFFSET_PTR(PCELL) (((SFreeCell *)(PCELL))->nxOffset)
|
|
||||||
|
|
||||||
#define TDB_SPAGE_FREE_CELL_SIZE(PCELL) ((u16 *)TDB_SPAGE_FREE_CELL_SIZE_PTR(PCELL))[0]
|
|
||||||
#define TDB_SPAGE_FREE_CELL_NXOFFSET(PCELL) ((u16 *)TDB_SPAGE_FREE_CELL_NXOFFSET_PTR(PCELL))[0]
|
|
||||||
|
|
||||||
#define TDB_SPAGE_FREE_CELL_SIZE_SET(PCELL, SIZE) (TDB_SPAGE_FREE_CELL_SIZE(PCELL) = (SIZE))
|
|
||||||
#define TDB_SPAGE_FREE_CELL_NXOFFSET_SET(PCELL, OFFSET) (TDB_SPAGE_FREE_CELL_NXOFFSET(PCELL) = (OFFSET))
|
|
||||||
|
|
||||||
/* For large page */
|
|
||||||
#define TDB_LPAGE_FREE_CELL_SIZE_PTR(PCELL) (((SFreeCellL *)(PCELL))->szCell)
|
|
||||||
#define TDB_LPAGE_FREE_CELL_NXOFFSET_PTR(PCELL) (((SFreeCellL *)(PCELL))->nxOffset)
|
|
||||||
|
|
||||||
#define TDB_LPAGE_FREE_CELL_SIZE(PCELL) TDB_GET_U24(TDB_LPAGE_FREE_CELL_SIZE_PTR(PCELL))
|
|
||||||
#define TDB_LPAGE_FREE_CELL_NXOFFSET(PCELL) TDB_GET_U24(TDB_LPAGE_FREE_CELL_NXOFFSET_PTR(PCELL))
|
|
||||||
|
|
||||||
#define TDB_LPAGE_FREE_CELL_SIZE_SET(PCELL, SIZE) TDB_PUT_U24(TDB_LPAGE_FREE_CELL_SIZE_PTR(PCELL), SIZE)
|
|
||||||
#define TDB_LPAGE_FREE_CELL_NXOFFSET_SET(PCELL, OFFSET) TDB_PUT_U24(TDB_LPAGE_FREE_CELL_NXOFFSET_PTR(PCELL), OFFSET)
|
|
||||||
|
|
||||||
/* For page */
|
|
||||||
#define TDB_PAGE_FREE_CELL_SIZE_PTR(PPAGE, PCELL) \
|
|
||||||
(TDB_IS_LARGE_PAGE(pPage) ? TDB_LPAGE_FREE_CELL_SIZE_PTR(PCELL) : TDB_SPAGE_FREE_CELL_SIZE_PTR(PCELL))
|
|
||||||
#define TDB_PAGE_FREE_CELL_NXOFFSET_PTR(PPAGE, PCELL) \
|
|
||||||
(TDB_IS_LARGE_PAGE(pPage) ? TDB_LPAGE_FREE_CELL_NXOFFSET_PTR(PCELL) : TDB_SPAGE_FREE_CELL_NXOFFSET_PTR(PCELL))
|
|
||||||
|
|
||||||
#define TDB_PAGE_FREE_CELL_SIZE(PPAGE, PCELL) \
|
|
||||||
(TDB_IS_LARGE_PAGE(pPage) ? TDB_LPAGE_FREE_CELL_SIZE(PCELL) : TDB_SPAGE_FREE_CELL_SIZE(PCELL))
|
|
||||||
#define TDB_PAGE_FREE_CELL_NXOFFSET(PPAGE, PCELL) \
|
|
||||||
(TDB_IS_LARGE_PAGE(pPage) ? TDB_LPAGE_FREE_CELL_NXOFFSET(PCELL) : TDB_SPAGE_FREE_CELL_NXOFFSET(PCELL))
|
|
||||||
|
|
||||||
#define TDB_PAGE_FREE_CELL_SIZE_SET(PPAGE, PCELL, SIZE) \
|
|
||||||
do { \
|
|
||||||
if (TDB_IS_LARGE_PAGE(PPAGE)) { \
|
|
||||||
TDB_LPAGE_FREE_CELL_SIZE_SET(PCELL, SIZE); \
|
|
||||||
} else { \
|
|
||||||
TDB_SPAGE_FREE_CELL_SIZE_SET(PCELL, SIZE); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
#define TDB_PAGE_FREE_CELL_NXOFFSET_SET(PPAGE, PCELL, OFFSET) \
|
|
||||||
do { \
|
|
||||||
if (TDB_IS_LARGE_PAGE(PPAGE)) { \
|
|
||||||
TDB_LPAGE_FREE_CELL_NXOFFSET_SET(PCELL, OFFSET); \
|
|
||||||
} else { \
|
|
||||||
TDB_SPAGE_FREE_CELL_NXOFFSET_SET(PCELL, OFFSET); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static int tdbPageAllocate(SPage *pPage, int size, SCell **ppCell);
|
|
||||||
static int tdbPageDefragment(SPage *pPage);
|
|
||||||
|
|
||||||
int tdbPageCreate(int pageSize, SPage **ppPage, void *(*xMalloc)(void *, size_t), void *arg) {
|
|
||||||
SPage *pPage;
|
|
||||||
u8 *ptr;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
ASSERT(TDB_IS_PGSIZE_VLD(pageSize));
|
|
||||||
|
|
||||||
*ppPage = NULL;
|
|
||||||
size = pageSize + sizeof(*pPage);
|
|
||||||
|
|
||||||
ptr = (u8 *)((*xMalloc)(arg, size));
|
|
||||||
if (pPage == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(ptr, 0, size);
|
|
||||||
pPage = (SPage *)(ptr + pageSize);
|
|
||||||
|
|
||||||
pPage->pData = ptr;
|
|
||||||
pPage->pageSize = pageSize;
|
|
||||||
if (pageSize < 65536) {
|
|
||||||
pPage->szOffset = 2;
|
|
||||||
pPage->szPageHdr = sizeof(SPageHdr);
|
|
||||||
pPage->szFreeCell = sizeof(SFreeCell);
|
|
||||||
} else {
|
|
||||||
pPage->szOffset = 3;
|
|
||||||
pPage->szPageHdr = sizeof(SPageHdrL);
|
|
||||||
pPage->szFreeCell = sizeof(SFreeCellL);
|
|
||||||
}
|
|
||||||
TDB_INIT_PAGE_LOCK(pPage);
|
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
|
|
||||||
*ppPage = pPage;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tdbPageDestroy(SPage *pPage, void (*xFree)(void *arg, void *ptr), void *arg) {
|
|
||||||
u8 *ptr;
|
|
||||||
|
|
||||||
ptr = pPage->pData;
|
|
||||||
(*xFree)(arg, ptr);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tdbPageInsertCell(SPage *pPage, int idx, SCell *pCell, int szCell) {
|
|
||||||
int ret;
|
|
||||||
SCell *pTarget;
|
|
||||||
u8 *pTmp;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
if (pPage->nOverflow || szCell + pPage->szOffset > pPage->nFree) {
|
|
||||||
// TODO: need to figure out if pCell may be used by outside of this function
|
|
||||||
j = pPage->nOverflow++;
|
|
||||||
|
|
||||||
pPage->apOvfl[j] = pCell;
|
|
||||||
pPage->aiOvfl[j] = idx;
|
|
||||||
} else {
|
|
||||||
ret = tdbPageAllocate(pPage, szCell, &pTarget);
|
|
||||||
if (ret < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(pTarget, pCell, szCell);
|
|
||||||
pTmp = pPage->pCellIdx + idx * pPage->szOffset;
|
|
||||||
memmove(pTmp + pPage->szOffset, pTmp, pPage->pFreeStart - pTmp - pPage->szOffset);
|
|
||||||
TDB_PAGE_CELL_OFFSET_AT_SET(pPage, idx, pTarget - pPage->pData);
|
|
||||||
TDB_PAGE_NCELLS_SET(pPage, TDB_PAGE_NCELLS(pPage) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tdbPageDropCell(SPage *pPage, int idx) {
|
|
||||||
// TODO
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tdbPageAllocate(SPage *pPage, int size, SCell **ppCell) {
|
|
||||||
SCell *pCell;
|
|
||||||
SFreeCell *pFreeCell;
|
|
||||||
u8 *pOffset;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ASSERT(pPage->nFree > size + pPage->szOffset);
|
|
||||||
|
|
||||||
pCell = NULL;
|
|
||||||
*ppCell = NULL;
|
|
||||||
|
|
||||||
// 1. Try to allocate from the free space area
|
|
||||||
if (pPage->pFreeEnd - pPage->pFreeStart > size + pPage->szOffset) {
|
|
||||||
pPage->pFreeEnd -= size;
|
|
||||||
pPage->pFreeStart += pPage->szOffset;
|
|
||||||
pCell = pPage->pFreeEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Try to allocate from the page free list
|
|
||||||
if ((pCell == NULL) && (pPage->pFreeEnd - pPage->pFreeStart >= pPage->szOffset) && TDB_PAGE_FCELL(pPage)) {
|
|
||||||
int szCell;
|
|
||||||
int nxOffset;
|
|
||||||
|
|
||||||
pCell = pPage->pData + TDB_PAGE_FCELL(pPage);
|
|
||||||
pOffset = TDB_IS_LARGE_PAGE(pPage) ? ((SPageHdrL *)(pPage->pPageHdr))[0].fCell
|
|
||||||
: (u8 *)&(((SPageHdr *)(pPage->pPageHdr))[0].fCell);
|
|
||||||
szCell = TDB_PAGE_FREE_CELL_SIZE(pPage, pCell);
|
|
||||||
nxOffset = TDB_PAGE_FREE_CELL_NXOFFSET(pPage, pCell);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
// Find a cell
|
|
||||||
if (szCell >= size) {
|
|
||||||
if (szCell - size >= pPage->szFreeCell) {
|
|
||||||
SCell *pTmpCell = pCell + size;
|
|
||||||
|
|
||||||
TDB_PAGE_FREE_CELL_SIZE_SET(pPage, pTmpCell, szCell - size);
|
|
||||||
TDB_PAGE_FREE_CELL_NXOFFSET_SET(pPage, pTmpCell, nxOffset);
|
|
||||||
// TODO: *pOffset = pTmpCell - pPage->pData;
|
|
||||||
} else {
|
|
||||||
TDB_PAGE_NFREE_SET(pPage, TDB_PAGE_NFREE(pPage) + szCell - size);
|
|
||||||
// TODO: *pOffset = nxOffset;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not find a cell yet
|
|
||||||
if (nxOffset > 0) {
|
|
||||||
pCell = pPage->pData + nxOffset;
|
|
||||||
pOffset = TDB_PAGE_FREE_CELL_NXOFFSET_PTR(pPage, pCell);
|
|
||||||
szCell = TDB_PAGE_FREE_CELL_SIZE(pPage, pCell);
|
|
||||||
nxOffset = TDB_PAGE_FREE_CELL_NXOFFSET(pPage, pCell);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
pCell = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pCell) {
|
|
||||||
pPage->pFreeStart = pPage->pFreeStart + pPage->szOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Try to dfragment and allocate again
|
|
||||||
if (pCell == NULL) {
|
|
||||||
ret = tdbPageDefragment(pPage);
|
|
||||||
if (ret < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(pPage->pFreeEnd - pPage->pFreeStart > size + pPage->szOffset);
|
|
||||||
ASSERT(pPage->nFree == pPage->pFreeEnd - pPage->pFreeStart);
|
|
||||||
|
|
||||||
// Allocate from the free space area again
|
|
||||||
pPage->pFreeEnd -= size;
|
|
||||||
pPage->pFreeStart += pPage->szOffset;
|
|
||||||
pCell = pPage->pFreeEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(pCell != NULL);
|
|
||||||
|
|
||||||
pPage->nFree = pPage->nFree - size - pPage->szOffset;
|
|
||||||
*ppCell = pCell;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tdbPageFree(SPage *pPage, int idx, SCell *pCell, int size) {
|
|
||||||
// TODO
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tdbPageDefragment(SPage *pPage) {
|
|
||||||
// TODO
|
|
||||||
ASSERT(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -255,6 +255,10 @@ int tdbPagerNewPage(SPager *pPager, SPgno *ppgno, SPage **ppPage, int (*initPage
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tdbPagerReturnPage(SPager *pPager, SPage *pPage) {
|
||||||
|
tdbPCacheRelease(pPager->pCache, pPage);
|
||||||
|
}
|
||||||
|
|
||||||
static int tdbPagerAllocFreePage(SPager *pPager, SPgno *ppgno) {
|
static int tdbPagerAllocFreePage(SPager *pPager, SPgno *ppgno) {
|
||||||
// TODO: Allocate a page from the free list
|
// TODO: Allocate a page from the free list
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -21,9 +21,14 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct SBTree SBTree;
|
typedef struct SBTree SBTree;
|
||||||
typedef struct SBtCursor SBtCursor;
|
typedef struct SBTC SBTC;
|
||||||
|
typedef struct SBtInfo {
|
||||||
|
SPgno root;
|
||||||
|
int nLevel;
|
||||||
|
int nData;
|
||||||
|
} SBtInfo;
|
||||||
|
|
||||||
struct SBtCursor {
|
struct SBTC {
|
||||||
SBTree *pBt;
|
SBTree *pBt;
|
||||||
i8 iPage;
|
i8 iPage;
|
||||||
SPage *pPage;
|
SPage *pPage;
|
||||||
|
@ -33,10 +38,19 @@ struct SBtCursor {
|
||||||
void *pBuf;
|
void *pBuf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SBTree
|
||||||
int tdbBtreeOpen(int keyLen, int valLen, SPager *pFile, FKeyComparator kcmpr, SBTree **ppBt);
|
int tdbBtreeOpen(int keyLen, int valLen, SPager *pFile, FKeyComparator kcmpr, SBTree **ppBt);
|
||||||
int tdbBtreeClose(SBTree *pBt);
|
int tdbBtreeClose(SBTree *pBt);
|
||||||
int tdbBtreeCursor(SBtCursor *pCur, SBTree *pBt);
|
int tdbBtCursorInsert(SBTC *pCur, const void *pKey, int kLen, const void *pVal, int vLen);
|
||||||
int tdbBtCursorInsert(SBtCursor *pCur, const void *pKey, int kLen, const void *pVal, int vLen);
|
int tdbBtreeGet(SBTree *pBt, const void *pKey, int kLen, void **ppVal, int *vLen);
|
||||||
|
|
||||||
|
// SBTC
|
||||||
|
int tdbBtcOpen(SBTC *pCur, SBTree *pBt);
|
||||||
|
int tdbBtcMoveToFirst(SBTC *pBtc);
|
||||||
|
int tdbBtcMoveToLast(SBTC *pBtc);
|
||||||
|
int tdbBtcMoveTo(SBTC *pBtc, const void *pKey, int kLen);
|
||||||
|
int tdbBtreeNext(SBTC *pBtc, void **ppKey, int *kLen, void **ppVal, int *vLen);
|
||||||
|
int tdbBtcClose(SBTC *pBtc);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,20 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct STDb STDb;
|
typedef struct STDB STDB;
|
||||||
|
typedef struct STDBC STDBC;
|
||||||
|
|
||||||
int tdbDbOpen(const char *fname, int keyLen, int valLen, FKeyComparator keyCmprFn, STEnv *pEnv, STDb **ppDb);
|
// STDB
|
||||||
int tdbDbClose(STDb *pDb);
|
int tdbDbOpen(const char *fname, int keyLen, int valLen, FKeyComparator keyCmprFn, STEnv *pEnv, STDB **ppDb);
|
||||||
int tdbDbDrop(STDb *pDb);
|
int tdbDbClose(STDB *pDb);
|
||||||
int tdbDbInsert(STDb *pDb, const void *pKey, int keyLen, const void *pVal, int valLen);
|
int tdbDbDrop(STDB *pDb);
|
||||||
|
int tdbDbInsert(STDB *pDb, const void *pKey, int keyLen, const void *pVal, int valLen);
|
||||||
|
int tdbDbGet(STDB *pDb, const void *pKey, int kLen, void **ppVal, int *vLen);
|
||||||
|
|
||||||
|
// STDBC
|
||||||
|
int tdbDbcOpen(STDB *pDb, STDBC **ppDbc);
|
||||||
|
int tdbDbNext(STDBC *pDbc, void **ppKey, int *kLen, void **ppVal, int *vLen);
|
||||||
|
int tdbDbcClose(STDBC *pDbc);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ static FORCE_INLINE int tdbCmprPgId(const void *p1, const void *p2) {
|
||||||
// tdb_log
|
// tdb_log
|
||||||
#define tdbError(var)
|
#define tdbError(var)
|
||||||
|
|
||||||
typedef TD_DLIST(STDb) STDbList;
|
typedef TD_DLIST(STDB) STDbList;
|
||||||
typedef TD_DLIST(SPgFile) SPgFileList;
|
typedef TD_DLIST(SPgFile) SPgFileList;
|
||||||
typedef TD_DLIST_NODE(SPgFile) SPgFileListNode;
|
typedef TD_DLIST_NODE(SPgFile) SPgFileListNode;
|
||||||
|
|
||||||
|
@ -141,8 +141,8 @@ typedef int (*FKeyComparator)(const void *pKey1, int kLen1, const void *pKey2, i
|
||||||
#define TDB_FLAG_IS(flags, flag) ((flags) == (flag))
|
#define TDB_FLAG_IS(flags, flag) ((flags) == (flag))
|
||||||
#define TDB_FLAG_HAS(flags, flag) (((flags) & (flag)) != 0)
|
#define TDB_FLAG_HAS(flags, flag) (((flags) & (flag)) != 0)
|
||||||
#define TDB_FLAG_NO(flags, flag) ((flags) & (flag) == 0)
|
#define TDB_FLAG_NO(flags, flag) ((flags) & (flag) == 0)
|
||||||
#define TDB_FLAG_ADD(flags, flag) ((flags) |= (flag))
|
#define TDB_FLAG_ADD(flags, flag) ((flags) | (flag))
|
||||||
#define TDB_FLAG_REMOVE(flags, flag) ((flags) &= (~(flag)))
|
#define TDB_FLAG_REMOVE(flags, flag) ((flags) & (~(flag)))
|
||||||
|
|
||||||
typedef struct SPager SPager;
|
typedef struct SPager SPager;
|
||||||
typedef struct SPCache SPCache;
|
typedef struct SPCache SPCache;
|
||||||
|
|
|
@ -25,7 +25,6 @@ extern "C" {
|
||||||
u8 isLocalPage; \
|
u8 isLocalPage; \
|
||||||
u8 isDirty; \
|
u8 isDirty; \
|
||||||
i32 nRef; \
|
i32 nRef; \
|
||||||
SPCache *pCache; \
|
|
||||||
SPage *pFreeNext; \
|
SPage *pFreeNext; \
|
||||||
SPage *pHashNext; \
|
SPage *pHashNext; \
|
||||||
SPage *pLruNext; \
|
SPage *pLruNext; \
|
||||||
|
@ -37,7 +36,7 @@ extern "C" {
|
||||||
int tdbPCacheOpen(int pageSize, int cacheSize, SPCache **ppCache);
|
int tdbPCacheOpen(int pageSize, int cacheSize, SPCache **ppCache);
|
||||||
int tdbPCacheClose(SPCache *pCache);
|
int tdbPCacheClose(SPCache *pCache);
|
||||||
SPage *tdbPCacheFetch(SPCache *pCache, const SPgid *pPgid, bool alcNewPage);
|
SPage *tdbPCacheFetch(SPCache *pCache, const SPgid *pPgid, bool alcNewPage);
|
||||||
void tdbPCacheRelease(SPage *pPage);
|
void tdbPCacheRelease(SPCache *pCache, SPage *pPage);
|
||||||
int tdbPCacheGetPageSize(SPCache *pCache);
|
int tdbPCacheGetPageSize(SPCache *pCache);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -27,9 +27,6 @@ typedef struct {
|
||||||
int szOffset;
|
int szOffset;
|
||||||
int szPageHdr;
|
int szPageHdr;
|
||||||
int szFreeCell;
|
int szFreeCell;
|
||||||
// flags
|
|
||||||
u16 (*getFlags)(SPage *);
|
|
||||||
void (*setFlags)(SPage *, u16);
|
|
||||||
// cell number
|
// cell number
|
||||||
int (*getCellNum)(SPage *);
|
int (*getCellNum)(SPage *);
|
||||||
void (*setCellNum)(SPage *, int);
|
void (*setCellNum)(SPage *, int);
|
||||||
|
@ -45,6 +42,9 @@ typedef struct {
|
||||||
// cell offset at idx
|
// cell offset at idx
|
||||||
int (*getCellOffset)(SPage *, int);
|
int (*getCellOffset)(SPage *, int);
|
||||||
void (*setCellOffset)(SPage *, int, int);
|
void (*setCellOffset)(SPage *, int, int);
|
||||||
|
// free cell info
|
||||||
|
void (*getFreeCellInfo)(SCell *pCell, int *szCell, int *nxOffset);
|
||||||
|
void (*setFreeCellInfo)(SCell *pCell, int szCell, int nxOffset);
|
||||||
} SPageMethods;
|
} SPageMethods;
|
||||||
|
|
||||||
// Page footer
|
// Page footer
|
||||||
|
@ -54,48 +54,27 @@ typedef struct __attribute__((__packed__)) {
|
||||||
|
|
||||||
struct SPage {
|
struct SPage {
|
||||||
pthread_spinlock_t lock;
|
pthread_spinlock_t lock;
|
||||||
u8 *pData;
|
|
||||||
int pageSize;
|
int pageSize;
|
||||||
|
u8 *pData;
|
||||||
SPageMethods *pPageMethods;
|
SPageMethods *pPageMethods;
|
||||||
// Fields below used by pager and am
|
// Fields below used by pager and am
|
||||||
u8 szAmHdr;
|
|
||||||
u8 *pPageHdr;
|
u8 *pPageHdr;
|
||||||
u8 *pAmHdr;
|
|
||||||
u8 *pCellIdx;
|
u8 *pCellIdx;
|
||||||
u8 *pFreeStart;
|
u8 *pFreeStart;
|
||||||
u8 *pFreeEnd;
|
u8 *pFreeEnd;
|
||||||
SPageFtr *pPageFtr;
|
SPageFtr *pPageFtr;
|
||||||
int kLen; // key length of the page, -1 for unknown
|
|
||||||
int vLen; // value length of the page, -1 for unknown
|
|
||||||
int nFree;
|
|
||||||
int maxLocal;
|
|
||||||
int minLocal;
|
|
||||||
int nOverflow;
|
int nOverflow;
|
||||||
SCell *apOvfl[4];
|
SCell *apOvfl[4];
|
||||||
int aiOvfl[4];
|
int aiOvfl[4];
|
||||||
|
int kLen; // key length of the page, -1 for unknown
|
||||||
|
int vLen; // value length of the page, -1 for unknown
|
||||||
|
int maxLocal;
|
||||||
|
int minLocal;
|
||||||
|
int (*xCellSize)(const SPage *, SCell *);
|
||||||
// Fields used by SPCache
|
// Fields used by SPCache
|
||||||
TDB_PCACHE_PAGE
|
TDB_PCACHE_PAGE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For page */
|
|
||||||
#define TDB_PAGE_FLAGS(pPage) (*(pPage)->pPageMethods->getFlags)(pPage)
|
|
||||||
#define TDB_PAGE_NCELLS(pPage) (*(pPage)->pPageMethods->getCellNum)(pPage)
|
|
||||||
#define TDB_PAGE_CCELLS(pPage) (*(pPage)->pPageMethods->getCellBody)(pPage)
|
|
||||||
#define TDB_PAGE_FCELL(pPage) (*(pPage)->pPageMethods->getCellFree)(pPage)
|
|
||||||
#define TDB_PAGE_NFREE(pPage) (*(pPage)->pPageMethods->getFreeBytes)(pPage)
|
|
||||||
#define TDB_PAGE_CELL_OFFSET_AT(pPage, idx) (*(pPage)->pPageMethods->getCellOffset)(pPage, idx)
|
|
||||||
|
|
||||||
#define TDB_PAGE_FLAGS_SET(pPage, FLAGS) (*(pPage)->pPageMethods->setFlags)(pPage, FLAGS)
|
|
||||||
#define TDB_PAGE_NCELLS_SET(pPage, NCELLS) (*(pPage)->pPageMethods->setCellNum)(pPage, NCELLS)
|
|
||||||
#define TDB_PAGE_CCELLS_SET(pPage, CCELLS) (*(pPage)->pPageMethods->setCellBody)(pPage, CCELLS)
|
|
||||||
#define TDB_PAGE_FCELL_SET(pPage, FCELL) (*(pPage)->pPageMethods->setCellFree)(pPage, FCELL)
|
|
||||||
#define TDB_PAGE_NFREE_SET(pPage, NFREE) (*(pPage)->pPageMethods->setFreeBytes)(pPage, NFREE)
|
|
||||||
#define TDB_PAGE_CELL_OFFSET_AT_SET(pPage, idx, OFFSET) (*(pPage)->pPageMethods->setCellOffset)(pPage, idx, OFFSET)
|
|
||||||
|
|
||||||
#define TDB_PAGE_OFFSET_SIZE(pPage) ((pPage)->pPageMethods->szOffset)
|
|
||||||
|
|
||||||
#define TDB_PAGE_CELL_AT(pPage, idx) ((pPage)->pData + TDB_PAGE_CELL_OFFSET_AT(pPage, idx))
|
|
||||||
|
|
||||||
// For page lock
|
// For page lock
|
||||||
#define P_LOCK_SUCC 0
|
#define P_LOCK_SUCC 0
|
||||||
#define P_LOCK_BUSY 1
|
#define P_LOCK_BUSY 1
|
||||||
|
@ -119,10 +98,43 @@ struct SPage {
|
||||||
})
|
})
|
||||||
|
|
||||||
// APIs
|
// APIs
|
||||||
|
#define TDB_PAGE_TOTAL_CELLS(pPage) ((pPage)->nOverflow + (pPage)->pPageMethods->getCellNum(pPage))
|
||||||
|
#define TDB_PAGE_USABLE_SIZE(pPage) ((u8 *)(pPage)->pPageFtr - (pPage)->pCellIdx)
|
||||||
|
#define TDB_PAGE_PGNO(pPage) ((pPage)->pgid.pgno)
|
||||||
|
#define TDB_BYTES_CELL_TAKEN(pPage, pCell) ((*(pPage)->xCellSize)(pPage, pCell) + (pPage)->pPageMethods->szOffset)
|
||||||
|
#define TDB_PAGE_OFFSET_SIZE(pPage) ((pPage)->pPageMethods->szOffset)
|
||||||
|
|
||||||
int tdbPageCreate(int pageSize, SPage **ppPage, void *(*xMalloc)(void *, size_t), void *arg);
|
int tdbPageCreate(int pageSize, SPage **ppPage, void *(*xMalloc)(void *, size_t), void *arg);
|
||||||
int tdbPageDestroy(SPage *pPage, void (*xFree)(void *arg, void *ptr), void *arg);
|
int tdbPageDestroy(SPage *pPage, void (*xFree)(void *arg, void *ptr), void *arg);
|
||||||
int tdbPageInsertCell(SPage *pPage, int idx, SCell *pCell, int szCell);
|
void tdbPageZero(SPage *pPage, u8 szAmHdr, int (*xCellSize)(const SPage *, SCell *));
|
||||||
|
void tdbPageInit(SPage *pPage, u8 szAmHdr, int (*xCellSize)(const SPage *, SCell *));
|
||||||
|
int tdbPageInsertCell(SPage *pPage, int idx, SCell *pCell, int szCell, u8 asOvfl);
|
||||||
int tdbPageDropCell(SPage *pPage, int idx);
|
int tdbPageDropCell(SPage *pPage, int idx);
|
||||||
|
void tdbPageCopy(SPage *pFromPage, SPage *pToPage);
|
||||||
|
|
||||||
|
static inline SCell *tdbPageGetCell(SPage *pPage, int idx) {
|
||||||
|
SCell *pCell;
|
||||||
|
int iOvfl;
|
||||||
|
int lidx;
|
||||||
|
|
||||||
|
ASSERT(idx >= 0 && idx < TDB_PAGE_TOTAL_CELLS(pPage));
|
||||||
|
|
||||||
|
iOvfl = 0;
|
||||||
|
for (; iOvfl < pPage->nOverflow; iOvfl++) {
|
||||||
|
if (pPage->aiOvfl[iOvfl] == idx) {
|
||||||
|
pCell = pPage->apOvfl[iOvfl];
|
||||||
|
return pCell;
|
||||||
|
} else if (pPage->aiOvfl[iOvfl] > idx) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lidx = idx - iOvfl;
|
||||||
|
ASSERT(lidx >= 0 && lidx < pPage->pPageMethods->getCellNum(pPage));
|
||||||
|
pCell = pPage->pData + pPage->pPageMethods->getCellOffset(pPage, lidx);
|
||||||
|
|
||||||
|
return pCell;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ int tdbPagerCommit(SPager *pPager);
|
||||||
int tdbPagerGetPageSize(SPager *pPager);
|
int tdbPagerGetPageSize(SPager *pPager);
|
||||||
int tdbPagerFetchPage(SPager *pPager, SPgno pgno, SPage **ppPage, int (*initPage)(SPage *, void *), void *arg);
|
int tdbPagerFetchPage(SPager *pPager, SPgno pgno, SPage **ppPage, int (*initPage)(SPage *, void *), void *arg);
|
||||||
int tdbPagerNewPage(SPager *pPager, SPgno *ppgno, SPage **ppPage, int (*initPage)(SPage *, void *), void *arg);
|
int tdbPagerNewPage(SPager *pPager, SPgno *ppgno, SPage **ppPage, int (*initPage)(SPage *, void *), void *arg);
|
||||||
|
void tdbPagerReturnPage(SPager *pPager, SPage *pPage);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,38 @@ int tdbGetFileSize(const char *fname, int pgSize, SPgno *pSize);
|
||||||
|
|
||||||
int tdbPRead(int fd, void *pData, int count, i64 offset);
|
int tdbPRead(int fd, void *pData, int count, i64 offset);
|
||||||
|
|
||||||
|
#define TDB_REALLOC(PTR, SIZE) \
|
||||||
|
({ \
|
||||||
|
void *nPtr; \
|
||||||
|
if ((PTR) == NULL || ((int *)(PTR))[-1] < (SIZE)) { \
|
||||||
|
nPtr = realloc((PTR) ? (char *)(PTR) - sizeof(int) : NULL, (SIZE) + sizeof(int)); \
|
||||||
|
if (nPtr) { \
|
||||||
|
((int *)nPtr)[0] = (SIZE); \
|
||||||
|
nPtr = (char *)nPtr + sizeof(int); \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
nPtr = (PTR); \
|
||||||
|
} \
|
||||||
|
nPtr; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define TDB_FREE(PTR) \
|
||||||
|
do { \
|
||||||
|
if (PTR) { \
|
||||||
|
free((char *)(PTR) - sizeof(int)); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static inline void *tdbOsMalloc(void *arg, size_t size) {
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
ptr = malloc(size);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void tdbOsFree(void *arg, void *ptr) { free(ptr); }
|
||||||
|
|
||||||
static inline int tdbPutVarInt(u8 *p, int v) {
|
static inline int tdbPutVarInt(u8 *p, int v) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,25 @@
|
||||||
extern SPageMethods pageMethods;
|
extern SPageMethods pageMethods;
|
||||||
extern SPageMethods pageLargeMethods;
|
extern SPageMethods pageLargeMethods;
|
||||||
|
|
||||||
typedef struct __attribute__((__packed__)) {
|
#define TDB_PAGE_HDR_SIZE(pPage) ((pPage)->pPageMethods->szPageHdr)
|
||||||
u16 szCell;
|
#define TDB_PAGE_FREE_CELL_SIZE(pPage) ((pPage)->pPageMethods->szFreeCell)
|
||||||
u16 nxOffset;
|
#define TDB_PAGE_NCELLS(pPage) (*(pPage)->pPageMethods->getCellNum)(pPage)
|
||||||
} SFreeCell;
|
#define TDB_PAGE_CCELLS(pPage) (*(pPage)->pPageMethods->getCellBody)(pPage)
|
||||||
|
#define TDB_PAGE_FCELL(pPage) (*(pPage)->pPageMethods->getCellFree)(pPage)
|
||||||
|
#define TDB_PAGE_NFREE(pPage) (*(pPage)->pPageMethods->getFreeBytes)(pPage)
|
||||||
|
#define TDB_PAGE_CELL_OFFSET_AT(pPage, idx) (*(pPage)->pPageMethods->getCellOffset)(pPage, idx)
|
||||||
|
#define TDB_PAGE_NCELLS_SET(pPage, NCELLS) (*(pPage)->pPageMethods->setCellNum)(pPage, NCELLS)
|
||||||
|
#define TDB_PAGE_CCELLS_SET(pPage, CCELLS) (*(pPage)->pPageMethods->setCellBody)(pPage, CCELLS)
|
||||||
|
#define TDB_PAGE_FCELL_SET(pPage, FCELL) (*(pPage)->pPageMethods->setCellFree)(pPage, FCELL)
|
||||||
|
#define TDB_PAGE_NFREE_SET(pPage, NFREE) (*(pPage)->pPageMethods->setFreeBytes)(pPage, NFREE)
|
||||||
|
#define TDB_PAGE_CELL_OFFSET_AT_SET(pPage, idx, OFFSET) (*(pPage)->pPageMethods->setCellOffset)(pPage, idx, OFFSET)
|
||||||
|
#define TDB_PAGE_CELL_AT(pPage, idx) ((pPage)->pData + TDB_PAGE_CELL_OFFSET_AT(pPage, idx))
|
||||||
|
#define TDB_PAGE_MAX_FREE_BLOCK(pPage, szAmHdr) \
|
||||||
|
((pPage)->pageSize - (szAmHdr)-TDB_PAGE_HDR_SIZE(pPage) - sizeof(SPageFtr))
|
||||||
|
|
||||||
static int tdbPageAllocate(SPage *pPage, int size, SCell **ppCell);
|
static int tdbPageAllocate(SPage *pPage, int size, SCell **ppCell);
|
||||||
static int tdbPageDefragment(SPage *pPage);
|
static int tdbPageDefragment(SPage *pPage);
|
||||||
|
static int tdbPageFree(SPage *pPage, int idx, SCell *pCell, int szCell);
|
||||||
|
|
||||||
int tdbPageCreate(int pageSize, SPage **ppPage, void *(*xMalloc)(void *, size_t), void *arg) {
|
int tdbPageCreate(int pageSize, SPage **ppPage, void *(*xMalloc)(void *, size_t), void *arg) {
|
||||||
SPage *pPage;
|
SPage *pPage;
|
||||||
|
@ -35,25 +47,26 @@ int tdbPageCreate(int pageSize, SPage **ppPage, void *(*xMalloc)(void *, size_t)
|
||||||
|
|
||||||
*ppPage = NULL;
|
*ppPage = NULL;
|
||||||
size = pageSize + sizeof(*pPage);
|
size = pageSize + sizeof(*pPage);
|
||||||
|
if (xMalloc == NULL) {
|
||||||
|
xMalloc = tdbOsMalloc;
|
||||||
|
}
|
||||||
|
|
||||||
ptr = (u8 *)((*xMalloc)(arg, size));
|
ptr = (u8 *)((*xMalloc)(arg, size));
|
||||||
if (pPage == NULL) {
|
if (ptr == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(ptr, 0, size);
|
memset(ptr, 0, size);
|
||||||
pPage = (SPage *)(ptr + pageSize);
|
pPage = (SPage *)(ptr + pageSize);
|
||||||
|
|
||||||
pPage->pData = ptr;
|
TDB_INIT_PAGE_LOCK(pPage);
|
||||||
pPage->pageSize = pageSize;
|
pPage->pageSize = pageSize;
|
||||||
|
pPage->pData = ptr;
|
||||||
if (pageSize < 65536) {
|
if (pageSize < 65536) {
|
||||||
pPage->pPageMethods = &pageMethods;
|
pPage->pPageMethods = &pageMethods;
|
||||||
} else {
|
} else {
|
||||||
pPage->pPageMethods = &pageLargeMethods;
|
pPage->pPageMethods = &pageLargeMethods;
|
||||||
}
|
}
|
||||||
TDB_INIT_PAGE_LOCK(pPage);
|
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
|
|
||||||
*ppPage = pPage;
|
*ppPage = pPage;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -62,157 +75,365 @@ int tdbPageCreate(int pageSize, SPage **ppPage, void *(*xMalloc)(void *, size_t)
|
||||||
int tdbPageDestroy(SPage *pPage, void (*xFree)(void *arg, void *ptr), void *arg) {
|
int tdbPageDestroy(SPage *pPage, void (*xFree)(void *arg, void *ptr), void *arg) {
|
||||||
u8 *ptr;
|
u8 *ptr;
|
||||||
|
|
||||||
|
if (!xFree) {
|
||||||
|
xFree = tdbOsFree;
|
||||||
|
}
|
||||||
|
|
||||||
ptr = pPage->pData;
|
ptr = pPage->pData;
|
||||||
(*xFree)(arg, ptr);
|
(*xFree)(arg, ptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tdbPageInsertCell(SPage *pPage, int idx, SCell *pCell, int szCell) {
|
void tdbPageZero(SPage *pPage, u8 szAmHdr, int (*xCellSize)(const SPage *, SCell *)) {
|
||||||
int ret;
|
pPage->pPageHdr = pPage->pData + szAmHdr;
|
||||||
SCell *pTarget;
|
TDB_PAGE_NCELLS_SET(pPage, 0);
|
||||||
u8 *pTmp;
|
TDB_PAGE_CCELLS_SET(pPage, pPage->pageSize - sizeof(SPageFtr));
|
||||||
int j;
|
TDB_PAGE_FCELL_SET(pPage, 0);
|
||||||
|
TDB_PAGE_NFREE_SET(pPage, TDB_PAGE_MAX_FREE_BLOCK(pPage, szAmHdr));
|
||||||
|
pPage->pCellIdx = pPage->pPageHdr + TDB_PAGE_HDR_SIZE(pPage);
|
||||||
|
pPage->pFreeStart = pPage->pCellIdx;
|
||||||
|
pPage->pFreeEnd = pPage->pData + TDB_PAGE_CCELLS(pPage);
|
||||||
|
pPage->pPageFtr = (SPageFtr *)(pPage->pData + pPage->pageSize - sizeof(SPageFtr));
|
||||||
|
pPage->nOverflow = 0;
|
||||||
|
pPage->xCellSize = xCellSize;
|
||||||
|
|
||||||
if (pPage->nOverflow || szCell + TDB_PAGE_OFFSET_SIZE(pPage) > pPage->nFree) {
|
ASSERT((u8 *)pPage->pPageFtr == pPage->pFreeEnd);
|
||||||
// TODO: need to figure out if pCell may be used by outside of this function
|
}
|
||||||
j = pPage->nOverflow++;
|
|
||||||
|
|
||||||
pPage->apOvfl[j] = pCell;
|
void tdbPageInit(SPage *pPage, u8 szAmHdr, int (*xCellSize)(const SPage *, SCell *)) {
|
||||||
pPage->aiOvfl[j] = idx;
|
pPage->pPageHdr = pPage->pData + szAmHdr;
|
||||||
} else {
|
pPage->pCellIdx = pPage->pPageHdr + TDB_PAGE_HDR_SIZE(pPage);
|
||||||
ret = tdbPageAllocate(pPage, szCell, &pTarget);
|
pPage->pFreeStart = pPage->pCellIdx + TDB_PAGE_OFFSET_SIZE(pPage) * TDB_PAGE_NCELLS(pPage);
|
||||||
if (ret < 0) {
|
pPage->pFreeEnd = pPage->pData + TDB_PAGE_CCELLS(pPage);
|
||||||
return -1;
|
pPage->pPageFtr = (SPageFtr *)(pPage->pData + pPage->pageSize - sizeof(SPageFtr));
|
||||||
|
pPage->nOverflow = 0;
|
||||||
|
pPage->xCellSize = xCellSize;
|
||||||
|
|
||||||
|
ASSERT(pPage->pFreeEnd >= pPage->pFreeStart);
|
||||||
|
ASSERT(pPage->pFreeEnd - pPage->pFreeStart <= TDB_PAGE_NFREE(pPage));
|
||||||
|
}
|
||||||
|
|
||||||
|
int tdbPageInsertCell(SPage *pPage, int idx, SCell *pCell, int szCell, u8 asOvfl) {
|
||||||
|
int nFree;
|
||||||
|
int nCells;
|
||||||
|
int iOvfl;
|
||||||
|
int lidx; // local idx
|
||||||
|
SCell *pNewCell;
|
||||||
|
|
||||||
|
ASSERT(szCell <= TDB_PAGE_MAX_FREE_BLOCK(pPage, pPage->pPageHdr - pPage->pData));
|
||||||
|
|
||||||
|
nFree = TDB_PAGE_NFREE(pPage);
|
||||||
|
nCells = TDB_PAGE_NCELLS(pPage);
|
||||||
|
iOvfl = 0;
|
||||||
|
|
||||||
|
for (; iOvfl < pPage->nOverflow; iOvfl++) {
|
||||||
|
if (pPage->aiOvfl[iOvfl] >= idx) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(pTarget, pCell, szCell);
|
lidx = idx - iOvfl;
|
||||||
pTmp = pPage->pCellIdx + idx * TDB_PAGE_OFFSET_SIZE(pPage);
|
|
||||||
memmove(pTmp + TDB_PAGE_OFFSET_SIZE(pPage), pTmp, pPage->pFreeStart - pTmp - TDB_PAGE_OFFSET_SIZE(pPage));
|
if (asOvfl || nFree < szCell + TDB_PAGE_OFFSET_SIZE(pPage)) {
|
||||||
TDB_PAGE_CELL_OFFSET_AT_SET(pPage, idx, pTarget - pPage->pData);
|
// TODO: make it extensible
|
||||||
TDB_PAGE_NCELLS_SET(pPage, TDB_PAGE_NCELLS(pPage) + 1);
|
// add the cell as an overflow cell
|
||||||
|
for (int i = pPage->nOverflow; i > iOvfl; i--) {
|
||||||
|
pPage->apOvfl[i] = pPage->apOvfl[i - 1];
|
||||||
|
pPage->aiOvfl[i] = pPage->aiOvfl[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: here has memory leak
|
||||||
|
pNewCell = (SCell *)malloc(szCell);
|
||||||
|
memcpy(pNewCell, pCell, szCell);
|
||||||
|
|
||||||
|
pPage->apOvfl[iOvfl] = pNewCell;
|
||||||
|
pPage->aiOvfl[iOvfl] = idx;
|
||||||
|
pPage->nOverflow++;
|
||||||
|
iOvfl++;
|
||||||
|
} else {
|
||||||
|
// page must has enough space to hold the cell locally
|
||||||
|
tdbPageAllocate(pPage, szCell, &pNewCell);
|
||||||
|
|
||||||
|
memcpy(pNewCell, pCell, szCell);
|
||||||
|
|
||||||
|
// no overflow cell exists in this page
|
||||||
|
u8 *src = pPage->pCellIdx + TDB_PAGE_OFFSET_SIZE(pPage) * lidx;
|
||||||
|
u8 *dest = src + TDB_PAGE_OFFSET_SIZE(pPage);
|
||||||
|
memmove(dest, src, pPage->pFreeStart - dest);
|
||||||
|
TDB_PAGE_CELL_OFFSET_AT_SET(pPage, lidx, pNewCell - pPage->pData);
|
||||||
|
TDB_PAGE_NCELLS_SET(pPage, nCells + 1);
|
||||||
|
|
||||||
|
ASSERT(pPage->pFreeStart == pPage->pCellIdx + TDB_PAGE_OFFSET_SIZE(pPage) * (nCells + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; iOvfl < pPage->nOverflow; iOvfl++) {
|
||||||
|
pPage->aiOvfl[iOvfl]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tdbPageDropCell(SPage *pPage, int idx) {
|
int tdbPageDropCell(SPage *pPage, int idx) {
|
||||||
// TODO
|
int lidx;
|
||||||
|
SCell *pCell;
|
||||||
|
int szCell;
|
||||||
|
int nCells;
|
||||||
|
int iOvfl;
|
||||||
|
|
||||||
|
nCells = TDB_PAGE_NCELLS(pPage);
|
||||||
|
|
||||||
|
ASSERT(idx >= 0 && idx < nCells + pPage->nOverflow);
|
||||||
|
|
||||||
|
iOvfl = 0;
|
||||||
|
for (; iOvfl < pPage->nOverflow; iOvfl++) {
|
||||||
|
if (pPage->aiOvfl[iOvfl] == idx) {
|
||||||
|
// remove the over flow cell
|
||||||
|
for (; (++iOvfl) < pPage->nOverflow;) {
|
||||||
|
pPage->aiOvfl[iOvfl - 1] = pPage->aiOvfl[iOvfl] - 1;
|
||||||
|
pPage->apOvfl[iOvfl - 1] = pPage->apOvfl[iOvfl];
|
||||||
|
}
|
||||||
|
|
||||||
|
pPage->nOverflow--;
|
||||||
|
return 0;
|
||||||
|
} else if (pPage->aiOvfl[iOvfl] > idx) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lidx = idx - iOvfl;
|
||||||
|
pCell = TDB_PAGE_CELL_AT(pPage, lidx);
|
||||||
|
szCell = (*pPage->xCellSize)(pPage, pCell);
|
||||||
|
tdbPageFree(pPage, lidx, pCell, szCell);
|
||||||
|
TDB_PAGE_NCELLS_SET(pPage, nCells - 1);
|
||||||
|
|
||||||
|
for (; iOvfl < pPage->nOverflow; iOvfl++) {
|
||||||
|
pPage->aiOvfl[iOvfl]--;
|
||||||
|
ASSERT(pPage->aiOvfl[iOvfl] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tdbPageAllocate(SPage *pPage, int size, SCell **ppCell) {
|
void tdbPageCopy(SPage *pFromPage, SPage *pToPage) {
|
||||||
SCell *pCell;
|
int delta, nFree;
|
||||||
SFreeCell *pFreeCell;
|
|
||||||
|
pToPage->pFreeStart = pToPage->pPageHdr + (pFromPage->pFreeStart - pFromPage->pPageHdr);
|
||||||
|
pToPage->pFreeEnd = (u8 *)(pToPage->pPageFtr) - ((u8 *)pFromPage->pPageFtr - pFromPage->pFreeEnd);
|
||||||
|
|
||||||
|
ASSERT(pToPage->pFreeEnd >= pToPage->pFreeStart);
|
||||||
|
|
||||||
|
memcpy(pToPage->pPageHdr, pFromPage->pPageHdr, pFromPage->pFreeStart - pFromPage->pPageHdr);
|
||||||
|
memcpy(pToPage->pFreeEnd, pFromPage->pFreeEnd, (u8 *)pFromPage->pPageFtr - pFromPage->pFreeEnd);
|
||||||
|
|
||||||
|
ASSERT(TDB_PAGE_CCELLS(pToPage) == pToPage->pFreeEnd - pToPage->pData);
|
||||||
|
|
||||||
|
delta = (pToPage->pPageHdr - pToPage->pData) - (pFromPage->pPageHdr - pFromPage->pData);
|
||||||
|
if (delta != 0) {
|
||||||
|
nFree = TDB_PAGE_NFREE(pFromPage);
|
||||||
|
TDB_PAGE_NFREE_SET(pToPage, nFree - delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the overflow cells
|
||||||
|
for (int iOvfl = 0; iOvfl < pFromPage->nOverflow; iOvfl++) {
|
||||||
|
pToPage->aiOvfl[iOvfl] = pFromPage->aiOvfl[iOvfl];
|
||||||
|
pToPage->apOvfl[iOvfl] = pFromPage->apOvfl[iOvfl];
|
||||||
|
}
|
||||||
|
pToPage->nOverflow = pFromPage->nOverflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdbPageAllocate(SPage *pPage, int szCell, SCell **ppCell) {
|
||||||
|
SCell *pFreeCell;
|
||||||
u8 *pOffset;
|
u8 *pOffset;
|
||||||
|
int nFree;
|
||||||
int ret;
|
int ret;
|
||||||
|
int cellFree;
|
||||||
|
SCell *pCell = NULL;
|
||||||
|
|
||||||
ASSERT(pPage->nFree > size + TDB_PAGE_OFFSET_SIZE(pPage));
|
|
||||||
|
|
||||||
pCell = NULL;
|
|
||||||
*ppCell = NULL;
|
*ppCell = NULL;
|
||||||
|
nFree = TDB_PAGE_NFREE(pPage);
|
||||||
|
|
||||||
// 1. Try to allocate from the free space area
|
ASSERT(nFree >= szCell + TDB_PAGE_OFFSET_SIZE(pPage));
|
||||||
if (pPage->pFreeEnd - pPage->pFreeStart > size + TDB_PAGE_OFFSET_SIZE(pPage)) {
|
ASSERT(TDB_PAGE_CCELLS(pPage) == pPage->pFreeEnd - pPage->pData);
|
||||||
pPage->pFreeEnd -= size;
|
|
||||||
pPage->pFreeStart += TDB_PAGE_OFFSET_SIZE(pPage);
|
// 1. Try to allocate from the free space block area
|
||||||
|
if (pPage->pFreeEnd - pPage->pFreeStart >= szCell + TDB_PAGE_OFFSET_SIZE(pPage)) {
|
||||||
|
pPage->pFreeEnd -= szCell;
|
||||||
pCell = pPage->pFreeEnd;
|
pCell = pPage->pFreeEnd;
|
||||||
|
TDB_PAGE_CCELLS_SET(pPage, pPage->pFreeEnd - pPage->pData);
|
||||||
|
goto _alloc_finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Try to allocate from the page free list
|
// 2. Try to allocate from the page free list
|
||||||
if ((pCell == NULL) && (pPage->pFreeEnd - pPage->pFreeStart >= TDB_PAGE_OFFSET_SIZE(pPage)) &&
|
cellFree = TDB_PAGE_FCELL(pPage);
|
||||||
TDB_PAGE_FCELL(pPage)) {
|
ASSERT(cellFree == 0 || cellFree > pPage->pFreeEnd - pPage->pData);
|
||||||
#if 0
|
if (cellFree && pPage->pFreeEnd - pPage->pFreeStart >= TDB_PAGE_OFFSET_SIZE(pPage)) {
|
||||||
int szCell;
|
SCell *pPrevFreeCell = NULL;
|
||||||
int nxOffset;
|
int szPrevFreeCell;
|
||||||
|
int szFreeCell;
|
||||||
pCell = pPage->pData + TDB_PAGE_FCELL(pPage);
|
int nxFreeCell;
|
||||||
pOffset = TDB_IS_LARGE_PAGE(pPage) ? ((SPageHdrL *)(pPage->pPageHdr))[0].fCell
|
int newSize;
|
||||||
: (u8 *)&(((SPageHdr *)(pPage->pPageHdr))[0].fCell);
|
|
||||||
szCell = TDB_PAGE_FREE_CELL_SIZE(pPage, pCell);
|
|
||||||
nxOffset = TDB_PAGE_FREE_CELL_NXOFFSET(pPage, pCell);
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Find a cell
|
if (cellFree == 0) break;
|
||||||
if (szCell >= size) {
|
|
||||||
if (szCell - size >= pPage->szFreeCell) {
|
|
||||||
SCell *pTmpCell = pCell + size;
|
|
||||||
|
|
||||||
TDB_PAGE_FREE_CELL_SIZE_SET(pPage, pTmpCell, szCell - size);
|
pFreeCell = pPage->pData + cellFree;
|
||||||
TDB_PAGE_FREE_CELL_NXOFFSET_SET(pPage, pTmpCell, nxOffset);
|
pPage->pPageMethods->getFreeCellInfo(pFreeCell, &szFreeCell, &nxFreeCell);
|
||||||
// TODO: *pOffset = pTmpCell - pPage->pData;
|
|
||||||
|
if (szFreeCell >= szCell) {
|
||||||
|
pCell = pFreeCell;
|
||||||
|
|
||||||
|
newSize = szFreeCell - szCell;
|
||||||
|
pFreeCell += szCell;
|
||||||
|
if (newSize >= TDB_PAGE_FREE_CELL_SIZE(pPage)) {
|
||||||
|
pPage->pPageMethods->setFreeCellInfo(pFreeCell, newSize, nxFreeCell);
|
||||||
|
if (pPrevFreeCell) {
|
||||||
|
pPage->pPageMethods->setFreeCellInfo(pPrevFreeCell, szPrevFreeCell, pFreeCell - pPage->pData);
|
||||||
} else {
|
} else {
|
||||||
TDB_PAGE_NFREE_SET(pPage, TDB_PAGE_NFREE(pPage) + szCell - size);
|
TDB_PAGE_FCELL_SET(pPage, pFreeCell - pPage->pData);
|
||||||
// TODO: *pOffset = nxOffset;
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not find a cell yet
|
|
||||||
if (nxOffset > 0) {
|
|
||||||
pCell = pPage->pData + nxOffset;
|
|
||||||
pOffset = TDB_PAGE_FREE_CELL_NXOFFSET_PTR(pPage, pCell);
|
|
||||||
szCell = TDB_PAGE_FREE_CELL_SIZE(pPage, pCell);
|
|
||||||
nxOffset = TDB_PAGE_FREE_CELL_NXOFFSET(pPage, pCell);
|
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
pCell = NULL;
|
if (pPrevFreeCell) {
|
||||||
break;
|
pPage->pPageMethods->setFreeCellInfo(pPrevFreeCell, szPrevFreeCell, nxFreeCell);
|
||||||
|
} else {
|
||||||
|
TDB_PAGE_FCELL_SET(pPage, nxFreeCell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pCell) {
|
goto _alloc_finish;
|
||||||
pPage->pFreeStart = pPage->pFreeStart + pPage->szOffset;
|
} else {
|
||||||
|
pPrevFreeCell = pFreeCell;
|
||||||
|
szPrevFreeCell = szFreeCell;
|
||||||
|
cellFree = nxFreeCell;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Try to dfragment and allocate again
|
// 3. Try to dfragment and allocate again
|
||||||
if (pCell == NULL) {
|
tdbPageDefragment(pPage);
|
||||||
ret = tdbPageDefragment(pPage);
|
ASSERT(pPage->pFreeEnd - pPage->pFreeStart == nFree);
|
||||||
if (ret < 0) {
|
ASSERT(nFree == TDB_PAGE_NFREE(pPage));
|
||||||
return -1;
|
ASSERT(pPage->pFreeEnd - pPage->pData == TDB_PAGE_CCELLS(pPage));
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(pPage->pFreeEnd - pPage->pFreeStart > size + TDB_PAGE_OFFSET_SIZE(pPage));
|
pPage->pFreeEnd -= szCell;
|
||||||
ASSERT(pPage->nFree == pPage->pFreeEnd - pPage->pFreeStart);
|
|
||||||
|
|
||||||
// Allocate from the free space area again
|
|
||||||
pPage->pFreeEnd -= size;
|
|
||||||
pPage->pFreeStart += TDB_PAGE_OFFSET_SIZE(pPage);
|
|
||||||
pCell = pPage->pFreeEnd;
|
pCell = pPage->pFreeEnd;
|
||||||
}
|
TDB_PAGE_CCELLS_SET(pPage, pPage->pFreeEnd - pPage->pData);
|
||||||
|
|
||||||
ASSERT(pCell != NULL);
|
_alloc_finish:
|
||||||
|
ASSERT(pCell);
|
||||||
pPage->nFree = pPage->nFree - size - TDB_PAGE_OFFSET_SIZE(pPage);
|
pPage->pFreeStart += TDB_PAGE_OFFSET_SIZE(pPage);
|
||||||
|
TDB_PAGE_NFREE_SET(pPage, nFree - szCell - TDB_PAGE_OFFSET_SIZE(pPage));
|
||||||
*ppCell = pCell;
|
*ppCell = pCell;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tdbPageFree(SPage *pPage, int idx, SCell *pCell, int size) {
|
static int tdbPageFree(SPage *pPage, int idx, SCell *pCell, int szCell) {
|
||||||
// TODO
|
int nFree;
|
||||||
|
int cellFree;
|
||||||
|
u8 *dest;
|
||||||
|
u8 *src;
|
||||||
|
|
||||||
|
ASSERT(pCell >= pPage->pFreeEnd);
|
||||||
|
ASSERT(pCell + szCell <= (u8 *)(pPage->pPageFtr));
|
||||||
|
ASSERT(pCell == TDB_PAGE_CELL_AT(pPage, idx));
|
||||||
|
|
||||||
|
nFree = TDB_PAGE_NFREE(pPage);
|
||||||
|
|
||||||
|
if (pCell == pPage->pFreeEnd) {
|
||||||
|
pPage->pFreeEnd += szCell;
|
||||||
|
TDB_PAGE_CCELLS_SET(pPage, pPage->pFreeEnd - pPage->pData);
|
||||||
|
} else {
|
||||||
|
if (szCell >= TDB_PAGE_FREE_CELL_SIZE(pPage)) {
|
||||||
|
cellFree = TDB_PAGE_FCELL(pPage);
|
||||||
|
pPage->pPageMethods->setFreeCellInfo(pCell, szCell, cellFree);
|
||||||
|
TDB_PAGE_FCELL_SET(pPage, pCell - pPage->pData);
|
||||||
|
} else {
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest = pPage->pCellIdx + TDB_PAGE_OFFSET_SIZE(pPage) * idx;
|
||||||
|
src = dest + TDB_PAGE_OFFSET_SIZE(pPage);
|
||||||
|
memmove(dest, src, pPage->pFreeStart - src);
|
||||||
|
|
||||||
|
pPage->pFreeStart -= TDB_PAGE_OFFSET_SIZE(pPage);
|
||||||
|
nFree = nFree + szCell + TDB_PAGE_OFFSET_SIZE(pPage);
|
||||||
|
TDB_PAGE_NFREE_SET(pPage, nFree);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tdbPageDefragment(SPage *pPage) {
|
static int tdbPageDefragment(SPage *pPage) {
|
||||||
// TODO
|
int nFree;
|
||||||
ASSERT(0);
|
int nCells;
|
||||||
|
SCell *pCell;
|
||||||
|
SCell *pNextCell;
|
||||||
|
SCell *pTCell;
|
||||||
|
int szCell;
|
||||||
|
int idx;
|
||||||
|
int iCell;
|
||||||
|
|
||||||
|
ASSERT(pPage->pFreeEnd - pPage->pFreeStart < nFree);
|
||||||
|
|
||||||
|
nFree = TDB_PAGE_NFREE(pPage);
|
||||||
|
nCells = TDB_PAGE_NCELLS(pPage);
|
||||||
|
|
||||||
|
// Loop to compact the page content
|
||||||
|
// Here we use an O(n^2) algorithm to do the job since
|
||||||
|
// this is a low frequency job.
|
||||||
|
pNextCell = (u8 *)pPage->pPageFtr;
|
||||||
|
pCell = NULL;
|
||||||
|
for (iCell = 0;; iCell++) {
|
||||||
|
// compact over
|
||||||
|
if (iCell == nCells) {
|
||||||
|
pPage->pFreeEnd = pNextCell;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < nCells; i++) {
|
||||||
|
if (TDB_PAGE_CELL_OFFSET_AT(pPage, i) < pNextCell - pPage->pData) {
|
||||||
|
pTCell = TDB_PAGE_CELL_AT(pPage, i);
|
||||||
|
if (pCell == NULL || pCell < pTCell) {
|
||||||
|
pCell = pTCell;
|
||||||
|
idx = i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(pCell != NULL);
|
||||||
|
|
||||||
|
szCell = (*pPage->xCellSize)(pPage, pCell);
|
||||||
|
|
||||||
|
ASSERT(pCell + szCell <= pNextCell);
|
||||||
|
if (pCell + szCell < pNextCell) {
|
||||||
|
memmove(pNextCell - szCell, pCell, szCell);
|
||||||
|
}
|
||||||
|
|
||||||
|
pCell = NULL;
|
||||||
|
pNextCell = pNextCell - szCell;
|
||||||
|
TDB_PAGE_CELL_OFFSET_AT_SET(pPage, idx, pNextCell - pPage->pData);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(pPage->pFreeEnd - pPage->pFreeStart == nFree);
|
||||||
|
TDB_PAGE_CCELLS_SET(pPage, pPage->pFreeEnd - pPage->pData);
|
||||||
|
TDB_PAGE_FCELL_SET(pPage, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------------- */
|
||||||
typedef struct __attribute__((__packed__)) {
|
typedef struct __attribute__((__packed__)) {
|
||||||
u16 flags;
|
|
||||||
u16 cellNum;
|
u16 cellNum;
|
||||||
u16 cellBody;
|
u16 cellBody;
|
||||||
u16 cellFree;
|
u16 cellFree;
|
||||||
u16 nFree;
|
u16 nFree;
|
||||||
} SPageHdr;
|
} SPageHdr;
|
||||||
|
|
||||||
// flags
|
typedef struct __attribute__((__packed__)) {
|
||||||
static inline u16 getPageFlags(SPage *pPage) { return ((SPageHdr *)(pPage->pPageHdr))[0].flags; }
|
u16 szCell;
|
||||||
static inline void setPageFlags(SPage *pPage, u16 flags) { ((SPageHdr *)(pPage->pPageHdr))[0].flags = flags; }
|
u16 nxOffset;
|
||||||
|
} SFreeCell;
|
||||||
|
|
||||||
// cellNum
|
// cellNum
|
||||||
static inline int getPageCellNum(SPage *pPage) { return ((SPageHdr *)(pPage->pPageHdr))[0].cellNum; }
|
static inline int getPageCellNum(SPage *pPage) { return ((SPageHdr *)(pPage->pPageHdr))[0].cellNum; }
|
||||||
|
@ -253,12 +474,23 @@ static inline void setPageCellOffset(SPage *pPage, int idx, int offset) {
|
||||||
((u16 *)pPage->pCellIdx)[idx] = (u16)offset;
|
((u16 *)pPage->pCellIdx)[idx] = (u16)offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// free cell info
|
||||||
|
static inline void getPageFreeCellInfo(SCell *pCell, int *szCell, int *nxOffset) {
|
||||||
|
SFreeCell *pFreeCell = (SFreeCell *)pCell;
|
||||||
|
*szCell = pFreeCell->szCell;
|
||||||
|
*nxOffset = pFreeCell->nxOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void setPageFreeCellInfo(SCell *pCell, int szCell, int nxOffset) {
|
||||||
|
SFreeCell *pFreeCell = (SFreeCell *)pCell;
|
||||||
|
pFreeCell->szCell = szCell;
|
||||||
|
pFreeCell->nxOffset = nxOffset;
|
||||||
|
}
|
||||||
|
|
||||||
SPageMethods pageMethods = {
|
SPageMethods pageMethods = {
|
||||||
2, // szOffset
|
2, // szOffset
|
||||||
sizeof(SPageHdr), // szPageHdr
|
sizeof(SPageHdr), // szPageHdr
|
||||||
sizeof(SFreeCell), // szFreeCell
|
sizeof(SFreeCell), // szFreeCell
|
||||||
getPageFlags, // getPageFlags
|
|
||||||
setPageFlags, // setFlagsp
|
|
||||||
getPageCellNum, // getCellNum
|
getPageCellNum, // getCellNum
|
||||||
setPageCellNum, // setCellNum
|
setPageCellNum, // setCellNum
|
||||||
getPageCellBody, // getCellBody
|
getPageCellBody, // getCellBody
|
||||||
|
@ -268,5 +500,7 @@ SPageMethods pageMethods = {
|
||||||
getPageNFree, // getFreeBytes
|
getPageNFree, // getFreeBytes
|
||||||
setPageNFree, // setFreeBytes
|
setPageNFree, // setFreeBytes
|
||||||
getPageCellOffset, // getCellOffset
|
getPageCellOffset, // getCellOffset
|
||||||
setPageCellOffset // setCellOffset
|
setPageCellOffset, // setCellOffset
|
||||||
|
getPageFreeCellInfo, // getFreeCellInfo
|
||||||
|
setPageFreeCellInfo // setFreeCellInfo
|
||||||
};
|
};
|
|
@ -16,7 +16,6 @@
|
||||||
#include "tdbInt.h"
|
#include "tdbInt.h"
|
||||||
|
|
||||||
typedef struct __attribute__((__packed__)) {
|
typedef struct __attribute__((__packed__)) {
|
||||||
u16 flags;
|
|
||||||
u8 cellNum[3];
|
u8 cellNum[3];
|
||||||
u8 cellBody[3];
|
u8 cellBody[3];
|
||||||
u8 cellFree[3];
|
u8 cellFree[3];
|
||||||
|
@ -28,10 +27,6 @@ typedef struct __attribute__((__packed__)) {
|
||||||
u8 nxOffset[3];
|
u8 nxOffset[3];
|
||||||
} SFreeCellL;
|
} SFreeCellL;
|
||||||
|
|
||||||
// flags
|
|
||||||
static inline u16 getPageFlags(SPage *pPage) { return ((SPageHdrL *)(pPage->pPageHdr))[0].flags; }
|
|
||||||
static inline void setPageFlags(SPage *pPage, u16 flags) { ((SPageHdrL *)(pPage->pPageHdr))[0].flags = flags; }
|
|
||||||
|
|
||||||
// cellNum
|
// cellNum
|
||||||
static inline int getPageCellNum(SPage *pPage) { return TDB_GET_U24(((SPageHdrL *)(pPage->pPageHdr))[0].cellNum); }
|
static inline int getPageCellNum(SPage *pPage) { return TDB_GET_U24(((SPageHdrL *)(pPage->pPageHdr))[0].cellNum); }
|
||||||
static inline void setPageCellNum(SPage *pPage, int cellNum) {
|
static inline void setPageCellNum(SPage *pPage, int cellNum) {
|
||||||
|
@ -66,12 +61,23 @@ static inline void setPageCellOffset(SPage *pPage, int idx, int offset) {
|
||||||
TDB_PUT_U24(pPage->pCellIdx + 3 * idx, offset);
|
TDB_PUT_U24(pPage->pCellIdx + 3 * idx, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// free cell info
|
||||||
|
static inline void getPageFreeCellInfo(SCell *pCell, int *szCell, int *nxOffset) {
|
||||||
|
SFreeCellL *pFreeCell = (SFreeCellL *)pCell;
|
||||||
|
*szCell = TDB_GET_U24(pFreeCell->szCell);
|
||||||
|
*nxOffset = TDB_GET_U24(pFreeCell->nxOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void setPageFreeCellInfo(SCell *pCell, int szCell, int nxOffset) {
|
||||||
|
SFreeCellL *pFreeCell = (SFreeCellL *)pCell;
|
||||||
|
TDB_PUT_U24(pFreeCell->szCell, szCell);
|
||||||
|
TDB_PUT_U24(pFreeCell->nxOffset, nxOffset);
|
||||||
|
}
|
||||||
|
|
||||||
SPageMethods pageLargeMethods = {
|
SPageMethods pageLargeMethods = {
|
||||||
3, // szOffset
|
3, // szOffset
|
||||||
sizeof(SPageHdrL), // szPageHdr
|
sizeof(SPageHdrL), // szPageHdr
|
||||||
sizeof(SFreeCellL), // szFreeCell
|
sizeof(SFreeCellL), // szFreeCell
|
||||||
getPageFlags, // getPageFlags
|
|
||||||
setPageFlags, // setFlagsp
|
|
||||||
getPageCellNum, // getCellNum
|
getPageCellNum, // getCellNum
|
||||||
setPageCellNum, // setCellNum
|
setPageCellNum, // setCellNum
|
||||||
getPageCellBody, // getCellBody
|
getPageCellBody, // getCellBody
|
||||||
|
@ -81,5 +87,7 @@ SPageMethods pageLargeMethods = {
|
||||||
getPageNFree, // getFreeBytes
|
getPageNFree, // getFreeBytes
|
||||||
setPageNFree, // setFreeBytes
|
setPageNFree, // setFreeBytes
|
||||||
getPageCellOffset, // getCellOffset
|
getPageCellOffset, // getCellOffset
|
||||||
setPageCellOffset // setCellOffset
|
setPageCellOffset, // setCellOffset
|
||||||
|
getPageFreeCellInfo, // getFreeCellInfo
|
||||||
|
setPageFreeCellInfo // setFreeCellInfo
|
||||||
};
|
};
|
|
@ -2,24 +2,138 @@
|
||||||
|
|
||||||
#include "tdbInt.h"
|
#include "tdbInt.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
typedef struct SPoolMem {
|
||||||
|
int64_t size;
|
||||||
|
struct SPoolMem *prev;
|
||||||
|
struct SPoolMem *next;
|
||||||
|
} SPoolMem;
|
||||||
|
|
||||||
|
static SPoolMem *openPool() {
|
||||||
|
SPoolMem *pPool = (SPoolMem *)malloc(sizeof(*pPool));
|
||||||
|
|
||||||
|
pPool->prev = pPool->next = pPool;
|
||||||
|
pPool->size = 0;
|
||||||
|
|
||||||
|
return pPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void closePool(SPoolMem *pPool) {
|
||||||
|
SPoolMem *pMem;
|
||||||
|
|
||||||
|
do {
|
||||||
|
pMem = pPool->next;
|
||||||
|
|
||||||
|
if (pMem == pPool) break;
|
||||||
|
|
||||||
|
pMem->next->prev = pMem->prev;
|
||||||
|
pMem->prev->next = pMem->next;
|
||||||
|
pPool->size -= pMem->size;
|
||||||
|
|
||||||
|
free(pMem);
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
assert(pPool->size == 0);
|
||||||
|
|
||||||
|
free(pPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *poolMalloc(void *arg, int size) {
|
||||||
|
void *ptr = NULL;
|
||||||
|
SPoolMem *pPool = (SPoolMem *)arg;
|
||||||
|
SPoolMem *pMem;
|
||||||
|
|
||||||
|
pMem = (SPoolMem *)malloc(sizeof(*pMem) + size);
|
||||||
|
if (pMem == NULL) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pMem->size = sizeof(*pMem) + size;
|
||||||
|
pMem->next = pPool->next;
|
||||||
|
pMem->prev = pPool;
|
||||||
|
|
||||||
|
pPool->next->prev = pMem;
|
||||||
|
pPool->next = pMem;
|
||||||
|
pPool->size += pMem->size;
|
||||||
|
|
||||||
|
ptr = (void *)(&pMem[1]);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void poolFree(void *arg, void *ptr) {
|
||||||
|
SPoolMem *pPool = (SPoolMem *)arg;
|
||||||
|
SPoolMem *pMem;
|
||||||
|
|
||||||
|
pMem = &(((SPoolMem *)ptr)[-1]);
|
||||||
|
|
||||||
|
pMem->next->prev = pMem->prev;
|
||||||
|
pMem->prev->next = pMem->next;
|
||||||
|
pPool->size -= pMem->size;
|
||||||
|
|
||||||
|
free(pMem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tKeyCmpr(const void *pKey1, int kLen1, const void *pKey2, int kLen2) {
|
||||||
|
int k1, k2;
|
||||||
|
|
||||||
|
std::string s1((char *)pKey1 + 3, kLen1 - 3);
|
||||||
|
std::string s2((char *)pKey2 + 3, kLen2 - 3);
|
||||||
|
k1 = stoi(s1);
|
||||||
|
k2 = stoi(s2);
|
||||||
|
|
||||||
|
if (k1 < k2) {
|
||||||
|
return -1;
|
||||||
|
} else if (k1 > k2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tDefaultKeyCmpr(const void *pKey1, int keyLen1, const void *pKey2, int keyLen2) {
|
||||||
|
int mlen;
|
||||||
|
int cret;
|
||||||
|
|
||||||
|
ASSERT(keyLen1 > 0 && keyLen2 > 0 && pKey1 != NULL && pKey2 != NULL);
|
||||||
|
|
||||||
|
mlen = keyLen1 < keyLen2 ? keyLen1 : keyLen2;
|
||||||
|
cret = memcmp(pKey1, pKey2, mlen);
|
||||||
|
if (cret == 0) {
|
||||||
|
if (keyLen1 < keyLen2) {
|
||||||
|
cret = -1;
|
||||||
|
} else if (keyLen1 > keyLen2) {
|
||||||
|
cret = 1;
|
||||||
|
} else {
|
||||||
|
cret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cret;
|
||||||
|
}
|
||||||
|
|
||||||
TEST(tdb_test, simple_test) {
|
TEST(tdb_test, simple_test) {
|
||||||
int ret;
|
int ret;
|
||||||
STEnv *pEnv;
|
STEnv *pEnv;
|
||||||
STDb *pDb;
|
STDB *pDb;
|
||||||
|
FKeyComparator compFunc;
|
||||||
|
int nData = 10000000;
|
||||||
|
|
||||||
// Open Env
|
// Open Env
|
||||||
ret = tdbEnvOpen("tdb", 1024, 20, &pEnv);
|
ret = tdbEnvOpen("tdb", 4096, 256000, &pEnv);
|
||||||
GTEST_ASSERT_EQ(ret, 0);
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
// Create a database
|
// Create a database
|
||||||
ret = tdbDbOpen("db.db", TDB_VARIANT_LEN, TDB_VARIANT_LEN, NULL, pEnv, &pDb);
|
compFunc = tKeyCmpr;
|
||||||
|
ret = tdbDbOpen("db.db", TDB_VARIANT_LEN, TDB_VARIANT_LEN, compFunc, pEnv, &pDb);
|
||||||
GTEST_ASSERT_EQ(ret, 0);
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
{ // Insert some data
|
{
|
||||||
char key[64];
|
char key[64];
|
||||||
char val[64];
|
char val[64];
|
||||||
|
|
||||||
for (int i = 1; i <= 1000; i++) {
|
{ // Insert some data
|
||||||
|
|
||||||
|
for (int i = 1; i <= nData; i++) {
|
||||||
sprintf(key, "key%d", i);
|
sprintf(key, "key%d", i);
|
||||||
sprintf(val, "value%d", i);
|
sprintf(val, "value%d", i);
|
||||||
ret = tdbDbInsert(pDb, key, strlen(key), val, strlen(val));
|
ret = tdbDbInsert(pDb, key, strlen(key), val, strlen(val));
|
||||||
|
@ -27,6 +141,54 @@ TEST(tdb_test, simple_test) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // Query the data
|
||||||
|
void *pVal = NULL;
|
||||||
|
int vLen;
|
||||||
|
|
||||||
|
for (int i = 1; i <= nData; i++) {
|
||||||
|
sprintf(key, "key%d", i);
|
||||||
|
sprintf(val, "value%d", i);
|
||||||
|
|
||||||
|
ret = tdbDbGet(pDb, key, strlen(key), &pVal, &vLen);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
GTEST_ASSERT_EQ(vLen, strlen(val));
|
||||||
|
GTEST_ASSERT_EQ(memcmp(val, pVal, vLen), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TDB_FREE(pVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Iterate to query the DB data
|
||||||
|
STDBC *pDBC;
|
||||||
|
void *pKey = NULL;
|
||||||
|
void *pVal = NULL;
|
||||||
|
int vLen, kLen;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
ret = tdbDbcOpen(pDb, &pDBC);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
ret = tdbDbNext(pDBC, &pKey, &kLen, &pVal, &vLen);
|
||||||
|
if (ret < 0) break;
|
||||||
|
|
||||||
|
// std::cout.write((char *)pKey, kLen) /* << " " << kLen */ << " ";
|
||||||
|
// std::cout.write((char *)pVal, vLen) /* << " " << vLen */;
|
||||||
|
// std::cout << std::endl;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
GTEST_ASSERT_EQ(count, nData);
|
||||||
|
|
||||||
|
tdbDbcClose(pDBC);
|
||||||
|
|
||||||
|
TDB_FREE(pKey);
|
||||||
|
TDB_FREE(pVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = tdbDbDrop(pDb);
|
ret = tdbDbDrop(pDb);
|
||||||
GTEST_ASSERT_EQ(ret, 0);
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue