• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #5034

24 Apr 2026 11:25AM UTC coverage: 73.058%. Remained the same
#5034

push

travis-ci

web-flow
merge: from main to 3.0 branch #35224

merge: from main to 3.0 branch[manual-only]

1336 of 1975 new or added lines in 48 files covered. (67.65%)

14149 existing lines in 164 files now uncovered.

275896 of 377640 relevant lines covered (73.06%)

132944440.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.14
/source/util/src/thash.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15

16
#define _DEFAULT_SOURCE
17
#include "thash.h"
18
#include "os.h"
19
#include "taoserror.h"
20
#include "tlog.h"
21

22
// the add ref count operation may trigger the warning if the reference count is greater than the MAX_WARNING_REF_COUNT
23
#define MAX_WARNING_REF_COUNT    10000
24
#define HASH_MAX_CAPACITY        (1024 * 1024 * 1024)
25
#define HASH_DEFAULT_LOAD_FACTOR (0.75)
26
#define HASH_INDEX(v, c)         ((v) & ((c)-1))
27

28
#define HASH_NEED_RESIZE(_h) ((_h)->size >= (_h)->capacity * HASH_DEFAULT_LOAD_FACTOR)
29

30
#define GET_HASH_NODE_KEY(_n)  ((char *)(_n) + sizeof(SHashNode) + (_n)->dataLen)
31
#define GET_HASH_NODE_DATA(_n) ((char *)(_n) + sizeof(SHashNode))
32
#define GET_HASH_PNODE(_n)     ((SHashNode *)((char *)(_n) - sizeof(SHashNode)))
33

34
#define FREE_HASH_NODE(_fp, _n)                              \
35
  do {                                                       \
36
    if (_fp != NULL && (((SHashNode *)(_n))->dataLen > 0)) { \
37
      (_fp)(GET_HASH_NODE_DATA(_n));                         \
38
    }                                                        \
39
    taosMemoryFreeClear(_n);                                 \
40
  } while (0);
41

42
struct SHashNode {
43
  SHashNode *next;
44
  uint32_t   hashVal;   // the hash value of key
45
  uint32_t   dataLen;   // length of data
46
  uint32_t   keyLen;    // length of the key
47
  uint16_t   refCount;  // reference count
48
  int8_t     removed;   // flag to indicate removed
49
#ifdef TD_ASTRA_32
50
  uint32_t paddingAligned;
51
#endif
52
  char data[];
53
};
54

55
typedef struct SHashEntry {
56
  int32_t    num;    // number of elements in current entry
57
  SRWLatch   latch;  // entry latch
58
  SHashNode *next;
59
} SHashEntry;
60

61
struct SHashObj {
62
  int64_t           size;          // number of elements in hash table
63
  size_t            capacity;      // number of slots
64
  SHashEntry      **hashList;
65
  _hash_fn_t        hashFp;        // hash function
66
  _equal_fn_t       equalFp;       // equal function
67
  _hash_free_fn_t   freeFp;        // hash node free callback function
68
  SRWLatch          lock;          // read-write spin lock
69
  SHashLockTypeE    type;          // lock type
70
  bool              enableUpdate;  // enable update
71
  SArray           *pMemBlock;     // memory block allocated for SHashEntry
72
  _hash_before_fn_t callbackFp;    // function invoked before return the value to caller
73
  //  int64_t           compTimes;
74
};
75

76
/*
77
 * Function definition
78
 */
79
static FORCE_INLINE void taosHashWLock(SHashObj *pHashObj) {
80
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
81
    return;
2,147,483,647✔
82
  }
83
  taosWLockLatch(&pHashObj->lock);
2,147,483,647✔
84
}
85

86
static FORCE_INLINE void taosHashWUnlock(SHashObj *pHashObj) {
87
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
88
    return;
2,147,483,647✔
89
  }
90

91
  taosWUnLockLatch(&pHashObj->lock);
2,147,483,647✔
92
}
93

94
static FORCE_INLINE void taosHashRLock(SHashObj *pHashObj) {
95
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
96
    return;
2,147,483,647✔
97
  }
98

99
  taosRLockLatch(&pHashObj->lock);
2,147,483,647✔
100
}
101

102
static FORCE_INLINE void taosHashRUnlock(SHashObj *pHashObj) {
103
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
104
    return;
2,147,483,647✔
105
  }
106

107
  taosRUnLockLatch(&pHashObj->lock);
2,147,483,647✔
108
}
109

110
static FORCE_INLINE void taosHashEntryWLock(const SHashObj *pHashObj, SHashEntry *pe) {
111
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
112
    return;
2,147,483,647✔
113
  }
114
  taosWLockLatch(&pe->latch);
2,147,483,647✔
115
}
116

117
static FORCE_INLINE void taosHashEntryWUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
118
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
119
    return;
2,147,483,647✔
120
  }
121

122
  taosWUnLockLatch(&pe->latch);
2,147,483,647✔
123
}
124

125
static FORCE_INLINE void taosHashEntryRLock(const SHashObj *pHashObj, SHashEntry *pe) {
126
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
127
    return;
2,147,483,647✔
128
  }
129

130
  taosRLockLatch(&pe->latch);
2,147,483,647✔
131
}
132

133
static FORCE_INLINE void taosHashEntryRUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
134
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
135
    return;
2,147,483,647✔
136
  }
137

138
  taosRUnLockLatch(&pe->latch);
2,147,483,647✔
139
}
140

141
static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
142
  int32_t len = (length < HASH_MAX_CAPACITY ? length : HASH_MAX_CAPACITY);
2,147,483,647✔
143

144
  int32_t i = 4;
2,147,483,647✔
145
  while (i < len) i = (i << 1u);
2,147,483,647✔
146
  return i;
2,147,483,647✔
147
}
148

149
static FORCE_INLINE SHashNode *doSearchInEntryList(SHashObj *pHashObj, SHashEntry *pe, const void *key, size_t keyLen,
150
                                                   uint32_t hashVal) {
151
  SHashNode *pNode = pe->next;
2,147,483,647✔
152
  while (pNode) {
2,147,483,647✔
153
    // atomic_add_fetch_64(&pHashObj->compTimes, 1);
154
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
2,147,483,647✔
155
        pNode->removed == 0) {
2,147,483,647✔
156
      break;
2,147,483,647✔
157
    }
158

159
    pNode = pNode->next;
2,147,483,647✔
160
  }
161

162
  return pNode;
2,147,483,647✔
163
}
164

165
/**
166
 * resize the hash list if the threshold is reached
167
 *
168
 * @param pHashObj
169
 */
170
static void taosHashTableResize(SHashObj *pHashObj);
171

172
/**
173
 * allocate and initialize a hash node
174
 *
175
 * @param key      key of object for hash, usually a null-terminated string
176
 * @param keyLen   length of key
177
 * @param pData    data to be stored in hash node
178
 * @param dsize    size of data
179
 * @return         SHashNode
180
 */
181
static SHashNode *doCreateHashNode(const void *key, size_t keyLen, const void *pData, size_t dsize, uint32_t hashVal);
182

183
/**
184
 * update the hash node
185
 *
186
 * @param pHashObj   hash table object
187
 * @param pe         hash table entry to operate on
188
 * @param prev       previous node
189
 * @param pNode      the old node with requested key
190
 * @param pNewNode   the new node with requested key
191
 */
192
static FORCE_INLINE void doUpdateHashNode(SHashObj *pHashObj, SHashEntry *pe, SHashNode *prev, SHashNode *pNode,
193
                                          SHashNode *pNewNode) {
194
  (void)atomic_sub_fetch_16(&pNode->refCount, 1);
2,147,483,647✔
195
  if (prev != NULL) {
2,147,483,647✔
196
    prev->next = pNewNode;
241,427,654✔
197
  } else {
198
    pe->next = pNewNode;
2,147,483,647✔
199
  }
200

201
  if (pNode->refCount <= 0) {
2,147,483,647✔
202
    pNewNode->next = pNode->next;
2,147,483,647✔
203

204
    FREE_HASH_NODE(pHashObj->freeFp, pNode);
2,147,483,647✔
205
  } else {
UNCOV
206
    pNewNode->next = pNode;
×
UNCOV
207
    pe->num++;
×
UNCOV
208
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
×
209
  }
210
}
2,147,483,647✔
211

212
/**
213
 * insert the hash node at the front of the linked list
214
 *
215
 * @param pHashObj   hash table object
216
 * @param pNode      the old node with requested key
217
 */
218
static void pushfrontNodeInEntryList(SHashEntry *pEntry, SHashNode *pNode);
219

220
/**
221
 * Check whether the hash table is empty or not.
222
 *
223
 * @param pHashObj the hash table object
224
 * @return if the hash table is empty or not
225
 */
226
static FORCE_INLINE bool taosHashTableEmpty(const SHashObj *pHashObj);
227

228
/**
229
 *
230
 * @param pHashObj
231
 * @return
232
 */
233
static FORCE_INLINE bool taosHashTableEmpty(const SHashObj *pHashObj) { return taosHashGetSize(pHashObj) == 0; }
2,147,483,647✔
234

235
SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool update, SHashLockTypeE type) {
2,147,483,647✔
236
  if (fn == NULL) {
2,147,483,647✔
237
    terrno = TSDB_CODE_INVALID_PARA;
×
238
    return NULL;
×
239
  }
240

241
  if (capacity == 0) {
2,147,483,647✔
242
    capacity = 4;
222,490,517✔
243
  }
244

245
  SHashObj *pHashObj = (SHashObj *)taosMemoryMalloc(sizeof(SHashObj));
2,147,483,647✔
246
  if (pHashObj == NULL) {
2,147,483,647✔
247
    return NULL;
×
248
  }
249

250
  // the max slots is not defined by user
251
  pHashObj->capacity = taosHashCapacity((int32_t)capacity);
2,147,483,647✔
252
  pHashObj->size = 0;
2,147,483,647✔
253

254
  pHashObj->equalFp = memcmp;
2,147,483,647✔
255
  pHashObj->hashFp = fn;
2,147,483,647✔
256
  pHashObj->type = type;
2,147,483,647✔
257
  pHashObj->lock = 0;
2,147,483,647✔
258
  pHashObj->enableUpdate = update;
2,147,483,647✔
259
  pHashObj->freeFp = NULL;
2,147,483,647✔
260
  pHashObj->callbackFp = NULL;
2,147,483,647✔
261

262
  pHashObj->hashList = (SHashEntry **)taosMemoryMalloc(pHashObj->capacity * sizeof(void *));
2,147,483,647✔
263
  if (pHashObj->hashList == NULL) {
2,147,483,647✔
264
    taosMemoryFree(pHashObj);
×
265
    return NULL;
×
266
  }
267

268
  pHashObj->pMemBlock = taosArrayInit(8, sizeof(void *));
2,147,483,647✔
269
  if (pHashObj->pMemBlock == NULL) {
2,147,483,647✔
270
    taosMemoryFree(pHashObj->hashList);
×
271
    taosMemoryFree(pHashObj);
×
272
    return NULL;
×
273
  }
274

275
  void *p = taosMemoryMalloc(pHashObj->capacity * sizeof(SHashEntry));
2,147,483,647✔
276
  if (p == NULL) {
2,147,483,647✔
277
    taosArrayDestroy(pHashObj->pMemBlock);
×
278
    taosMemoryFree(pHashObj->hashList);
×
279
    taosMemoryFree(pHashObj);
×
280
    return NULL;
×
281
  }
282

283
  for (int32_t i = 0; i < pHashObj->capacity; ++i) {
2,147,483,647✔
284
    pHashObj->hashList[i] = (void *)((char *)p + i * sizeof(SHashEntry));
2,147,483,647✔
285
    pHashObj->hashList[i]->num = 0;
2,147,483,647✔
286
    pHashObj->hashList[i]->latch = 0;
2,147,483,647✔
287
    pHashObj->hashList[i]->next = NULL;
2,147,483,647✔
288
  }
289

290
  if (taosArrayPush(pHashObj->pMemBlock, &p) == NULL) {
2,147,483,647✔
291
    taosMemoryFree(p);
×
292
    taosArrayDestroy(pHashObj->pMemBlock);
×
293
    taosMemoryFree(pHashObj->hashList);
×
294
    taosMemoryFree(pHashObj);
×
295
    return NULL;
×
296
  }
297
  return pHashObj;
2,147,483,647✔
298
}
299

300
void taosHashSetEqualFp(SHashObj *pHashObj, _equal_fn_t fp) {
13,756,310✔
301
  if (pHashObj != NULL && fp != NULL) {
13,756,310✔
302
    pHashObj->equalFp = fp;
13,756,873✔
303
  }
304
}
13,756,310✔
305

306
void taosHashSetFreeFp(SHashObj *pHashObj, _hash_free_fn_t fp) {
1,530,315,406✔
307
  if (pHashObj != NULL && fp != NULL) {
1,530,315,406✔
308
    pHashObj->freeFp = fp;
1,530,342,336✔
309
  }
310
}
1,530,317,936✔
311

312
int32_t taosHashGetSize(const SHashObj *pHashObj) {
2,147,483,647✔
313
  if (pHashObj == NULL) {
2,147,483,647✔
314
    return 0;
513,468,138✔
315
  }
316
  return (int32_t)atomic_load_64((int64_t *)&pHashObj->size);
2,147,483,647✔
317
}
318

319
int32_t taosHashPut(SHashObj *pHashObj, const void *key, size_t keyLen, const void *data, size_t size) {
2,147,483,647✔
320
  if (pHashObj == NULL || key == NULL || keyLen == 0) {
2,147,483,647✔
321
    return terrno = TSDB_CODE_INVALID_PTR;
126✔
322
  }
323

324
  int32_t     code = TSDB_CODE_SUCCESS;
2,147,483,647✔
325
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
2,147,483,647✔
326

327
  // need the resize process, write lock applied
328
  if (HASH_NEED_RESIZE(pHashObj)) {
2,147,483,647✔
329
    taosHashWLock(pHashObj);
330
    taosHashTableResize(pHashObj);
334,428,554✔
331
    taosHashWUnlock(pHashObj);
332
  }
333

334
  SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
2,147,483,647✔
335
  if (pNewNode == NULL) {
2,147,483,647✔
336
    code = terrno;
×
337
    return code;
×
338
  }
339

340
  // disable resize
341
  taosHashRLock(pHashObj);
342

343
  uint32_t    slot = HASH_INDEX(hashVal, pHashObj->capacity);
2,147,483,647✔
344
  SHashEntry *pe = pHashObj->hashList[slot];
2,147,483,647✔
345

346
  taosHashEntryWLock(pHashObj, pe);
347

348
  SHashNode *pNode = pe->next;
2,147,483,647✔
349
  SHashNode *prev = NULL;
2,147,483,647✔
350
  while (pNode) {
2,147,483,647✔
351
    if ((pNode->keyLen == keyLen) && (*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0 &&
2,147,483,647✔
352
        pNode->removed == 0) {
2,147,483,647✔
353
      break;
2,147,483,647✔
354
    }
355

356
    prev = pNode;
2,147,483,647✔
357
    pNode = pNode->next;
2,147,483,647✔
358
  }
359

360
  if (pNode == NULL) {
2,147,483,647✔
361
    // no data in hash table with the specified key, add it into hash table
362
    pushfrontNodeInEntryList(pe, pNewNode);
2,147,483,647✔
363
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
2,147,483,647✔
364
  } else {
365
    // not support the update operation, return error
366
    if (pHashObj->enableUpdate) {
2,147,483,647✔
367
      doUpdateHashNode(pHashObj, pe, prev, pNode, pNewNode);
368
    } else {
369
      taosMemoryFreeClear(pNewNode);
10,584,240✔
370
      terrno = TSDB_CODE_DUP_KEY;
10,578,964✔
371
      code = terrno;
12,228,616✔
372
      goto _exit;
12,228,059✔
373
    }
374
  }
375
  
376
_exit:
2,147,483,647✔
377

378
  taosHashEntryWUnlock(pHashObj, pe);
379
  taosHashRUnlock(pHashObj);
380
  return code;
2,147,483,647✔
381
}
382

383
static void *taosHashGetImpl(SHashObj *pHashObj, const void *key, size_t keyLen, void **d, int32_t *size, bool addRef);
384

385
void *taosHashGet(SHashObj *pHashObj, const void *key, size_t keyLen) {
2,147,483,647✔
386
  void *p = NULL;
2,147,483,647✔
387
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, false);
2,147,483,647✔
388
}
389

390
int32_t taosHashGetDup(SHashObj *pHashObj, const void *key, size_t keyLen, void *destBuf) {
2,147,483,647✔
391
  terrno = 0;
2,147,483,647✔
392
  void *data = taosHashGetImpl(pHashObj, key, keyLen, &destBuf, 0, false);
2,147,483,647✔
393
  return terrno;
2,147,483,647✔
394
}
395

396
int32_t taosHashGetDup_m(SHashObj *pHashObj, const void *key, size_t keyLen, void **destBuf, int32_t *size) {
×
397
  terrno = 0;
×
398
  void *data = taosHashGetImpl(pHashObj, key, keyLen, destBuf, size, false);
×
399
  return terrno;
×
400
}
401

402
void *taosHashGetImpl(SHashObj *pHashObj, const void *key, size_t keyLen, void **d, int32_t *size, bool addRef) {
2,147,483,647✔
403
  if (pHashObj == NULL || keyLen == 0 || key == NULL) {
2,147,483,647✔
404
    terrno = TSDB_CODE_INVALID_PTR;
2,147,483,647✔
405
    return NULL;
2,147,483,647✔
406
  }
407

408
  if ((atomic_load_64((int64_t *)&pHashObj->size) == 0)) {
2,147,483,647✔
409
    return NULL;
2,147,483,647✔
410
  }
411

412
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
2,147,483,647✔
413

414
  // only add the read lock to disable the resize process
415
  taosHashRLock(pHashObj);
416

417
  int32_t     slot = HASH_INDEX(hashVal, pHashObj->capacity);
2,147,483,647✔
418
  SHashEntry *pe = pHashObj->hashList[slot];
2,147,483,647✔
419

420
  // no data, return directly
421
  if (atomic_load_32(&pe->num) == 0) {
2,147,483,647✔
422
    taosHashRUnlock(pHashObj);
423
    return NULL;
2,147,483,647✔
424
  }
425

426
  char *data = NULL;
2,147,483,647✔
427
  taosHashEntryRLock(pHashObj, pe);
428

429
  SHashNode *pNode = doSearchInEntryList(pHashObj, pe, key, keyLen, hashVal);
2,147,483,647✔
430
  if (pNode != NULL) {
2,147,483,647✔
431
    if (pHashObj->callbackFp != NULL) {
2,147,483,647✔
432
      pHashObj->callbackFp(GET_HASH_NODE_DATA(pNode));
×
433
    }
434

435
    if (size != NULL) {
2,147,483,647✔
436
      if (*d == NULL) {
×
437
        *size = pNode->dataLen;
×
438
        *d = taosMemoryCalloc(1, *size);
×
439
        if (*d == NULL) {
×
440
          return NULL;
×
441
        }
442
      } else if (*size < pNode->dataLen) {
×
443
        *size = pNode->dataLen;
×
444
        char *tmp = taosMemoryRealloc(*d, *size);
×
445
        if (tmp == NULL) {
×
446
          return NULL;
×
447
        }
448

449
        *d = tmp;
×
450
      }
451
    }
452

453
    if (addRef) {
2,147,483,647✔
454
      (void)atomic_add_fetch_16(&pNode->refCount, 1);
2,147,483,647✔
455
    }
456

457
    if (*d != NULL) {
2,147,483,647✔
458
      memcpy(*d, GET_HASH_NODE_DATA(pNode), pNode->dataLen);
2,147,483,647✔
459
    }
460

461
    data = GET_HASH_NODE_DATA(pNode);
2,147,483,647✔
462
  }
463

464
  taosHashEntryRUnlock(pHashObj, pe);
465
  taosHashRUnlock(pHashObj);
466

467
  return data;
2,147,483,647✔
468
}
469

470
int32_t taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
2,147,483,647✔
471
  if (pHashObj == NULL || taosHashTableEmpty(pHashObj) || key == NULL || keyLen == 0) {
2,147,483,647✔
472
    return TSDB_CODE_INVALID_PARA;
113,317,931✔
473
  }
474

475
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
2,147,483,647✔
476

477
  // disable the resize process
478
  taosHashRLock(pHashObj);
479

480
  int32_t     slot = HASH_INDEX(hashVal, pHashObj->capacity);
2,147,483,647✔
481
  SHashEntry *pe = pHashObj->hashList[slot];
2,147,483,647✔
482

483
  taosHashEntryWLock(pHashObj, pe);
484

485
  // double check after locked
486
  if (pe->num == 0) {
2,147,483,647✔
487
    taosHashEntryWUnlock(pHashObj, pe);
488
    taosHashRUnlock(pHashObj);
489
    return TSDB_CODE_NOT_FOUND;
547,956✔
490
  }
491

492
  int        code = TSDB_CODE_NOT_FOUND;
2,147,483,647✔
493
  SHashNode *pNode = pe->next;
2,147,483,647✔
494
  SHashNode *prevNode = NULL;
2,147,483,647✔
495

496
  while (pNode) {
2,147,483,647✔
497
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
2,147,483,647✔
498
        pNode->removed == 0) {
2,147,483,647✔
499
      code = 0;  // it is found
2,147,483,647✔
500

501
      (void)atomic_sub_fetch_16(&pNode->refCount, 1);
2,147,483,647✔
502
      pNode->removed = 1;
2,147,483,647✔
503
      if (pNode->refCount <= 0) {
2,147,483,647✔
504
        if (prevNode == NULL) {
2,147,483,647✔
505
          pe->next = pNode->next;
2,147,483,647✔
506
        } else {
507
          prevNode->next = pNode->next;
13,350,165✔
508
        }
509

510
        pe->num--;
2,147,483,647✔
511
        (void)atomic_sub_fetch_64(&pHashObj->size, 1);
2,147,483,647✔
512
        FREE_HASH_NODE(pHashObj->freeFp, pNode);
2,147,483,647✔
513
      }
514
    } else {
515
      prevNode = pNode;
518,323,251✔
516
      pNode = pNode->next;
518,323,251✔
517
    }
518
  }
519

520
  taosHashEntryWUnlock(pHashObj, pe);
521
  taosHashRUnlock(pHashObj);
522

523
  return code;
2,147,483,647✔
524
}
525

526
void taosHashClear(SHashObj *pHashObj) {
2,147,483,647✔
527
  if (pHashObj == NULL) {
2,147,483,647✔
528
    return;
884,121,907✔
529
  }
530

531
  SHashNode *pNode, *pNext;
532

533
  taosHashWLock(pHashObj);
534

535
  for (int32_t i = 0; i < pHashObj->capacity; ++i) {
2,147,483,647✔
536
    SHashEntry *pEntry = pHashObj->hashList[i];
2,147,483,647✔
537
    if (pEntry->num == 0) {
2,147,483,647✔
538
      continue;
2,147,483,647✔
539
    }
540

541
    pNode = pEntry->next;
2,147,483,647✔
542
    while (pNode) {
2,147,483,647✔
543
      pNext = pNode->next;
2,147,483,647✔
544
      FREE_HASH_NODE(pHashObj->freeFp, pNode);
2,147,483,647✔
545

546
      pNode = pNext;
2,147,483,647✔
547
    }
548

549
    pEntry->num = 0;
2,147,483,647✔
550
    pEntry->next = NULL;
2,147,483,647✔
551
  }
552

553
  pHashObj->size = 0;
2,147,483,647✔
554
  taosHashWUnlock(pHashObj);
555
}
556

557
// the input paras should be SHashObj **, so the origin input will be set by taosMemoryFreeClear(*pHashObj)
558
void taosHashCleanup(SHashObj *pHashObj) {
2,147,483,647✔
559
  if (pHashObj == NULL) {
2,147,483,647✔
560
    return;
2,147,483,647✔
561
  }
562

563
  taosHashClear(pHashObj);
2,147,483,647✔
564
  taosMemoryFreeClear(pHashObj->hashList);
2,147,483,647✔
565

566
  // destroy mem block
567
  size_t memBlock = taosArrayGetSize(pHashObj->pMemBlock);
2,147,483,647✔
568
  for (int32_t i = 0; i < memBlock; ++i) {
2,147,483,647✔
569
    void *p = taosArrayGetP(pHashObj->pMemBlock, i);
2,147,483,647✔
570
    taosMemoryFreeClear(p);
2,147,483,647✔
571
  }
572

573
  taosArrayDestroy(pHashObj->pMemBlock);
2,147,483,647✔
574
  taosMemoryFree(pHashObj);
2,147,483,647✔
575
}
576

577
// for profile only
578
int32_t taosHashGetMaxOverflowLinkLength(const SHashObj *pHashObj) {
×
579
  if (pHashObj == NULL || taosHashTableEmpty(pHashObj)) {
×
580
    return 0;
×
581
  }
582

583
  int32_t num = 0;
×
584

585
  taosHashRLock((SHashObj *)pHashObj);
586
  for (int32_t i = 0; i < pHashObj->size; ++i) {
×
587
    SHashEntry *pEntry = pHashObj->hashList[i];
×
588

589
    // fine grain per entry lock is not held since this is used
590
    // for profiling only and doesn't need an accurate count.
591
    if (num < pEntry->num) {
×
592
      num = pEntry->num;
×
593
    }
594
  }
595

596
  taosHashRUnlock((SHashObj *)pHashObj);
597
  return num;
×
598
}
599

600
void taosHashTableResize(SHashObj *pHashObj) {
334,426,995✔
601
  if (!HASH_NEED_RESIZE(pHashObj)) {
334,426,995✔
602
    return;
13,637✔
603
  }
604

605
  int32_t newCapacity = (int32_t)(pHashObj->capacity << 1u);
334,412,837✔
606
  if (newCapacity > HASH_MAX_CAPACITY) {
334,413,358✔
607
    //    uDebug("current capacity:%zu, maximum capacity:%d, no resize applied due to limitation is reached",
608
    //           pHashObj->capacity, HASH_MAX_CAPACITY);
609
    return;
×
610
  }
611

612
  int64_t      st = taosGetTimestampUs();
334,414,674✔
613
  SHashEntry **pNewEntryList = taosMemoryRealloc(pHashObj->hashList, sizeof(SHashEntry *) * newCapacity);
334,414,674✔
614
  if (pNewEntryList == NULL) {
334,413,863✔
615
    //    uDebug("cache resize failed due to out of memory, capacity remain:%zu", pHashObj->capacity);
616
    return;
×
617
  }
618

619
  pHashObj->hashList = pNewEntryList;
334,413,863✔
620

621
  size_t inc = newCapacity - pHashObj->capacity;
334,414,426✔
622
  void  *p = taosMemoryCalloc(inc, sizeof(SHashEntry));
334,413,629✔
623
  if (p == NULL) {
334,411,364✔
624
    return;
×
625
  }
626

627
  for (int32_t i = 0; i < inc; ++i) {
2,147,483,647✔
628
    pHashObj->hashList[i + pHashObj->capacity] = (void *)((char *)p + i * sizeof(SHashEntry));
2,147,483,647✔
629
  }
630

631
  if (taosArrayPush(pHashObj->pMemBlock, &p) == NULL) {
668,828,468✔
632
    taosMemoryFree(p);
×
633
    return;
×
634
  }
635

636
  pHashObj->capacity = newCapacity;
334,414,984✔
637
  for (int32_t idx = 0; idx < pHashObj->capacity; ++idx) {
2,147,483,647✔
638
    SHashEntry *pe = pHashObj->hashList[idx];
2,147,483,647✔
639
    SHashNode  *pNode;
640
    SHashNode  *pNext;
641
    SHashNode  *pPrev = NULL;
2,147,483,647✔
642

643
    if (pe->num == 0) {
2,147,483,647✔
644
      continue;
2,147,483,647✔
645
    }
646

647
    pNode = pe->next;
2,147,483,647✔
648

649
    while (pNode != NULL) {
2,147,483,647✔
650
      int32_t newIdx = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
2,147,483,647✔
651
      pNext = pNode->next;
2,147,483,647✔
652
      if (newIdx != idx) {
2,147,483,647✔
653
        pe->num -= 1;
2,147,483,647✔
654
        if (pPrev == NULL) {
2,147,483,647✔
655
          pe->next = pNext;
2,087,742,794✔
656
        } else {
657
          pPrev->next = pNext;
315,385,935✔
658
        }
659

660
        SHashEntry *pNewEntry = pHashObj->hashList[newIdx];
2,147,483,647✔
661
        pushfrontNodeInEntryList(pNewEntry, pNode);
2,147,483,647✔
662
      } else {
663
        pPrev = pNode;
2,147,483,647✔
664
      }
665
      pNode = pNext;
2,147,483,647✔
666
    }
667
  }
668

669
  int64_t et = taosGetTimestampUs();
334,413,801✔
670

671
  //  uDebug("hash table resize completed, new capacity:%d, load factor:%f, elapsed time:%fms",
672
  //  (int32_t)pHashObj->capacity,
673
  //         ((double)pHashObj->size) / pHashObj->capacity, (et - st) / 1000.0);
674
}
675

676
SHashNode *doCreateHashNode(const void *key, size_t keyLen, const void *pData, size_t dsize, uint32_t hashVal) {
2,147,483,647✔
677
#ifdef _TD_LOONGARCH_64
678
  SHashNode *pNewNode = taosMemoryCalloc(1, sizeof(SHashNode) + keyLen + dsize + 1);
679
#else
680
  SHashNode *pNewNode = taosMemoryMalloc(sizeof(SHashNode) + keyLen + dsize + 1);
2,147,483,647✔
681
#endif
682

683
  if (pNewNode == NULL) {
2,147,483,647✔
684
    return NULL;
×
685
  }
686

687
  pNewNode->keyLen = (uint32_t)keyLen;
2,147,483,647✔
688
  pNewNode->hashVal = hashVal;
2,147,483,647✔
689
  pNewNode->dataLen = (uint32_t)dsize;
2,147,483,647✔
690
  pNewNode->refCount = 1;
2,147,483,647✔
691
  pNewNode->removed = 0;
2,147,483,647✔
692
  pNewNode->next = NULL;
2,147,483,647✔
693

694
  if (pData) memcpy(GET_HASH_NODE_DATA(pNewNode), pData, dsize);
2,147,483,647✔
695
  memcpy(GET_HASH_NODE_KEY(pNewNode), key, keyLen);
2,147,483,647✔
696

697
  return pNewNode;
2,147,483,647✔
698
}
699

700
void pushfrontNodeInEntryList(SHashEntry *pEntry, SHashNode *pNode) {
2,147,483,647✔
701
  pNode->next = pEntry->next;
2,147,483,647✔
702
  pEntry->next = pNode;
2,147,483,647✔
703
  pEntry->num += 1;
2,147,483,647✔
704
}
2,147,483,647✔
705

706
size_t taosHashGetMemSize(const SHashObj *pHashObj) {
×
707
  if (pHashObj == NULL) {
×
708
    return 0;
×
709
  }
710

711
  return (pHashObj->capacity * (sizeof(SHashEntry) + sizeof(void *))) + sizeof(SHashNode) * taosHashGetSize(pHashObj) +
×
712
         sizeof(SHashObj);
713
}
714

715
void *taosHashGetKey(void *data, size_t *keyLen) {
2,147,483,647✔
716
  SHashNode *node = GET_HASH_PNODE(data);
2,147,483,647✔
717
  if (keyLen != NULL) {
2,147,483,647✔
718
    *keyLen = node->keyLen;
2,147,483,647✔
719
  }
720

721
  return GET_HASH_NODE_KEY(node);
2,147,483,647✔
722
}
723

724
int32_t taosHashGetValueSize(void *data) {
2,096,627,440✔
725
  SHashNode *node = GET_HASH_PNODE(data);
2,096,627,440✔
726
  return node->dataLen;
2,096,627,590✔
727
}
728

729
// release the pNode, return next pNode, and lock the current entry
730
static void *taosHashReleaseNode(SHashObj *pHashObj, void *p, int *slot) {
2,147,483,647✔
731
  SHashNode *pOld = (SHashNode *)GET_HASH_PNODE(p);
2,147,483,647✔
732
  SHashNode *prevNode = NULL;
2,147,483,647✔
733

734
  *slot = HASH_INDEX(pOld->hashVal, pHashObj->capacity);
2,147,483,647✔
735
  SHashEntry *pe = pHashObj->hashList[*slot];
2,147,483,647✔
736

737
  taosHashEntryWLock(pHashObj, pe);
738

739
  SHashNode *pNode = pe->next;
2,147,483,647✔
740
  while (pNode) {
2,147,483,647✔
741
    if (pNode == pOld) break;
2,147,483,647✔
742

743
    prevNode = pNode;
2,147,483,647✔
744
    pNode = pNode->next;
2,147,483,647✔
745
  }
746

747
  if (pNode) {
2,147,483,647✔
748
    pNode = pNode->next;
2,147,483,647✔
749
    while (pNode) {
2,147,483,647✔
750
      if (pNode->removed == 0) break;
2,147,483,647✔
751
      pNode = pNode->next;
21,372✔
752
    }
753

754
    (void)atomic_sub_fetch_16(&pOld->refCount, 1);
2,147,483,647✔
755
    if (pOld->refCount <= 0) {
2,147,483,647✔
756
      if (prevNode) {
501,286,302✔
757
        prevNode->next = pOld->next;
519,587✔
758
      } else {
759
        pe->next = pOld->next;
500,766,715✔
760
        SHashNode *x = pe->next;
500,772,128✔
761
        if (x != NULL) {
762
        }
763
      }
764

765
      pe->num--;
501,285,785✔
766
      (void)atomic_sub_fetch_64(&pHashObj->size, 1);
501,293,413✔
767
      FREE_HASH_NODE(pHashObj->freeFp, pOld);
501,293,074✔
768
    }
769
  } else {
770
    //    uError("pNode:%p data:%p is not there!!!", pNode, p);
771
  }
772

773
  return pNode;
2,147,483,647✔
774
}
775

776
void *taosHashIterate(SHashObj *pHashObj, void *p) {
2,147,483,647✔
777
  if (pHashObj == NULL || pHashObj->size == 0) return NULL;
2,147,483,647✔
778

779
  int   slot = 0;
2,147,483,647✔
780
  char *data = NULL;
2,147,483,647✔
781

782
  // only add the read lock to disable the resize process
783
  taosHashRLock(pHashObj);
784

785
  SHashNode *pNode = NULL;
2,147,483,647✔
786
  if (p) {
2,147,483,647✔
787
    pNode = taosHashReleaseNode(pHashObj, p, &slot);
2,147,483,647✔
788
    if (pNode == NULL) {
2,147,483,647✔
789
      SHashEntry *pe = pHashObj->hashList[slot];
2,147,483,647✔
790
      taosHashEntryWUnlock(pHashObj, pe);
791

792
      slot = slot + 1;
2,147,483,647✔
793
    }
794
  }
795

796
  if (pNode == NULL) {
2,147,483,647✔
797
    for (; slot < pHashObj->capacity; ++slot) {
2,147,483,647✔
798
      SHashEntry *pe = pHashObj->hashList[slot];
2,147,483,647✔
799

800
      taosHashEntryWLock(pHashObj, pe);
801

802
      pNode = pe->next;
2,147,483,647✔
803
      while (pNode) {
2,147,483,647✔
804
        if (pNode->removed == 0) break;
2,147,483,647✔
805
        pNode = pNode->next;
1,907,985✔
806
      }
807

808
      if (pNode) break;
2,147,483,647✔
809

810
      taosHashEntryWUnlock(pHashObj, pe);
811
    }
812
  }
813

814
  if (pNode) {
2,147,483,647✔
815
    SHashEntry *pe = pHashObj->hashList[slot];
2,147,483,647✔
816

817
    /*uint16_t prevRef = atomic_load_16(&pNode->refCount);*/
818
    uint16_t afterRef = atomic_add_fetch_16(&pNode->refCount, 1);
2,147,483,647✔
819

820
    data = GET_HASH_NODE_DATA(pNode);
2,147,483,647✔
821

822
    if (afterRef >= MAX_WARNING_REF_COUNT) {
2,147,483,647✔
823
      uWarn("hash entry ref count is abnormally high: %d", afterRef);
×
824
    }
825

826
    taosHashEntryWUnlock(pHashObj, pe);
827
  }
828

829
  taosHashRUnlock(pHashObj);
830
  return data;
2,147,483,647✔
831
}
832

833
void taosHashCancelIterate(SHashObj *pHashObj, void *p) {
2,147,483,647✔
834
  if (pHashObj == NULL || p == NULL) return;
2,147,483,647✔
835

836
  // only add the read lock to disable the resize process
837
  taosHashRLock(pHashObj);
838

839
  int   slot;
2,147,483,647✔
840
  void *tp = taosHashReleaseNode(pHashObj, p, &slot);
2,147,483,647✔
841

842
  SHashEntry *pe = pHashObj->hashList[slot];
2,147,483,647✔
843

844
  taosHashEntryWUnlock(pHashObj, pe);
845
  taosHashRUnlock(pHashObj);
846
}
847

848
// TODO remove it
849
void *taosHashAcquire(SHashObj *pHashObj, const void *key, size_t keyLen) {
2,147,483,647✔
850
  void *p = NULL;
2,147,483,647✔
851
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, true);
2,147,483,647✔
852
}
853

854
void taosHashRelease(SHashObj *pHashObj, void *p) { taosHashCancelIterate(pHashObj, p); }
2,147,483,647✔
855

856
int64_t taosHashGetCompTimes(SHashObj *pHashObj) { return 0 /*atomic_load_64(&pHashObj->compTimes)*/; }
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc