mirror of
https://github.com/taosdata/TDengine
synced 2026-05-24 10:09:01 +00:00
383 lines
8.7 KiB
C++
383 lines
8.7 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#define ALLOW_FORBID_FUNC
|
|
#include "os.h"
|
|
#include "tdb.h"
|
|
#include "tdbInt.h"
|
|
|
|
#include <shared_mutex>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <vector>
|
|
#include "tlog.h"
|
|
|
|
|
|
typedef struct SPoolMem {
|
|
int64_t size;
|
|
struct SPoolMem *prev;
|
|
struct SPoolMem *next;
|
|
} SPoolMem;
|
|
|
|
static SPoolMem *openPool() {
|
|
SPoolMem *pPool = (SPoolMem *)taosMemoryMalloc(sizeof(*pPool));
|
|
|
|
pPool->prev = pPool->next = pPool;
|
|
pPool->size = 0;
|
|
|
|
return pPool;
|
|
}
|
|
|
|
static void clearPool(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;
|
|
|
|
taosMemoryFree(pMem);
|
|
} while (1);
|
|
|
|
TD_ALWAYS_ASSERT(pPool->size == 0);
|
|
}
|
|
|
|
static void closePool(SPoolMem *pPool) {
|
|
clearPool(pPool);
|
|
taosMemoryFree(pPool);
|
|
}
|
|
|
|
static void *poolMalloc(void *arg, size_t size) {
|
|
void *ptr = NULL;
|
|
SPoolMem *pPool = (SPoolMem *)arg;
|
|
SPoolMem *pMem;
|
|
|
|
pMem = (SPoolMem *)taosMemoryMalloc(sizeof(*pMem) + size);
|
|
if (pMem == NULL) {
|
|
TD_ALWAYS_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;
|
|
|
|
taosMemoryFree(pMem);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static TDB *openEnv(char const *envName, int const pageSize, int const pageNum) {
|
|
TDB *pEnv = NULL;
|
|
|
|
int ret = tdbOpen(envName, pageSize, pageNum, &pEnv, 0, 0, NULL);
|
|
if (ret) {
|
|
pEnv = NULL;
|
|
}
|
|
|
|
return pEnv;
|
|
}
|
|
|
|
struct STTB {
|
|
TDB *pEnv;
|
|
SBTree *pBt;
|
|
};
|
|
|
|
struct SBTree {
|
|
SPgno root;
|
|
int keyLen;
|
|
int valLen;
|
|
SPager *pPager;
|
|
tdb_cmpr_fn_t kcmpr;
|
|
int pageSize;
|
|
int maxLocal;
|
|
int minLocal;
|
|
int maxLeaf;
|
|
int minLeaf;
|
|
SBtInfo info;
|
|
char *tbname;
|
|
void *pBuf;
|
|
};
|
|
|
|
TEST(upgrade_test, upgrade_full) {
|
|
taosRemoveDir("tdb");
|
|
|
|
// open Env
|
|
TDB *pEnv = openEnv("tdb", 4096, 64);
|
|
GTEST_ASSERT_NE(pEnv, nullptr);
|
|
|
|
// open db
|
|
TTB *pTb = NULL;
|
|
tdb_cmpr_fn_t compFunc = tDefaultKeyCmpr;
|
|
int ret = tdbTbOpen("free.db", 4, 0, compFunc, pEnv, &pTb, 0);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
|
|
SBTree* pBt = pTb->pBt;
|
|
SPager *pPager = pBt->pPager;
|
|
// open the pool
|
|
SPoolMem *pPool = openPool();
|
|
|
|
// start a transaction
|
|
TXN *txn = NULL;
|
|
tdbBegin(pEnv, &txn, poolMalloc, poolFree, pPool, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED);
|
|
|
|
for (int i = pBt->root + 1; i <= 700; i++) {
|
|
SPgno pgno = i;
|
|
SPage *pPage = NULL;
|
|
SBtreeInitPageArg arg;
|
|
arg.flags = 0x1 | 0x2; // root leaf node;
|
|
arg.pBt = pBt;
|
|
tdbPagerFetchPage(pPager, &pgno, &pPage, tdbBtreeInitPage, &arg, txn);
|
|
tdbPagerWrite(pPager, pPage);
|
|
tdbPagerReturnPage(pPager, pPage, txn);
|
|
}
|
|
|
|
for (int i = pBt->root + 1; i <= pBt->root + 680; i++) {
|
|
ret = tdbTbInsert(pTb, &i, sizeof(i), NULL, 0, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
}
|
|
|
|
// commit current transaction
|
|
tdbCommit(pEnv, txn);
|
|
tdbPostCommit(pEnv, txn);
|
|
|
|
tdbBtreeToStack(pBt);
|
|
|
|
tdbBegin(pEnv, &txn, poolMalloc, poolFree, pPool, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED);
|
|
|
|
for (int i = 1; i <= 680; i++) {
|
|
SPgno pgno;
|
|
ret = tdbBtreePopFreePage(pBt, &pgno, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
GTEST_ASSERT_NE(pgno, 0);
|
|
}
|
|
|
|
SPgno pgno;
|
|
ret = tdbBtreePopFreePage(pBt, &pgno, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
GTEST_ASSERT_EQ(pgno, 0);
|
|
|
|
tdbCommit(pEnv, txn);
|
|
tdbPostCommit(pEnv, txn);
|
|
|
|
closePool(pPool);
|
|
|
|
// Close a database
|
|
tdbTbClose(pTb);
|
|
|
|
// Close Env
|
|
tdbClose(pEnv);
|
|
}
|
|
|
|
|
|
TEST(upgrade_test, upgrade_rebalanced) {
|
|
taosRemoveDir("tdb");
|
|
|
|
// open Env
|
|
TDB *pEnv = openEnv("tdb", 4096, 64);
|
|
GTEST_ASSERT_NE(pEnv, nullptr);
|
|
|
|
// open db
|
|
TTB *pTb = NULL;
|
|
tdb_cmpr_fn_t compFunc = tDefaultKeyCmpr;
|
|
int ret = tdbTbOpen("free.db", 4, 0, compFunc, pEnv, &pTb, 0);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
|
|
SBTree* pBt = pTb->pBt;
|
|
SPager *pPager = pBt->pPager;
|
|
// open the pool
|
|
SPoolMem *pPool = openPool();
|
|
|
|
// start a transaction
|
|
TXN *txn = NULL;
|
|
tdbBegin(pEnv, &txn, poolMalloc, poolFree, pPool, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED);
|
|
|
|
for (int i = pBt->root + 1; i <= 700; i++) {
|
|
SPgno pgno = i;
|
|
SPage *pPage = NULL;
|
|
SBtreeInitPageArg arg;
|
|
arg.flags = 0x1 | 0x2; // root leaf node;
|
|
arg.pBt = pBt;
|
|
tdbPagerFetchPage(pPager, &pgno, &pPage, tdbBtreeInitPage, &arg, txn);
|
|
tdbPagerWrite(pPager, pPage);
|
|
tdbPagerReturnPage(pPager, pPage, txn);
|
|
}
|
|
|
|
for (int i = pBt->root + 1; i <= pBt->root + 700; i++) {
|
|
ret = tdbTbInsert(pTb, &i, sizeof(i), NULL, 0, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
}
|
|
|
|
// commit current transaction
|
|
tdbCommit(pEnv, txn);
|
|
tdbPostCommit(pEnv, txn);
|
|
|
|
tdbBtreeToStack(pBt);
|
|
|
|
tdbBegin(pEnv, &txn, poolMalloc, poolFree, pPool, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED);
|
|
|
|
SPgno pgno;
|
|
ret = tdbBtreePopFreePage(pBt, &pgno, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
GTEST_ASSERT_EQ(pgno, 0);
|
|
|
|
for (int i = pBt->root + 1; i <= pBt->root + 700; i++) {
|
|
SPgno pgno = i;
|
|
SPage *pPage = NULL;
|
|
SBtreeInitPageArg arg;
|
|
arg.flags = 0x1 | 0x2; // root leaf node;
|
|
arg.pBt = pBt;
|
|
tdbPagerFetchPage(pPager, &pgno, &pPage, tdbBtreeInitPage, &arg, txn);
|
|
tdbBtreePushFreePage(pBt, pPage, txn);
|
|
tdbPagerReturnPage(pPager, pPage, txn);
|
|
}
|
|
|
|
for (int i = pBt->root + 700; i >= pBt->root + 1; i--) {
|
|
SPgno pgno;
|
|
ret = tdbBtreePopFreePage(pBt, &pgno, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
GTEST_ASSERT_EQ(pgno, i);
|
|
}
|
|
|
|
ret = tdbBtreePopFreePage(pBt, &pgno, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
GTEST_ASSERT_EQ(pgno, 0);
|
|
|
|
tdbCommit(pEnv, txn);
|
|
tdbPostCommit(pEnv, txn);
|
|
|
|
closePool(pPool);
|
|
|
|
// Close a database
|
|
tdbTbClose(pTb);
|
|
|
|
// Close Env
|
|
tdbClose(pEnv);
|
|
}
|
|
|
|
|
|
TEST(upgrade_test, push_pop_after_upgrade) {
|
|
taosRemoveDir("tdb");
|
|
|
|
// open Env
|
|
TDB *pEnv = openEnv("tdb", 4096, 64);
|
|
GTEST_ASSERT_NE(pEnv, nullptr);
|
|
|
|
// open db
|
|
TTB *pTb = NULL;
|
|
tdb_cmpr_fn_t compFunc = tDefaultKeyCmpr;
|
|
int ret = tdbTbOpen("free.db", 4, 0, compFunc, pEnv, &pTb, 0);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
|
|
SBTree* pBt = pTb->pBt;
|
|
SPager *pPager = pBt->pPager;
|
|
// open the pool
|
|
SPoolMem *pPool = openPool();
|
|
|
|
// start a transaction
|
|
TXN *txn = NULL;
|
|
tdbBegin(pEnv, &txn, poolMalloc, poolFree, pPool, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED);
|
|
|
|
for (int i = pBt->root + 1; i <= pBt->root + 700; i++) {
|
|
SPgno pgno = i;
|
|
SPage *pPage = NULL;
|
|
SBtreeInitPageArg arg;
|
|
arg.flags = 0x1 | 0x2; // root leaf node;
|
|
arg.pBt = pBt;
|
|
tdbPagerFetchPage(pPager, &pgno, &pPage, tdbBtreeInitPage, &arg, txn);
|
|
tdbPagerWrite(pPager, pPage);
|
|
tdbPagerReturnPage(pPager, pPage, txn);
|
|
}
|
|
|
|
for (int i = pBt->root + 1; i <= pBt->root + 680; i++) {
|
|
ret = tdbTbInsert(pTb, &i, sizeof(i), NULL, 0, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
}
|
|
|
|
// commit current transaction
|
|
tdbCommit(pEnv, txn);
|
|
tdbPostCommit(pEnv, txn);
|
|
|
|
tdbBtreeToStack(pBt);
|
|
|
|
tdbBegin(pEnv, &txn, poolMalloc, poolFree, pPool, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED);
|
|
|
|
for (int i = pBt->root + 681; i <= pBt->root + 700; i++) {
|
|
SPgno pgno = i;
|
|
SPage *pPage = NULL;
|
|
SBtreeInitPageArg arg;
|
|
arg.flags = 0x1 | 0x2; // root leaf node;
|
|
arg.pBt = pBt;
|
|
tdbPagerFetchPage(pPager, &pgno, &pPage, tdbBtreeInitPage, &arg, txn);
|
|
tdbBtreePushFreePage(pBt, pPage, txn);
|
|
tdbPagerReturnPage(pPager, pPage, txn);
|
|
}
|
|
|
|
for (int i = pBt->root + 700; i >= pBt->root + 681; i--) {
|
|
SPgno pgno;
|
|
ret = tdbBtreePopFreePage(pBt, &pgno, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
GTEST_ASSERT_EQ(pgno, i);
|
|
}
|
|
|
|
for (int i = 1; i <= 680; i++) {
|
|
SPgno pgno;
|
|
ret = tdbBtreePopFreePage(pBt, &pgno, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
GTEST_ASSERT_NE(pgno, 0);
|
|
}
|
|
|
|
SPgno pgno;
|
|
ret = tdbBtreePopFreePage(pBt, &pgno, txn);
|
|
GTEST_ASSERT_EQ(ret, 0);
|
|
GTEST_ASSERT_EQ(pgno, 0);
|
|
|
|
tdbCommit(pEnv, txn);
|
|
tdbPostCommit(pEnv, txn);
|
|
|
|
closePool(pPool);
|
|
|
|
// Close a database
|
|
tdbTbClose(pTb);
|
|
|
|
// Close Env
|
|
tdbClose(pEnv);
|
|
}
|