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

taosdata / TDengine / #3768

28 Mar 2025 10:15AM UTC coverage: 33.726% (-0.3%) from 33.993%
#3768

push

travis-ci

happyguoxy
test:alter lcov result

144891 of 592084 branches covered (24.47%)

Branch coverage included in aggregate %.

218795 of 486283 relevant lines covered (44.99%)

765715.29 hits per line

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

75.83
/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) {               \
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) {
1,785,877✔
81
    return;
1,396,741✔
82
  }
83
  taosWLockLatch(&pHashObj->lock);
389,136✔
84
}
85

86
static FORCE_INLINE void taosHashWUnlock(SHashObj *pHashObj) {
87
  if (pHashObj->type == HASH_NO_LOCK) {
6,003✔
88
    return;
1,396,628✔
89
  }
90

91
  taosWUnLockLatch(&pHashObj->lock);
403,359✔
92
}
93

94
static FORCE_INLINE void taosHashRLock(SHashObj *pHashObj) {
95
  if (pHashObj->type == HASH_NO_LOCK) {
13,702,399✔
96
    return;
9,006,060✔
97
  }
98

99
  taosRLockLatch(&pHashObj->lock);
6,322,529✔
100
}
101

102
static FORCE_INLINE void taosHashRUnlock(SHashObj *pHashObj) {
103
  if (pHashObj->type == HASH_NO_LOCK) {
15,338,117!
104
    return;
8,990,783✔
105
  }
106

107
  taosRUnLockLatch(&pHashObj->lock);
6,347,334✔
108
}
109

110
static FORCE_INLINE void taosHashEntryWLock(const SHashObj *pHashObj, SHashEntry *pe) {
111
  if (pHashObj->type == HASH_NO_LOCK) {
44,321,471✔
112
    return;
38,828,747✔
113
  }
114
  taosWLockLatch(&pe->latch);
5,492,724✔
115
}
116

117
static FORCE_INLINE void taosHashEntryWUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
118
  if (pHashObj->type == HASH_NO_LOCK) {
40,196,307✔
119
    return;
38,835,239✔
120
  }
121

122
  taosWUnLockLatch(&pe->latch);
5,493,350✔
123
}
124

125
static FORCE_INLINE void taosHashEntryRLock(const SHashObj *pHashObj, SHashEntry *pe) {
126
  if (pHashObj->type == HASH_NO_LOCK) {
9,601,821✔
127
    return;
5,663,921✔
128
  }
129

130
  taosRLockLatch(&pe->latch);
3,937,900✔
131
}
132

133
static FORCE_INLINE void taosHashEntryRUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
134
  if (pHashObj->type == HASH_NO_LOCK) {
9,559,096✔
135
    return;
5,670,477✔
136
  }
137

138
  taosRUnLockLatch(&pe->latch);
3,888,619✔
139
}
140

141
static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
142
  int32_t len = (length < HASH_MAX_CAPACITY ? length : HASH_MAX_CAPACITY);
1,774,088✔
143

144
  int32_t i = 4;
1,774,088✔
145
  while (i < len) i = (i << 1u);
6,655,273✔
146
  return i;
1,774,088✔
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;
9,600,353✔
152
  while (pNode) {
11,312,694✔
153
    // atomic_add_fetch_64(&pHashObj->compTimes, 1);
154
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
10,881,705✔
155
        pNode->removed == 0) {
9,163,596!
156
      break;
9,163,958✔
157
    }
158

159
    pNode = pNode->next;
1,712,341✔
160
  }
161

162
  return pNode;
9,594,947✔
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);
41,594✔
195
  if (prev != NULL) {
41,598✔
196
    prev->next = pNewNode;
372✔
197
  } else {
198
    pe->next = pNewNode;
41,226✔
199
  }
200

201
  if (pNode->refCount <= 0) {
41,598✔
202
    pNewNode->next = pNode->next;
41,597✔
203

204
    FREE_HASH_NODE(pHashObj->freeFp, pNode);
41,597!
205
  } else {
206
    pNewNode->next = pNode;
1✔
207
    pe->num++;
1✔
208
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
1✔
209
  }
210
}
41,599✔
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; }
277,341✔
234

235
SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool update, SHashLockTypeE type) {
1,773,294✔
236
  if (fn == NULL) {
1,773,294!
237
    terrno = TSDB_CODE_INVALID_PARA;
×
238
    return NULL;
×
239
  }
240

241
  if (capacity == 0) {
1,773,294✔
242
    capacity = 4;
6,072✔
243
  }
244

245
  SHashObj *pHashObj = (SHashObj *)taosMemoryMalloc(sizeof(SHashObj));
1,773,294!
246
  if (pHashObj == NULL) {
1,774,088!
247
    return NULL;
×
248
  }
249

250
  // the max slots is not defined by user
251
  pHashObj->capacity = taosHashCapacity((int32_t)capacity);
1,774,088✔
252
  pHashObj->size = 0;
1,774,088✔
253

254
  pHashObj->equalFp = memcmp;
1,774,088✔
255
  pHashObj->hashFp = fn;
1,774,088✔
256
  pHashObj->type = type;
1,774,088✔
257
  pHashObj->lock = 0;
1,774,088✔
258
  pHashObj->enableUpdate = update;
1,774,088✔
259
  pHashObj->freeFp = NULL;
1,774,088✔
260
  pHashObj->callbackFp = NULL;
1,774,088✔
261

262
  pHashObj->hashList = (SHashEntry **)taosMemoryMalloc(pHashObj->capacity * sizeof(void *));
1,774,088✔
263
  if (pHashObj->hashList == NULL) {
1,773,936!
264
    taosMemoryFree(pHashObj);
×
265
    return NULL;
×
266
  }
267

268
  pHashObj->pMemBlock = taosArrayInit(8, sizeof(void *));
1,773,936✔
269
  if (pHashObj->pMemBlock == NULL) {
1,773,771!
270
    taosMemoryFree(pHashObj->hashList);
×
271
    taosMemoryFree(pHashObj);
×
272
    return NULL;
×
273
  }
274

275
  void *p = taosMemoryMalloc(pHashObj->capacity * sizeof(SHashEntry));
1,773,771!
276
  if (p == NULL) {
1,773,724!
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) {
171,658,652✔
284
    pHashObj->hashList[i] = (void *)((char *)p + i * sizeof(SHashEntry));
169,884,928✔
285
    pHashObj->hashList[i]->num = 0;
169,884,928✔
286
    pHashObj->hashList[i]->latch = 0;
169,884,928✔
287
    pHashObj->hashList[i]->next = NULL;
169,884,928✔
288
  }
289

290
  if (taosArrayPush(pHashObj->pMemBlock, &p) == NULL) {
3,547,442!
291
    taosMemoryFree(p);
×
292
    taosArrayDestroy(pHashObj->pMemBlock);
×
293
    taosMemoryFree(pHashObj->hashList);
×
294
    taosMemoryFree(pHashObj);
×
295
    return NULL;
×
296
  }
297
  return pHashObj;
1,773,718✔
298
}
299

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

306
void taosHashSetFreeFp(SHashObj *pHashObj, _hash_free_fn_t fp) {
209,085✔
307
  if (pHashObj != NULL && fp != NULL) {
209,085!
308
    pHashObj->freeFp = fp;
209,085✔
309
  }
310
}
209,085✔
311

312
int32_t taosHashGetSize(const SHashObj *pHashObj) {
1,342,675✔
313
  if (pHashObj == NULL) {
1,342,675✔
314
    return 0;
6,211✔
315
  }
316
  return (int32_t)atomic_load_64((int64_t *)&pHashObj->size);
1,336,464✔
317
}
318

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

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

327
  // need the resize process, write lock applied
328
  if (HASH_NEED_RESIZE(pHashObj)) {
2,317,876✔
329
    taosHashWLock(pHashObj);
330
    taosHashTableResize(pHashObj);
6,003✔
331
    taosHashWUnlock(pHashObj);
332
  }
333

334
  SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
2,317,876✔
335
  if (pNewNode == NULL) {
2,317,458!
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,312,761✔
344
  SHashEntry *pe = pHashObj->hashList[slot];
2,312,761✔
345

346
  taosHashEntryWLock(pHashObj, pe);
347

348
  SHashNode *pNode = pe->next;
2,318,145✔
349
  SHashNode *prev = NULL;
2,318,145✔
350
  while (pNode) {
2,492,539✔
351
    if ((pNode->keyLen == keyLen) && (*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0 &&
216,024✔
352
        pNode->removed == 0) {
41,628!
353
      break;
41,628✔
354
    }
355

356
    prev = pNode;
174,394✔
357
    pNode = pNode->next;
174,394✔
358
  }
359

360
  if (pNode == NULL) {
2,318,143✔
361
    // no data in hash table with the specified key, add it into hash table
362
    pushfrontNodeInEntryList(pe, pNewNode);
2,275,051✔
363
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
2,275,441✔
364
  } else {
365
    // not support the update operation, return error
366
    if (pHashObj->enableUpdate) {
43,092✔
367
      doUpdateHashNode(pHashObj, pe, prev, pNode, pNewNode);
368
    } else {
369
      taosMemoryFreeClear(pNewNode);
1,498!
370
      terrno = TSDB_CODE_DUP_KEY;
1,498✔
371
      code = terrno;
31✔
372
      goto _exit;
31✔
373
    }
374
  }
375
  
376
_exit:
2,318,894✔
377

378
  taosHashEntryWUnlock(pHashObj, pe);
379
  taosHashRUnlock(pHashObj);
380
  return code;
2,317,018✔
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) {
9,056,267✔
386
  void *p = NULL;
9,056,267✔
387
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, false);
9,056,267✔
388
}
389

390
int32_t taosHashGetDup(SHashObj *pHashObj, const void *key, size_t keyLen, void *destBuf) {
433,136✔
391
  terrno = 0;
433,136✔
392
  void *data = taosHashGetImpl(pHashObj, key, keyLen, &destBuf, 0, false);
433,149✔
393
  return terrno;
433,159✔
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) {
10,770,263✔
403
  if (pHashObj == NULL || keyLen == 0 || key == NULL) {
10,770,263!
404
    return NULL;
405
  }
406

407
  if ((atomic_load_64((int64_t *)&pHashObj->size) == 0)) {
10,788,791✔
408
    return NULL;
459,532✔
409
  }
410

411
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
10,328,207✔
412

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

416
  int32_t     slot = HASH_INDEX(hashVal, pHashObj->capacity);
10,356,405✔
417
  SHashEntry *pe = pHashObj->hashList[slot];
10,356,405✔
418

419
  // no data, return directly
420
  if (atomic_load_32(&pe->num) == 0) {
10,356,405✔
421
    taosHashRUnlock(pHashObj);
422
    return NULL;
741,576✔
423
  }
424

425
  char *data = NULL;
9,601,821✔
426
  taosHashEntryRLock(pHashObj, pe);
427

428
  SHashNode *pNode = doSearchInEntryList(pHashObj, pe, key, keyLen, hashVal);
9,594,947✔
429
  if (pNode != NULL) {
9,594,947✔
430
    if (pHashObj->callbackFp != NULL) {
9,162,971!
431
      pHashObj->callbackFp(GET_HASH_NODE_DATA(pNode));
×
432
    }
433

434
    if (size != NULL) {
9,162,971!
435
      if (*d == NULL) {
×
436
        *size = pNode->dataLen;
×
437
        *d = taosMemoryCalloc(1, *size);
×
438
        if (*d == NULL) {
×
439
          return NULL;
×
440
        }
441
      } else if (*size < pNode->dataLen) {
×
442
        *size = pNode->dataLen;
×
443
        char *tmp = taosMemoryRealloc(*d, *size);
×
444
        if (tmp == NULL) {
×
445
          return NULL;
×
446
        }
447

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

452
    if (addRef) {
9,162,971✔
453
      (void)atomic_add_fetch_16(&pNode->refCount, 1);
1,268,878✔
454
    }
455

456
    if (*d != NULL) {
9,127,120✔
457
      memcpy(*d, GET_HASH_NODE_DATA(pNode), pNode->dataLen);
431,528✔
458
    }
459

460
    data = GET_HASH_NODE_DATA(pNode);
9,127,120✔
461
  }
462

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

466
  return data;
9,615,655✔
467
}
468

469
int32_t taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
277,329✔
470
  if (pHashObj == NULL || taosHashTableEmpty(pHashObj) || key == NULL || keyLen == 0) {
554,678!
471
    return TSDB_CODE_INVALID_PARA;
2,655✔
472
  }
473

474
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
274,682✔
475

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

479
  int32_t     slot = HASH_INDEX(hashVal, pHashObj->capacity);
274,704✔
480
  SHashEntry *pe = pHashObj->hashList[slot];
274,704✔
481

482
  taosHashEntryWLock(pHashObj, pe);
483

484
  // double check after locked
485
  if (pe->num == 0) {
274,695✔
486
    taosHashEntryWUnlock(pHashObj, pe);
487
    taosHashRUnlock(pHashObj);
488
    return TSDB_CODE_NOT_FOUND;
94✔
489
  }
490

491
  int        code = TSDB_CODE_NOT_FOUND;
274,601✔
492
  SHashNode *pNode = pe->next;
274,601✔
493
  SHashNode *prevNode = NULL;
274,601✔
494

495
  while (pNode) {
554,407✔
496
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
279,782✔
497
        pNode->removed == 0) {
279,624✔
498
      code = 0;  // it is found
274,599✔
499

500
      (void)atomic_sub_fetch_16(&pNode->refCount, 1);
274,599✔
501
      pNode->removed = 1;
274,606✔
502
      if (pNode->refCount <= 0) {
274,606✔
503
        if (prevNode == NULL) {
269,567✔
504
          pe->next = pNode->next;
269,430✔
505
        } else {
506
          prevNode->next = pNode->next;
137✔
507
        }
508

509
        pe->num--;
269,567✔
510
        (void)atomic_sub_fetch_64(&pHashObj->size, 1);
269,567✔
511
        FREE_HASH_NODE(pHashObj->freeFp, pNode);
269,570!
512
      }
513
    } else {
514
      prevNode = pNode;
5,203✔
515
      pNode = pNode->next;
5,203✔
516
    }
517
  }
518

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

522
  return code;
274,611✔
523
}
524

525
void taosHashClear(SHashObj *pHashObj) {
1,884,132✔
526
  if (pHashObj == NULL) {
1,884,132✔
527
    return;
104,258✔
528
  }
529

530
  SHashNode *pNode, *pNext;
531

532
  taosHashWLock(pHashObj);
533

534
  for (int32_t i = 0; i < pHashObj->capacity; ++i) {
167,836,500✔
535
    SHashEntry *pEntry = pHashObj->hashList[i];
166,042,516✔
536
    if (pEntry->num == 0) {
166,042,516✔
537
      continue;
164,223,046✔
538
    }
539

540
    pNode = pEntry->next;
1,819,470✔
541
    while (pNode) {
3,730,348✔
542
      pNext = pNode->next;
1,896,888✔
543
      FREE_HASH_NODE(pHashObj->freeFp, pNode);
1,896,888!
544

545
      pNode = pNext;
1,910,878✔
546
    }
547

548
    pEntry->num = 0;
1,833,460✔
549
    pEntry->next = NULL;
1,833,460✔
550
  }
551

552
  pHashObj->size = 0;
1,793,984✔
553
  taosHashWUnlock(pHashObj);
554
}
555

556
// the input paras should be SHashObj **, so the origin input will be set by taosMemoryFreeClear(*pHashObj)
557
void taosHashCleanup(SHashObj *pHashObj) {
2,180,907✔
558
  if (pHashObj == NULL) {
2,180,907✔
559
    return;
415,940✔
560
  }
561

562
  taosHashClear(pHashObj);
1,764,967✔
563
  taosMemoryFreeClear(pHashObj->hashList);
1,765,111!
564

565
  // destroy mem block
566
  size_t memBlock = taosArrayGetSize(pHashObj->pMemBlock);
1,765,493✔
567
  for (int32_t i = 0; i < memBlock; ++i) {
3,537,009✔
568
    void *p = taosArrayGetP(pHashObj->pMemBlock, i);
1,771,284✔
569
    taosMemoryFreeClear(p);
1,771,027!
570
  }
571

572
  taosArrayDestroy(pHashObj->pMemBlock);
1,765,725✔
573
  taosMemoryFree(pHashObj);
1,765,678!
574
}
575

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

582
  int32_t num = 0;
×
583

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

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

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

599
void taosHashTableResize(SHashObj *pHashObj) {
6,003✔
600
  if (!HASH_NEED_RESIZE(pHashObj)) {
6,003!
601
    return;
×
602
  }
603

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

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

618
  pHashObj->hashList = pNewEntryList;
6,003✔
619

620
  size_t inc = newCapacity - pHashObj->capacity;
6,003✔
621
  void  *p = taosMemoryCalloc(inc, sizeof(SHashEntry));
6,003!
622
  if (p == NULL) {
6,003!
623
    return;
×
624
  }
625

626
  for (int32_t i = 0; i < inc; ++i) {
382,827✔
627
    pHashObj->hashList[i + pHashObj->capacity] = (void *)((char *)p + i * sizeof(SHashEntry));
376,824✔
628
  }
629

630
  if (taosArrayPush(pHashObj->pMemBlock, &p) == NULL) {
12,006!
631
    taosMemoryFree(p);
×
632
    return;
×
633
  }
634

635
  pHashObj->capacity = newCapacity;
6,003✔
636
  for (int32_t idx = 0; idx < pHashObj->capacity; ++idx) {
759,635✔
637
    SHashEntry *pe = pHashObj->hashList[idx];
753,640✔
638
    SHashNode  *pNode;
639
    SHashNode  *pNext;
640
    SHashNode  *pPrev = NULL;
753,640✔
641

642
    if (pe->num == 0) {
753,640✔
643
      continue;
423,833✔
644
    }
645

646
    pNode = pe->next;
329,807✔
647

648
    while (pNode != NULL) {
682,318✔
649
      int32_t newIdx = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
352,519✔
650
      pNext = pNode->next;
352,519✔
651
      if (newIdx != idx) {
352,519✔
652
        pe->num -= 1;
69,905✔
653
        if (pPrev == NULL) {
69,905✔
654
          pe->next = pNext;
66,287✔
655
        } else {
656
          pPrev->next = pNext;
3,618✔
657
        }
658

659
        SHashEntry *pNewEntry = pHashObj->hashList[newIdx];
69,905✔
660
        pushfrontNodeInEntryList(pNewEntry, pNode);
69,905✔
661
      } else {
662
        pPrev = pNode;
282,614✔
663
      }
664
      pNode = pNext;
352,511✔
665
    }
666
  }
667

668
  int64_t et = taosGetTimestampUs();
6,003✔
669

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

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

682
  if (pNewNode == NULL) {
2,316,273!
683
    return NULL;
×
684
  }
685

686
  pNewNode->keyLen = (uint32_t)keyLen;
2,316,273✔
687
  pNewNode->hashVal = hashVal;
2,316,273✔
688
  pNewNode->dataLen = (uint32_t)dsize;
2,316,273✔
689
  pNewNode->refCount = 1;
2,316,273✔
690
  pNewNode->removed = 0;
2,316,273✔
691
  pNewNode->next = NULL;
2,316,273✔
692

693
  if (pData) memcpy(GET_HASH_NODE_DATA(pNewNode), pData, dsize);
2,316,273✔
694
  memcpy(GET_HASH_NODE_KEY(pNewNode), key, keyLen);
2,316,273✔
695

696
  return pNewNode;
2,316,273✔
697
}
698

699
void pushfrontNodeInEntryList(SHashEntry *pEntry, SHashNode *pNode) {
2,345,811✔
700
  pNode->next = pEntry->next;
2,345,811✔
701
  pEntry->next = pNode;
2,345,811✔
702
  pEntry->num += 1;
2,345,811✔
703
}
2,345,811✔
704

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

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

714
void *taosHashGetKey(void *data, size_t *keyLen) {
244,557✔
715
  SHashNode *node = GET_HASH_PNODE(data);
244,557✔
716
  if (keyLen != NULL) {
244,557✔
717
    *keyLen = node->keyLen;
87,529✔
718
  }
719

720
  return GET_HASH_NODE_KEY(node);
244,557✔
721
}
722

723
int32_t taosHashGetValueSize(void *data) {
8✔
724
  SHashNode *node = GET_HASH_PNODE(data);
8✔
725
  return node->dataLen;
8✔
726
}
727

728
// release the pNode, return next pNode, and lock the current entry
729
static void *taosHashReleaseNode(SHashObj *pHashObj, void *p, int *slot) {
1,846,881✔
730
  SHashNode *pOld = (SHashNode *)GET_HASH_PNODE(p);
1,846,881✔
731
  SHashNode *prevNode = NULL;
1,846,881✔
732

733
  *slot = HASH_INDEX(pOld->hashVal, pHashObj->capacity);
1,846,881✔
734
  SHashEntry *pe = pHashObj->hashList[*slot];
1,846,881✔
735

736
  taosHashEntryWLock(pHashObj, pe);
737

738
  SHashNode *pNode = pe->next;
1,847,076✔
739
  while (pNode) {
1,908,217!
740
    if (pNode == pOld) break;
1,908,223✔
741

742
    prevNode = pNode;
61,141✔
743
    pNode = pNode->next;
61,141✔
744
  }
745

746
  if (pNode) {
1,847,076!
747
    pNode = pNode->next;
1,847,101✔
748
    while (pNode) {
1,847,101✔
749
      if (pNode->removed == 0) break;
45,960!
750
      pNode = pNode->next;
×
751
    }
752

753
    (void)atomic_sub_fetch_16(&pOld->refCount, 1);
1,847,101✔
754
    if (pOld->refCount <= 0) {
1,847,106✔
755
      if (prevNode) {
5,040!
756
        prevNode->next = pOld->next;
×
757
      } else {
758
        pe->next = pOld->next;
5,040✔
759
        SHashNode *x = pe->next;
5,040✔
760
        if (x != NULL) {
761
        }
762
      }
763

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

772
  return pNode;
1,847,097✔
773
}
774

775
void *taosHashIterate(SHashObj *pHashObj, void *p) {
2,024,476✔
776
  if (pHashObj == NULL || pHashObj->size == 0) return NULL;
2,024,476✔
777

778
  int   slot = 0;
1,626,190✔
779
  char *data = NULL;
1,626,190✔
780

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

784
  SHashNode *pNode = NULL;
1,624,886✔
785
  if (p) {
1,624,886✔
786
    pNode = taosHashReleaseNode(pHashObj, p, &slot);
1,069,186✔
787
    if (pNode == NULL) {
1,069,234✔
788
      SHashEntry *pe = pHashObj->hashList[slot];
1,035,508✔
789
      taosHashEntryWUnlock(pHashObj, pe);
790

791
      slot = slot + 1;
1,035,502✔
792
    }
793
  }
794

795
  if (pNode == NULL) {
1,624,928✔
796
    for (; slot < pHashObj->capacity; ++slot) {
40,436,604✔
797
      SHashEntry *pe = pHashObj->hashList[slot];
39,887,125✔
798

799
      taosHashEntryWLock(pHashObj, pe);
800

801
      pNode = pe->next;
39,887,819✔
802
      while (pNode) {
39,887,819✔
803
        if (pNode->removed == 0) break;
1,044,444!
804
        pNode = pNode->next;
×
805
      }
806

807
      if (pNode) break;
39,887,819✔
808

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

813
  if (pNode) {
1,626,425✔
814
    SHashEntry *pe = pHashObj->hashList[slot];
1,078,165✔
815

816
    /*uint16_t prevRef = atomic_load_16(&pNode->refCount);*/
817
    uint16_t afterRef = atomic_add_fetch_16(&pNode->refCount, 1);
1,078,165✔
818

819
    data = GET_HASH_NODE_DATA(pNode);
1,078,193✔
820

821
    if (afterRef >= MAX_WARNING_REF_COUNT) {
1,078,193!
822
      uWarn("hash entry ref count is abnormally high: %d", afterRef);
×
823
    }
824

825
    taosHashEntryWUnlock(pHashObj, pe);
826
  }
827

828
  taosHashRUnlock(pHashObj);
829
  return data;
1,626,421✔
830
}
831

832
void taosHashCancelIterate(SHashObj *pHashObj, void *p) {
779,355✔
833
  if (pHashObj == NULL || p == NULL) return;
779,355!
834

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

838
  int   slot;
839
  void *tp = taosHashReleaseNode(pHashObj, p, &slot);
777,883✔
840

841
  SHashEntry *pe = pHashObj->hashList[slot];
777,880✔
842

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

847
// TODO remove it
848
void *taosHashAcquire(SHashObj *pHashObj, const void *key, size_t keyLen) {
1,276,379✔
849
  void *p = NULL;
1,276,379✔
850
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, true);
1,276,379✔
851
}
852

853
void taosHashRelease(SHashObj *pHashObj, void *p) { taosHashCancelIterate(pHashObj, p); }
768,805✔
854

855
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