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

taosdata / TDengine / #3543

29 Nov 2024 02:58AM UTC coverage: 60.842% (+0.02%) from 60.819%
#3543

push

travis-ci

web-flow
Merge pull request #28973 from taosdata/merge/mainto3.0

merge: from main to 3.0

120460 of 253224 branches covered (47.57%)

Branch coverage included in aggregate %.

706 of 908 new or added lines in 18 files covered. (77.75%)

2401 existing lines in 137 files now uncovered.

201633 of 276172 relevant lines covered (73.01%)

19045673.23 hits per line

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

82.2
/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
  char       data[];
50
};
51

52
typedef struct SHashEntry {
53
  int32_t    num;    // number of elements in current entry
54
  SRWLatch   latch;  // entry latch
55
  SHashNode *next;
56
} SHashEntry;
57

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

73
/*
74
 * Function definition
75
 */
76
static FORCE_INLINE void taosHashWLock(SHashObj *pHashObj) {
77
  if (pHashObj->type == HASH_NO_LOCK) {
184,825,742✔
78
    return;
129,982,234✔
79
  }
80
  taosWLockLatch(&pHashObj->lock);
54,843,508✔
81
}
82

83
static FORCE_INLINE void taosHashWUnlock(SHashObj *pHashObj) {
84
  if (pHashObj->type == HASH_NO_LOCK) {
3,523,384✔
85
    return;
130,141,577✔
86
  }
87

88
  taosWUnLockLatch(&pHashObj->lock);
54,297,972✔
89
}
90

91
static FORCE_INLINE void taosHashRLock(SHashObj *pHashObj) {
92
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
93
    return;
1,881,504,486✔
94
  }
95

96
  taosRLockLatch(&pHashObj->lock);
753,990,775✔
97
}
98

99
static FORCE_INLINE void taosHashRUnlock(SHashObj *pHashObj) {
100
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647!
101
    return;
1,881,331,396✔
102
  }
103

104
  taosRUnLockLatch(&pHashObj->lock);
777,989,224✔
105
}
106

107
static FORCE_INLINE void taosHashEntryWLock(const SHashObj *pHashObj, SHashEntry *pe) {
108
  if (pHashObj->type == HASH_NO_LOCK) {
2,147,483,647✔
109
    return;
2,147,483,647✔
110
  }
111
  taosWLockLatch(&pe->latch);
998,914,773✔
112
}
113

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

119
  taosWUnLockLatch(&pe->latch);
998,895,505✔
120
}
121

122
static FORCE_INLINE void taosHashEntryRLock(const SHashObj *pHashObj, SHashEntry *pe) {
123
  if (pHashObj->type == HASH_NO_LOCK) {
1,185,792,584✔
124
    return;
855,258,397✔
125
  }
126

127
  taosRLockLatch(&pe->latch);
330,534,187✔
128
}
129

130
static FORCE_INLINE void taosHashEntryRUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
131
  if (pHashObj->type == HASH_NO_LOCK) {
1,198,806,389✔
132
    return;
859,177,204✔
133
  }
134

135
  taosRUnLockLatch(&pe->latch);
339,629,185✔
136
}
137

138
static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
139
  int32_t len = (length < HASH_MAX_CAPACITY ? length : HASH_MAX_CAPACITY);
180,173,787✔
140

141
  int32_t i = 4;
180,173,787✔
142
  while (i < len) i = (i << 1u);
614,157,366✔
143
  return i;
180,173,787✔
144
}
145

146
static FORCE_INLINE SHashNode *doSearchInEntryList(SHashObj *pHashObj, SHashEntry *pe, const void *key, size_t keyLen,
147
                                                   uint32_t hashVal) {
148
  SHashNode *pNode = pe->next;
1,198,766,561✔
149
  while (pNode) {
1,517,652,079✔
150
    // atomic_add_fetch_64(&pHashObj->compTimes, 1);
151
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
1,351,512,107✔
152
        pNode->removed == 0) {
1,032,850,230!
153
      break;
1,032,957,440✔
154
    }
155

156
    pNode = pNode->next;
318,885,518✔
157
  }
158

159
  return pNode;
1,199,097,412✔
160
}
161

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

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

180
/**
181
 * update the hash node
182
 *
183
 * @param pHashObj   hash table object
184
 * @param pe         hash table entry to operate on
185
 * @param prev       previous node
186
 * @param pNode      the old node with requested key
187
 * @param pNewNode   the new node with requested key
188
 */
189
static FORCE_INLINE void doUpdateHashNode(SHashObj *pHashObj, SHashEntry *pe, SHashNode *prev, SHashNode *pNode,
190
                                          SHashNode *pNewNode) {
191
  (void)atomic_sub_fetch_16(&pNode->refCount, 1);
45,313,024✔
192
  if (prev != NULL) {
45,343,076✔
193
    prev->next = pNewNode;
87,005✔
194
  } else {
195
    pe->next = pNewNode;
45,256,071✔
196
  }
197

198
  if (pNode->refCount <= 0) {
45,343,076!
199
    pNewNode->next = pNode->next;
45,350,105✔
200

201
    FREE_HASH_NODE(pHashObj->freeFp, pNode);
45,350,105✔
202
  } else {
203
    pNewNode->next = pNode;
×
204
    pe->num++;
×
205
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
×
206
  }
207
}
45,352,186✔
208

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

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

225
/**
226
 *
227
 * @param pHashObj
228
 * @return
229
 */
230
static FORCE_INLINE bool taosHashTableEmpty(const SHashObj *pHashObj) { return taosHashGetSize(pHashObj) == 0; }
68,363,241✔
231

232
SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool update, SHashLockTypeE type) {
180,750,763✔
233
  if (fn == NULL) {
180,750,763!
234
    terrno = TSDB_CODE_INVALID_PARA;
×
235
    return NULL;
×
236
  }
237

238
  if (capacity == 0) {
180,750,763✔
239
    capacity = 4;
3,909,584✔
240
  }
241

242
  SHashObj *pHashObj = (SHashObj *)taosMemoryMalloc(sizeof(SHashObj));
180,750,763✔
243
  if (pHashObj == NULL) {
180,173,787!
244
    return NULL;
×
245
  }
246

247
  // the max slots is not defined by user
248
  pHashObj->capacity = taosHashCapacity((int32_t)capacity);
180,173,787✔
249
  pHashObj->size = 0;
180,173,787✔
250

251
  pHashObj->equalFp = memcmp;
180,173,787✔
252
  pHashObj->hashFp = fn;
180,173,787✔
253
  pHashObj->type = type;
180,173,787✔
254
  pHashObj->lock = 0;
180,173,787✔
255
  pHashObj->enableUpdate = update;
180,173,787✔
256
  pHashObj->freeFp = NULL;
180,173,787✔
257
  pHashObj->callbackFp = NULL;
180,173,787✔
258

259
  pHashObj->hashList = (SHashEntry **)taosMemoryMalloc(pHashObj->capacity * sizeof(void *));
180,173,787✔
260
  if (pHashObj->hashList == NULL) {
180,432,621!
261
    taosMemoryFree(pHashObj);
×
262
    return NULL;
×
263
  }
264

265
  pHashObj->pMemBlock = taosArrayInit(8, sizeof(void *));
180,432,621✔
266
  if (pHashObj->pMemBlock == NULL) {
182,355,823!
267
    taosMemoryFree(pHashObj->hashList);
×
268
    taosMemoryFree(pHashObj);
×
269
    return NULL;
×
270
  }
271

272
  void *p = taosMemoryMalloc(pHashObj->capacity * sizeof(SHashEntry));
182,355,823✔
273
  if (p == NULL) {
180,626,258!
UNCOV
274
    taosArrayDestroy(pHashObj->pMemBlock);
×
275
    taosMemoryFree(pHashObj->hashList);
×
276
    taosMemoryFree(pHashObj);
×
277
    return NULL;
×
278
  }
279

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

287
  if (taosArrayPush(pHashObj->pMemBlock, &p) == NULL) {
361,793,287!
288
    taosMemoryFree(p);
×
289
    taosArrayDestroy(pHashObj->pMemBlock);
×
290
    taosMemoryFree(pHashObj->hashList);
×
291
    taosMemoryFree(pHashObj);
×
292
    return NULL;
70,662✔
293
  }
294
  return pHashObj;
181,081,257✔
295
}
296

297
void taosHashSetEqualFp(SHashObj *pHashObj, _equal_fn_t fp) {
2,078,520✔
298
  if (pHashObj != NULL && fp != NULL) {
2,078,520!
299
    pHashObj->equalFp = fp;
2,078,553✔
300
  }
301
}
2,078,520✔
302

303
void taosHashSetFreeFp(SHashObj *pHashObj, _hash_free_fn_t fp) {
10,203,428✔
304
  if (pHashObj != NULL && fp != NULL) {
10,203,428!
305
    pHashObj->freeFp = fp;
10,205,483✔
306
  }
307
}
10,203,428✔
308

309
int32_t taosHashGetSize(const SHashObj *pHashObj) {
276,577,498✔
310
  if (pHashObj == NULL) {
276,577,498✔
311
    return 0;
189,104✔
312
  }
313
  return (int32_t)atomic_load_64((int64_t *)&pHashObj->size);
276,388,394✔
314
}
315

316
int32_t taosHashPut(SHashObj *pHashObj, const void *key, size_t keyLen, const void *data, size_t size) {
600,000,001✔
317
  if (pHashObj == NULL || key == NULL || keyLen == 0) {
600,000,001!
318
    return terrno = TSDB_CODE_INVALID_PTR;
×
319
  }
320

321
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
600,179,833✔
322

323
  // need the resize process, write lock applied
324
  if (HASH_NEED_RESIZE(pHashObj)) {
599,368,213✔
325
    taosHashWLock(pHashObj);
326
    taosHashTableResize(pHashObj);
3,523,473✔
327
    taosHashWUnlock(pHashObj);
328
  }
329

330
  // disable resize
331
  taosHashRLock(pHashObj);
332

333
  int32_t     code = TSDB_CODE_SUCCESS;
600,050,625✔
334
  uint32_t    slot = HASH_INDEX(hashVal, pHashObj->capacity);
600,050,625✔
335
  SHashEntry *pe = pHashObj->hashList[slot];
600,050,625✔
336

337
  taosHashEntryWLock(pHashObj, pe);
338

339
  SHashNode *pNode = pe->next;
598,398,116✔
340
  SHashNode *prev = NULL;
598,398,116✔
341
  while (pNode) {
716,689,374✔
342
    if ((pNode->keyLen == keyLen) && (*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0 &&
163,739,538✔
343
        pNode->removed == 0) {
45,493,712!
344
      break;
45,494,062✔
345
    }
346

347
    prev = pNode;
118,291,258✔
348
    pNode = pNode->next;
118,291,258✔
349
  }
350

351
  if (pNode == NULL) {
598,443,898✔
352
    // no data in hash table with the specified key, add it into hash table
353
    SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
552,023,792✔
354
    if (pNewNode == NULL) {
552,218,843!
355
      // terrno = TSDB_CODE_OUT_OF_MEMORY;
356
      code = terrno;
×
357
      goto _exit;
×
358
    }
359

360
    pushfrontNodeInEntryList(pe, pNewNode);
552,218,843✔
361
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
551,372,979✔
362
  } else {
363
    // not support the update operation, return error
364
    if (pHashObj->enableUpdate) {
46,420,106✔
365
      SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
45,319,710✔
366
      if (pNewNode == NULL) {
45,313,024!
367
        // terrno = TSDB_CODE_OUT_OF_MEMORY;
368
        code = terrno;
×
369
        goto _exit;
×
370
      }
371

372
      doUpdateHashNode(pHashObj, pe, prev, pNode, pNewNode);
373
    } else {
374
      terrno = TSDB_CODE_DUP_KEY;
1,100,396✔
375
      code = terrno;
164,844✔
376
      goto _exit;
164,598✔
377
    }
378
  }
379
_exit:
602,397,599✔
380
  taosHashEntryWUnlock(pHashObj, pe);
381
  taosHashRUnlock(pHashObj);
382
  return code;
602,086,253✔
383
}
384

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

387
void *taosHashGet(SHashObj *pHashObj, const void *key, size_t keyLen) {
1,338,266,664✔
388
  void *p = NULL;
1,338,266,664✔
389
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, false);
1,338,266,664✔
390
}
391

392
int32_t taosHashGetDup(SHashObj *pHashObj, const void *key, size_t keyLen, void *destBuf) {
59,149,285✔
393
  terrno = 0;
59,149,285✔
394
  void *data = taosHashGetImpl(pHashObj, key, keyLen, &destBuf, 0, false);
59,142,355✔
395
  return terrno;
59,191,155✔
396
}
397

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

404
void *taosHashGetImpl(SHashObj *pHashObj, const void *key, size_t keyLen, void **d, int32_t *size, bool addRef) {
1,495,260,066✔
405
  if (pHashObj == NULL || keyLen == 0 || key == NULL) {
1,495,260,066!
406
    return NULL;
42,178,177✔
407
  }
408

409
  if ((atomic_load_64((int64_t *)&pHashObj->size) == 0)) {
1,453,081,889✔
410
    return NULL;
62,911,748✔
411
  }
412

413
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
1,356,707,346✔
414

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

418
  int32_t     slot = HASH_INDEX(hashVal, pHashObj->capacity);
1,396,469,209✔
419
  SHashEntry *pe = pHashObj->hashList[slot];
1,396,469,209✔
420

421
  // no data, return directly
422
  if (atomic_load_32(&pe->num) == 0) {
1,396,469,209✔
423
    taosHashRUnlock(pHashObj);
424
    return NULL;
176,522,471✔
425
  }
426

427
  char *data = NULL;
1,185,792,584✔
428
  taosHashEntryRLock(pHashObj, pe);
429

430
  SHashNode *pNode = doSearchInEntryList(pHashObj, pe, key, keyLen, hashVal);
1,199,097,412✔
431
  if (pNode != NULL) {
1,199,097,412✔
432
    if (pHashObj->callbackFp != NULL) {
1,032,547,799!
433
      pHashObj->callbackFp(GET_HASH_NODE_DATA(pNode));
×
434
    }
435

436
    if (size != NULL) {
1,032,547,799!
437
      if (*d == NULL) {
×
438
        *size = pNode->dataLen;
×
439
        *d = taosMemoryCalloc(1, *size);
×
440
        if (*d == NULL) {
×
441
          return NULL;
×
442
        }
443
      } else if (*size < pNode->dataLen) {
×
444
        *size = pNode->dataLen;
×
445
        char *tmp = taosMemoryRealloc(*d, *size);
×
446
        if (tmp == NULL) {
×
447
          return NULL;
×
448
        }
449

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

454
    if (addRef) {
1,032,547,799✔
455
      (void)atomic_add_fetch_16(&pNode->refCount, 1);
103,361,623✔
456
    }
457

458
    if (*d != NULL) {
1,032,256,776✔
459
      memcpy(*d, GET_HASH_NODE_DATA(pNode), pNode->dataLen);
59,044,998✔
460
    }
461

462
    data = GET_HASH_NODE_DATA(pNode);
1,032,256,776✔
463
  }
464

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

468
  return data;
1,208,413,395✔
469
}
470

471
int32_t taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
68,357,833✔
472
  if (pHashObj == NULL || taosHashTableEmpty(pHashObj) || key == NULL || keyLen == 0) {
136,650,806!
473
    return TSDB_CODE_INVALID_PARA;
1,073,900✔
474
  }
475

476
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
67,213,665✔
477

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

481
  int32_t     slot = HASH_INDEX(hashVal, pHashObj->capacity);
67,286,886✔
482
  SHashEntry *pe = pHashObj->hashList[slot];
67,286,886✔
483

484
  taosHashEntryWLock(pHashObj, pe);
485

486
  // double check after locked
487
  if (pe->num == 0) {
67,234,720✔
488
    taosHashEntryWUnlock(pHashObj, pe);
489
    taosHashRUnlock(pHashObj);
490
    return TSDB_CODE_NOT_FOUND;
5,627✔
491
  }
492

493
  int        code = TSDB_CODE_NOT_FOUND;
67,229,093✔
494
  SHashNode *pNode = pe->next;
67,229,093✔
495
  SHashNode *prevNode = NULL;
67,229,093✔
496

497
  while (pNode) {
142,811,178✔
498
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
75,508,152✔
499
        pNode->removed == 0) {
75,468,035✔
500
      code = 0;  // it is found
67,231,920✔
501

502
      (void)atomic_sub_fetch_16(&pNode->refCount, 1);
67,231,920✔
503
      pNode->removed = 1;
67,311,445✔
504
      if (pNode->refCount <= 0) {
67,311,445✔
505
        if (prevNode == NULL) {
59,070,858✔
506
          pe->next = pNode->next;
59,037,556✔
507
        } else {
508
          prevNode->next = pNode->next;
33,302✔
509
        }
510

511
        pe->num--;
59,070,858✔
512
        (void)atomic_sub_fetch_64(&pHashObj->size, 1);
59,070,858✔
513
        FREE_HASH_NODE(pHashObj->freeFp, pNode);
59,071,261✔
514
      }
515
    } else {
516
      prevNode = pNode;
8,286,717✔
517
      pNode = pNode->next;
8,286,717✔
518
    }
519
  }
520

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

524
  return code;
67,286,759✔
525
}
526

527
void taosHashClear(SHashObj *pHashObj) {
193,767,223✔
528
  if (pHashObj == NULL) {
193,767,223✔
529
    return;
12,464,954✔
530
  }
531

532
  SHashNode *pNode, *pNext;
533

534
  taosHashWLock(pHashObj);
535

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

542
    pNode = pEntry->next;
438,652,226✔
543
    while (pNode) {
928,343,066✔
544
      pNext = pNode->next;
489,216,121✔
545
      FREE_HASH_NODE(pHashObj->freeFp, pNode);
489,216,121✔
546

547
      pNode = pNext;
489,690,840✔
548
    }
549

550
    pEntry->num = 0;
439,126,945✔
551
    pEntry->next = NULL;
439,126,945✔
552
  }
553

554
  pHashObj->size = 0;
180,916,165✔
555
  taosHashWUnlock(pHashObj);
556
}
557

558
// the input paras should be SHashObj **, so the origin input will be set by taosMemoryFreeClear(*pHashObj)
559
void taosHashCleanup(SHashObj *pHashObj) {
235,264,420✔
560
  if (pHashObj == NULL) {
235,264,420✔
561
    return;
53,880,352✔
562
  }
563

564
  taosHashClear(pHashObj);
181,384,068✔
565
  taosMemoryFreeClear(pHashObj->hashList);
181,649,279!
566

567
  // destroy mem block
568
  size_t memBlock = taosArrayGetSize(pHashObj->pMemBlock);
181,592,929✔
569
  for (int32_t i = 0; i < memBlock; ++i) {
366,941,132✔
570
    void *p = taosArrayGetP(pHashObj->pMemBlock, i);
184,981,322✔
571
    taosMemoryFreeClear(p);
184,702,897✔
572
  }
573

574
  taosArrayDestroy(pHashObj->pMemBlock);
181,959,810✔
575
  taosMemoryFree(pHashObj);
181,740,288✔
576
}
577

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

584
  int32_t num = 0;
×
585

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

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

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

601
void taosHashTableResize(SHashObj *pHashObj) {
3,523,382✔
602
  if (!HASH_NEED_RESIZE(pHashObj)) {
3,523,382✔
603
    return;
10✔
604
  }
605

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

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

620
  pHashObj->hashList = pNewEntryList;
3,523,423✔
621

622
  size_t inc = newCapacity - pHashObj->capacity;
3,523,423✔
623
  void  *p = taosMemoryCalloc(inc, sizeof(SHashEntry));
3,523,423✔
624
  if (p == NULL) {
3,523,460!
625
    return;
×
626
  }
627

628
  for (int32_t i = 0; i < inc; ++i) {
454,410,069✔
629
    pHashObj->hashList[i + pHashObj->capacity] = (void *)((char *)p + i * sizeof(SHashEntry));
450,886,609✔
630
  }
631

632
  if (taosArrayPush(pHashObj->pMemBlock, &p) == NULL) {
7,046,756!
633
    taosMemoryFree(p);
×
634
    return;
×
635
  }
636

637
  pHashObj->capacity = newCapacity;
3,523,296✔
638
  for (int32_t idx = 0; idx < pHashObj->capacity; ++idx) {
903,148,563✔
639
    SHashEntry *pe = pHashObj->hashList[idx];
899,994,534✔
640
    SHashNode  *pNode;
641
    SHashNode  *pNext;
642
    SHashNode  *pPrev = NULL;
899,994,534✔
643

644
    if (pe->num == 0) {
899,994,534✔
645
      continue;
529,094,723✔
646
    }
647

648
    pNode = pe->next;
370,899,811✔
649

650
    while (pNode != NULL) {
833,939,107✔
651
      int32_t newIdx = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
463,408,563✔
652
      pNext = pNode->next;
463,408,563✔
653
      if (newIdx != idx) {
463,408,563✔
654
        pe->num -= 1;
125,895,244✔
655
        if (pPrev == NULL) {
125,895,244✔
656
          pe->next = pNext;
102,946,809✔
657
        } else {
658
          pPrev->next = pNext;
22,948,435✔
659
        }
660

661
        SHashEntry *pNewEntry = pHashObj->hashList[newIdx];
125,895,244✔
662
        pushfrontNodeInEntryList(pNewEntry, pNode);
125,895,244✔
663
      } else {
664
        pPrev = pNode;
337,513,319✔
665
      }
666
      pNode = pNext;
463,039,296✔
667
    }
668
  }
669

670
  int64_t et = taosGetTimestampUs();
3,523,388✔
671

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

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

684
  if (pNewNode == NULL) {
597,056,870!
685
    return NULL;
×
686
  }
687

688
  pNewNode->keyLen = (uint32_t)keyLen;
597,056,870✔
689
  pNewNode->hashVal = hashVal;
597,056,870✔
690
  pNewNode->dataLen = (uint32_t)dsize;
597,056,870✔
691
  pNewNode->refCount = 1;
597,056,870✔
692
  pNewNode->removed = 0;
597,056,870✔
693
  pNewNode->next = NULL;
597,056,870✔
694

695
  if (pData) memcpy(GET_HASH_NODE_DATA(pNewNode), pData, dsize);
597,056,870✔
696
  memcpy(GET_HASH_NODE_KEY(pNewNode), key, keyLen);
597,056,870✔
697

698
  return pNewNode;
597,056,870✔
699
}
700

701
void pushfrontNodeInEntryList(SHashEntry *pEntry, SHashNode *pNode) {
676,545,764✔
702
  pNode->next = pEntry->next;
676,545,764✔
703
  pEntry->next = pNode;
676,545,764✔
704
  pEntry->num += 1;
676,545,764✔
705
}
676,545,764✔
706

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

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

716
void *taosHashGetKey(void *data, size_t *keyLen) {
19,743,861✔
717
  SHashNode *node = GET_HASH_PNODE(data);
19,743,861✔
718
  if (keyLen != NULL) {
19,743,861✔
719
    *keyLen = node->keyLen;
9,470,609✔
720
  }
721

722
  return GET_HASH_NODE_KEY(node);
19,743,861✔
723
}
724

725
int32_t taosHashGetValueSize(void *data) {
48,888✔
726
  SHashNode *node = GET_HASH_PNODE(data);
48,888✔
727
  return node->dataLen;
48,888✔
728
}
729

730
// release the pNode, return next pNode, and lock the current entry
731
static void *taosHashReleaseNode(SHashObj *pHashObj, void *p, int *slot) {
528,699,254✔
732
  SHashNode *pOld = (SHashNode *)GET_HASH_PNODE(p);
528,699,254✔
733
  SHashNode *prevNode = NULL;
528,699,254✔
734

735
  *slot = HASH_INDEX(pOld->hashVal, pHashObj->capacity);
528,699,254✔
736
  SHashEntry *pe = pHashObj->hashList[*slot];
528,699,254✔
737

738
  taosHashEntryWLock(pHashObj, pe);
739

740
  SHashNode *pNode = pe->next;
527,668,913✔
741
  while (pNode) {
593,415,841!
742
    if (pNode == pOld) break;
593,426,490✔
743

744
    prevNode = pNode;
65,746,928✔
745
    pNode = pNode->next;
65,746,928✔
746
  }
747

748
  if (pNode) {
527,668,913✔
749
    pNode = pNode->next;
527,667,246✔
750
    while (pNode) {
527,669,265✔
751
      if (pNode->removed == 0) break;
59,217,371✔
752
      pNode = pNode->next;
2,019✔
753
    }
754

755
    (void)atomic_sub_fetch_16(&pOld->refCount, 1);
527,667,246✔
756
    if (pOld->refCount <= 0) {
529,219,429✔
757
      if (prevNode) {
8,255,155✔
758
        prevNode->next = pOld->next;
562✔
759
      } else {
760
        pe->next = pOld->next;
8,254,593✔
761
        SHashNode *x = pe->next;
8,254,593✔
762
        if (x != NULL) {
763
        }
764
      }
765

766
      pe->num--;
8,255,155✔
767
      (void)atomic_sub_fetch_64(&pHashObj->size, 1);
8,255,155✔
768
      FREE_HASH_NODE(pHashObj->freeFp, pOld);
8,254,549✔
769
    }
770
  } else {
771
    //    uError("pNode:%p data:%p is not there!!!", pNode, p);
772
  }
773

774
  return pNode;
529,226,672✔
775
}
776

777
void *taosHashIterate(SHashObj *pHashObj, void *p) {
523,419,907✔
778
  if (pHashObj == NULL || pHashObj->size == 0) return NULL;
523,419,907✔
779

780
  int   slot = 0;
485,623,635✔
781
  char *data = NULL;
485,623,635✔
782

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

786
  SHashNode *pNode = NULL;
480,660,974✔
787
  if (p) {
480,660,974✔
788
    pNode = taosHashReleaseNode(pHashObj, p, &slot);
420,055,368✔
789
    if (pNode == NULL) {
420,077,459✔
790
      SHashEntry *pe = pHashObj->hashList[slot];
366,348,174✔
791
      taosHashEntryWUnlock(pHashObj, pe);
792

793
      slot = slot + 1;
366,282,763✔
794
    }
795
  }
796

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

801
      taosHashEntryWLock(pHashObj, pe);
802

803
      pNode = pe->next;
2,147,483,647✔
804
      while (pNode) {
2,147,483,647✔
805
        if (pNode->removed == 0) break;
371,811,297✔
806
        pNode = pNode->next;
56,132✔
807
      }
808

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

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

815
  if (pNode) {
485,614,879✔
816
    SHashEntry *pe = pHashObj->hashList[slot];
425,509,024✔
817

818
    /*uint16_t prevRef = atomic_load_16(&pNode->refCount);*/
819
    uint16_t afterRef = atomic_add_fetch_16(&pNode->refCount, 1);
425,509,024✔
820

821
    data = GET_HASH_NODE_DATA(pNode);
425,725,064✔
822

823
    if (afterRef >= MAX_WARNING_REF_COUNT) {
425,725,064!
824
      uWarn("hash entry ref count is abnormally high: %d", afterRef);
×
825
    }
826

827
    taosHashEntryWUnlock(pHashObj, pe);
828
  }
829

830
  taosHashRUnlock(pHashObj);
831
  return data;
485,744,024✔
832
}
833

834
void taosHashCancelIterate(SHashObj *pHashObj, void *p) {
108,589,441✔
835
  if (pHashObj == NULL || p == NULL) return;
108,589,441!
836

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

840
  int   slot;
841
  void *tp = taosHashReleaseNode(pHashObj, p, &slot);
109,092,748✔
842

843
  SHashEntry *pe = pHashObj->hashList[slot];
109,186,201✔
844

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

849
// TODO remove it
850
void *taosHashAcquire(SHashObj *pHashObj, const void *key, size_t keyLen) {
103,746,899✔
851
  void *p = NULL;
103,746,899✔
852
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, true);
103,746,899✔
853
}
854

855
void taosHashRelease(SHashObj *pHashObj, void *p) { taosHashCancelIterate(pHashObj, p); }
102,927,114✔
856

857
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