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

taosdata / TDengine / #4131

20 May 2025 07:22AM UTC coverage: 63.096% (+0.7%) from 62.384%
#4131

push

travis-ci

web-flow
docs(datain): add topic meta options docs in tmq (#31147)

157751 of 318088 branches covered (49.59%)

Branch coverage included in aggregate %.

243052 of 317143 relevant lines covered (76.64%)

18743283.33 hits per line

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

76.58
/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) {
198,643,714✔
81
    return;
149,084,398✔
82
  }
83
  taosWLockLatch(&pHashObj->lock);
49,559,316✔
84
}
85

86
static FORCE_INLINE void taosHashWUnlock(SHashObj *pHashObj) {
87
  if (pHashObj->type == HASH_NO_LOCK) {
4,252,591✔
88
    return;
149,222,007✔
89
  }
90

91
  taosWUnLockLatch(&pHashObj->lock);
49,476,553✔
92
}
93

94
static FORCE_INLINE void taosHashRLock(SHashObj *pHashObj) {
95
  if (pHashObj->type == HASH_NO_LOCK) {
2,113,006,265✔
96
    return;
1,701,910,822✔
97
  }
98

99
  taosRLockLatch(&pHashObj->lock);
908,879,977✔
100
}
101

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

107
  taosRUnLockLatch(&pHashObj->lock);
932,858,628✔
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);
1,205,584,604✔
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);
1,206,732,745✔
123
}
124

125
static FORCE_INLINE void taosHashEntryRLock(const SHashObj *pHashObj, SHashEntry *pe) {
126
  if (pHashObj->type == HASH_NO_LOCK) {
1,100,950,501✔
127
    return;
729,832,764✔
128
  }
129

130
  taosRLockLatch(&pe->latch);
371,117,737✔
131
}
132

133
static FORCE_INLINE void taosHashEntryRUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
134
  if (pHashObj->type == HASH_NO_LOCK) {
1,114,491,929✔
135
    return;
734,215,361✔
136
  }
137

138
  taosRUnLockLatch(&pe->latch);
380,276,568✔
139
}
140

141
static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
142
  int32_t len = (length < HASH_MAX_CAPACITY ? length : HASH_MAX_CAPACITY);
193,296,880✔
143

144
  int32_t i = 4;
193,296,880✔
145
  while (i < len) i = (i << 1u);
702,339,506✔
146
  return i;
193,296,880✔
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;
1,114,508,096✔
152
  while (pNode) {
1,454,233,803✔
153
    // atomic_add_fetch_64(&pHashObj->compTimes, 1);
154
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
1,367,879,065✔
155
        pNode->removed == 0) {
1,027,716,530!
156
      break;
1,027,861,055✔
157
    }
158

159
    pNode = pNode->next;
339,725,707✔
160
  }
161

162
  return pNode;
1,114,215,793✔
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);
36,548,996✔
195
  if (prev != NULL) {
36,549,261✔
196
    prev->next = pNewNode;
102,662✔
197
  } else {
198
    pe->next = pNewNode;
36,446,599✔
199
  }
200

201
  if (pNode->refCount <= 0) {
36,549,261!
202
    pNewNode->next = pNode->next;
36,552,854✔
203

204
    FREE_HASH_NODE(pHashObj->freeFp, pNode);
36,552,854!
205
  } else {
206
    pNewNode->next = pNode;
×
207
    pe->num++;
×
208
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
×
209
  }
210
}
36,542,546✔
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; }
82,679,605✔
234

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

241
  if (capacity == 0) {
192,608,708✔
242
    capacity = 4;
4,296,570✔
243
  }
244

245
  SHashObj *pHashObj = (SHashObj *)taosMemoryMalloc(sizeof(SHashObj));
192,608,708!
246
  if (pHashObj == NULL) {
193,296,880!
247
    return NULL;
×
248
  }
249

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

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

262
  pHashObj->hashList = (SHashEntry **)taosMemoryMalloc(pHashObj->capacity * sizeof(void *));
193,296,880!
263
  if (pHashObj->hashList == NULL) {
193,917,978!
264
    taosMemoryFree(pHashObj);
×
265
    return NULL;
×
266
  }
267

268
  pHashObj->pMemBlock = taosArrayInit(8, sizeof(void *));
193,917,978✔
269
  if (pHashObj->pMemBlock == NULL) {
194,509,834!
270
    taosMemoryFree(pHashObj->hashList);
×
271
    taosMemoryFree(pHashObj);
×
272
    return NULL;
×
273
  }
274

275
  void *p = taosMemoryMalloc(pHashObj->capacity * sizeof(SHashEntry));
194,509,834✔
276
  if (p == NULL) {
194,365,534!
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) {
386,271,386!
291
    taosMemoryFree(p);
×
292
    taosArrayDestroy(pHashObj->pMemBlock);
×
293
    taosMemoryFree(pHashObj->hashList);
×
294
    taosMemoryFree(pHashObj);
×
295
    return NULL;
×
296
  }
297
  return pHashObj;
191,905,852✔
298
}
299

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

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

312
int32_t taosHashGetSize(const SHashObj *pHashObj) {
262,292,696✔
313
  if (pHashObj == NULL) {
262,292,696✔
314
    return 0;
271,163✔
315
  }
316
  return (int32_t)atomic_load_64((int64_t *)&pHashObj->size);
262,021,533✔
317
}
318

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

324
  int32_t     code = TSDB_CODE_SUCCESS;
666,820,542✔
325
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
666,820,542✔
326

327
  // need the resize process, write lock applied
328
  if (HASH_NEED_RESIZE(pHashObj)) {
666,674,960✔
329
    taosHashWLock(pHashObj);
330
    taosHashTableResize(pHashObj);
4,252,736✔
331
    taosHashWUnlock(pHashObj);
332
  }
333

334
  SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
666,674,912✔
335
  if (pNewNode == NULL) {
666,750,569!
336
    code = terrno;
×
337
    return code;
×
338
  }
339

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

343
  uint32_t    slot = HASH_INDEX(hashVal, pHashObj->capacity);
667,787,636✔
344
  SHashEntry *pe = pHashObj->hashList[slot];
667,787,636✔
345

346
  taosHashEntryWLock(pHashObj, pe);
347

348
  SHashNode *pNode = pe->next;
666,595,378✔
349
  SHashNode *prev = NULL;
666,595,378✔
350
  while (pNode) {
824,230,516✔
351
    if ((pNode->keyLen == keyLen) && (*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0 &&
194,542,724✔
352
        pNode->removed == 0) {
36,904,577!
353
      break;
36,907,085✔
354
    }
355

356
    prev = pNode;
157,635,138✔
357
    pNode = pNode->next;
157,635,138✔
358
  }
359

360
  if (pNode == NULL) {
666,594,877✔
361
    // no data in hash table with the specified key, add it into hash table
362
    pushfrontNodeInEntryList(pe, pNewNode);
629,489,976✔
363
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
629,037,957✔
364
  } else {
365
    // not support the update operation, return error
366
    if (pHashObj->enableUpdate) {
37,104,901✔
367
      doUpdateHashNode(pHashObj, pe, prev, pNode, pNewNode);
368
    } else {
369
      taosMemoryFreeClear(pNewNode);
555,905!
370
      terrno = TSDB_CODE_DUP_KEY;
555,872✔
371
      code = terrno;
356,223✔
372
      goto _exit;
355,999✔
373
    }
374
  }
375
  
376
_exit:
669,177,825✔
377

378
  taosHashEntryWUnlock(pHashObj, pe);
379
  taosHashRUnlock(pHashObj);
380
  return code;
668,920,154✔
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) {
1,169,334,395✔
386
  void *p = NULL;
1,169,334,395✔
387
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, false);
1,169,334,395✔
388
}
389

390
int32_t taosHashGetDup(SHashObj *pHashObj, const void *key, size_t keyLen, void *destBuf) {
56,007,582✔
391
  terrno = 0;
56,007,582✔
392
  void *data = taosHashGetImpl(pHashObj, key, keyLen, &destBuf, 0, false);
56,002,688✔
393
  return terrno;
56,076,595✔
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) {
1,352,436,385✔
403
  if (pHashObj == NULL || keyLen == 0 || key == NULL) {
1,352,436,385!
404
    return NULL;
45,917,423✔
405
  }
406

407
  if ((atomic_load_64((int64_t *)&pHashObj->size) == 0)) {
1,306,518,962✔
408
    return NULL;
64,960,028✔
409
  }
410

411
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
1,208,114,552✔
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);
1,248,678,137✔
417
  SHashEntry *pe = pHashObj->hashList[slot];
1,248,678,137✔
418

419
  // no data, return directly
420
  if (atomic_load_32(&pe->num) == 0) {
1,248,678,137✔
421
    taosHashRUnlock(pHashObj);
422
    return NULL;
113,419,056✔
423
  }
424

425
  char *data = NULL;
1,100,950,501✔
426
  taosHashEntryRLock(pHashObj, pe);
427

428
  SHashNode *pNode = doSearchInEntryList(pHashObj, pe, key, keyLen, hashVal);
1,114,215,793✔
429
  if (pNode != NULL) {
1,114,215,793✔
430
    if (pHashObj->callbackFp != NULL) {
1,027,586,987!
431
      pHashObj->callbackFp(GET_HASH_NODE_DATA(pNode));
×
432
    }
433

434
    if (size != NULL) {
1,027,586,987!
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) {
1,027,586,987✔
453
      (void)atomic_add_fetch_16(&pNode->refCount, 1);
131,072,138✔
454
    }
455

456
    if (*d != NULL) {
1,027,863,123✔
457
      memcpy(*d, GET_HASH_NODE_DATA(pNode), pNode->dataLen);
55,904,746✔
458
    }
459

460
    data = GET_HASH_NODE_DATA(pNode);
1,027,863,123✔
461
  }
462

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

466
  return data;
1,125,078,821✔
467
}
468

469
int32_t taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
82,670,400✔
470
  if (pHashObj == NULL || taosHashTableEmpty(pHashObj) || key == NULL || keyLen == 0) {
165,189,756!
471
    return TSDB_CODE_INVALID_PARA;
927,327✔
472
  }
473

474
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
81,582,824✔
475

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

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

482
  taosHashEntryWLock(pHashObj, pe);
483

484
  // double check after locked
485
  if (pe->num == 0) {
81,629,812✔
486
    taosHashEntryWUnlock(pHashObj, pe);
487
    taosHashRUnlock(pHashObj);
488
    return TSDB_CODE_NOT_FOUND;
6,406✔
489
  }
490

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

495
  while (pNode) {
172,248,088✔
496
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
90,498,785✔
497
        pNode->removed == 0) {
90,247,413✔
498
      code = 0;  // it is found
81,641,702✔
499

500
      (void)atomic_sub_fetch_16(&pNode->refCount, 1);
81,641,702✔
501
      pNode->removed = 1;
81,795,142✔
502
      if (pNode->refCount <= 0) {
81,795,142✔
503
        if (prevNode == NULL) {
73,168,285✔
504
          pe->next = pNode->next;
72,956,599✔
505
        } else {
506
          prevNode->next = pNode->next;
211,686✔
507
        }
508

509
        pe->num--;
73,168,285✔
510
        (void)atomic_sub_fetch_64(&pHashObj->size, 1);
73,168,285✔
511
        FREE_HASH_NODE(pHashObj->freeFp, pNode);
73,170,668!
512
      }
513
    } else {
514
      prevNode = pNode;
8,873,681✔
515
      pNode = pNode->next;
8,873,681✔
516
    }
517
  }
518

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

522
  return code;
81,745,895✔
523
}
524

525
void taosHashClear(SHashObj *pHashObj) {
207,132,573✔
526
  if (pHashObj == NULL) {
207,132,573✔
527
    return;
12,741,583✔
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;
515,564,334✔
541
    while (pNode) {
1,065,254,353✔
542
      pNext = pNode->next;
548,734,528✔
543
      FREE_HASH_NODE(pHashObj->freeFp, pNode);
548,734,528!
544

545
      pNode = pNext;
549,690,019✔
546
    }
547

548
    pEntry->num = 0;
516,519,825✔
549
    pEntry->next = NULL;
516,519,825✔
550
  }
551

552
  pHashObj->size = 0;
194,445,969✔
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) {
254,288,638✔
558
  if (pHashObj == NULL) {
254,288,638✔
559
    return;
59,932,040✔
560
  }
561

562
  taosHashClear(pHashObj);
194,356,598✔
563
  taosMemoryFreeClear(pHashObj->hashList);
194,518,458!
564

565
  // destroy mem block
566
  size_t memBlock = taosArrayGetSize(pHashObj->pMemBlock);
194,674,139✔
567
  for (int32_t i = 0; i < memBlock; ++i) {
393,824,504✔
568
    void *p = taosArrayGetP(pHashObj->pMemBlock, i);
198,468,654✔
569
    taosMemoryFreeClear(p);
197,953,167!
570
  }
571

572
  taosArrayDestroy(pHashObj->pMemBlock);
195,355,850✔
573
  taosMemoryFree(pHashObj);
194,961,714!
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) {
4,252,573✔
600
  if (!HASH_NEED_RESIZE(pHashObj)) {
4,252,573✔
601
    return;
1,148✔
602
  }
603

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

618
  pHashObj->hashList = pNewEntryList;
4,251,430✔
619

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

626
  for (int32_t i = 0; i < inc; ++i) {
492,602,451✔
627
    pHashObj->hashList[i + pHashObj->capacity] = (void *)((char *)p + i * sizeof(SHashEntry));
488,350,960✔
628
  }
629

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

635
  pHashObj->capacity = newCapacity;
4,251,382✔
636
  for (int32_t idx = 0; idx < pHashObj->capacity; ++idx) {
978,143,679✔
637
    SHashEntry *pe = pHashObj->hashList[idx];
975,054,818✔
638
    SHashNode  *pNode;
639
    SHashNode  *pNext;
640
    SHashNode  *pPrev = NULL;
975,054,818✔
641

642
    if (pe->num == 0) {
975,054,818✔
643
      continue;
385,978,964✔
644
    }
645

646
    pNode = pe->next;
589,075,854✔
647

648
    while (pNode != NULL) {
1,211,665,621✔
649
      int32_t newIdx = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
623,752,288✔
650
      pNext = pNode->next;
623,752,288✔
651
      if (newIdx != idx) {
623,752,288✔
652
        pe->num -= 1;
257,799,754✔
653
        if (pPrev == NULL) {
257,799,754✔
654
          pe->next = pNext;
252,161,674✔
655
        } else {
656
          pPrev->next = pNext;
5,638,080✔
657
        }
658

659
        SHashEntry *pNewEntry = pHashObj->hashList[newIdx];
257,799,754✔
660
        pushfrontNodeInEntryList(pNewEntry, pNode);
257,799,754✔
661
      } else {
662
        pPrev = pNode;
365,952,534✔
663
      }
664
      pNode = pNext;
622,589,767✔
665
    }
666
  }
667

668
  int64_t et = taosGetTimestampUs();
4,251,521✔
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) {
666,477,983✔
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);
666,477,983!
680
#endif
681

682
  if (pNewNode == NULL) {
667,180,556!
683
    return NULL;
×
684
  }
685

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

693
  if (pData) memcpy(GET_HASH_NODE_DATA(pNewNode), pData, dsize);
667,180,556✔
694
  memcpy(GET_HASH_NODE_KEY(pNewNode), key, keyLen);
667,180,556✔
695

696
  return pNewNode;
667,180,556✔
697
}
698

699
void pushfrontNodeInEntryList(SHashEntry *pEntry, SHashNode *pNode) {
885,723,654✔
700
  pNode->next = pEntry->next;
885,723,654✔
701
  pEntry->next = pNode;
885,723,654✔
702
  pEntry->num += 1;
885,723,654✔
703
}
885,723,654✔
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) {
25,836,895✔
715
  SHashNode *node = GET_HASH_PNODE(data);
25,836,895✔
716
  if (keyLen != NULL) {
25,836,895✔
717
    *keyLen = node->keyLen;
9,878,703✔
718
  }
719

720
  return GET_HASH_NODE_KEY(node);
25,836,895✔
721
}
722

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

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

733
  *slot = HASH_INDEX(pOld->hashVal, pHashObj->capacity);
562,360,656✔
734
  SHashEntry *pe = pHashObj->hashList[*slot];
562,360,656✔
735

736
  taosHashEntryWLock(pHashObj, pe);
737

738
  SHashNode *pNode = pe->next;
561,284,908✔
739
  while (pNode) {
717,961,805!
740
    if (pNode == pOld) break;
717,963,881✔
741

742
    prevNode = pNode;
156,676,897✔
743
    pNode = pNode->next;
156,676,897✔
744
  }
745

746
  if (pNode) {
561,284,908✔
747
    pNode = pNode->next;
561,274,032✔
748
    while (pNode) {
561,318,084✔
749
      if (pNode->removed == 0) break;
57,384,635✔
750
      pNode = pNode->next;
44,052✔
751
    }
752

753
    (void)atomic_sub_fetch_16(&pOld->refCount, 1);
561,274,032✔
754
    if (pOld->refCount <= 0) {
562,956,233✔
755
      if (prevNode) {
8,658,536✔
756
        prevNode->next = pOld->next;
576✔
757
      } else {
758
        pe->next = pOld->next;
8,657,960✔
759
        SHashNode *x = pe->next;
8,657,960✔
760
        if (x != NULL) {
761
        }
762
      }
763

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

772
  return pNode;
562,890,336✔
773
}
774

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

778
  int   slot = 0;
497,784,534✔
779
  char *data = NULL;
497,784,534✔
780

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

784
  SHashNode *pNode = NULL;
493,526,624✔
785
  if (p) {
493,526,624✔
786
    pNode = taosHashReleaseNode(pHashObj, p, &slot);
424,752,414✔
787
    if (pNode == NULL) {
424,700,344✔
788
      SHashEntry *pe = pHashObj->hashList[slot];
374,015,919✔
789
      taosHashEntryWUnlock(pHashObj, pe);
790

791
      slot = slot + 1;
373,937,215✔
792
    }
793
  }
794

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

799
      taosHashEntryWLock(pHashObj, pe);
800

801
      pNode = pe->next;
2,147,483,647✔
802
      while (pNode) {
2,147,483,647✔
803
        if (pNode->removed == 0) break;
381,101,403✔
804
        pNode = pNode->next;
10,387✔
805
      }
806

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

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

813
  if (pNode) {
497,714,166✔
814
    SHashEntry *pe = pHashObj->hashList[slot];
431,825,535✔
815

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

819
    data = GET_HASH_NODE_DATA(pNode);
432,166,408✔
820

821
    if (afterRef >= MAX_WARNING_REF_COUNT) {
432,166,408!
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;
497,967,280✔
830
}
831

832
void taosHashCancelIterate(SHashObj *pHashObj, void *p) {
137,727,420✔
833
  if (pHashObj == NULL || p == NULL) return;
137,727,420!
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);
138,148,967✔
840

841
  SHashEntry *pe = pHashObj->hashList[slot];
138,265,126✔
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) {
135,258,871✔
849
  void *p = NULL;
135,258,871✔
850
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, true);
135,258,871✔
851
}
852

853
void taosHashRelease(SHashObj *pHashObj, void *p) { taosHashCancelIterate(pHashObj, p); }
130,296,167✔
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