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

taosdata / TDengine / #5058

17 May 2026 01:15AM UTC coverage: 73.387% (-0.02%) from 73.406%
#5058

push

travis-ci

web-flow
feat (TDgpt): Dynamic Model Synchronization Enhancements (#35344)

* refactor: do some internal refactor.

* fix: fix multiprocess sync issue.

* feat: add dynamic anomaly detection and forecasting services

* fix: log error message for undeploying model in exception handling

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: handle undeploy when model exists only on disk

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/286aafa0-c3ce-4c27-b803-2707571e9dc1

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: guard dynamic registry concurrent access

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/5e4db858-6458-40f4-ac28-d1b1b7f97c18

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: tighten service list locking scope

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/5e4db858-6458-40f4-ac28-d1b1b7f97c18

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: restore prophet support and update tests per review feedback

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/92298ae1-7da6-4d07-b20e-101c7cd0b26b

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: improve test name and move copy inside lock scope

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/92298ae1-7da6-4d07-b20e-101c7cd0b26b

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* Potential fix for pull request finding

Co-au... (continued)

281656 of 383795 relevant lines covered (73.39%)

135114337.11 hits per line

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

80.81
/source/util/src/tlrucache.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 "tlrucache.h"
18
#include "os.h"
19
#include "taoserror.h"
20
#include "tarray.h"
21
#include "tdef.h"
22
#include "tlog.h"
23
#include "tutil.h"
24

25
typedef struct SLRUEntry      SLRUEntry;
26
typedef struct SLRUEntryTable SLRUEntryTable;
27
typedef struct SLRUCacheShard SLRUCacheShard;
28
typedef struct SShardedCache  SShardedCache;
29

30
enum {
31
  TAOS_LRU_IN_CACHE = (1 << 0),  // Whether this entry is referenced by the hash table.
32

33
  TAOS_LRU_IS_HIGH_PRI = (1 << 1),  // Whether this entry is high priority entry.
34

35
  TAOS_LRU_IN_HIGH_PRI_POOL = (1 << 2),  // Whether this entry is in high-pri pool.
36

37
  TAOS_LRU_HAS_HIT = (1 << 3),  // Whether this entry has had any lookups (hits).
38
};
39

40
struct SLRUEntry {
41
  void                  *value;
42
  _taos_lru_deleter_t    deleter;
43
  _taos_lru_overwriter_t overwriter;
44
  void                  *ud;
45
  SLRUEntry             *nextHash;
46
  SLRUEntry             *next;
47
  SLRUEntry             *prev;
48
  size_t                 totalCharge;
49
  size_t                 keyLength;
50
  uint32_t               hash;
51
  uint32_t               refs;
52
  uint8_t                flags;
53
  char                   keyData[1];
54
};
55

56
#define TAOS_LRU_ENTRY_IN_CACHE(h)     ((h)->flags & TAOS_LRU_IN_CACHE)
57
#define TAOS_LRU_ENTRY_IN_HIGH_POOL(h) ((h)->flags & TAOS_LRU_IN_HIGH_PRI_POOL)
58
#define TAOS_LRU_ENTRY_IS_HIGH_PRI(h)  ((h)->flags & TAOS_LRU_IS_HIGH_PRI)
59
#define TAOS_LRU_ENTRY_HAS_HIT(h)      ((h)->flags & TAOS_LRU_HAS_HIT)
60

61
#define TAOS_LRU_ENTRY_SET_IN_CACHE(h, inCache) \
62
  do {                                          \
63
    if (inCache) {                              \
64
      (h)->flags |= TAOS_LRU_IN_CACHE;          \
65
    } else {                                    \
66
      (h)->flags &= ~TAOS_LRU_IN_CACHE;         \
67
    }                                           \
68
  } while (0)
69
#define TAOS_LRU_ENTRY_SET_IN_HIGH_POOL(h, inHigh) \
70
  do {                                             \
71
    if (inHigh) {                                  \
72
      (h)->flags |= TAOS_LRU_IN_HIGH_PRI_POOL;     \
73
    } else {                                       \
74
      (h)->flags &= ~TAOS_LRU_IN_HIGH_PRI_POOL;    \
75
    }                                              \
76
  } while (0)
77
#define TAOS_LRU_ENTRY_SET_PRIORITY(h, priority) \
78
  do {                                           \
79
    if (priority == TAOS_LRU_PRIORITY_HIGH) {    \
80
      (h)->flags |= TAOS_LRU_IS_HIGH_PRI;        \
81
    } else {                                     \
82
      (h)->flags &= ~TAOS_LRU_IS_HIGH_PRI;       \
83
    }                                            \
84
  } while (0)
85
#define TAOS_LRU_ENTRY_SET_HIT(h) ((h)->flags |= TAOS_LRU_HAS_HIT)
86

87
#define TAOS_LRU_ENTRY_HAS_REFS(h) ((h)->refs > 0)
88
#define TAOS_LRU_ENTRY_REF(h)      (++(h)->refs)
89

90
static bool taosLRUEntryUnref(SLRUEntry *entry) {
75,113,906✔
91
  --entry->refs;
75,113,906✔
92
  return entry->refs == 0;
75,170,059✔
93
}
94

95
static void taosLRUEntryFree(SLRUEntry *entry) {
125,873,706✔
96
  if (entry->deleter) {
125,873,706✔
97
    (*entry->deleter)(entry->keyData, entry->keyLength, entry->value, entry->ud);
124,612,218✔
98
  }
99

100
  taosMemoryFree(entry);
125,874,280✔
101
}
125,849,549✔
102

103
typedef void (*_taos_lru_table_func_t)(SLRUEntry *entry);
104

105
struct SLRUEntryTable {
106
  int         lengthBits;
107
  SLRUEntry **list;
108
  uint32_t    elems;
109
  int         maxLengthBits;
110
};
111

112
static int taosLRUEntryTableInit(SLRUEntryTable *table, int maxUpperHashBits) {
276,096,339✔
113
  table->lengthBits = 16;
276,096,339✔
114
  table->list = taosMemoryCalloc(1 << table->lengthBits, sizeof(SLRUEntry *));
276,096,838✔
115
  if (!table->list) {
276,106,316✔
116
    TAOS_RETURN(terrno);
×
117
  }
118

119
  table->elems = 0;
276,106,191✔
120
  table->maxLengthBits = maxUpperHashBits;
276,106,191✔
121

122
  TAOS_RETURN(TSDB_CODE_SUCCESS);
276,106,191✔
123
}
124

125
static void taosLRUEntryTableApply(SLRUEntryTable *table, _taos_lru_table_func_t func, uint32_t begin, uint32_t end) {
276,072,930✔
126
  for (uint32_t i = begin; i < end; ++i) {
2,147,483,647✔
127
    SLRUEntry *h = table->list[i];
2,147,483,647✔
128
    while (h) {
2,147,483,647✔
129
      SLRUEntry *n = h->nextHash;
1,250,126✔
130
      func(h);
1,250,126✔
131
      h = n;
2,147,483,647✔
132
    }
133
  }
134
}
324,168✔
135

136
static void taosLRUEntryTableFree(SLRUEntry *entry) {
1,250,126✔
137
  if (!TAOS_LRU_ENTRY_HAS_REFS(entry)) {
1,250,126✔
138
    taosLRUEntryFree(entry);
1,250,126✔
139
  }
140
}
1,250,126✔
141

142
static void taosLRUEntryTableCleanup(SLRUEntryTable *table) {
276,073,315✔
143
  taosLRUEntryTableApply(table, taosLRUEntryTableFree, 0, 1 << table->lengthBits);
276,073,315✔
144

145
  taosMemoryFree(table->list);
276,073,899✔
146
}
276,072,253✔
147

148
static int taosLRUEntryTableApplyF(SLRUEntryTable *table, _taos_lru_functor_t functor, void *ud) {
2,605,748✔
149
  int      ret = 0;
2,605,748✔
150
  uint32_t end = 1 << table->lengthBits;
2,605,748✔
151
  for (uint32_t i = 0; i < end; ++i) {
2,147,483,647✔
152
    SLRUEntry *h = table->list[i];
2,147,483,647✔
153
    while (h) {
2,147,483,647✔
154
      SLRUEntry *n = h->nextHash;
63,394,874✔
155
      ret = functor(h->keyData, h->keyLength, h->value, ud);
63,395,245✔
156
      if (ret) {
63,399,021✔
157
        return ret;
×
158
      }
159
      h = n;
63,399,021✔
160
    }
161
  }
162

163
  return ret;
1,264✔
164
}
165

166
static SLRUEntry **taosLRUEntryTableFindPtr(SLRUEntryTable *table, const void *key, size_t keyLen, uint32_t hash) {
304,161,614✔
167
  SLRUEntry **entry = &table->list[hash >> (32 - table->lengthBits)];
304,161,614✔
168
  while (*entry && ((*entry)->hash != hash || memcmp(key, (*entry)->keyData, keyLen) != 0)) {
310,140,116✔
169
    entry = &(*entry)->nextHash;
5,150,424✔
170
  }
171

172
  return entry;
304,949,312✔
173
}
174

175
static void taosLRUEntryTableResize(SLRUEntryTable *table) {
×
176
  int lengthBits = table->lengthBits;
×
177
  if (lengthBits >= table->maxLengthBits) {
×
178
    return;
×
179
  }
180

181
  if (lengthBits >= 31) {
×
182
    return;
×
183
  }
184

185
  uint32_t    oldLength = 1 << lengthBits;
×
186
  int         newLengthBits = lengthBits + 1;
×
187
  SLRUEntry **newList = taosMemoryCalloc(1 << newLengthBits, sizeof(SLRUEntry *));
×
188
  if (!newList) {
×
189
    return;
×
190
  }
191
  uint32_t count = 0;
×
192
  for (uint32_t i = 0; i < oldLength; ++i) {
×
193
    SLRUEntry *entry = table->list[i];
×
194
    while (entry) {
×
195
      SLRUEntry  *next = entry->nextHash;
×
196
      uint32_t    hash = entry->hash;
×
197
      SLRUEntry **ptr = &newList[hash >> (32 - newLengthBits)];
×
198
      entry->nextHash = *ptr;
×
199
      *ptr = entry;
×
200
      entry = next;
×
201
      ++count;
×
202
    }
203
  }
204

205
  taosMemoryFree(table->list);
×
206
  table->list = newList;
×
207
  table->lengthBits = newLengthBits;
×
208
}
209

210
static SLRUEntry *taosLRUEntryTableLookup(SLRUEntryTable *table, const void *key, size_t keyLen, uint32_t hash) {
109,079,022✔
211
  return *taosLRUEntryTableFindPtr(table, key, keyLen, hash);
109,079,022✔
212
}
213

214
static SLRUEntry *taosLRUEntryTableInsert(SLRUEntryTable *table, SLRUEntry *entry) {
125,873,814✔
215
  SLRUEntry **ptr = taosLRUEntryTableFindPtr(table, entry->keyData, entry->keyLength, entry->hash);
125,873,814✔
216
  SLRUEntry  *old = *ptr;
125,864,979✔
217
  entry->nextHash = (old == NULL) ? NULL : old->nextHash;
125,869,802✔
218
  *ptr = entry;
125,876,480✔
219
  if (old == NULL) {
125,876,109✔
220
    ++table->elems;
71,257,927✔
221
    if ((table->elems >> table->lengthBits) > 0) {
71,256,256✔
222
      taosLRUEntryTableResize(table);
×
223
    }
224
  }
225

226
  return old;
125,865,513✔
227
}
228

229
static SLRUEntry *taosLRUEntryTableRemove(SLRUEntryTable *table, const void *key, size_t keyLen, uint32_t hash) {
70,169,302✔
230
  SLRUEntry **entry = taosLRUEntryTableFindPtr(table, key, keyLen, hash);
70,169,302✔
231
  SLRUEntry  *result = *entry;
70,169,302✔
232
  if (result) {
70,169,302✔
233
    *entry = result->nextHash;
70,010,378✔
234
    --table->elems;
70,010,378✔
235
  }
236

237
  return result;
70,169,302✔
238
}
239

240
struct SLRUCacheShard {
241
  size_t         capacity;
242
  size_t         highPriPoolUsage;
243
  bool           strictCapacity;
244
  double         highPriPoolRatio;
245
  double         highPriPoolCapacity;
246
  SLRUEntry      lru;
247
  SLRUEntry     *lruLowPri;
248
  SLRUEntryTable table;
249
  size_t         usage;     // Memory size for entries residing in the cache.
250
  size_t         lruUsage;  // Memory size for entries residing only in the LRU list.
251
  TdThreadMutex  mutex;
252
};
253

254
#define TAOS_LRU_CACHE_SHARD_HASH32(key, len) (MurmurHash3_32((key), (len)))
255

256
static void taosLRUCacheShardMaintainPoolSize(SLRUCacheShard *shard) {
8,548,378✔
257
  while (shard->highPriPoolUsage > shard->highPriPoolCapacity) {
9,127,150✔
258
    shard->lruLowPri = shard->lruLowPri->next;
578,772✔
259
    TAOS_LRU_ENTRY_SET_IN_HIGH_POOL(shard->lruLowPri, false);
578,772✔
260

261
    shard->highPriPoolUsage -= shard->lruLowPri->totalCharge;
578,772✔
262
  }
263
}
8,548,378✔
264

265
static void taosLRUCacheShardLRUInsert(SLRUCacheShard *shard, SLRUEntry *e) {
134,376,865✔
266
  if (shard->highPriPoolRatio > 0 && (TAOS_LRU_ENTRY_IS_HIGH_PRI(e) || TAOS_LRU_ENTRY_HAS_HIT(e))) {
134,376,865✔
267
    e->next = &shard->lru;
8,545,795✔
268
    e->prev = shard->lru.prev;
8,548,770✔
269

270
    e->prev->next = e;
8,547,941✔
271
    e->next->prev = e;
8,547,941✔
272

273
    TAOS_LRU_ENTRY_SET_IN_HIGH_POOL(e, true);
8,547,941✔
274
    shard->highPriPoolUsage += e->totalCharge;
8,547,941✔
275
    taosLRUCacheShardMaintainPoolSize(shard);
8,547,941✔
276
  } else {
277
    e->next = shard->lruLowPri->next;
125,826,989✔
278
    e->prev = shard->lruLowPri;
125,831,188✔
279

280
    e->prev->next = e;
125,861,974✔
281
    e->next->prev = e;
125,862,723✔
282

283
    TAOS_LRU_ENTRY_SET_IN_HIGH_POOL(e, false);
125,838,201✔
284
    shard->lruLowPri = e;
125,842,362✔
285
  }
286

287
  shard->lruUsage += e->totalCharge;
134,398,593✔
288
}
134,418,319✔
289

290
static void taosLRUCacheShardLRURemove(SLRUCacheShard *shard, SLRUEntry *e) {
133,151,043✔
291
  if (shard->lruLowPri == e) {
133,151,043✔
292
    shard->lruLowPri = e->prev;
1,274,942✔
293
  }
294
  e->next->prev = e->prev;
133,151,175✔
295
  e->prev->next = e->next;
133,130,267✔
296
  e->prev = e->next = NULL;
132,975,175✔
297

298
  shard->lruUsage -= e->totalCharge;
132,980,501✔
299
  if (TAOS_LRU_ENTRY_IN_HIGH_POOL(e)) {
132,978,275✔
300
    shard->highPriPoolUsage -= e->totalCharge;
7,136,826✔
301
  }
302
}
133,025,028✔
303

304
static void taosLRUCacheShardEvictLRU(SLRUCacheShard *shard, size_t charge, SArray *deleted) {
281,034,056✔
305
  while (shard->usage + charge > shard->capacity && shard->lru.next != &shard->lru) {
285,952,136✔
306
    SLRUEntry *old = shard->lru.next;
4,918,080✔
307

308
    taosLRUCacheShardLRURemove(shard, old);
4,918,080✔
309
    SLRUEntry *tentry = taosLRUEntryTableRemove(&shard->table, old->keyData, old->keyLength, old->hash);
4,918,080✔
310
    TAOS_LRU_ENTRY_SET_IN_CACHE(old, false);
4,918,080✔
311
    shard->usage -= old->totalCharge;
4,918,080✔
312

313
    if (!taosArrayPush(deleted, &old)) {
4,918,080✔
314
      // ignore this round's eviting
315
    }
316
  }
317
}
281,028,393✔
318

319
static void taosLRUCacheShardSetCapacity(SLRUCacheShard *shard, size_t capacity) {
276,121,280✔
320
  SArray *lastReferenceList = taosArrayInit(16, POINTER_BYTES);
276,121,280✔
321
  if (!lastReferenceList) {
276,114,596✔
322
    return;
×
323
  }
324

325
  (void)taosThreadMutexLock(&shard->mutex);
276,114,596✔
326

327
  shard->capacity = capacity;
276,125,297✔
328
  shard->highPriPoolCapacity = capacity * shard->highPriPoolRatio;
276,125,214✔
329
  taosLRUCacheShardEvictLRU(shard, 0, lastReferenceList);
276,123,569✔
330

331
  (void)taosThreadMutexUnlock(&shard->mutex);
276,114,354✔
332

333
  for (int i = 0; i < taosArrayGetSize(lastReferenceList); ++i) {
276,122,728✔
334
    SLRUEntry *entry = taosArrayGetP(lastReferenceList, i);
×
335
    taosLRUEntryFree(entry);
×
336
  }
337
  taosArrayDestroy(lastReferenceList);
276,118,059✔
338
}
339

340
static int taosLRUCacheShardInit(SLRUCacheShard *shard, size_t capacity, bool strict, double highPriPoolRatio,
276,095,873✔
341
                                 int maxUpperHashBits) {
342
  TAOS_CHECK_RETURN(taosLRUEntryTableInit(&shard->table, maxUpperHashBits));
276,095,873✔
343

344
  (void)taosThreadMutexInit(&shard->mutex, NULL);
276,105,349✔
345

346
  (void)taosThreadMutexLock(&shard->mutex);
276,103,425✔
347
  shard->capacity = 0;
276,105,207✔
348
  shard->highPriPoolUsage = 0;
276,105,207✔
349
  shard->strictCapacity = strict;
276,105,249✔
350
  shard->highPriPoolRatio = highPriPoolRatio;
276,105,743✔
351
  shard->highPriPoolCapacity = 0;
276,105,246✔
352

353
  shard->usage = 0;
276,104,537✔
354
  shard->lruUsage = 0;
276,104,130✔
355

356
  shard->lru.next = &shard->lru;
276,105,221✔
357
  shard->lru.prev = &shard->lru;
276,103,066✔
358
  shard->lruLowPri = &shard->lru;
276,101,626✔
359
  (void)taosThreadMutexUnlock(&shard->mutex);
276,094,299✔
360

361
  taosLRUCacheShardSetCapacity(shard, capacity);
276,103,328✔
362

363
  TAOS_RETURN(TSDB_CODE_SUCCESS);
276,092,439✔
364
}
365

366
static void taosLRUCacheShardCleanup(SLRUCacheShard *shard) {
276,074,798✔
367
  (void)taosThreadMutexDestroy(&shard->mutex);
276,074,798✔
368

369
  taosLRUEntryTableCleanup(&shard->table);
276,075,000✔
370
}
276,073,457✔
371

372
static LRUStatus taosLRUCacheShardInsertEntry(SLRUCacheShard *shard, SLRUEntry *e, LRUHandle **handle,
125,887,605✔
373
                                              bool freeOnFail) {
374
  LRUStatus  status = TAOS_LRU_STATUS_OK;
125,887,605✔
375
  SLRUEntry *toFree = NULL;
125,887,605✔
376
  SArray    *lastReferenceList = NULL;
125,887,605✔
377
  if (shard->usage + e->totalCharge > shard->capacity) {
125,887,605✔
378
    lastReferenceList = taosArrayInit(16, POINTER_BYTES);
4,918,080✔
379
    if (!lastReferenceList) {
4,918,080✔
380
      taosLRUEntryFree(e);
×
381
      return TAOS_LRU_STATUS_FAIL;
×
382
    }
383
  }
384

385
  (void)taosThreadMutexLock(&shard->mutex);
125,888,659✔
386

387
  if (shard->usage + e->totalCharge > shard->capacity && shard->lru.next != &shard->lru) {
125,885,582✔
388
    if (!lastReferenceList) {
4,918,080✔
389
      lastReferenceList = taosArrayInit(16, POINTER_BYTES);
×
390
      if (!lastReferenceList) {
×
391
        taosLRUEntryFree(e);
×
392
        (void)taosThreadMutexUnlock(&shard->mutex);
×
393
        return TAOS_LRU_STATUS_FAIL;
×
394
      }
395
    }
396
    taosLRUCacheShardEvictLRU(shard, e->totalCharge, lastReferenceList);
4,918,080✔
397
  }
398

399
  if (shard->usage + e->totalCharge > shard->capacity && (shard->strictCapacity || handle == NULL)) {
125,887,066✔
400
    TAOS_LRU_ENTRY_SET_IN_CACHE(e, false);
×
401
    if (handle == NULL) {
×
402
      toFree = e;
×
403
    } else {
404
      if (freeOnFail) {
×
405
        taosLRUEntryFree(e);
×
406

407
        *handle = NULL;
×
408
      }
409

410
      status = TAOS_LRU_STATUS_INCOMPLETE;
×
411
    }
412
  } else {
413
    SLRUEntry *old = taosLRUEntryTableInsert(&shard->table, e);
125,877,791✔
414
    shard->usage += e->totalCharge;
125,857,708✔
415
    if (old != NULL) {
125,858,034✔
416
      status = TAOS_LRU_STATUS_OK_OVERWRITTEN;
54,599,545✔
417

418
      if (old->overwriter) {
54,599,545✔
419
        (*old->overwriter)(old->keyData, old->keyLength, old->value, old->ud);
54,599,545✔
420
      }
421

422
      TAOS_LRU_ENTRY_SET_IN_CACHE(old, false);
54,587,029✔
423
      if (!TAOS_LRU_ENTRY_HAS_REFS(old)) {
54,587,400✔
424
        taosLRUCacheShardLRURemove(shard, old);
634✔
425
        shard->usage -= old->totalCharge;
634✔
426

427
        toFree = old;
256✔
428
      }
429
    }
430
    if (handle == NULL) {
125,830,300✔
431
      taosLRUCacheShardLRUInsert(shard, e);
113,993,950✔
432
    } else {
433
      if (!TAOS_LRU_ENTRY_HAS_REFS(e)) {
11,836,350✔
434
        TAOS_LRU_ENTRY_REF(e);
11,836,350✔
435
      }
436

437
      *handle = (LRUHandle *)e;
11,836,350✔
438
    }
439
  }
440

441
_exit:
125,854,719✔
442
  (void)taosThreadMutexUnlock(&shard->mutex);
125,854,719✔
443

444
  if (toFree) {
125,862,455✔
445
    taosLRUEntryFree(toFree);
634✔
446
  }
447

448
  for (int i = 0; i < taosArrayGetSize(lastReferenceList); ++i) {
130,783,503✔
449
    SLRUEntry *entry = taosArrayGetP(lastReferenceList, i);
4,918,080✔
450

451
    taosLRUEntryFree(entry);
4,918,080✔
452
  }
453
  taosArrayDestroy(lastReferenceList);
125,837,657✔
454

455
  return status;
125,818,358✔
456
}
457

458
static LRUStatus taosLRUCacheShardInsert(SLRUCacheShard *shard, const void *key, size_t keyLen, uint32_t hash,
125,878,274✔
459
                                         void *value, size_t charge, _taos_lru_deleter_t deleter,
460
                                         _taos_lru_overwriter_t overwriter, LRUHandle **handle, LRUPriority priority,
461
                                         void *ud) {
462
  SLRUEntry *e = taosMemoryCalloc(1, sizeof(SLRUEntry) - 1 + keyLen);
125,878,274✔
463
  if (!e) {
125,840,033✔
464
    if (deleter) {
×
465
      (*deleter)(key, keyLen, value, ud);
×
466
    }
467
    return TAOS_LRU_STATUS_FAIL;
×
468
  }
469

470
  e->value = value;
125,840,033✔
471
  e->flags = 0;
125,832,242✔
472
  e->deleter = deleter;
125,830,626✔
473
  e->overwriter = overwriter;
125,831,441✔
474
  e->ud = ud;
125,839,166✔
475
  e->keyLength = keyLen;
125,827,658✔
476
  e->hash = hash;
125,834,707✔
477
  e->refs = 0;
125,842,641✔
478
  e->next = e->prev = NULL;
125,857,111✔
479
  TAOS_LRU_ENTRY_SET_IN_CACHE(e, true);
125,873,508✔
480

481
  TAOS_LRU_ENTRY_SET_PRIORITY(e, priority);
125,877,953✔
482
  memcpy(e->keyData, key, keyLen);
125,879,007✔
483
  // TODO: e->CalcTotalCharge(charge, metadataChargePolicy);
484
  e->totalCharge = charge;
125,878,695✔
485

486
  return taosLRUCacheShardInsertEntry(shard, e, handle, true);
125,884,711✔
487
}
488

489
static LRUHandle *taosLRUCacheShardLookup(SLRUCacheShard *shard, const void *key, size_t keyLen, uint32_t hash) {
109,073,116✔
490
  SLRUEntry *e = NULL;
109,073,116✔
491

492
  (void)taosThreadMutexLock(&shard->mutex);
109,073,116✔
493
  e = taosLRUEntryTableLookup(&shard->table, key, keyLen, hash);
109,087,729✔
494
  if (e != NULL) {
109,059,672✔
495
    if (!TAOS_LRU_ENTRY_HAS_REFS(e)) {
63,320,409✔
496
      taosLRUCacheShardLRURemove(shard, e);
63,320,976✔
497
    }
498
    TAOS_LRU_ENTRY_REF(e);
63,270,982✔
499
    TAOS_LRU_ENTRY_SET_HIT(e);
63,271,353✔
500
  }
501

502
  (void)taosThreadMutexUnlock(&shard->mutex);
109,053,652✔
503

504
  return (LRUHandle *)e;
109,063,942✔
505
}
506

507
static void taosLRUCacheShardErase(SLRUCacheShard *shard, const void *key, size_t keyLen, uint32_t hash) {
171,784✔
508
  bool lastReference = false;
171,784✔
509
  (void)taosThreadMutexLock(&shard->mutex);
171,784✔
510

511
  SLRUEntry *e = taosLRUEntryTableRemove(&shard->table, key, keyLen, hash);
171,784✔
512
  if (e != NULL) {
171,784✔
513
    TAOS_LRU_ENTRY_SET_IN_CACHE(e, false);
12,860✔
514
    if (!TAOS_LRU_ENTRY_HAS_REFS(e)) {
12,860✔
515
      taosLRUCacheShardLRURemove(shard, e);
12,860✔
516

517
      shard->usage -= e->totalCharge;
12,860✔
518
      lastReference = true;
12,860✔
519
    }
520
  }
521

522
  (void)taosThreadMutexUnlock(&shard->mutex);
171,784✔
523

524
  if (lastReference) {
171,784✔
525
    taosLRUEntryFree(e);
12,860✔
526
  }
527
}
171,784✔
528

529
static int taosLRUCacheShardApply(SLRUCacheShard *shard, _taos_lru_functor_t functor, void *ud) {
2,605,012✔
530
  int ret;
531

532
  (void)taosThreadMutexLock(&shard->mutex);
2,605,012✔
533

534
  ret = taosLRUEntryTableApplyF(&shard->table, functor, ud);
2,607,795✔
535

536
  (void)taosThreadMutexUnlock(&shard->mutex);
2,608,434✔
537

538
  return ret;
2,608,434✔
539
}
540

541
static void taosLRUCacheShardEraseUnrefEntries(SLRUCacheShard *shard) {
102,828,013✔
542
  SArray *lastReferenceList = taosArrayInit(16, POINTER_BYTES);
102,828,013✔
543

544
  (void)taosThreadMutexLock(&shard->mutex);
102,826,152✔
545

546
  while (shard->lru.next != &shard->lru) {
167,750,135✔
547
    SLRUEntry *old = shard->lru.next;
64,920,514✔
548
    taosLRUCacheShardLRURemove(shard, old);
64,920,514✔
549
    SLRUEntry *tentry = taosLRUEntryTableRemove(&shard->table, old->keyData, old->keyLength, old->hash);
64,920,514✔
550
    TAOS_LRU_ENTRY_SET_IN_CACHE(old, false);
64,920,514✔
551
    shard->usage -= old->totalCharge;
64,920,514✔
552

553
    if (!taosArrayPush(lastReferenceList, &old)) {
64,920,514✔
554
      taosLRUEntryFree(old);
×
555
      return;
×
556
    }
557
  }
558

559
  (void)taosThreadMutexUnlock(&shard->mutex);
102,828,883✔
560

561
  for (int i = 0; i < taosArrayGetSize(lastReferenceList); ++i) {
167,750,154✔
562
    SLRUEntry *entry = taosArrayGetP(lastReferenceList, i);
64,920,514✔
563

564
    taosLRUEntryFree(entry);
64,920,514✔
565
  }
566

567
  taosArrayDestroy(lastReferenceList);
102,829,754✔
568
}
569

570
static bool taosLRUCacheShardRef(SLRUCacheShard *shard, LRUHandle *handle) {
×
571
  SLRUEntry *e = (SLRUEntry *)handle;
×
572
  (void)taosThreadMutexLock(&shard->mutex);
×
573

574
  TAOS_LRU_ENTRY_REF(e);
×
575

576
  (void)taosThreadMutexUnlock(&shard->mutex);
×
577

578
  return true;
×
579
}
580

581
static bool taosLRUCacheShardRelease(SLRUCacheShard *shard, LRUHandle *handle, bool eraseIfLastRef) {
75,159,616✔
582
  if (handle == NULL) {
75,159,616✔
583
    return false;
×
584
  }
585

586
  SLRUEntry *e = (SLRUEntry *)handle;
75,159,616✔
587
  bool       lastReference = false;
75,159,616✔
588

589
  (void)taosThreadMutexLock(&shard->mutex);
75,159,616✔
590

591
  lastReference = taosLRUEntryUnref(e);
75,178,592✔
592
  if (lastReference && TAOS_LRU_ENTRY_IN_CACHE(e)) {
75,144,824✔
593
    if (shard->usage > shard->capacity || eraseIfLastRef) {
20,544,436✔
594
      SLRUEntry *tentry = taosLRUEntryTableRemove(&shard->table, e->keyData, e->keyLength, e->hash);
158,924✔
595
      TAOS_LRU_ENTRY_SET_IN_CACHE(e, false);
158,924✔
596
    } else {
597
      taosLRUCacheShardLRUInsert(shard, e);
20,385,512✔
598

599
      lastReference = false;
20,384,924✔
600
    }
601
  }
602

603
  if (lastReference && e->value) {
75,142,010✔
604
    shard->usage -= e->totalCharge;
54,760,054✔
605
  }
606

607
  (void)taosThreadMutexUnlock(&shard->mutex);
75,148,317✔
608

609
  if (lastReference) {
75,192,592✔
610
    taosLRUEntryFree(e);
54,807,920✔
611
  }
612

613
  return lastReference;
75,181,070✔
614
}
615

616
static size_t taosLRUCacheShardGetUsage(SLRUCacheShard *shard) {
369,952,359✔
617
  size_t usage = 0;
369,952,359✔
618

619
  (void)taosThreadMutexLock(&shard->mutex);
369,952,359✔
620
  usage = shard->usage;
369,952,359✔
621
  (void)taosThreadMutexUnlock(&shard->mutex);
369,952,359✔
622

623
  return usage;
369,952,359✔
624
}
625

626
static int32_t taosLRUCacheShardGetElems(SLRUCacheShard *shard) {
381,249,867✔
627
  int32_t elems = 0;
381,249,867✔
628

629
  (void)taosThreadMutexLock(&shard->mutex);
381,249,867✔
630
  elems = shard->table.elems;
381,249,867✔
631
  (void)taosThreadMutexUnlock(&shard->mutex);
381,249,867✔
632

633
  return elems;
381,249,867✔
634
}
635

636
static size_t taosLRUCacheShardGetPinnedUsage(SLRUCacheShard *shard) {
×
637
  size_t usage = 0;
×
638

639
  (void)taosThreadMutexLock(&shard->mutex);
×
640

641
  usage = shard->usage - shard->lruUsage;
×
642

643
  (void)taosThreadMutexUnlock(&shard->mutex);
×
644

645
  return usage;
×
646
}
647

648
static void taosLRUCacheShardSetStrictCapacity(SLRUCacheShard *shard, bool strict) {
102,855,454✔
649
  (void)taosThreadMutexLock(&shard->mutex);
102,855,454✔
650

651
  shard->strictCapacity = strict;
102,855,103✔
652

653
  (void)taosThreadMutexUnlock(&shard->mutex);
102,856,295✔
654
}
102,856,291✔
655

656
struct SShardedCache {
657
  uint32_t      shardMask;
658
  TdThreadMutex capacityMutex;
659
  size_t        capacity;
660
  bool          strictCapacity;
661
  uint64_t      lastId;  // atomic var for last id
662
};
663

664
struct SLRUCache {
665
  SShardedCache   shardedCache;
666
  SLRUCacheShard *shards;
667
  int             numShards;
668
};
669

670
static int getDefaultCacheShardBits(size_t capacity) {
30,514,860✔
671
  int    numShardBits = 0;
30,514,860✔
672
  size_t minShardSize = 512 * 1024;
30,514,860✔
673
  size_t numShards = capacity / minShardSize;
30,514,860✔
674
  while (numShards >>= 1) {
117,453,304✔
675
    if (++numShardBits >= 6) {
87,118,728✔
676
      return numShardBits;
180,284✔
677
    }
678
  }
679

680
  return numShardBits;
30,334,576✔
681
}
682

683
SLRUCache *taosLRUCacheInit(size_t capacity, int numShardBits, double highPriPoolRatio) {
36,201,336✔
684
  if (numShardBits >= 20) {
36,201,336✔
685
    return NULL;
408✔
686
  }
687
  if (highPriPoolRatio < 0.0 || highPriPoolRatio > 1.0) {
36,200,928✔
688
    return NULL;
×
689
  }
690
  SLRUCache *cache = taosMemoryCalloc(1, sizeof(SLRUCache));
36,201,749✔
691
  if (!cache) {
36,200,650✔
692
    return NULL;
×
693
  }
694

695
  if (numShardBits < 0) {
36,200,650✔
696
    numShardBits = getDefaultCacheShardBits(capacity);
30,513,976✔
697
  }
698

699
  int numShards = 1 << numShardBits;
36,200,683✔
700
  cache->shards = taosMemoryCalloc(numShards, sizeof(SLRUCacheShard));
36,200,683✔
701
  if (!cache->shards) {
36,202,427✔
702
    taosMemoryFree(cache);
×
703
    return NULL;
×
704
  }
705

706
  bool   strictCapacity = 1;
36,201,774✔
707
  size_t perShard = (capacity + (numShards - 1)) / numShards;
36,201,774✔
708
  for (int i = 0; i < numShards; ++i) {
312,294,938✔
709
    if (TSDB_CODE_SUCCESS !=
276,093,164✔
710
        taosLRUCacheShardInit(&cache->shards[i], perShard, strictCapacity, highPriPoolRatio, 32 - numShardBits)) {
276,088,665✔
711
      taosMemoryFree(cache->shards);
×
712
      taosMemoryFree(cache);
×
713
      return NULL;
×
714
    }
715
  }
716

717
  cache->numShards = numShards;
36,206,273✔
718

719
  cache->shardedCache.shardMask = (1 << numShardBits) - 1;
36,203,005✔
720
  cache->shardedCache.strictCapacity = strictCapacity;
36,202,102✔
721
  cache->shardedCache.capacity = capacity;
36,202,530✔
722
  cache->shardedCache.lastId = 1;
36,202,167✔
723

724
  (void)taosThreadMutexInit(&cache->shardedCache.capacityMutex, NULL);
36,202,512✔
725

726
  return cache;
36,202,577✔
727
}
728

729
void taosLRUCacheCleanup(SLRUCache *cache) {
342,522,893✔
730
  if (cache) {
342,522,893✔
731
    if (cache->shards) {
36,188,891✔
732
      int numShards = cache->numShards;
36,188,891✔
733
      for (int i = 0; i < numShards; ++i) {
312,261,287✔
734
        taosLRUCacheShardCleanup(&cache->shards[i]);
276,071,943✔
735
      }
736
      taosMemoryFree(cache->shards);
36,189,344✔
737
      cache->shards = 0;
36,189,344✔
738
    }
739

740
    (void)taosThreadMutexDestroy(&cache->shardedCache.capacityMutex);
36,189,232✔
741

742
    taosMemoryFree(cache);
36,189,344✔
743
  }
744
}
342,523,346✔
745

746
LRUStatus taosLRUCacheInsert(SLRUCache *cache, const void *key, size_t keyLen, void *value, size_t charge,
125,905,486✔
747
                             _taos_lru_deleter_t deleter, _taos_lru_overwriter_t overwriter, LRUHandle **handle,
748
                             LRUPriority priority, void *ud) {
749
  uint32_t hash = TAOS_LRU_CACHE_SHARD_HASH32(key, keyLen);
125,905,486✔
750
  uint32_t shardIndex = hash & cache->shardedCache.shardMask;
125,878,398✔
751

752
  return taosLRUCacheShardInsert(&cache->shards[shardIndex], key, keyLen, hash, value, charge, deleter, overwriter,
125,887,302✔
753
                                 handle, priority, ud);
754
}
755

756
LRUHandle *taosLRUCacheLookup(SLRUCache *cache, const void *key, size_t keyLen) {
109,087,850✔
757
  uint32_t hash = TAOS_LRU_CACHE_SHARD_HASH32(key, keyLen);
109,087,850✔
758
  uint32_t shardIndex = hash & cache->shardedCache.shardMask;
109,069,881✔
759

760
  return taosLRUCacheShardLookup(&cache->shards[shardIndex], key, keyLen, hash);
109,070,623✔
761
}
762

763
void taosLRUCacheErase(SLRUCache *cache, const void *key, size_t keyLen) {
171,784✔
764
  uint32_t hash = TAOS_LRU_CACHE_SHARD_HASH32(key, keyLen);
171,784✔
765
  uint32_t shardIndex = hash & cache->shardedCache.shardMask;
171,784✔
766

767
  return taosLRUCacheShardErase(&cache->shards[shardIndex], key, keyLen, hash);
171,784✔
768
}
769

770
void taosLRUCacheApply(SLRUCache *cache, _taos_lru_functor_t functor, void *ud) {
1,183,498✔
771
  int numShards = cache->numShards;
1,183,498✔
772
  for (int i = 0; i < numShards; ++i) {
3,792,603✔
773
    if (taosLRUCacheShardApply(&cache->shards[i], functor, ud)) {
2,607,760✔
774
      break;
×
775
    }
776
  }
777
}
1,184,843✔
778

779
void taosLRUCacheEraseUnrefEntries(SLRUCache *cache) {
15,766,835✔
780
  int numShards = cache->numShards;
15,766,835✔
781
  for (int i = 0; i < numShards; ++i) {
118,596,369✔
782
    taosLRUCacheShardEraseUnrefEntries(&cache->shards[i]);
102,828,827✔
783
  }
784
}
15,767,542✔
785

786
bool taosLRUCacheRef(SLRUCache *cache, LRUHandle *handle) {
×
787
  if (handle == NULL) {
×
788
    return false;
×
789
  }
790

791
  uint32_t hash = ((SLRUEntry *)handle)->hash;
×
792
  uint32_t shardIndex = hash & cache->shardedCache.shardMask;
×
793

794
  return taosLRUCacheShardRef(&cache->shards[shardIndex], handle);
×
795
}
796

797
bool taosLRUCacheRelease(SLRUCache *cache, LRUHandle *handle, bool eraseIfLastRef) {
75,111,723✔
798
  if (handle == NULL) {
75,111,723✔
799
    return false;
×
800
  }
801

802
  uint32_t hash = ((SLRUEntry *)handle)->hash;
75,111,723✔
803
  uint32_t shardIndex = hash & cache->shardedCache.shardMask;
75,115,433✔
804

805
  return taosLRUCacheShardRelease(&cache->shards[shardIndex], handle, eraseIfLastRef);
75,116,678✔
806
}
807

808
void *taosLRUCacheValue(SLRUCache *cache, LRUHandle *handle) { return ((SLRUEntry *)handle)->value; }
63,142,490✔
809

810
void taosLRUCacheUpdate(SLRUCache *cache, LRUHandle *handle, void *value) { ((SLRUEntry *)handle)->value = value; }
×
811

812
size_t taosLRUCacheGetUsage(SLRUCache *cache) {
175,182,350✔
813
  size_t usage = 0;
175,182,350✔
814

815
  for (int i = 0; i < cache->numShards; ++i) {
545,134,709✔
816
    usage += taosLRUCacheShardGetUsage(&cache->shards[i]);
369,952,359✔
817
  }
818

819
  return usage;
175,182,350✔
820
}
821

822
int32_t taosLRUCacheGetElems(SLRUCache *cache) {
175,447,094✔
823
  int32_t elems = 0;
175,447,094✔
824

825
  for (int i = 0; i < cache->numShards; ++i) {
556,696,961✔
826
    elems += taosLRUCacheShardGetElems(&cache->shards[i]);
381,249,867✔
827
  }
828

829
  return elems;
175,447,094✔
830
}
831

832
size_t taosLRUCacheGetPinnedUsage(SLRUCache *cache) {
×
833
  size_t usage = 0;
×
834

835
  for (int i = 0; i < cache->numShards; ++i) {
×
836
    usage += taosLRUCacheShardGetPinnedUsage(&cache->shards[i]);
×
837
  }
838

839
  return usage;
×
840
}
841

842
void taosLRUCacheSetCapacity(SLRUCache *cache, size_t capacity) {
9,858✔
843
  uint32_t numShards = cache->numShards;
9,858✔
844
  size_t   perShard = (capacity + (numShards - 1)) / numShards;
9,858✔
845

846
  (void)taosThreadMutexLock(&cache->shardedCache.capacityMutex);
9,858✔
847

848
  for (int i = 0; i < numShards; ++i) {
29,574✔
849
    taosLRUCacheShardSetCapacity(&cache->shards[i], perShard);
19,716✔
850
  }
851

852
  cache->shardedCache.capacity = capacity;
9,858✔
853

854
  (void)taosThreadMutexUnlock(&cache->shardedCache.capacityMutex);
9,858✔
855
}
9,858✔
856

857
size_t taosLRUCacheGetCapacity(SLRUCache *cache) {
×
858
  size_t capacity = 0;
×
859

860
  (void)taosThreadMutexLock(&cache->shardedCache.capacityMutex);
×
861

862
  capacity = cache->shardedCache.capacity;
×
863

864
  (void)taosThreadMutexUnlock(&cache->shardedCache.capacityMutex);
×
865

866
  return capacity;
×
867
}
868

869
void taosLRUCacheSetStrictCapacity(SLRUCache *cache, bool strict) {
15,780,397✔
870
  uint32_t numShards = cache->numShards;
15,780,397✔
871

872
  (void)taosThreadMutexLock(&cache->shardedCache.capacityMutex);
15,780,999✔
873

874
  for (int i = 0; i < numShards; ++i) {
118,636,877✔
875
    taosLRUCacheShardSetStrictCapacity(&cache->shards[i], strict);
102,855,878✔
876
  }
877

878
  cache->shardedCache.strictCapacity = strict;
15,780,999✔
879

880
  (void)taosThreadMutexUnlock(&cache->shardedCache.capacityMutex);
15,780,999✔
881
}
15,779,988✔
882

883
bool taosLRUCacheIsStrictCapacity(SLRUCache *cache) {
204✔
884
  bool strict = false;
204✔
885

886
  (void)taosThreadMutexLock(&cache->shardedCache.capacityMutex);
204✔
887

888
  strict = cache->shardedCache.strictCapacity;
204✔
889

890
  (void)taosThreadMutexUnlock(&cache->shardedCache.capacityMutex);
204✔
891

892
  return strict;
204✔
893
}
894

895
int32_t taosLRUCacheGetNumShards(SLRUCache *cache) {
5,057,443✔
896
  if (!cache) {
5,057,443✔
897
    return 0;
204✔
898
  }
899
  return cache->numShards;
5,057,239✔
900
}
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