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

taosdata / TDengine / #3534

21 Nov 2024 07:36AM UTC coverage: 60.825% (+2.0%) from 58.848%
#3534

push

travis-ci

web-flow
Merge pull request #28810 from taosdata/ehn/add-sync-heartbeat-sent-time-to-log

ehn:add-sync-heartbeat-sent-time-to-log

120023 of 252376 branches covered (47.56%)

Branch coverage included in aggregate %.

43 of 47 new or added lines in 3 files covered. (91.49%)

2254 existing lines in 162 files now uncovered.

200876 of 275203 relevant lines covered (72.99%)

16110754.39 hits per line

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

81.6
/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) {
181,104,067✔
78
    return;
128,788,047✔
79
  }
80
  taosWLockLatch(&pHashObj->lock);
52,316,020✔
81
}
82

83
static FORCE_INLINE void taosHashWUnlock(SHashObj *pHashObj) {
84
  if (pHashObj->type == HASH_NO_LOCK) {
3,358,844✔
85
    return;
129,037,199✔
86
  }
87

88
  taosWUnLockLatch(&pHashObj->lock);
52,031,665✔
89
}
90

91
static FORCE_INLINE void taosHashRLock(SHashObj *pHashObj) {
92
  if (pHashObj->type == HASH_NO_LOCK) {
2,001,202,180✔
93
    return;
1,700,963,387✔
94
  }
95

96
  taosRLockLatch(&pHashObj->lock);
731,598,258✔
97
}
98

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

104
  taosRUnLockLatch(&pHashObj->lock);
751,416,382✔
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);
1,058,015,418✔
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);
1,053,369,750✔
120
}
121

122
static FORCE_INLINE void taosHashEntryRLock(const SHashObj *pHashObj, SHashEntry *pe) {
123
  if (pHashObj->type == HASH_NO_LOCK) {
1,100,955,965✔
124
    return;
801,594,279✔
125
  }
126

127
  taosRLockLatch(&pe->latch);
299,361,686✔
128
}
129

130
static FORCE_INLINE void taosHashEntryRUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
131
  if (pHashObj->type == HASH_NO_LOCK) {
1,111,534,710✔
132
    return;
804,477,191✔
133
  }
134

135
  taosRUnLockLatch(&pe->latch);
307,057,519✔
136
}
137

138
static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
139
  int32_t len = (length < HASH_MAX_CAPACITY ? length : HASH_MAX_CAPACITY);
176,928,114✔
140

141
  int32_t i = 4;
176,928,114✔
142
  while (i < len) i = (i << 1u);
601,755,852✔
143
  return i;
176,928,114✔
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,112,569,664✔
149
  while (pNode) {
1,397,543,829✔
150
    // atomic_add_fetch_64(&pHashObj->compTimes, 1);
151
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
1,254,775,817✔
152
        pNode->removed == 0) {
969,205,018!
153
      break;
969,337,678✔
154
    }
155

156
    pNode = pNode->next;
284,974,165✔
157
  }
158

159
  return pNode;
1,112,105,690✔
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);
52,607,211✔
192
  if (prev != NULL) {
52,626,138✔
193
    prev->next = pNewNode;
76,994✔
194
  } else {
195
    pe->next = pNewNode;
52,549,144✔
196
  }
197

198
  if (pNode->refCount <= 0) {
52,626,138!
199
    pNewNode->next = pNode->next;
52,627,172✔
200

201
    FREE_HASH_NODE(pHashObj->freeFp, pNode);
52,627,172!
202
  } else {
203
    pNewNode->next = pNode;
×
204
    pe->num++;
×
205
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
×
206
  }
207
}
52,623,436✔
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; }
59,406,772✔
231

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

238
  if (capacity == 0) {
176,880,271✔
239
    capacity = 4;
2,826,730✔
240
  }
241

242
  SHashObj *pHashObj = (SHashObj *)taosMemoryMalloc(sizeof(SHashObj));
176,880,271✔
243
  if (pHashObj == NULL) {
176,928,114!
UNCOV
244
    return NULL;
×
245
  }
246

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

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

259
  pHashObj->hashList = (SHashEntry **)taosMemoryMalloc(pHashObj->capacity * sizeof(void *));
176,928,114✔
260
  if (pHashObj->hashList == NULL) {
177,575,679!
UNCOV
261
    taosMemoryFree(pHashObj);
×
UNCOV
262
    return NULL;
×
263
  }
264

265
  pHashObj->pMemBlock = taosArrayInit(8, sizeof(void *));
177,575,679✔
266
  if (pHashObj->pMemBlock == NULL) {
178,212,177!
UNCOV
267
    taosMemoryFree(pHashObj->hashList);
×
UNCOV
268
    taosMemoryFree(pHashObj);
×
UNCOV
269
    return NULL;
×
270
  }
271

272
  void *p = taosMemoryMalloc(pHashObj->capacity * sizeof(SHashEntry));
178,212,177✔
273
  if (p == NULL) {
178,200,877✔
274
    taosArrayDestroy(pHashObj->pMemBlock);
1,341,028✔
UNCOV
275
    taosMemoryFree(pHashObj->hashList);
×
UNCOV
276
    taosMemoryFree(pHashObj);
×
UNCOV
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) {
353,109,760!
288
    taosMemoryFree(p);
×
289
    taosArrayDestroy(pHashObj->pMemBlock);
×
290
    taosMemoryFree(pHashObj->hashList);
×
291
    taosMemoryFree(pHashObj);
×
292
    return NULL;
×
293
  }
294
  return pHashObj;
176,249,911✔
295
}
296

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

303
void taosHashSetFreeFp(SHashObj *pHashObj, _hash_free_fn_t fp) {
9,736,263✔
304
  if (pHashObj != NULL && fp != NULL) {
9,736,263!
305
    pHashObj->freeFp = fp;
9,737,273✔
306
  }
307
}
9,736,263✔
308

309
int32_t taosHashGetSize(const SHashObj *pHashObj) {
257,845,326✔
310
  if (pHashObj == NULL) {
257,845,326✔
311
    return 0;
210,056✔
312
  }
313
  return (int32_t)atomic_load_64((int64_t *)&pHashObj->size);
257,635,270✔
314
}
315

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

321
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
597,958,865✔
322

323
  // need the resize process, write lock applied
324
  if (HASH_NEED_RESIZE(pHashObj)) {
597,105,608✔
325
    taosHashWLock(pHashObj);
326
    taosHashTableResize(pHashObj);
3,358,866✔
327
    taosHashWUnlock(pHashObj);
328
  }
329

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

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

337
  taosHashEntryWLock(pHashObj, pe);
338

339
  SHashNode *pNode = pe->next;
596,452,918✔
340
  SHashNode *prev = NULL;
596,452,918✔
341
  while (pNode) {
680,545,092✔
342
    if ((pNode->keyLen == keyLen) && (*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0 &&
136,908,686✔
343
        pNode->removed == 0) {
52,825,547!
344
      break;
52,825,770✔
345
    }
346

347
    prev = pNode;
84,092,174✔
348
    pNode = pNode->next;
84,092,174✔
349
  }
350

351
  if (pNode == NULL) {
596,462,176✔
352
    // no data in hash table with the specified key, add it into hash table
353
    SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
543,435,585✔
354
    if (pNewNode == NULL) {
543,101,003!
355
      // terrno = TSDB_CODE_OUT_OF_MEMORY;
UNCOV
356
      code = terrno;
×
UNCOV
357
      goto _exit;
×
358
    }
359

360
    pushfrontNodeInEntryList(pe, pNewNode);
543,101,003✔
361
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
542,650,357✔
362
  } else {
363
    // not support the update operation, return error
364
    if (pHashObj->enableUpdate) {
53,026,591✔
365
      SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
52,595,826✔
366
      if (pNewNode == NULL) {
52,607,211!
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;
430,765✔
375
      code = terrno;
217,473✔
376
      goto _exit;
217,265✔
377
    }
378
  }
379
_exit:
599,805,209✔
380
  taosHashEntryWUnlock(pHashObj, pe);
381
  taosHashRUnlock(pHashObj);
382
  return code;
599,122,523✔
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,210,245,986✔
388
  void *p = NULL;
1,210,245,986✔
389
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, false);
1,210,245,986✔
390
}
391

392
int32_t taosHashGetDup(SHashObj *pHashObj, const void *key, size_t keyLen, void *destBuf) {
55,192,967✔
393
  terrno = 0;
55,192,967✔
394
  void *data = taosHashGetImpl(pHashObj, key, keyLen, &destBuf, 0, false);
55,195,997✔
395
  return terrno;
55,237,404✔
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,360,647,319✔
405
  if (pHashObj == NULL || keyLen == 0 || key == NULL) {
1,360,647,319!
406
    return NULL;
37,405,086✔
407
  }
408

409
  if ((atomic_load_64((int64_t *)&pHashObj->size) == 0)) {
1,323,242,233✔
410
    return NULL;
74,029,235✔
411
  }
412

413
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
1,224,828,828✔
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,257,667,457✔
419
  SHashEntry *pe = pHashObj->hashList[slot];
1,257,667,457✔
420

421
  // no data, return directly
422
  if (atomic_load_32(&pe->num) == 0) {
1,257,667,457✔
423
    taosHashRUnlock(pHashObj);
424
    return NULL;
128,153,366✔
425
  }
426

427
  char *data = NULL;
1,100,955,965✔
428
  taosHashEntryRLock(pHashObj, pe);
429

430
  SHashNode *pNode = doSearchInEntryList(pHashObj, pe, key, keyLen, hashVal);
1,112,105,690✔
431
  if (pNode != NULL) {
1,112,105,690✔
432
    if (pHashObj->callbackFp != NULL) {
969,170,816!
433
      pHashObj->callbackFp(GET_HASH_NODE_DATA(pNode));
×
434
    }
435

436
    if (size != NULL) {
969,170,816!
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) {
969,170,816✔
455
      (void)atomic_add_fetch_16(&pNode->refCount, 1);
99,749,888✔
456
    }
457

458
    if (*d != NULL) {
968,599,836✔
459
      memcpy(*d, GET_HASH_NODE_DATA(pNode), pNode->dataLen);
55,095,284✔
460
    }
461

462
    data = GET_HASH_NODE_DATA(pNode);
968,599,836✔
463
  }
464

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

468
  return data;
1,117,581,499✔
469
}
470

471
int32_t taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
59,402,662✔
472
  if (pHashObj == NULL || taosHashTableEmpty(pHashObj) || key == NULL || keyLen == 0) {
118,765,117!
473
    return TSDB_CODE_INVALID_PARA;
286,856✔
474
  }
475

476
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
59,071,489✔
477

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

481
  int32_t     slot = HASH_INDEX(hashVal, pHashObj->capacity);
59,113,120✔
482
  SHashEntry *pe = pHashObj->hashList[slot];
59,113,120✔
483

484
  taosHashEntryWLock(pHashObj, pe);
485

486
  // double check after locked
487
  if (pe->num == 0) {
59,072,291✔
488
    taosHashEntryWUnlock(pHashObj, pe);
489
    taosHashRUnlock(pHashObj);
490
    return TSDB_CODE_NOT_FOUND;
4,252✔
491
  }
492

493
  int        code = TSDB_CODE_NOT_FOUND;
59,068,039✔
494
  SHashNode *pNode = pe->next;
59,068,039✔
495
  SHashNode *prevNode = NULL;
59,068,039✔
496

497
  while (pNode) {
125,353,145✔
498
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
66,229,969✔
499
        pNode->removed == 0) {
66,196,011✔
500
      code = 0;  // it is found
59,072,000✔
501

502
      (void)atomic_sub_fetch_16(&pNode->refCount, 1);
59,072,000✔
503
      pNode->removed = 1;
59,134,255✔
504
      if (pNode->refCount <= 0) {
59,134,255✔
505
        if (prevNode == NULL) {
52,004,816✔
506
          pe->next = pNode->next;
51,972,625✔
507
        } else {
508
          prevNode->next = pNode->next;
32,191✔
509
        }
510

511
        pe->num--;
52,004,816✔
512
        (void)atomic_sub_fetch_64(&pHashObj->size, 1);
52,004,816✔
513
        FREE_HASH_NODE(pHashObj->freeFp, pNode);
51,999,639✔
514
      }
515
    } else {
516
      prevNode = pNode;
7,167,186✔
517
      pNode = pNode->next;
7,167,186✔
518
    }
519
  }
520

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

524
  return code;
59,101,110✔
525
}
526

527
void taosHashClear(SHashObj *pHashObj) {
190,092,657✔
528
  if (pHashObj == NULL) {
190,092,657✔
529
    return;
12,347,456✔
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;
450,235,601✔
543
    while (pNode) {
938,302,895✔
544
      pNext = pNode->next;
487,328,045✔
545
      FREE_HASH_NODE(pHashObj->freeFp, pNode);
487,328,045✔
546

547
      pNode = pNext;
488,067,294✔
548
    }
549

550
    pEntry->num = 0;
450,974,850✔
551
    pEntry->next = NULL;
450,974,850✔
552
  }
553

554
  pHashObj->size = 0;
177,710,020✔
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) {
230,653,976✔
560
  if (pHashObj == NULL) {
230,653,976✔
561
    return;
52,924,526✔
562
  }
563

564
  taosHashClear(pHashObj);
177,729,450✔
565
  taosMemoryFreeClear(pHashObj->hashList);
177,789,428!
566

567
  // destroy mem block
568
  size_t memBlock = taosArrayGetSize(pHashObj->pMemBlock);
177,865,281✔
569
  for (int32_t i = 0; i < memBlock; ++i) {
359,067,241✔
570
    void *p = taosArrayGetP(pHashObj->pMemBlock, i);
180,911,792✔
571
    taosMemoryFreeClear(p);
180,479,363!
572
  }
573

574
  taosArrayDestroy(pHashObj->pMemBlock);
178,155,449✔
575
  taosMemoryFree(pHashObj);
177,964,918✔
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,358,751✔
602
  if (!HASH_NEED_RESIZE(pHashObj)) {
3,358,751✔
603
    return;
7✔
604
  }
605

606
  int32_t newCapacity = (int32_t)(pHashObj->capacity << 1u);
3,358,744✔
607
  if (newCapacity > HASH_MAX_CAPACITY) {
3,358,744!
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,358,725✔
614
  SHashEntry **pNewEntryList = taosMemoryRealloc(pHashObj->hashList, sizeof(SHashEntry *) * newCapacity);
3,358,725✔
615
  if (pNewEntryList == NULL) {
3,358,737!
616
    //    uDebug("cache resize failed due to out of memory, capacity remain:%zu", pHashObj->capacity);
617
    return;
×
618
  }
619

620
  pHashObj->hashList = pNewEntryList;
3,358,737✔
621

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

628
  for (int32_t i = 0; i < inc; ++i) {
385,742,990✔
629
    pHashObj->hashList[i + pHashObj->capacity] = (void *)((char *)p + i * sizeof(SHashEntry));
382,384,106✔
630
  }
631

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

637
  pHashObj->capacity = newCapacity;
3,358,790✔
638
  for (int32_t idx = 0; idx < pHashObj->capacity; ++idx) {
766,776,553✔
639
    SHashEntry *pe = pHashObj->hashList[idx];
763,686,305✔
640
    SHashNode  *pNode;
641
    SHashNode  *pNext;
642
    SHashNode  *pPrev = NULL;
763,686,305✔
643

644
    if (pe->num == 0) {
763,686,305✔
645
      continue;
457,531,922✔
646
    }
647

648
    pNode = pe->next;
306,154,383✔
649

650
    while (pNode != NULL) {
666,616,220✔
651
      int32_t newIdx = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
360,730,379✔
652
      pNext = pNode->next;
360,730,379✔
653
      if (newIdx != idx) {
360,730,379✔
654
        pe->num -= 1;
74,345,185✔
655
        if (pPrev == NULL) {
74,345,185✔
656
          pe->next = pNext;
59,407,156✔
657
        } else {
658
          pPrev->next = pNext;
14,938,029✔
659
        }
660

661
        SHashEntry *pNewEntry = pHashObj->hashList[newIdx];
74,345,185✔
662
        pushfrontNodeInEntryList(pNewEntry, pNode);
74,345,185✔
663
      } else {
664
        pPrev = pNode;
286,385,194✔
665
      }
666
      pNode = pNext;
360,461,837✔
667
    }
668
  }
669

670
  int64_t et = taosGetTimestampUs();
3,358,868✔
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) {
595,695,628✔
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);
595,695,628✔
682
#endif
683

684
  if (pNewNode == NULL) {
595,554,224!
UNCOV
685
    return NULL;
×
686
  }
687

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

695
  if (pData) memcpy(GET_HASH_NODE_DATA(pNewNode), pData, dsize);
595,554,224✔
696
  memcpy(GET_HASH_NODE_KEY(pNewNode), key, keyLen);
595,554,224✔
697

698
  return pNewNode;
595,554,224✔
699
}
700

701
void pushfrontNodeInEntryList(SHashEntry *pEntry, SHashNode *pNode) {
616,436,194✔
702
  pNode->next = pEntry->next;
616,436,194✔
703
  pEntry->next = pNode;
616,436,194✔
704
  pEntry->num += 1;
616,436,194✔
705
}
616,436,194✔
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,823,229✔
717
  SHashNode *node = GET_HASH_PNODE(data);
19,823,229✔
718
  if (keyLen != NULL) {
19,823,229✔
719
    *keyLen = node->keyLen;
10,481,177✔
720
  }
721

722
  return GET_HASH_NODE_KEY(node);
19,823,229✔
723
}
724

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

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

735
  *slot = HASH_INDEX(pOld->hashVal, pHashObj->capacity);
470,478,751✔
736
  SHashEntry *pe = pHashObj->hashList[*slot];
470,478,751✔
737

738
  taosHashEntryWLock(pHashObj, pe);
739

740
  SHashNode *pNode = pe->next;
469,768,687✔
741
  while (pNode) {
519,207,677!
742
    if (pNode == pOld) break;
519,223,844✔
743

744
    prevNode = pNode;
49,438,990✔
745
    pNode = pNode->next;
49,438,990✔
746
  }
747

748
  if (pNode) {
469,768,687!
749
    pNode = pNode->next;
469,773,352✔
750
    while (pNode) {
469,774,724✔
751
      if (pNode->removed == 0) break;
45,115,185✔
752
      pNode = pNode->next;
1,372✔
753
    }
754

755
    (void)atomic_sub_fetch_16(&pOld->refCount, 1);
469,773,352✔
756
    if (pOld->refCount <= 0) {
470,893,480✔
757
      if (prevNode) {
7,134,332✔
758
        prevNode->next = pOld->next;
498✔
759
      } else {
760
        pe->next = pOld->next;
7,133,834✔
761
        SHashNode *x = pe->next;
7,133,834✔
762
        if (x != NULL) {
763
        }
764
      }
765

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

774
  return pNode;
470,861,779✔
775
}
776

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

780
  int   slot = 0;
431,359,465✔
781
  char *data = NULL;
431,359,465✔
782

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

786
  SHashNode *pNode = NULL;
426,301,998✔
787
  if (p) {
426,301,998✔
788
    pNode = taosHashReleaseNode(pHashObj, p, &slot);
363,135,306✔
789
    if (pNode == NULL) {
363,167,718✔
790
      SHashEntry *pe = pHashObj->hashList[slot];
324,241,487✔
791
      taosHashEntryWUnlock(pHashObj, pe);
792

793
      slot = slot + 1;
324,227,368✔
794
    }
795
  }
796

797
  if (pNode == NULL) {
426,320,291✔
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;
332,124,006✔
806
        pNode = pNode->next;
47,948✔
807
      }
808

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

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

815
  if (pNode) {
431,352,956✔
816
    SHashEntry *pe = pHashObj->hashList[slot];
371,008,315✔
817

818
    /*uint16_t prevRef = atomic_load_16(&pNode->refCount);*/
819
    uint16_t afterRef = atomic_add_fetch_16(&pNode->refCount, 1);
371,008,315✔
820

821
    data = GET_HASH_NODE_DATA(pNode);
371,075,411✔
822

823
    if (afterRef >= MAX_WARNING_REF_COUNT) {
371,075,411!
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;
431,368,352✔
832
}
833

834
void taosHashCancelIterate(SHashObj *pHashObj, void *p) {
107,298,392✔
835
  if (pHashObj == NULL || p == NULL) return;
107,298,392!
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);
107,749,582✔
842

843
  SHashEntry *pe = pHashObj->hashList[slot];
107,784,503✔
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) {
102,445,046✔
851
  void *p = NULL;
102,445,046✔
852
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, true);
102,445,046✔
853
}
854

855
void taosHashRelease(SHashObj *pHashObj, void *p) { taosHashCancelIterate(pHashObj, p); }
99,358,581✔
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