tskiplist.h 7.0 KB
Newer Older
H
hzcheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * 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 TBASE_TSKIPLIST_H
#define TBASE_TSKIPLIST_H

#ifdef __cplusplus
extern "C" {
#endif

S
slguan 已提交
23
#include "os.h"
H
hzcheng 已提交
24
#include "taosdef.h"
H
more  
hzcheng 已提交
25
#include "tarray.h"
H
hzcheng 已提交
26 27 28 29 30

/*
 * key of each node
 * todo move to as the global structure in all search codes...
 */
H
more  
hzcheng 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#define MAX_SKIP_LIST_LEVEL 15
#define SKIP_LIST_RECORD_PERFORMANCE 0

typedef char *SSkipListKey;
typedef char *(*__sl_key_fn_t)(const void *);

/**
 * the format of skip list node is as follows:
 * +------------+-----------------------+------------------------+-----+------+
 * | node level | forward pointer array | backward pointer array | key | data |
 * +------------+-----------------------+------------------------+-----+------+
 * the skiplist node is located in a consecutive memory area, key will not be copy to skip list
 */
typedef struct SSkipListNode {
  uint8_t level;
} SSkipListNode;
H
hzcheng 已提交
47

H
more  
hzcheng 已提交
48
#define SL_NODE_HEADER_SIZE(_l) (sizeof(SSkipListNode) + ((_l) << 1u) * POINTER_BYTES)
H
hzcheng 已提交
49

H
more  
hzcheng 已提交
50 51 52
#define SL_GET_FORWARD_POINTER(n, _l) ((SSkipListNode **)((char *)(n) + sizeof(SSkipListNode)))[(_l)]
#define SL_GET_BACKWARD_POINTER(n, _l) \
  ((SSkipListNode **)((char *)(n) + sizeof(SSkipListNode) + ((n)->level) * POINTER_BYTES))[(_l)]
H
hzcheng 已提交
53

H
more  
hzcheng 已提交
54 55
#define SL_GET_NODE_DATA(n) ((char*)(n) + SL_NODE_HEADER_SIZE((n)->level))
#define SL_GET_NODE_KEY(s, n) ((s)->keyFn(SL_GET_NODE_DATA(n)))
56

H
hzcheng 已提交
57
#define SL_GET_NODE_LEVEL(n) *(uint8_t *)((n))
H
hzcheng 已提交
58 59

/*
H
more  
hzcheng 已提交
60
 * @version 0.3
H
hzcheng 已提交
61
 * @date   2017/11/12
H
more  
hzcheng 已提交
62 63
 * the simple version of skip list.
 *
S
slguan 已提交
64
 * for multi-thread safe purpose, we employ pthread_rwlock_t to guarantee to generate
H
more  
hzcheng 已提交
65 66 67
 * deterministic result. Later, we will remove the lock in SkipList to further enhance the performance.
 * In this case, one should use the concurrent skip list (by using michael-scott algorithm) instead of
 * this simple version in a multi-thread environment, to achieve higher performance of read/write operations.
H
hzcheng 已提交
68 69
 *
 * Note: Duplicated primary key situation.
S
slguan 已提交
70
 * In case of duplicated primary key, two ways can be employed to handle this situation:
H
more  
hzcheng 已提交
71 72 73
 * 1. add as normal insertion without special process.
 * 2. add an overflow pointer at each list node, all nodes with the same key will be added in the overflow pointer.
 *    In this case, the total steps of each search will be reduced significantly.
S
slguan 已提交
74 75 76 77
 *    Currently, we implement the skip list in a line with the first means, maybe refactor it soon.
 *
 *    Memory consumption: the memory alignment causes many memory wasted. So, employ a memory
 *    pool will significantly reduce the total memory consumption, as well as the calloc/malloc operation costs.
H
hzcheng 已提交
78 79 80 81 82 83 84 85 86
 *
 */

// state struct, record following information:
// number of links in each level.
// avg search steps, for latest 1000 queries
// avg search rsp time, for latest 1000 queries
// total memory size
typedef struct tSkipListState {
H
more  
hzcheng 已提交
87
  // in bytes, sizeof(SSkipList)+sizeof(SSkipListNode)*SSkipList->nSize
H
hzcheng 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
  uint64_t nTotalMemSize;
  uint64_t nLevelNodeCnt[MAX_SKIP_LIST_LEVEL];
  uint64_t queryCount;  // total query count

  /*
   * only record latest 1000 queries
   * when the value==1000, = 0,
   * nTotalStepsForQueries = 0,
   * nTotalElapsedTimeForQueries = 0
   */
  uint64_t nRecQueries;
  uint16_t nTotalStepsForQueries;
  uint64_t nTotalElapsedTimeForQueries;

  uint16_t nInsertObjs;
  uint16_t nTotalStepsForInsert;
  uint64_t nTotalElapsedTimeForInsert;
} tSkipListState;

H
more  
hzcheng 已提交
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
typedef struct SSkipListKeyInfo {
  uint8_t dupKey : 2;  // if allow duplicated key in the skip list
  uint8_t type : 6;    // key type
  uint8_t len;         // maximum key length, used in case of string key
} SSkipListKeyInfo;

typedef struct SSkipList {
  __compar_fn_t    comparFn;
  __sl_key_fn_t    keyFn;
  uint32_t         size;
  uint8_t          maxLevel;
  uint8_t          level;
  SSkipListKeyInfo keyInfo;

  pthread_rwlock_t *lock;
  SSkipListNode *   pHead;

#if SKIP_LIST_RECORD_PERFORMANCE
  tSkipListState state;  // skiplist state
#endif
H
hzcheng 已提交
127

H
more  
hzcheng 已提交
128
} SSkipList;
H
hzcheng 已提交
129

S
slguan 已提交
130 131 132 133
/*
 * iterate the skiplist
 * this will cause the multi-thread problem, when the skiplist is destroyed, the iterate may
 * continue iterating the skiplist, so add the reference count for skiplist
H
more  
hzcheng 已提交
134
 * TODO add the ref for skip list when one iterator is created
S
slguan 已提交
135 136
 */
typedef struct SSkipListIterator {
H
more  
hzcheng 已提交
137 138
  SSkipList *    pSkipList;
  SSkipListNode *cur;
S
slguan 已提交
139 140 141
  int64_t        num;
} SSkipListIterator;

H
more  
hzcheng 已提交
142 143 144 145 146 147
/**
 *
 * @param nMaxLevel   maximum skip list level
 * @param keyType     type of key
 * @param dupKey      allow the duplicated key in the skip list
 * @return
H
hzcheng 已提交
148
 */
H
more  
hzcheng 已提交
149 150
SSkipList *tSkipListCreate(uint8_t nMaxLevel, uint8_t keyType, uint8_t keyLen, uint8_t dupKey, uint8_t threadsafe,
                           __sl_key_fn_t fn);
H
hzcheng 已提交
151

H
more  
hzcheng 已提交
152 153 154 155 156 157
/**
 *
 * @param pSkipList
 * @return                NULL will always be returned
 */
void *tSkipListDestroy(SSkipList *pSkipList);
H
hzcheng 已提交
158

H
more  
hzcheng 已提交
159 160 161 162 163 164 165
/**
 *
 * @param pSkipList
 * @param level
 * @param headSize
 */
void tSkipListRandNodeInfo(SSkipList *pSkipList, int32_t *level, int32_t *headSize);
H
hzcheng 已提交
166

H
more  
hzcheng 已提交
167 168 169 170 171 172 173
/**
 * put the skip list node into the skip list.
 * If failed, NULL will be returned, otherwise, the pNode will be returned.
 *
 * @param pSkipList
 * @param pNode
 * @return
H
hzcheng 已提交
174
 */
H
more  
hzcheng 已提交
175
SSkipListNode *tSkipListPut(SSkipList *pSkipList, SSkipListNode *pNode);
H
hzcheng 已提交
176

H
more  
hzcheng 已提交
177 178 179 180 181 182 183
/**
 * get only *one* node of which key is equalled to pKey, even there are more than one nodes are of the same key
 *
 * @param pSkipList
 * @param pKey
 * @param keyType
 * @return
H
hzcheng 已提交
184
 */
H
more  
hzcheng 已提交
185
SArray* tSkipListGet(SSkipList *pSkipList, SSkipListKey pKey, int16_t keyType);
H
hzcheng 已提交
186

H
more  
hzcheng 已提交
187
/**
H
hjxilinx 已提交
188
 * get the size of skip list
H
more  
hzcheng 已提交
189 190 191
 * @param pSkipList
 * @return
 */
H
hjxilinx 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
size_t tSkipListGetSize(const SSkipList* pSkipList);

/**
 * create skiplist iterator
 * @param pSkipList
 * @return
 */
SSkipListIterator* tSkipListCreateIter(SSkipList *pSkipList);

/**
 * forward the skip list iterator
 * @param iter
 * @return
 */
bool tSkipListIterNext(SSkipListIterator *iter);

/**
 * get the element of skip list node
 * @param iter
 * @return
 */
SSkipListNode *tSkipListIterGet(SSkipListIterator *iter);

/**
 * destroy the skip list node
 * @param iter
 * @return
 */
void* tSkipListDestroyIter(SSkipListIterator* iter);
H
hzcheng 已提交
221 222 223 224 225 226 227 228 229

/*
 * remove only one node of the pKey value.
 * If more than one node has the same value, any one will be removed
 *
 * @Return
 * true: one node has been removed
 * false: no node has been removed
 */
H
more  
hzcheng 已提交
230
bool tSkipListRemove(SSkipList *pSkipList, SSkipListKey *pKey);
H
hzcheng 已提交
231 232 233 234

/*
 * remove the specified node in parameters
 */
H
more  
hzcheng 已提交
235
void tSkipListRemoveNode(SSkipList *pSkipList, SSkipListNode *pNode);
H
hzcheng 已提交
236

S
slguan 已提交
237

H
hzcheng 已提交
238 239 240 241 242
#ifdef __cplusplus
}
#endif

#endif  // TBASE_TSKIPLIST_H