sskiplist.h 6.4 KB
Newer Older
H
hzcheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 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/>.
 */
15
#if 0
H
hzcheng 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206

#ifndef TBASE_TSKIPLIST_H
#define TBASE_TSKIPLIST_H

#ifdef __cplusplus
extern "C" {
#endif

#define MAX_SKIP_LIST_LEVEL 20

#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>

#include "os.h"
#include "ttypes.h"

/*
 * key of each node
 * todo move to as the global structure in all search codes...
 */

const static size_t SKIP_LIST_STR_KEY_LENGTH_THRESHOLD = 15;
typedef tVariant    tSkipListKey;

typedef enum tSkipListPointQueryType {
  INCLUDE_POINT_QUERY,
  EXCLUDE_POINT_QUERY,
} tSkipListPointQueryType;

typedef struct tSkipListNode {
  uint16_t nLevel;
  char *   pData;

  struct tSkipListNode **pForward;
  struct tSkipListNode **pBackward;

  tSkipListKey key;
} tSkipListNode;

/*
 * @version 0.2
 * @date   2017/11/12
 * the simple version of SkipList.
 * for multi-thread safe purpose, we employ pthread_rwlock_t to guarantee to generate
 * 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.
 *
 * Note: Duplicated primary key situation.
 * In case of duplicated primary key, two ways can be employed to handle this situation:
 * 1. add as normal insertion with out 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.
 *    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.
 *
 * 3. use the iterator pattern to refactor all routines to make it more clean
 */

// 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 {
  // in bytes, sizeof(tSkipList)+sizeof(tSkipListNode)*tSkipList->nSize
  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;

typedef struct tSkipList {
  tSkipListNode pHead;
  uint64_t      nSize;
  uint16_t      nMaxLevel;
  uint16_t      nLevel;
  uint16_t      keyType;
  uint16_t      nMaxKeyLen;

  __compar_fn_t    comparator;
  pthread_rwlock_t lock;   // will be removed soon
  tSkipListState   state;  // skiplist state
} tSkipList;

/*
 * 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
 * TODO add the ref for skiplist when one iterator is created
 */
typedef struct SSkipListIterator {
  tSkipList *    pSkipList;
  tSkipListNode *cur;
  int64_t        num;
} SSkipListIterator;

/*
 * query condition structure to denote the range query
 * todo merge the point query cond with range query condition
 */
typedef struct tSKipListQueryCond {
  // when the upper bounding == lower bounding, it is a point query
  tSkipListKey lowerBnd;
  tSkipListKey upperBnd;
  int32_t      lowerBndRelOptr;  // relation operator to denote if lower bound is
  int32_t      upperBndRelOptr;  // included or not
} tSKipListQueryCond;

tSkipList *SSkipListCreate(int16_t nMaxLevel, int16_t keyType, int16_t nMaxKeyLen);

void *SSkipListDestroy(tSkipList *pSkipList);

// create skip list key
tSkipListKey SSkipListCreateKey(int32_t type, char *val, size_t keyLength);

// destroy skip list key
void tSkipListDestroyKey(tSkipListKey *pKey);

// put data into skiplist
tSkipListNode *SSkipListPut(tSkipList *pSkipList, void *pData, tSkipListKey *pKey, int32_t insertIdenticalKey);

/*
 * get only *one* node of which key is equalled to pKey, even there are more
 * than one nodes are of the same key
 */
tSkipListNode *tSkipListGetOne(tSkipList *pSkipList, tSkipListKey *pKey);

/*
 * get all data with the same keys
 */
int32_t tSkipListGets(tSkipList *pSkipList, tSkipListKey *pKey, tSkipListNode ***pRes);

int32_t tSkipListIterateList(tSkipList *pSkipList, tSkipListNode ***pRes, bool (*fp)(tSkipListNode *, void *),
                             void *param);

/*
 * 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
 */
bool tSkipListRemove(tSkipList *pSkipList, tSkipListKey *pKey);

/*
 * remove the specified node in parameters
 */
void tSkipListRemoveNode(tSkipList *pSkipList, tSkipListNode *pNode);

// for debug purpose only
void SSkipListPrint(tSkipList *pSkipList, int16_t nlevel);

/*
 * range query & single point query function
 */
int32_t tSkipListQuery(tSkipList *pSkipList, tSKipListQueryCond *pQueryCond, tSkipListNode ***pResult);

/*
 * include/exclude point query
 */
int32_t tSkipListPointQuery(tSkipList *pSkipList, tSkipListKey *pKey, int32_t numOfKey, tSkipListPointQueryType type,
                            tSkipListNode ***pResult);

int32_t tSkipListIteratorReset(tSkipList *pSkipList, SSkipListIterator *iter);
bool tSkipListIteratorNext(SSkipListIterator *iter);
tSkipListNode *tSkipListIteratorGet(SSkipListIterator *iter);

#ifdef __cplusplus
}
#endif

#endif  // TBASE_TSKIPLIST_H
207
#endif