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

taosdata / TDengine / #4352

21 Jun 2025 07:48AM UTC coverage: 62.521% (+0.2%) from 62.366%
#4352

push

travis-ci

web-flow
docs: add OpenMetrics support and configuration details to taosAdapter documentation (#31427)

* docs: add OpenMetrics support and configuration details to taosAdapter documentation

* docs: enhance OpenMetrics section in taosAdapter documentation

156887 of 319947 branches covered (49.04%)

Branch coverage included in aggregate %.

242535 of 318911 relevant lines covered (76.05%)

6329998.33 hits per line

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

76.97
/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) {
80,740,410✔
81
    return;
64,865,546✔
82
  }
83
  taosWLockLatch(&pHashObj->lock);
15,874,864✔
84
}
85

86
static FORCE_INLINE void taosHashWUnlock(SHashObj *pHashObj) {
87
  if (pHashObj->type == HASH_NO_LOCK) {
1,224,298✔
88
    return;
64,866,145✔
89
  }
90

91
  taosWUnLockLatch(&pHashObj->lock);
15,941,583✔
92
}
93

94
static FORCE_INLINE void taosHashRLock(SHashObj *pHashObj) {
95
  if (pHashObj->type == HASH_NO_LOCK) {
665,690,564✔
96
    return;
582,602,658✔
97
  }
98

99
  taosRLockLatch(&pHashObj->lock);
197,211,521✔
100
}
101

102
static FORCE_INLINE void taosHashRUnlock(SHashObj *pHashObj) {
103
  if (pHashObj->type == HASH_NO_LOCK) {
780,332,470!
104
    return;
582,806,873✔
105
  }
106

107
  taosRUnLockLatch(&pHashObj->lock);
197,525,597✔
108
}
109

110
static FORCE_INLINE void taosHashEntryWLock(const SHashObj *pHashObj, SHashEntry *pe) {
111
  if (pHashObj->type == HASH_NO_LOCK) {
1,476,187,809✔
112
    return;
1,274,204,219✔
113
  }
114
  taosWLockLatch(&pe->latch);
201,983,590✔
115
}
116

117
static FORCE_INLINE void taosHashEntryWUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
118
  if (pHashObj->type == HASH_NO_LOCK) {
1,227,265,640✔
119
    return;
1,274,288,931✔
120
  }
121

122
  taosWUnLockLatch(&pe->latch);
201,891,513✔
123
}
124

125
static FORCE_INLINE void taosHashEntryRLock(const SHashObj *pHashObj, SHashEntry *pe) {
126
  if (pHashObj->type == HASH_NO_LOCK) {
402,289,348✔
127
    return;
303,070,841✔
128
  }
129

130
  taosRLockLatch(&pe->latch);
99,218,507✔
131
}
132

133
static FORCE_INLINE void taosHashEntryRUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
134
  if (pHashObj->type == HASH_NO_LOCK) {
402,253,073✔
135
    return;
303,094,102✔
136
  }
137

138
  taosRUnLockLatch(&pe->latch);
99,158,971✔
139
}
140

141
static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
142
  int32_t len = (length < HASH_MAX_CAPACITY ? length : HASH_MAX_CAPACITY);
79,157,027✔
143

144
  int32_t i = 4;
79,157,027✔
145
  while (i < len) i = (i << 1u);
238,585,208✔
146
  return i;
79,157,027✔
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;
402,308,965✔
152
  while (pNode) {
598,861,476✔
153
    // atomic_add_fetch_64(&pHashObj->compTimes, 1);
154
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
559,662,533✔
155
        pNode->removed == 0) {
363,128,550!
156
      break;
363,140,297✔
157
    }
158

159
    pNode = pNode->next;
196,552,511✔
160
  }
161

162
  return pNode;
402,339,240✔
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);
15,088,544✔
195
  if (prev != NULL) {
15,109,336✔
196
    prev->next = pNewNode;
67,550✔
197
  } else {
198
    pe->next = pNewNode;
15,041,786✔
199
  }
200

201
  if (pNode->refCount <= 0) {
15,109,336!
202
    pNewNode->next = pNode->next;
15,109,759✔
203

204
    FREE_HASH_NODE(pHashObj->freeFp, pNode);
15,109,759!
205
  } else {
206
    pNewNode->next = pNode;
×
207
    pe->num++;
×
208
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
×
209
  }
210
}
15,108,519✔
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; }
27,186,654✔
234

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

241
  if (capacity == 0) {
79,140,069✔
242
    capacity = 4;
485,257✔
243
  }
244

245
  SHashObj *pHashObj = (SHashObj *)taosMemoryMalloc(sizeof(SHashObj));
79,140,069!
246
  if (pHashObj == NULL) {
79,157,027!
247
    return NULL;
×
248
  }
249

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

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

262
  pHashObj->hashList = (SHashEntry **)taosMemoryMalloc(pHashObj->capacity * sizeof(void *));
79,157,027✔
263
  if (pHashObj->hashList == NULL) {
79,145,505!
264
    taosMemoryFree(pHashObj);
×
265
    return NULL;
×
266
  }
267

268
  pHashObj->pMemBlock = taosArrayInit(8, sizeof(void *));
79,145,505✔
269
  if (pHashObj->pMemBlock == NULL) {
79,174,737!
270
    taosMemoryFree(pHashObj->hashList);
×
271
    taosMemoryFree(pHashObj);
×
272
    return NULL;
×
273
  }
274

275
  void *p = taosMemoryMalloc(pHashObj->capacity * sizeof(SHashEntry));
79,174,737✔
276
  if (p == NULL) {
79,163,591!
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) {
158,319,928!
291
    taosMemoryFree(p);
×
292
    taosArrayDestroy(pHashObj->pMemBlock);
×
293
    taosMemoryFree(pHashObj->hashList);
×
294
    taosMemoryFree(pHashObj);
×
295
    return NULL;
×
296
  }
297
  return pHashObj;
79,156,337✔
298
}
299

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

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

312
int32_t taosHashGetSize(const SHashObj *pHashObj) {
93,063,417✔
313
  if (pHashObj == NULL) {
93,063,417✔
314
    return 0;
213,632✔
315
  }
316
  return (int32_t)atomic_load_64((int64_t *)&pHashObj->size);
92,849,785✔
317
}
318

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

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

327
  // need the resize process, write lock applied
328
  if (HASH_NEED_RESIZE(pHashObj)) {
147,244,786✔
329
    taosHashWLock(pHashObj);
330
    taosHashTableResize(pHashObj);
1,224,336✔
331
    taosHashWUnlock(pHashObj);
332
  }
333

334
  SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
147,244,765✔
335
  if (pNewNode == NULL) {
147,270,939!
336
    code = terrno;
×
337
    return code;
×
338
  }
339

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

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

346
  taosHashEntryWLock(pHashObj, pe);
347

348
  SHashNode *pNode = pe->next;
147,326,590✔
349
  SHashNode *prev = NULL;
147,326,590✔
350
  while (pNode) {
263,019,318✔
351
    if ((pNode->keyLen == keyLen) && (*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0 &&
130,954,914✔
352
        pNode->removed == 0) {
15,249,233!
353
      break;
15,249,855✔
354
    }
355

356
    prev = pNode;
115,692,728✔
357
    pNode = pNode->next;
115,692,728✔
358
  }
359

360
  if (pNode == NULL) {
147,314,259✔
361
    // no data in hash table with the specified key, add it into hash table
362
    pushfrontNodeInEntryList(pe, pNewNode);
132,068,335✔
363
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
132,052,344✔
364
  } else {
365
    // not support the update operation, return error
366
    if (pHashObj->enableUpdate) {
15,245,924✔
367
      doUpdateHashNode(pHashObj, pe, prev, pNode, pNewNode);
368
    } else {
369
      taosMemoryFreeClear(pNewNode);
157,380!
370
      terrno = TSDB_CODE_DUP_KEY;
157,255✔
371
      code = terrno;
161,111✔
372
      goto _exit;
159,705✔
373
    }
374
  }
375
  
376
_exit:
147,383,617✔
377

378
  taosHashEntryWUnlock(pHashObj, pe);
379
  taosHashRUnlock(pHashObj);
380
  return code;
147,403,784✔
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) {
450,403,044✔
386
  void *p = NULL;
450,403,044✔
387
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, false);
450,403,044✔
388
}
389

390
int32_t taosHashGetDup(SHashObj *pHashObj, const void *key, size_t keyLen, void *destBuf) {
13,445,947✔
391
  terrno = 0;
13,445,947✔
392
  void *data = taosHashGetImpl(pHashObj, key, keyLen, &destBuf, 0, false);
13,446,062✔
393
  return terrno;
13,453,240✔
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) {
500,001,788✔
403
  if (pHashObj == NULL || keyLen == 0 || key == NULL) {
500,001,788!
404
    return NULL;
13,029,768✔
405
  }
406

407
  if ((atomic_load_64((int64_t *)&pHashObj->size) == 0)) {
486,972,020✔
408
    return NULL;
31,383,893✔
409
  }
410

411
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
455,615,778✔
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);
457,019,153✔
417
  SHashEntry *pe = pHashObj->hashList[slot];
457,019,153✔
418

419
  // no data, return directly
420
  if (atomic_load_32(&pe->num) == 0) {
457,019,153✔
421
    taosHashRUnlock(pHashObj);
422
    return NULL;
54,756,558✔
423
  }
424

425
  char *data = NULL;
402,289,348✔
426
  taosHashEntryRLock(pHashObj, pe);
427

428
  SHashNode *pNode = doSearchInEntryList(pHashObj, pe, key, keyLen, hashVal);
402,339,240✔
429
  if (pNode != NULL) {
402,339,240✔
430
    if (pHashObj->callbackFp != NULL) {
363,110,929!
431
      pHashObj->callbackFp(GET_HASH_NODE_DATA(pNode));
×
432
    }
433

434
    if (size != NULL) {
363,110,929!
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) {
363,110,929✔
453
      (void)atomic_add_fetch_16(&pNode->refCount, 1);
34,437,285✔
454
    }
455

456
    if (*d != NULL) {
363,024,762✔
457
      memcpy(*d, GET_HASH_NODE_DATA(pNode), pNode->dataLen);
13,363,468✔
458
    }
459

460
    data = GET_HASH_NODE_DATA(pNode);
363,024,762✔
461
  }
462

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

466
  return data;
402,352,456✔
467
}
468

469
int32_t taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
27,185,185✔
470
  if (pHashObj == NULL || taosHashTableEmpty(pHashObj) || key == NULL || keyLen == 0) {
54,367,944!
471
    return TSDB_CODE_INVALID_PARA;
282,576✔
472
  }
473

474
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
26,898,714✔
475

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

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

482
  taosHashEntryWLock(pHashObj, pe);
483

484
  // double check after locked
485
  if (pe->num == 0) {
26,898,923✔
486
    taosHashEntryWUnlock(pHashObj, pe);
487
    taosHashRUnlock(pHashObj);
488
    return TSDB_CODE_NOT_FOUND;
3,610✔
489
  }
490

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

495
  while (pNode) {
55,809,378✔
496
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
28,908,383✔
497
        pNode->removed == 0) {
28,853,393✔
498
      code = 0;  // it is found
26,895,700✔
499

500
      (void)atomic_sub_fetch_16(&pNode->refCount, 1);
26,895,700✔
501
      pNode->removed = 1;
26,903,634✔
502
      if (pNode->refCount <= 0) {
26,903,634✔
503
        if (prevNode == NULL) {
24,945,286✔
504
          pe->next = pNode->next;
24,890,923✔
505
        } else {
506
          prevNode->next = pNode->next;
54,363✔
507
        }
508

509
        pe->num--;
24,945,286✔
510
        (void)atomic_sub_fetch_64(&pHashObj->size, 1);
24,945,286✔
511
        FREE_HASH_NODE(pHashObj->freeFp, pNode);
24,947,070!
512
      }
513
    } else {
514
      prevNode = pNode;
2,016,276✔
515
      pNode = pNode->next;
2,016,276✔
516
    }
517
  }
518

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

522
  return code;
26,898,884✔
523
}
524

525
void taosHashClear(SHashObj *pHashObj) {
82,468,193✔
526
  if (pHashObj == NULL) {
82,468,193✔
527
    return;
2,952,109✔
528
  }
529

530
  SHashNode *pNode, *pNext;
531

532
  taosHashWLock(pHashObj);
533

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

540
    pNode = pEntry->next;
92,552,369✔
541
    while (pNode) {
197,628,978✔
542
      pNext = pNode->next;
105,013,471✔
543
      FREE_HASH_NODE(pHashObj->freeFp, pNode);
105,013,471✔
544

545
      pNode = pNext;
105,076,609✔
546
    }
547

548
    pEntry->num = 0;
92,615,507✔
549
    pEntry->next = NULL;
92,615,507✔
550
  }
551

552
  pHashObj->size = 0;
79,583,430✔
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) {
109,079,099✔
558
  if (pHashObj == NULL) {
109,079,099✔
559
    return;
29,936,140✔
560
  }
561

562
  taosHashClear(pHashObj);
79,142,959✔
563
  taosMemoryFreeClear(pHashObj->hashList);
79,145,744!
564

565
  // destroy mem block
566
  size_t memBlock = taosArrayGetSize(pHashObj->pMemBlock);
79,152,887✔
567
  for (int32_t i = 0; i < memBlock; ++i) {
159,522,902✔
568
    void *p = taosArrayGetP(pHashObj->pMemBlock, i);
80,373,228✔
569
    taosMemoryFreeClear(p);
80,366,617!
570
  }
571

572
  taosArrayDestroy(pHashObj->pMemBlock);
79,149,674✔
573
  taosMemoryFree(pHashObj);
79,158,033!
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) {
1,224,307✔
600
  if (!HASH_NEED_RESIZE(pHashObj)) {
1,224,307✔
601
    return;
73✔
602
  }
603

604
  int32_t newCapacity = (int32_t)(pHashObj->capacity << 1u);
1,224,234✔
605
  if (newCapacity > HASH_MAX_CAPACITY) {
1,224,234!
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();
1,224,215✔
612
  SHashEntry **pNewEntryList = taosMemoryRealloc(pHashObj->hashList, sizeof(SHashEntry *) * newCapacity);
1,224,215!
613
  if (pNewEntryList == NULL) {
1,224,219!
614
    //    uDebug("cache resize failed due to out of memory, capacity remain:%zu", pHashObj->capacity);
615
    return;
×
616
  }
617

618
  pHashObj->hashList = pNewEntryList;
1,224,219✔
619

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

626
  for (int32_t i = 0; i < inc; ++i) {
23,438,011✔
627
    pHashObj->hashList[i + pHashObj->capacity] = (void *)((char *)p + i * sizeof(SHashEntry));
22,213,777✔
628
  }
629

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

635
  pHashObj->capacity = newCapacity;
1,224,220✔
636
  for (int32_t idx = 0; idx < pHashObj->capacity; ++idx) {
45,629,264✔
637
    SHashEntry *pe = pHashObj->hashList[idx];
44,410,447✔
638
    SHashNode  *pNode;
639
    SHashNode  *pNext;
640
    SHashNode  *pPrev = NULL;
44,410,447✔
641

642
    if (pe->num == 0) {
44,410,447✔
643
      continue;
26,888,781✔
644
    }
645

646
    pNode = pe->next;
17,521,666✔
647

648
    while (pNode != NULL) {
42,800,663✔
649
      int32_t newIdx = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
25,284,400✔
650
      pNext = pNode->next;
25,284,400✔
651
      if (newIdx != idx) {
25,284,400✔
652
        pe->num -= 1;
8,631,867✔
653
        if (pPrev == NULL) {
8,631,867✔
654
          pe->next = pNext;
7,455,246✔
655
        } else {
656
          pPrev->next = pNext;
1,176,621✔
657
        }
658

659
        SHashEntry *pNewEntry = pHashObj->hashList[newIdx];
8,631,867✔
660
        pushfrontNodeInEntryList(pNewEntry, pNode);
8,631,867✔
661
      } else {
662
        pPrev = pNode;
16,652,533✔
663
      }
664
      pNode = pNext;
25,278,997✔
665
    }
666
  }
667

668
  int64_t et = taosGetTimestampUs();
1,224,228✔
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) {
147,229,878✔
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);
147,229,878!
680
#endif
681

682
  if (pNewNode == NULL) {
147,304,994!
683
    return NULL;
×
684
  }
685

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

693
  if (pData) memcpy(GET_HASH_NODE_DATA(pNewNode), pData, dsize);
147,304,994✔
694
  memcpy(GET_HASH_NODE_KEY(pNewNode), key, keyLen);
147,304,994✔
695

696
  return pNewNode;
147,304,994✔
697
}
698

699
void pushfrontNodeInEntryList(SHashEntry *pEntry, SHashNode *pNode) {
140,685,620✔
700
  pNode->next = pEntry->next;
140,685,620✔
701
  pEntry->next = pNode;
140,685,620✔
702
  pEntry->num += 1;
140,685,620✔
703
}
140,685,620✔
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) {
20,976,316✔
715
  SHashNode *node = GET_HASH_PNODE(data);
20,976,316✔
716
  if (keyLen != NULL) {
20,976,316✔
717
    *keyLen = node->keyLen;
8,038,653✔
718
  }
719

720
  return GET_HASH_NODE_KEY(node);
20,976,316✔
721
}
722

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

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

733
  *slot = HASH_INDEX(pOld->hashVal, pHashObj->capacity);
110,406,854✔
734
  SHashEntry *pe = pHashObj->hashList[*slot];
110,406,854✔
735

736
  taosHashEntryWLock(pHashObj, pe);
737

738
  SHashNode *pNode = pe->next;
110,407,456✔
739
  while (pNode) {
217,508,139✔
740
    if (pNode == pOld) break;
217,503,562✔
741

742
    prevNode = pNode;
107,100,683✔
743
    pNode = pNode->next;
107,100,683✔
744
  }
745

746
  if (pNode) {
110,407,456✔
747
    pNode = pNode->next;
110,401,782✔
748
    while (pNode) {
110,401,791✔
749
      if (pNode->removed == 0) break;
9,450,449✔
750
      pNode = pNode->next;
9✔
751
    }
752

753
    (void)atomic_sub_fetch_16(&pOld->refCount, 1);
110,401,782✔
754
    if (pOld->refCount <= 0) {
110,419,301✔
755
      if (prevNode) {
1,960,223✔
756
        prevNode->next = pOld->next;
144✔
757
      } else {
758
        pe->next = pOld->next;
1,960,079✔
759
        SHashNode *x = pe->next;
1,960,079✔
760
        if (x != NULL) {
761
        }
762
      }
763

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

772
  return pNode;
110,415,507✔
773
}
774

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

778
  int   slot = 0;
114,123,615✔
779
  char *data = NULL;
114,123,615✔
780

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

784
  SHashNode *pNode = NULL;
114,116,613✔
785
  if (p) {
114,116,613✔
786
    pNode = taosHashReleaseNode(pHashObj, p, &slot);
75,661,067✔
787
    if (pNode == NULL) {
75,664,991✔
788
      SHashEntry *pe = pHashObj->hashList[slot];
66,780,570✔
789
      taosHashEntryWUnlock(pHashObj, pe);
790

791
      slot = slot + 1;
66,778,761✔
792
    }
793
  }
794

795
  if (pNode == NULL) {
114,118,728✔
796
    for (; slot < pHashObj->capacity; ++slot) {
1,229,224,430✔
797
      SHashEntry *pe = pHashObj->hashList[slot];
1,191,543,072✔
798

799
      taosHashEntryWLock(pHashObj, pe);
800

801
      pNode = pe->next;
1,191,463,998✔
802
      while (pNode) {
1,191,464,978✔
803
        if (pNode->removed == 0) break;
67,577,441✔
804
        pNode = pNode->next;
980✔
805
      }
806

807
      if (pNode) break;
1,191,463,998✔
808

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

813
  if (pNode) {
114,131,165✔
814
    SHashEntry *pe = pHashObj->hashList[slot];
76,462,418✔
815

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

819
    data = GET_HASH_NODE_DATA(pNode);
76,473,554✔
820

821
    if (afterRef >= MAX_WARNING_REF_COUNT) {
76,473,554!
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;
114,134,976✔
830
}
831

832
void taosHashCancelIterate(SHashObj *pHashObj, void *p) {
34,862,664✔
833
  if (pHashObj == NULL || p == NULL) return;
34,862,664!
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);
34,752,608✔
840

841
  SHashEntry *pe = pHashObj->hashList[slot];
34,750,617✔
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) {
35,787,604✔
849
  void *p = NULL;
35,787,604✔
850
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, true);
35,787,604✔
851
}
852

853
void taosHashRelease(SHashObj *pHashObj, void *p) { taosHashCancelIterate(pHashObj, p); }
34,007,321✔
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