homework-jianmu/source/util/src/tskiplist.c

700 lines
20 KiB
C

/*
* 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/>.
*/
#define _DEFAULT_SOURCE
#include "tskiplist.h"
#include "tcompare.h"
#include "tlog.h"
#include "tutil.h"
static int32_t initForwardBackwardPtr(SSkipList *pSkipList);
static SSkipListNode *getPriorNode(SSkipList *pSkipList, const char *val, int32_t order, SSkipListNode **pCur);
static void tSkipListRemoveNodeImpl(SSkipList *pSkipList, SSkipListNode *pNode);
static void tSkipListCorrectLevel(SSkipList *pSkipList);
static SSkipListIterator *doCreateSkipListIterator(SSkipList *pSkipList, int32_t order);
static void tSkipListDoInsert(SSkipList *pSkipList, SSkipListNode **direction, SSkipListNode *pNode, bool isForward);
static bool tSkipListGetPosToPut(SSkipList *pSkipList, SSkipListNode **backward, void *pData);
static SSkipListNode *tSkipListNewNode(uint8_t level);
#define tSkipListFreeNode(n) taosMemoryFreeClear((n))
static SSkipListNode *tSkipListPutImpl(SSkipList *pSkipList, void *pData, SSkipListNode **direction, bool isForward,
bool hasDup);
static FORCE_INLINE int32_t tSkipListWLock(SSkipList *pSkipList);
static FORCE_INLINE int32_t tSkipListRLock(SSkipList *pSkipList);
static FORCE_INLINE int32_t tSkipListUnlock(SSkipList *pSkipList);
static FORCE_INLINE int32_t getSkipListRandLevel(SSkipList *pSkipList);
SSkipList *tSkipListCreate(uint8_t maxLevel, uint8_t keyType, uint16_t keyLen, __compar_fn_t comparFn, uint8_t flags,
__sl_key_fn_t fn) {
SSkipList *pSkipList = (SSkipList *)taosMemoryCalloc(1, sizeof(SSkipList));
if (pSkipList == NULL) return NULL;
if (maxLevel > MAX_SKIP_LIST_LEVEL) {
maxLevel = MAX_SKIP_LIST_LEVEL;
}
pSkipList->maxLevel = maxLevel;
pSkipList->type = keyType;
pSkipList->len = keyLen;
pSkipList->flags = flags;
pSkipList->keyFn = fn;
pSkipList->seed = taosRand();
#if 0
// the function getkeycomparfunc is defined in common
if (comparFn == NULL) {
pSkipList->comparFn = getKeyComparFunc(keyType, TSDB_ORDER_ASC);
} else {
pSkipList->comparFn = comparFn;
}
#else
pSkipList->comparFn = comparFn;
#endif
if (initForwardBackwardPtr(pSkipList) < 0) {
tSkipListDestroy(pSkipList);
return NULL;
}
if (SL_IS_THREAD_SAFE(pSkipList)) {
pSkipList->lock = (TdThreadRwlock *)taosMemoryCalloc(1, sizeof(TdThreadRwlock));
if (pSkipList->lock == NULL) {
tSkipListDestroy(pSkipList);
return NULL;
}
if (taosThreadRwlockInit(pSkipList->lock, NULL) != 0) {
tSkipListDestroy(pSkipList);
return NULL;
}
}
taosSeedRand((uint32_t)taosGetTimestampSec());
#if SKIP_LIST_RECORD_PERFORMANCE
pSkipList->state.nTotalMemSize += sizeof(SSkipList);
#endif
return pSkipList;
}
void tSkipListDestroy(SSkipList *pSkipList) {
if (pSkipList == NULL) return;
tSkipListWLock(pSkipList);
SSkipListNode *pNode = SL_NODE_GET_FORWARD_POINTER(pSkipList->pHead, 0);
while (pNode != pSkipList->pTail) {
SSkipListNode *pTemp = pNode;
pNode = SL_NODE_GET_FORWARD_POINTER(pNode, 0);
tSkipListFreeNode(pTemp);
}
tSkipListUnlock(pSkipList);
if (pSkipList->lock != NULL) {
taosThreadRwlockDestroy(pSkipList->lock);
taosMemoryFreeClear(pSkipList->lock);
}
tSkipListFreeNode(pSkipList->pHead);
tSkipListFreeNode(pSkipList->pTail);
taosMemoryFreeClear(pSkipList);
}
SSkipListNode *tSkipListPut(SSkipList *pSkipList, void *pData) {
if (pSkipList == NULL || pData == NULL) return NULL;
SSkipListNode *backward[MAX_SKIP_LIST_LEVEL] = {0};
SSkipListNode *pNode = NULL;
tSkipListWLock(pSkipList);
bool hasDup = tSkipListGetPosToPut(pSkipList, backward, pData);
pNode = tSkipListPutImpl(pSkipList, pData, backward, false, hasDup);
tSkipListUnlock(pSkipList);
return pNode;
}
void tSkipListPutBatchByIter(SSkipList *pSkipList, void *iter, iter_next_fn_t iterate) {
SSkipListNode *backward[MAX_SKIP_LIST_LEVEL] = {0};
SSkipListNode *forward[MAX_SKIP_LIST_LEVEL] = {0};
bool hasDup = false;
char *pKey = NULL;
char *pDataKey = NULL;
int32_t compare = 0;
tSkipListWLock(pSkipList);
void *pData = iterate(iter);
if (pData == NULL) {
tSkipListUnlock(pSkipList);
return;
}
// backward to put the first data
hasDup = tSkipListGetPosToPut(pSkipList, backward, pData);
tSkipListPutImpl(pSkipList, pData, backward, false, hasDup);
for (int32_t level = 0; level < pSkipList->maxLevel; level++) {
forward[level] = SL_NODE_GET_BACKWARD_POINTER(backward[level], level);
}
// forward to put the rest of data
while ((pData = iterate(iter)) != NULL) {
pDataKey = pSkipList->keyFn(pData);
hasDup = false;
// Compare max key
pKey = SL_GET_MAX_KEY(pSkipList);
compare = pSkipList->comparFn(pDataKey, pKey);
if (compare > 0) {
for (int32_t i = 0; i < pSkipList->maxLevel; i++) {
forward[i] = SL_NODE_GET_BACKWARD_POINTER(pSkipList->pTail, i);
}
} else {
SSkipListNode *px = pSkipList->pHead;
for (int32_t i = pSkipList->maxLevel - 1; i >= 0; --i) {
if (i < pSkipList->level) {
// set new px
if (forward[i] != pSkipList->pHead) {
if (px == pSkipList->pHead ||
pSkipList->comparFn(SL_GET_NODE_KEY(pSkipList, forward[i]), SL_GET_NODE_KEY(pSkipList, px)) > 0) {
px = forward[i];
}
}
SSkipListNode *p = SL_NODE_GET_FORWARD_POINTER(px, i);
while (p != pSkipList->pTail) {
pKey = SL_GET_NODE_KEY(pSkipList, p);
compare = pSkipList->comparFn(pKey, pDataKey);
if (compare > 0) {
break;
} else {
if (compare == 0 && !hasDup) hasDup = true;
px = p;
p = SL_NODE_GET_FORWARD_POINTER(px, i);
}
}
}
forward[i] = px;
}
}
tSkipListPutImpl(pSkipList, pData, forward, true, hasDup);
}
tSkipListUnlock(pSkipList);
}
uint32_t tSkipListRemove(SSkipList *pSkipList, SSkipListKey key) {
uint32_t count = 0;
tSkipListWLock(pSkipList);
SSkipListNode *pNode = getPriorNode(pSkipList, key, TSDB_ORDER_ASC, NULL);
while (1) {
SSkipListNode *p = SL_NODE_GET_FORWARD_POINTER(pNode, 0);
if (p == pSkipList->pTail) {
break;
}
if (pSkipList->comparFn(key, SL_GET_NODE_KEY(pSkipList, p)) != 0) {
break;
}
tSkipListRemoveNodeImpl(pSkipList, p);
++count;
}
tSkipListCorrectLevel(pSkipList);
tSkipListUnlock(pSkipList);
return count;
}
SArray *tSkipListGet(SSkipList *pSkipList, SSkipListKey key) {
SArray *sa = taosArrayInit(1, POINTER_BYTES);
tSkipListRLock(pSkipList);
SSkipListNode *pNode = getPriorNode(pSkipList, key, TSDB_ORDER_ASC, NULL);
while (1) {
SSkipListNode *p = SL_NODE_GET_FORWARD_POINTER(pNode, 0);
if (p == pSkipList->pTail) {
break;
}
if (pSkipList->comparFn(key, SL_GET_NODE_KEY(pSkipList, p)) != 0) {
break;
}
taosArrayPush(sa, &p);
pNode = p;
}
tSkipListUnlock(pSkipList);
return sa;
}
void tSkipListRemoveNode(SSkipList *pSkipList, SSkipListNode *pNode) {
tSkipListWLock(pSkipList);
tSkipListRemoveNodeImpl(pSkipList, pNode);
tSkipListCorrectLevel(pSkipList);
tSkipListUnlock(pSkipList);
}
SSkipListIterator *tSkipListCreateIter(SSkipList *pSkipList) {
if (pSkipList == NULL) return NULL;
return doCreateSkipListIterator(pSkipList, TSDB_ORDER_ASC);
}
SSkipListIterator *tSkipListCreateIterFromVal(SSkipList *pSkipList, const char *val, int32_t type, int32_t order) {
if (order != TSDB_ORDER_ASC && order != TSDB_ORDER_DESC) {
return NULL;
}
SSkipListIterator *iter = doCreateSkipListIterator(pSkipList, order);
if (val == NULL) {
return iter;
}
tSkipListRLock(pSkipList);
iter->cur = getPriorNode(pSkipList, val, order, &(iter->next));
tSkipListUnlock(pSkipList);
return iter;
}
bool tSkipListIterNext(SSkipListIterator *iter) {
if (iter->pSkipList == NULL) return false;
SSkipList *pSkipList = iter->pSkipList;
tSkipListRLock(pSkipList);
if (iter->order == TSDB_ORDER_ASC) {
// no data in the skip list
if (iter->cur == pSkipList->pTail || iter->next == NULL) {
iter->cur = pSkipList->pTail;
tSkipListUnlock(pSkipList);
return false;
}
iter->cur = SL_NODE_GET_FORWARD_POINTER(iter->cur, 0);
// a new node is inserted into between iter->cur and iter->next, ignore it
if (iter->cur != iter->next && (iter->next != NULL)) {
iter->cur = iter->next;
}
iter->next = SL_NODE_GET_FORWARD_POINTER(iter->cur, 0);
iter->step++;
} else {
if (iter->cur == pSkipList->pHead) {
iter->cur = pSkipList->pHead;
tSkipListUnlock(pSkipList);
return false;
}
iter->cur = SL_NODE_GET_BACKWARD_POINTER(iter->cur, 0);
// a new node is inserted into between iter->cur and iter->next, ignore it
if (iter->cur != iter->next && (iter->next != NULL)) {
iter->cur = iter->next;
}
iter->next = SL_NODE_GET_BACKWARD_POINTER(iter->cur, 0);
iter->step++;
}
tSkipListUnlock(pSkipList);
return (iter->order == TSDB_ORDER_ASC) ? (iter->cur != pSkipList->pTail) : (iter->cur != pSkipList->pHead);
}
SSkipListNode *tSkipListIterGet(SSkipListIterator *iter) {
if (iter == NULL || iter->cur == iter->pSkipList->pTail || iter->cur == iter->pSkipList->pHead) {
return NULL;
} else {
return iter->cur;
}
}
void *tSkipListDestroyIter(SSkipListIterator *iter) {
if (iter == NULL) {
return NULL;
}
taosMemoryFreeClear(iter);
return NULL;
}
void tSkipListPrint(SSkipList *pSkipList, int16_t nlevel) {
if (pSkipList == NULL || pSkipList->level < nlevel || nlevel <= 0) {
return;
}
SSkipListNode *p = SL_NODE_GET_FORWARD_POINTER(pSkipList->pHead, nlevel - 1);
int32_t id = 1;
char *prev = NULL;
while (p != pSkipList->pTail) {
char *key = SL_GET_NODE_KEY(pSkipList, p);
if (prev != NULL) {
ASSERT(pSkipList->comparFn(prev, key) < 0);
}
switch (pSkipList->type) {
case TSDB_DATA_TYPE_INT:
fprintf(stdout, "%d: %d\n", id++, *(int32_t *)key);
break;
case TSDB_DATA_TYPE_SMALLINT:
case TSDB_DATA_TYPE_TINYINT:
case TSDB_DATA_TYPE_BIGINT:
fprintf(stdout, "%d: %" PRId64 " \n", id++, *(int64_t *)key);
break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_VARBINARY:
case TSDB_DATA_TYPE_GEOMETRY:
fprintf(stdout, "%d: %s \n", id++, key);
break;
case TSDB_DATA_TYPE_DOUBLE:
fprintf(stdout, "%d: %lf \n", id++, *(double *)key);
break;
default:
fprintf(stdout, "\n");
}
prev = SL_GET_NODE_KEY(pSkipList, p);
p = SL_NODE_GET_FORWARD_POINTER(p, nlevel - 1);
}
}
static void tSkipListDoInsert(SSkipList *pSkipList, SSkipListNode **direction, SSkipListNode *pNode, bool isForward) {
for (int32_t i = 0; i < pNode->level; ++i) {
SSkipListNode *x = direction[i];
if (isForward) {
SL_NODE_GET_BACKWARD_POINTER(pNode, i) = x;
SSkipListNode *next = SL_NODE_GET_FORWARD_POINTER(x, i);
SL_NODE_GET_BACKWARD_POINTER(next, i) = pNode;
SL_NODE_GET_FORWARD_POINTER(pNode, i) = next;
SL_NODE_GET_FORWARD_POINTER(x, i) = pNode;
} else {
SL_NODE_GET_FORWARD_POINTER(pNode, i) = x;
SSkipListNode *prev = SL_NODE_GET_BACKWARD_POINTER(x, i);
SL_NODE_GET_FORWARD_POINTER(prev, i) = pNode;
SL_NODE_GET_BACKWARD_POINTER(pNode, i) = prev;
SL_NODE_GET_BACKWARD_POINTER(x, i) = pNode;
}
}
if (pSkipList->level < pNode->level) pSkipList->level = pNode->level;
pSkipList->size += 1;
}
static SSkipListIterator *doCreateSkipListIterator(SSkipList *pSkipList, int32_t order) {
SSkipListIterator *iter = taosMemoryCalloc(1, sizeof(SSkipListIterator));
iter->pSkipList = pSkipList;
iter->order = order;
if (order == TSDB_ORDER_ASC) {
iter->cur = pSkipList->pHead;
iter->next = SL_NODE_GET_FORWARD_POINTER(iter->cur, 0);
} else {
iter->cur = pSkipList->pTail;
iter->next = SL_NODE_GET_BACKWARD_POINTER(iter->cur, 0);
}
return iter;
}
static FORCE_INLINE int32_t tSkipListWLock(SSkipList *pSkipList) {
if (pSkipList->lock) {
return taosThreadRwlockWrlock(pSkipList->lock);
}
return 0;
}
static FORCE_INLINE int32_t tSkipListRLock(SSkipList *pSkipList) {
if (pSkipList->lock) {
return taosThreadRwlockRdlock(pSkipList->lock);
}
return 0;
}
static FORCE_INLINE int32_t tSkipListUnlock(SSkipList *pSkipList) {
if (pSkipList->lock) {
return taosThreadRwlockUnlock(pSkipList->lock);
}
return 0;
}
static bool tSkipListGetPosToPut(SSkipList *pSkipList, SSkipListNode **backward, void *pData) {
int32_t compare = 0;
bool hasDupKey = false;
char *pDataKey = pSkipList->keyFn(pData);
if (pSkipList->size == 0) {
for (int32_t i = 0; i < pSkipList->maxLevel; i++) {
backward[i] = pSkipList->pTail;
}
} else {
char *pKey = NULL;
// Compare max key
pKey = SL_GET_MAX_KEY(pSkipList);
compare = pSkipList->comparFn(pDataKey, pKey);
if (compare >= 0) {
for (int32_t i = 0; i < pSkipList->maxLevel; i++) {
backward[i] = pSkipList->pTail;
}
return (compare == 0);
}
// Compare min key
pKey = SL_GET_MIN_KEY(pSkipList);
compare = pSkipList->comparFn(pDataKey, pKey);
if (compare < 0) {
for (int32_t i = 0; i < pSkipList->maxLevel; i++) {
backward[i] = SL_NODE_GET_FORWARD_POINTER(pSkipList->pHead, i);
}
return (compare == 0);
}
SSkipListNode *px = pSkipList->pTail;
for (int32_t i = pSkipList->maxLevel - 1; i >= 0; --i) {
if (i < pSkipList->level) {
SSkipListNode *p = SL_NODE_GET_BACKWARD_POINTER(px, i);
while (p != pSkipList->pHead) {
pKey = SL_GET_NODE_KEY(pSkipList, p);
compare = pSkipList->comparFn(pKey, pDataKey);
if (compare <= 0) {
if (compare == 0 && !hasDupKey) hasDupKey = true;
break;
} else {
px = p;
p = SL_NODE_GET_BACKWARD_POINTER(px, i);
}
}
}
backward[i] = px;
}
}
return hasDupKey;
}
static void tSkipListRemoveNodeImpl(SSkipList *pSkipList, SSkipListNode *pNode) {
int32_t level = pNode->level;
uint8_t dupMode = SL_DUP_MODE(pSkipList);
ASSERT(dupMode != SL_DISCARD_DUP_KEY && dupMode != SL_UPDATE_DUP_KEY);
for (int32_t j = level - 1; j >= 0; --j) {
SSkipListNode *prev = SL_NODE_GET_BACKWARD_POINTER(pNode, j);
SSkipListNode *next = SL_NODE_GET_FORWARD_POINTER(pNode, j);
SL_NODE_GET_FORWARD_POINTER(prev, j) = next;
SL_NODE_GET_BACKWARD_POINTER(next, j) = prev;
}
tSkipListFreeNode(pNode);
pSkipList->size--;
}
// Function must be called after calling tSkipListRemoveNodeImpl() function
static void tSkipListCorrectLevel(SSkipList *pSkipList) {
while (pSkipList->level > 0 &&
SL_NODE_GET_FORWARD_POINTER(pSkipList->pHead, pSkipList->level - 1) == pSkipList->pTail) {
pSkipList->level -= 1;
}
}
UNUSED_FUNC static FORCE_INLINE void recordNodeEachLevel(SSkipList *pSkipList,
int32_t level) { // record link count in each level
#if SKIP_LIST_RECORD_PERFORMANCE
for (int32_t i = 0; i < level; ++i) {
pSkipList->state.nLevelNodeCnt[i]++;
}
#endif
}
UNUSED_FUNC static FORCE_INLINE void removeNodeEachLevel(SSkipList *pSkipList, int32_t level) {
#if SKIP_LIST_RECORD_PERFORMANCE
for (int32_t i = 0; i < level; ++i) {
pSkipList->state.nLevelNodeCnt[i]--;
}
#endif
}
static FORCE_INLINE int32_t getSkipListNodeRandomHeight(SSkipList *pSkipList) {
const uint32_t factor = 4;
int32_t n = 1;
#ifdef WINDOWS
while ((taosRand() % factor) == 0 && n <= pSkipList->maxLevel) {
#else
while ((taosRandR(&(pSkipList->seed)) % factor) == 0 && n <= pSkipList->maxLevel) {
#endif
n++;
}
return n;
}
static FORCE_INLINE int32_t getSkipListRandLevel(SSkipList *pSkipList) {
int32_t level = 0;
if (pSkipList->size == 0) {
level = 1;
} else {
level = getSkipListNodeRandomHeight(pSkipList);
if (level > pSkipList->level) {
if (pSkipList->level < pSkipList->maxLevel) {
level = pSkipList->level + 1;
} else {
level = pSkipList->level;
}
}
}
return level;
}
// when order is TSDB_ORDER_ASC, return the last node with key less than val
// when order is TSDB_ORDER_DESC, return the first node with key large than val
static SSkipListNode *getPriorNode(SSkipList *pSkipList, const char *val, int32_t order, SSkipListNode **pCur) {
__compar_fn_t comparFn = pSkipList->comparFn;
SSkipListNode *pNode = NULL;
if (pCur != NULL) {
*pCur = NULL;
}
if (order == TSDB_ORDER_ASC) {
pNode = pSkipList->pHead;
for (int32_t i = pSkipList->level - 1; i >= 0; --i) {
SSkipListNode *p = SL_NODE_GET_FORWARD_POINTER(pNode, i);
while (p != pSkipList->pTail) {
char *key = SL_GET_NODE_KEY(pSkipList, p);
if (comparFn(key, val) < 0) {
pNode = p;
p = SL_NODE_GET_FORWARD_POINTER(p, i);
} else {
if (pCur != NULL) {
*pCur = p;
}
break;
}
}
}
} else {
pNode = pSkipList->pTail;
for (int32_t i = pSkipList->level - 1; i >= 0; --i) {
SSkipListNode *p = SL_NODE_GET_BACKWARD_POINTER(pNode, i);
while (p != pSkipList->pHead) {
char *key = SL_GET_NODE_KEY(pSkipList, p);
if (comparFn(key, val) > 0) {
pNode = p;
p = SL_NODE_GET_BACKWARD_POINTER(p, i);
} else {
if (pCur != NULL) {
*pCur = p;
}
break;
}
}
}
}
return pNode;
}
static int32_t initForwardBackwardPtr(SSkipList *pSkipList) {
uint32_t maxLevel = pSkipList->maxLevel;
// head info
pSkipList->pHead = tSkipListNewNode(maxLevel);
if (pSkipList->pHead == NULL) return -1;
// tail info
pSkipList->pTail = tSkipListNewNode(maxLevel);
if (pSkipList->pTail == NULL) {
tSkipListFreeNode(pSkipList->pHead);
return -1;
}
for (uint32_t i = 0; i < maxLevel; ++i) {
SL_NODE_GET_FORWARD_POINTER(pSkipList->pHead, i) = pSkipList->pTail;
SL_NODE_GET_BACKWARD_POINTER(pSkipList->pTail, i) = pSkipList->pHead;
}
return 0;
}
static SSkipListNode *tSkipListNewNode(uint8_t level) {
int32_t tsize = sizeof(SSkipListNode) + sizeof(SSkipListNode *) * level * 2;
SSkipListNode *pNode = (SSkipListNode *)taosMemoryCalloc(1, tsize);
if (pNode == NULL) return NULL;
pNode->level = level;
return pNode;
}
static SSkipListNode *tSkipListPutImpl(SSkipList *pSkipList, void *pData, SSkipListNode **direction, bool isForward,
bool hasDup) {
uint8_t dupMode = SL_DUP_MODE(pSkipList);
SSkipListNode *pNode = NULL;
if (hasDup && (dupMode != SL_ALLOW_DUP_KEY)) {
if (dupMode == SL_UPDATE_DUP_KEY) {
if (isForward) {
pNode = SL_NODE_GET_FORWARD_POINTER(direction[0], 0);
} else {
pNode = SL_NODE_GET_BACKWARD_POINTER(direction[0], 0);
}
if (pData) {
atomic_store_ptr(&(pNode->pData), pData);
}
}
} else {
pNode = tSkipListNewNode(getSkipListRandLevel(pSkipList));
if (pNode != NULL) {
pNode->pData = pData;
tSkipListDoInsert(pSkipList, direction, pNode, isForward);
}
}
return pNode;
}