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

taosdata / TDengine / #3531

19 Nov 2024 10:42AM UTC coverage: 60.213% (-0.006%) from 60.219%
#3531

push

travis-ci

web-flow
Merge pull request #28777 from taosdata/fix/3.0/TD-32366

fix:TD-32366/stmt add geometry datatype check

118529 of 252344 branches covered (46.97%)

Branch coverage included in aggregate %.

7 of 48 new or added lines in 3 files covered. (14.58%)

2282 existing lines in 115 files now uncovered.

199096 of 275161 relevant lines covered (72.36%)

6067577.83 hits per line

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

82.05
/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) {
72,403,513✔
78
    return;
57,181,733✔
79
  }
80
  taosWLockLatch(&pHashObj->lock);
15,221,780✔
81
}
82

83
static FORCE_INLINE void taosHashWUnlock(SHashObj *pHashObj) {
84
  if (pHashObj->type == HASH_NO_LOCK) {
1,238,345✔
85
    return;
57,182,915✔
86
  }
87

88
  taosWUnLockLatch(&pHashObj->lock);
15,040,476✔
89
}
90

91
static FORCE_INLINE void taosHashRLock(SHashObj *pHashObj) {
92
  if (pHashObj->type == HASH_NO_LOCK) {
757,864,867✔
93
    return;
691,528,255✔
94
  }
95

96
  taosRLockLatch(&pHashObj->lock);
163,369,907✔
97
}
98

99
static FORCE_INLINE void taosHashRUnlock(SHashObj *pHashObj) {
100
  if (pHashObj->type == HASH_NO_LOCK) {
857,083,546!
101
    return;
693,607,094✔
102
  }
103

104
  taosRUnLockLatch(&pHashObj->lock);
163,476,452✔
105
}
106

107
static FORCE_INLINE void taosHashEntryWLock(const SHashObj *pHashObj, SHashEntry *pe) {
108
  if (pHashObj->type == HASH_NO_LOCK) {
1,362,449,281✔
109
    return;
1,202,232,959✔
110
  }
111
  taosWLockLatch(&pe->latch);
160,216,322✔
112
}
113

114
static FORCE_INLINE void taosHashEntryWUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
115
  if (pHashObj->type == HASH_NO_LOCK) {
1,081,204,060✔
116
    return;
1,203,219,055✔
117
  }
118

119
  taosWUnLockLatch(&pe->latch);
160,151,330✔
120
}
121

122
static FORCE_INLINE void taosHashEntryRLock(const SHashObj *pHashObj, SHashEntry *pe) {
123
  if (pHashObj->type == HASH_NO_LOCK) {
429,514,454✔
124
    return;
345,712,630✔
125
  }
126

127
  taosRLockLatch(&pe->latch);
83,801,824✔
128
}
129

130
static FORCE_INLINE void taosHashEntryRUnlock(const SHashObj *pHashObj, SHashEntry *pe) {
131
  if (pHashObj->type == HASH_NO_LOCK) {
430,450,598✔
132
    return;
345,737,974✔
133
  }
134

135
  taosRUnLockLatch(&pe->latch);
84,712,624✔
136
}
137

138
static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
139
  int32_t len = (length < HASH_MAX_CAPACITY ? length : HASH_MAX_CAPACITY);
71,324,191✔
140

141
  int32_t i = 4;
71,324,191✔
142
  while (i < len) i = (i << 1u);
196,129,273✔
143
  return i;
71,324,191✔
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;
430,536,888✔
149
  while (pNode) {
587,568,107✔
150
    // atomic_add_fetch_64(&pHashObj->compTimes, 1);
151
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
494,475,140✔
152
        pNode->removed == 0) {
337,424,312!
153
      break;
337,439,735✔
154
    }
155

156
    pNode = pNode->next;
157,031,219✔
157
  }
158

159
  return pNode;
430,532,702✔
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);
14,898,162✔
192
  if (prev != NULL) {
14,907,109✔
193
    prev->next = pNewNode;
52,321✔
194
  } else {
195
    pe->next = pNewNode;
14,854,788✔
196
  }
197

198
  if (pNode->refCount <= 0) {
14,907,109!
199
    pNewNode->next = pNode->next;
14,909,332✔
200

201
    FREE_HASH_NODE(pHashObj->freeFp, pNode);
14,909,332!
202
  } else {
UNCOV
203
    pNewNode->next = pNode;
×
UNCOV
204
    pe->num++;
×
UNCOV
205
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
×
206
  }
207
}
14,907,459✔
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; }
22,991,820✔
231

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

238
  if (capacity == 0) {
71,322,587✔
239
    capacity = 4;
249,683✔
240
  }
241

242
  SHashObj *pHashObj = (SHashObj *)taosMemoryMalloc(sizeof(SHashObj));
71,322,587✔
243
  if (pHashObj == NULL) {
71,324,191!
244
    return NULL;
×
245
  }
246

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

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

259
  pHashObj->hashList = (SHashEntry **)taosMemoryMalloc(pHashObj->capacity * sizeof(void *));
71,324,191✔
260
  if (pHashObj->hashList == NULL) {
71,320,620!
261
    taosMemoryFree(pHashObj);
×
262
    return NULL;
×
263
  }
264

265
  pHashObj->pMemBlock = taosArrayInit(8, sizeof(void *));
71,320,620✔
266
  if (pHashObj->pMemBlock == NULL) {
71,331,368!
267
    taosMemoryFree(pHashObj->hashList);
×
268
    taosMemoryFree(pHashObj);
×
269
    return NULL;
×
270
  }
271

272
  void *p = taosMemoryMalloc(pHashObj->capacity * sizeof(SHashEntry));
71,331,368✔
273
  if (p == NULL) {
71,329,053✔
274
    taosArrayDestroy(pHashObj->pMemBlock);
2,260✔
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) {
142,647,854!
288
    taosMemoryFree(p);
×
289
    taosArrayDestroy(pHashObj->pMemBlock);
×
290
    taosMemoryFree(pHashObj->hashList);
×
291
    taosMemoryFree(pHashObj);
×
UNCOV
292
    return NULL;
×
293
  }
294
  return pHashObj;
71,321,061✔
295
}
296

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

303
void taosHashSetFreeFp(SHashObj *pHashObj, _hash_free_fn_t fp) {
1,874,448✔
304
  if (pHashObj != NULL && fp != NULL) {
1,874,448!
305
    pHashObj->freeFp = fp;
1,874,448✔
306
  }
307
}
1,874,448✔
308

309
int32_t taosHashGetSize(const SHashObj *pHashObj) {
90,775,399✔
310
  if (pHashObj == NULL) {
90,775,399✔
311
    return 0;
88,142✔
312
  }
313
  return (int32_t)atomic_load_64((int64_t *)&pHashObj->size);
90,687,257✔
314
}
315

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

321
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
197,492,272✔
322

323
  // need the resize process, write lock applied
324
  if (HASH_NEED_RESIZE(pHashObj)) {
196,936,682✔
325
    taosHashWLock(pHashObj);
326
    taosHashTableResize(pHashObj);
1,238,371✔
327
    taosHashWUnlock(pHashObj);
328
  }
329

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

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

337
  taosHashEntryWLock(pHashObj, pe);
338

339
  SHashNode *pNode = pe->next;
196,582,788✔
340
  SHashNode *prev = NULL;
196,582,788✔
341
  while (pNode) {
240,141,497✔
342
    if ((pNode->keyLen == keyLen) && (*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0 &&
58,580,167✔
343
        pNode->removed == 0) {
15,054,180✔
344
      break;
15,054,137✔
345
    }
346

347
    prev = pNode;
43,558,709✔
348
    pNode = pNode->next;
43,558,709✔
349
  }
350

351
  if (pNode == NULL) {
196,615,467✔
352
    // no data in hash table with the specified key, add it into hash table
353
    SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
180,427,861✔
354
    if (pNewNode == NULL) {
179,923,072!
355
      // terrno = TSDB_CODE_OUT_OF_MEMORY;
356
      code = terrno;
×
357
      goto _exit;
×
358
    }
359

360
    pushfrontNodeInEntryList(pe, pNewNode);
179,923,072✔
361
    (void)atomic_add_fetch_64(&pHashObj->size, 1);
179,321,374✔
362
  } else {
363
    // not support the update operation, return error
364
    if (pHashObj->enableUpdate) {
16,187,606✔
365
      SHashNode *pNewNode = doCreateHashNode(key, keyLen, data, size, hashVal);
14,894,033✔
366
      if (pNewNode == NULL) {
14,898,162!
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,293,573✔
375
      code = terrno;
155,024✔
376
      goto _exit;
154,584✔
377
    }
378
  }
379
_exit:
197,618,208✔
380
  taosHashEntryWUnlock(pHashObj, pe);
381
  taosHashRUnlock(pHashObj);
382
  return code;
197,439,038✔
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) {
510,567,612✔
388
  void *p = NULL;
510,567,612✔
389
  return taosHashGetImpl(pHashObj, key, keyLen, &p, 0, false);
510,567,612✔
390
}
391

392
int32_t taosHashGetDup(SHashObj *pHashObj, const void *key, size_t keyLen, void *destBuf) {
11,369,103✔
393
  terrno = 0;
11,369,103✔
394
  void *data = taosHashGetImpl(pHashObj, key, keyLen, &destBuf, 0, false);
11,368,785✔
395
  return terrno;
11,374,292✔
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) {
552,800,462✔
405
  if (pHashObj == NULL || keyLen == 0 || key == NULL) {
552,800,462!
406
    return NULL;
13,339,828✔
407
  }
408

409
  if ((atomic_load_64((int64_t *)&pHashObj->size) == 0)) {
539,460,634✔
410
    return NULL;
31,286,089✔
411
  }
412

413
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
508,148,948✔
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);
509,392,966✔
419
  SHashEntry *pe = pHashObj->hashList[slot];
509,392,966✔
420

421
  // no data, return directly
422
  if (atomic_load_32(&pe->num) == 0) {
509,392,966✔
423
    taosHashRUnlock(pHashObj);
424
    return NULL;
80,059,647✔
425
  }
426

427
  char *data = NULL;
429,514,454✔
428
  taosHashEntryRLock(pHashObj, pe);
429

430
  SHashNode *pNode = doSearchInEntryList(pHashObj, pe, key, keyLen, hashVal);
430,532,702✔
431
  if (pNode != NULL) {
430,532,702✔
432
    if (pHashObj->callbackFp != NULL) {
337,405,584!
433
      pHashObj->callbackFp(GET_HASH_NODE_DATA(pNode));
×
434
    }
435

436
    if (size != NULL) {
337,405,584!
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) {
337,405,584✔
455
      (void)atomic_add_fetch_16(&pNode->refCount, 1);
28,370,258✔
456
    }
457

458
    if (*d != NULL) {
337,323,480✔
459
      memcpy(*d, GET_HASH_NODE_DATA(pNode), pNode->dataLen);
11,292,438✔
460
    }
461

462
    data = GET_HASH_NODE_DATA(pNode);
337,323,480✔
463
  }
464

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

468
  return data;
430,534,987✔
469
}
470

471
int32_t taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
22,990,874✔
472
  if (pHashObj == NULL || taosHashTableEmpty(pHashObj) || key == NULL || keyLen == 0) {
45,982,109!
473
    return TSDB_CODE_INVALID_PARA;
278,418✔
474
  }
475

476
  uint32_t hashVal = (*pHashObj->hashFp)(key, (uint32_t)keyLen);
22,711,871✔
477

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

481
  int32_t     slot = HASH_INDEX(hashVal, pHashObj->capacity);
22,712,464✔
482
  SHashEntry *pe = pHashObj->hashList[slot];
22,712,464✔
483

484
  taosHashEntryWLock(pHashObj, pe);
485

486
  // double check after locked
487
  if (pe->num == 0) {
22,712,336✔
488
    taosHashEntryWUnlock(pHashObj, pe);
489
    taosHashRUnlock(pHashObj);
490
    return TSDB_CODE_NOT_FOUND;
2,531✔
491
  }
492

493
  int        code = TSDB_CODE_NOT_FOUND;
22,709,805✔
494
  SHashNode *pNode = pe->next;
22,709,805✔
495
  SHashNode *prevNode = NULL;
22,709,805✔
496

497
  while (pNode) {
47,264,587✔
498
    if ((pNode->keyLen == keyLen) && ((*(pHashObj->equalFp))(GET_HASH_NODE_KEY(pNode), key, keyLen) == 0) &&
24,550,436✔
499
        pNode->removed == 0) {
24,532,781✔
500
      code = 0;  // it is found
22,709,112✔
501

502
      (void)atomic_sub_fetch_16(&pNode->refCount, 1);
22,709,112✔
503
      pNode->removed = 1;
22,710,740✔
504
      if (pNode->refCount <= 0) {
22,710,740✔
505
        if (prevNode == NULL) {
20,888,525✔
506
          pe->next = pNode->next;
20,872,487✔
507
        } else {
508
          prevNode->next = pNode->next;
16,038✔
509
        }
510

511
        pe->num--;
20,888,525✔
512
        (void)atomic_sub_fetch_64(&pHashObj->size, 1);
20,888,525✔
513
        FREE_HASH_NODE(pHashObj->freeFp, pNode);
20,890,119✔
514
      }
515
    } else {
516
      prevNode = pNode;
1,842,046✔
517
      pNode = pNode->next;
1,842,046✔
518
    }
519
  }
520

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

524
  return code;
22,712,484✔
525
}
526

527
void taosHashClear(SHashObj *pHashObj) {
73,854,362✔
528
  if (pHashObj == NULL) {
73,854,362✔
529
    return;
2,689,220✔
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;
145,200,060✔
543
    while (pNode) {
306,320,491✔
544
      pNext = pNode->next;
161,304,380✔
545
      FREE_HASH_NODE(pHashObj->freeFp, pNode);
161,304,380✔
546

547
      pNode = pNext;
161,120,431✔
548
    }
549

550
    pEntry->num = 0;
145,016,111✔
551
    pEntry->next = NULL;
145,016,111✔
552
  }
553

554
  pHashObj->size = 0;
70,985,046✔
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) {
96,408,026✔
560
  if (pHashObj == NULL) {
96,408,026✔
561
    return;
25,474,759✔
562
  }
563

564
  taosHashClear(pHashObj);
70,933,267✔
565
  taosMemoryFreeClear(pHashObj->hashList);
70,938,225!
566

567
  // destroy mem block
568
  size_t memBlock = taosArrayGetSize(pHashObj->pMemBlock);
70,937,122✔
569
  for (int32_t i = 0; i < memBlock; ++i) {
143,103,456✔
570
    void *p = taosArrayGetP(pHashObj->pMemBlock, i);
72,171,298✔
571
    taosMemoryFreeClear(p);
72,168,696!
572
  }
573

574
  taosArrayDestroy(pHashObj->pMemBlock);
70,932,158✔
575
  taosMemoryFree(pHashObj);
70,938,677✔
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) {
1,238,345✔
602
  if (!HASH_NEED_RESIZE(pHashObj)) {
1,238,345✔
603
    return;
10✔
604
  }
605

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

620
  pHashObj->hashList = pNewEntryList;
1,238,363✔
621

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

628
  for (int32_t i = 0; i < inc; ++i) {
119,707,082✔
629
    pHashObj->hashList[i + pHashObj->capacity] = (void *)((char *)p + i * sizeof(SHashEntry));
118,468,732✔
630
  }
631

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

637
  pHashObj->capacity = newCapacity;
1,238,329✔
638
  for (int32_t idx = 0; idx < pHashObj->capacity; ++idx) {
236,238,708✔
639
    SHashEntry *pe = pHashObj->hashList[idx];
235,305,959✔
640
    SHashNode  *pNode;
641
    SHashNode  *pNext;
642
    SHashNode  *pPrev = NULL;
235,305,959✔
643

644
    if (pe->num == 0) {
235,305,959✔
645
      continue;
133,895,674✔
646
    }
647

648
    pNode = pe->next;
101,410,285✔
649

650
    while (pNode != NULL) {
233,281,130✔
651
      int32_t newIdx = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
132,176,425✔
652
      pNext = pNode->next;
132,176,425✔
653
      if (newIdx != idx) {
132,176,425✔
654
        pe->num -= 1;
43,909,232✔
655
        if (pPrev == NULL) {
43,909,232✔
656
          pe->next = pNext;
33,441,958✔
657
        } else {
658
          pPrev->next = pNext;
10,467,274✔
659
        }
660

661
        SHashEntry *pNewEntry = pHashObj->hashList[newIdx];
43,909,232✔
662
        pushfrontNodeInEntryList(pNewEntry, pNode);
43,909,232✔
663
      } else {
664
        pPrev = pNode;
88,267,193✔
665
      }
666
      pNode = pNext;
131,870,845✔
667
    }
668
  }
669

670
  int64_t et = taosGetTimestampUs();
1,238,336✔
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) {
195,004,744✔
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);
195,004,744✔
682
#endif
683

684
  if (pNewNode == NULL) {
195,120,488!
685
    return NULL;
×
686
  }
687

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

695
  if (pData) memcpy(GET_HASH_NODE_DATA(pNewNode), pData, dsize);
195,120,488✔
696
  memcpy(GET_HASH_NODE_KEY(pNewNode), key, keyLen);
195,120,488✔
697

698
  return pNewNode;
195,120,488✔
699
}
700

701
void pushfrontNodeInEntryList(SHashEntry *pEntry, SHashNode *pNode) {
222,662,160✔
702
  pNode->next = pEntry->next;
222,662,160✔
703
  pEntry->next = pNode;
222,662,160✔
704
  pEntry->num += 1;
222,662,160✔
705
}
222,662,160✔
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) {
16,743,214✔
717
  SHashNode *node = GET_HASH_PNODE(data);
16,743,214✔
718
  if (keyLen != NULL) {
16,743,214✔
719
    *keyLen = node->keyLen;
9,065,830✔
720
  }
721

722
  return GET_HASH_NODE_KEY(node);
16,743,214✔
723
}
724

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

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

735
  *slot = HASH_INDEX(pOld->hashVal, pHashObj->capacity);
90,984,377✔
736
  SHashEntry *pe = pHashObj->hashList[*slot];
90,984,377✔
737

738
  taosHashEntryWLock(pHashObj, pe);
739

740
  SHashNode *pNode = pe->next;
90,985,386✔
741
  while (pNode) {
99,910,598✔
742
    if (pNode == pOld) break;
99,908,811✔
743

744
    prevNode = pNode;
8,925,212✔
745
    pNode = pNode->next;
8,925,212✔
746
  }
747

748
  if (pNode) {
90,985,386✔
749
    pNode = pNode->next;
90,982,903✔
750
    while (pNode) {
90,983,884✔
751
      if (pNode->removed == 0) break;
7,126,936✔
752
      pNode = pNode->next;
981✔
753
    }
754

755
    (void)atomic_sub_fetch_16(&pOld->refCount, 1);
90,982,903✔
756
    if (pOld->refCount <= 0) {
90,990,226✔
757
      if (prevNode) {
1,824,569✔
758
        prevNode->next = pOld->next;
144✔
759
      } else {
760
        pe->next = pOld->next;
1,824,425✔
761
        SHashNode *x = pe->next;
1,824,425✔
762
        if (x != NULL) {
763
        }
764
      }
765

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

774
  return pNode;
90,988,522✔
775
}
776

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

780
  int   slot = 0;
97,033,295✔
781
  char *data = NULL;
97,033,295✔
782

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

786
  SHashNode *pNode = NULL;
96,834,232✔
787
  if (p) {
96,834,232✔
788
    pNode = taosHashReleaseNode(pHashObj, p, &slot);
61,939,503✔
789
    if (pNode == NULL) {
61,942,357✔
790
      SHashEntry *pe = pHashObj->hashList[slot];
55,501,883✔
791
      taosHashEntryWUnlock(pHashObj, pe);
792

793
      slot = slot + 1;
55,500,649✔
794
    }
795
  }
796

797
  if (pNode == NULL) {
96,835,852✔
798
    for (; slot < pHashObj->capacity; ++slot) {
1,086,728,529✔
799
      SHashEntry *pe = pHashObj->hashList[slot];
1,052,106,874✔
800

801
      taosHashEntryWLock(pHashObj, pe);
802

803
      pNode = pe->next;
1,052,041,884✔
804
      while (pNode) {
1,052,060,822✔
805
        if (pNode->removed == 0) break;
56,191,575✔
806
        pNode = pNode->next;
18,938✔
807
      }
808

809
      if (pNode) break;
1,052,041,884✔
810

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

815
  if (pNode) {
97,036,530✔
816
    SHashEntry *pe = pHashObj->hashList[slot];
62,613,892✔
817

818
    /*uint16_t prevRef = atomic_load_16(&pNode->refCount);*/
819
    uint16_t afterRef = atomic_add_fetch_16(&pNode->refCount, 1);
62,613,892✔
820

821
    data = GET_HASH_NODE_DATA(pNode);
62,617,564✔
822

823
    if (afterRef >= MAX_WARNING_REF_COUNT) {
62,617,564!
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;
97,033,706✔
832
}
833

834
void taosHashCancelIterate(SHashObj *pHashObj, void *p) {
29,157,901✔
835
  if (pHashObj == NULL || p == NULL) return;
29,157,901!
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);
29,047,882✔
842

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

855
void taosHashRelease(SHashObj *pHashObj, void *p) { taosHashCancelIterate(pHashObj, p); }
28,436,665✔
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