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

taosdata / TDengine / #4857

17 Nov 2025 09:53AM UTC coverage: 64.135% (-0.2%) from 64.286%
#4857

push

travis-ci

guanshengliang
Merge branch '3.0' into cover/3.0

218 of 311 new or added lines in 32 files covered. (70.1%)

5044 existing lines in 121 files now uncovered.

151302 of 235910 relevant lines covered (64.14%)

116627960.99 hits per line

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

86.17
/source/dnode/vnode/src/tsdb/tsdbMergeTree.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
#include "tlrucache.h"
17
#include "tsdb.h"
18
#include "tsdbFSet2.h"
19
#include "tsdbMerge.h"
20
#include "tsdbReadUtil.h"
21
#include "tsdbSttFileRW.h"
22
#include "ttypes.h"
23

24
typedef struct SSttStatisCacheKey {
25
  int64_t suid;
26
  int32_t vgId;
27
  int32_t fid;
28
} SSttStatisCacheKey;
29

30
typedef struct SSttStatisCacheValue {
31
  int64_t commitTs;
32
  SArray *pLevel;  // SArray<SArray<SSttTableRowsInfo>>
33
} SSttStatisCacheValue;
34

35
typedef struct SSttStatisFileCacheInfo {
36
  SLRUCache *    pStatisFileCache;
37
  TdThreadMutex  lock;
38
} SSttStatisFileCacheInfo;
39

40
static SSttStatisFileCacheInfo statisCacheInfo;
41
static TdThreadOnce tsCacheInit = PTHREAD_ONCE_INIT;
42

43
static int32_t getSttTableRowsInfo(SSttStatisCacheValue *pValue, int32_t numOfPKs, int32_t levelIdx, int32_t fileIdx,
44
                                   SSttTableRowsInfo *pSttTableRowsInfo);
45
static int32_t buildSttTableRowsInfoKV(SMergeTreeConf *pConf, int32_t vgId, SSttStatisCacheKey *pKey,
46
                                       SSttStatisCacheValue **pValue);
47
static void    clearStatisInfoCache(SLRUCache *pStatisCache, SSttStatisCacheKey *pKey, LRUHandle **pHandle);
48
static int32_t putStatisInfoIntoCache(SLRUCache *pCache, SSttStatisCacheKey *pKey, SSttStatisCacheValue *pValue,
49
                                      const char *id);
50
static int32_t getStatisInfoFromCache(SLRUCache *pCache, SSttStatisCacheKey *pKey, SSttStatisCacheValue **pValue,
51
                                      LRUHandle **pHandle, const char *id);
52
static void    releaseCacheHandle(SLRUCache *pCache, LRUHandle **pHandle, bool lock);
53
static void    freeStatisFileItems(const void *key, size_t keyLen, void *value, void *ud);
54
static int32_t getCacheValueSize(const SSttStatisCacheValue* pValue);
55

56
static void tLDataIterClose2(SLDataIter *pIter);
57

58
// SLDataIter =================================================
59
int32_t tCreateSttBlockLoadInfo(STSchema *pSchema, int16_t *colList, int32_t numOfCols, SSttBlockLoadInfo **pInfo) {
211,299,326✔
60
  *pInfo = NULL;
211,299,326✔
61

62
  SSttBlockLoadInfo *pLoadInfo = taosMemoryCalloc(1, sizeof(SSttBlockLoadInfo));
211,340,803✔
63
  if (pLoadInfo == NULL) {
211,249,423✔
64
    return terrno;
×
65
  }
66

67
  pLoadInfo->blockData[0].sttBlockIndex = -1;
211,249,423✔
68
  pLoadInfo->blockData[1].sttBlockIndex = -1;
211,255,611✔
69

70
  pLoadInfo->currentLoadBlockIndex = 1;
211,269,342✔
71

72
  int32_t code = tBlockDataCreate(&pLoadInfo->blockData[0].data);
211,308,419✔
73
  if (code) {
211,335,738✔
74
    taosMemoryFreeClear(pLoadInfo);
×
75
    return code;
×
76
  }
77

78
  code = tBlockDataCreate(&pLoadInfo->blockData[1].data);
211,335,738✔
79
  if (code) {
211,327,301✔
80
    taosMemoryFreeClear(pLoadInfo);
×
81
    return code;
×
82
  }
83

84
  pLoadInfo->aSttBlk = taosArrayInit(4, sizeof(SSttBlk));
211,327,301✔
85
  if (pLoadInfo->aSttBlk == NULL) {
211,393,752✔
86
    taosMemoryFreeClear(pLoadInfo);
×
87
    return terrno;
×
88
  }
89

90
  pLoadInfo->pSchema = pSchema;
211,380,849✔
91
  pLoadInfo->colIds = colList;
211,386,544✔
92
  pLoadInfo->numOfCols = numOfCols;
211,392,011✔
93

94
  *pInfo = pLoadInfo;
211,399,795✔
95
  return code;
211,371,350✔
96
}
97

98
static void freeItem(void *pValue) {
2,147,483,647✔
99
  SValue *p = (SValue *)pValue;
2,147,483,647✔
100
  if (IS_VAR_DATA_TYPE(p->type) || p->type == TSDB_DATA_TYPE_DECIMAL) {
2,147,483,647✔
101
    taosMemoryFree(p->pData);
13,174,972✔
102
  }
103
}
2,147,483,647✔
104

105
void destroySttBlockLoadInfo(SSttBlockLoadInfo *pLoadInfo) {
211,340,363✔
106
  if (pLoadInfo == NULL) {
211,340,363✔
107
    return;
×
108
  }
109

110
  pLoadInfo->currentLoadBlockIndex = 1;
211,340,363✔
111

112
  SBlockDataInfo *pInfo = &pLoadInfo->blockData[0];
211,394,479✔
113
  tBlockDataDestroy(&pInfo->data);
211,375,416✔
114
  pInfo->sttBlockIndex = -1;
211,373,324✔
115
  pInfo->pin = false;
211,378,375✔
116

117
  pInfo = &pLoadInfo->blockData[1];
211,365,499✔
118
  tBlockDataDestroy(&pInfo->data);
211,352,749✔
119
  pInfo->sttBlockIndex = -1;
211,398,313✔
120
  pInfo->pin = false;
211,401,917✔
121

122
  taosArrayDestroy(pLoadInfo->info.pUid);
211,399,594✔
123
  taosArrayDestroy(pLoadInfo->info.pCount);
211,389,337✔
124
  taosArrayDestroy(pLoadInfo->info.pFirstTs);
211,393,723✔
125
  taosArrayDestroy(pLoadInfo->info.pLastTs);
211,404,875✔
126

127
  taosArrayDestroyEx(pLoadInfo->info.pFirstKey, freeItem);
211,403,174✔
128
  taosArrayDestroyEx(pLoadInfo->info.pLastKey, freeItem);
211,388,167✔
129

130
  pLoadInfo->info.pUid = NULL;
211,393,973✔
131
  pLoadInfo->info.pFirstKey = NULL;
211,401,788✔
132
  pLoadInfo->info.pLastKey = NULL;
211,401,434✔
133
  pLoadInfo->info.pCount = NULL;
211,397,293✔
134
  pLoadInfo->info.pFirstTs = NULL;
211,377,216✔
135
  pLoadInfo->info.pLastTs = NULL;
211,412,509✔
136

137
  taosArrayDestroy(pLoadInfo->aSttBlk);
211,400,904✔
138
  taosMemoryFree(pLoadInfo);
211,402,142✔
139
}
140

141
void destroyLDataIter(SLDataIter *pIter) {
211,410,658✔
142
  tLDataIterClose2(pIter);
211,410,658✔
143
  destroySttBlockLoadInfo(pIter->pBlockLoadInfo);
211,364,263✔
144
  taosMemoryFree(pIter);
211,375,631✔
145
}
211,387,251✔
146

147
void destroySttBlockReader(SArray *pLDataIterArray, SSttBlockLoadCostInfo *pLoadCost) {
351,770,958✔
148
  if (pLDataIterArray == NULL) {
351,770,958✔
149
    return;
3,676,090✔
150
  }
151

152
  int32_t numOfLevel = taosArrayGetSize(pLDataIterArray);
348,094,868✔
153
  for (int32_t i = 0; i < numOfLevel; ++i) {
559,403,210✔
154
    SArray *pList = taosArrayGetP(pLDataIterArray, i);
211,289,494✔
155
    for (int32_t j = 0; j < taosArrayGetSize(pList); ++j) {
422,674,814✔
156
      SLDataIter *pIter = taosArrayGetP(pList, j);
211,434,148✔
157
      if (pIter->pBlockLoadInfo != NULL) {
211,430,687✔
158
        SSttBlockLoadCostInfo *pCost = &pIter->pBlockLoadInfo->cost;
211,435,734✔
159
        if (pLoadCost != NULL) {
211,428,646✔
160
          pLoadCost->loadBlocks += pCost->loadBlocks;
211,430,997✔
161
          pLoadCost->loadStatisBlocks += pCost->loadStatisBlocks;
211,429,028✔
162
          pLoadCost->blockElapsedTime += pCost->blockElapsedTime;
211,417,156✔
163
          pLoadCost->statisElapsedTime += pCost->statisElapsedTime;
211,417,103✔
164
        }
165
      }
166

167
      destroyLDataIter(pIter);
211,407,368✔
168
    }
169

170
    taosArrayDestroy(pList);
211,257,767✔
171
  }
172

173
  taosArrayDestroy(pLDataIterArray);
348,113,716✔
174
}
175

176
// choose the unpinned slot to load next data block
177
static void updateBlockLoadSlot(SSttBlockLoadInfo *pLoadInfo) {
128,876,736✔
178
  int32_t nextSlotIndex = pLoadInfo->currentLoadBlockIndex ^ 1;
128,876,736✔
179
  if (pLoadInfo->blockData[nextSlotIndex].pin) {
128,962,416✔
UNCOV
180
    nextSlotIndex = nextSlotIndex ^ 1;
×
181
  }
182

183
  pLoadInfo->currentLoadBlockIndex = nextSlotIndex;
128,998,827✔
184
}
128,936,903✔
185

186
static int32_t loadLastBlock(SLDataIter *pIter, const char *idStr, SBlockData **pResBlock) {
2,147,483,647✔
187
  if (pResBlock != NULL) {
2,147,483,647✔
188
    *pResBlock = NULL;
2,147,483,647✔
189
  }
190

191
  int32_t            code = 0;
2,147,483,647✔
192
  SSttBlockLoadInfo *pInfo = pIter->pBlockLoadInfo;
2,147,483,647✔
193

194
  if (pInfo->blockData[0].sttBlockIndex == pIter->iSttBlk) {
2,147,483,647✔
195
    if (pInfo->currentLoadBlockIndex != 0) {
2,147,483,647✔
196
      tsdbDebug("current load index is set to 0, block index:%d, fileVer:%" PRId64 ", due to uid:%" PRIu64
46,337✔
197
                ", load data, %s",
198
                pIter->iSttBlk, pIter->cid, pIter->uid, idStr);
199
      pInfo->currentLoadBlockIndex = 0;
46,337✔
200
    }
201

202
    *pResBlock = &pInfo->blockData[0].data;
2,147,483,647✔
203
    return code;
2,147,483,647✔
204
  }
205

206
  if (pInfo->blockData[1].sttBlockIndex == pIter->iSttBlk) {
2,147,483,647✔
207
    if (pInfo->currentLoadBlockIndex != 1) {
2,147,483,647✔
208
      tsdbDebug("current load index is set to 1, block index:%d, fileVer:%" PRId64 ", due to uid:%" PRIu64
40,716✔
209
                ", load data, %s",
210
                pIter->iSttBlk, pIter->cid, pIter->uid, idStr);
211
      pInfo->currentLoadBlockIndex = 1;
40,716✔
212
    }
213

214
    *pResBlock = &pInfo->blockData[1].data;
2,147,483,647✔
215
    return code;
2,147,483,647✔
216
  }
217

218
  if (pIter->pSttBlk == NULL || pInfo->pSchema == NULL) {
128,892,659✔
UNCOV
219
    return code;
×
220
  }
221

222
  updateBlockLoadSlot(pInfo);
128,952,676✔
223
  int64_t st = taosGetTimestampUs();
128,959,831✔
224

225
  SBlockData *pBlock = &pInfo->blockData[pInfo->currentLoadBlockIndex].data;
128,959,831✔
226
  code = tsdbSttFileReadBlockDataByColumn(pIter->pReader, pIter->pSttBlk, pBlock, pInfo->pSchema, &pInfo->colIds[1],
128,942,041✔
227
                                          pInfo->numOfCols - 1);
128,977,563✔
228
  if (code != TSDB_CODE_SUCCESS) {
128,980,045✔
UNCOV
229
    return code;
×
230
  }
231

232
  double el = (taosGetTimestampUs() - st) / 1000.0;
129,019,089✔
233
  pInfo->cost.blockElapsedTime += el;
129,019,089✔
234
  pInfo->cost.loadBlocks += 1;
128,990,649✔
235

236
  tsdbDebug("read stt block, total load:%" PRId64 ", trigger by uid:%" PRIu64 ", stt-fileVer:%" PRId64
129,012,733✔
237
            ", last block index:%d, entry:%d, rows:%d, uidRange:%" PRId64 "-%" PRId64 " tsRange:%" PRId64 "-%" PRId64
238
            " %p, elapsed time:%.2f ms, %s",
239
            pInfo->cost.loadBlocks, pIter->uid, pIter->cid, pIter->iSttBlk, pInfo->currentLoadBlockIndex, pBlock->nRow,
240
            pIter->pSttBlk->minUid, pIter->pSttBlk->maxUid, pIter->pSttBlk->minKey, pIter->pSttBlk->maxKey, pBlock, el,
241
            idStr);
242

243
  pInfo->blockData[pInfo->currentLoadBlockIndex].sttBlockIndex = pIter->iSttBlk;
129,013,298✔
244
  pIter->iRow = (pIter->backward) ? pInfo->blockData[pInfo->currentLoadBlockIndex].data.nRow : -1;
129,014,061✔
245

246
  tsdbDebug("last block index list:%d, %d, rowIndex:%d %s", pInfo->blockData[0].sttBlockIndex,
128,995,437✔
247
            pInfo->blockData[1].sttBlockIndex, pIter->iRow, idStr);
248

249
  *pResBlock = &pInfo->blockData[pInfo->currentLoadBlockIndex].data;
128,995,785✔
250
  return code;
128,961,248✔
251
}
252

253
// find the earliest block that contains the required records
254
static FORCE_INLINE int32_t findEarliestIndex(int32_t index, uint64_t uid, const SSttBlk *pBlockList, int32_t num,
255
                                              int32_t backward) {
256
  int32_t i = index;
148,456,498✔
257
  int32_t step = backward ? 1 : -1;
148,456,498✔
258
  while (i >= 0 && i < num && uid >= pBlockList[i].minUid && uid <= pBlockList[i].maxUid) {
298,233,310✔
259
    i += step;
149,776,812✔
260
  }
261
  return i - step;
148,422,042✔
262
}
263

264
static int32_t binarySearchForStartBlock(SSttBlk *pBlockList, int32_t num, uint64_t uid, int32_t backward) {
297,208,390✔
265
  int32_t midPos = -1;
297,208,390✔
266
  if (num <= 0) {
297,208,390✔
267
    return -1;
80,393,957✔
268
  }
269

270
  int32_t firstPos = 0;
216,814,433✔
271
  int32_t lastPos = num - 1;
216,814,433✔
272

273
  // find the first position which is bigger than the key
274
  if ((uid > pBlockList[lastPos].maxUid) || (uid < pBlockList[firstPos].minUid)) {
216,814,433✔
275
    return -1;
68,429,077✔
276
  }
277

278
  while (1) {
7,665,908✔
279
    if (uid >= pBlockList[firstPos].minUid && uid <= pBlockList[firstPos].maxUid) {
156,023,089✔
280
      return findEarliestIndex(firstPos, uid, pBlockList, num, backward);
141,840,242✔
281
    }
282

283
    if (uid > pBlockList[lastPos].maxUid || uid < pBlockList[firstPos].minUid) {
14,245,564✔
284
      return -1;
8,406✔
285
    }
286

287
    int32_t numOfRows = lastPos - firstPos + 1;
14,247,139✔
288
    midPos = (numOfRows >> 1u) + firstPos;
14,247,139✔
289

290
    if (uid < pBlockList[midPos].minUid) {
14,247,139✔
291
      lastPos = midPos - 1;
3,746,540✔
292
    } else if (uid > pBlockList[midPos].maxUid) {
10,500,543✔
293
      firstPos = midPos + 1;
3,919,368✔
294
    } else {
295
      return findEarliestIndex(midPos, uid, pBlockList, num, backward);
6,581,800✔
296
    }
297
  }
298
}
299

300
static FORCE_INLINE int32_t findEarliestRow(int32_t index, uint64_t uid, const uint64_t *uidList, int32_t num,
301
                                            int32_t backward) {
302
  int32_t i = index;
149,211,012✔
303
  int32_t step = backward ? 1 : -1;
149,211,012✔
304
  while (i >= 0 && i < num && uid == uidList[i]) {
2,147,483,647✔
305
    i += step;
2,147,483,647✔
306
  }
307
  return i - step;
149,179,597✔
308
}
309

310
static int32_t binarySearchForStartRowIndex(uint64_t *uidList, int32_t num, uint64_t uid, int32_t backward) {
149,241,604✔
311
  int32_t firstPos = 0;
149,241,604✔
312
  int32_t lastPos = num - 1;
149,241,604✔
313

314
  // find the first position which is bigger than the key
315
  if ((uid > uidList[lastPos]) || (uid < uidList[firstPos])) {
149,241,604✔
UNCOV
316
    return -1;
×
317
  }
318

319
  while (1) {
44,987,545✔
320
    if (uid == uidList[firstPos]) {
194,271,368✔
321
      return findEarliestRow(firstPos, uid, uidList, num, backward);
122,324,351✔
322
    }
323

324
    if (uid > uidList[lastPos] || uid < uidList[firstPos]) {
71,924,407✔
325
      return -1;
84,295✔
326
    }
327

328
    int32_t numOfRows = lastPos - firstPos + 1;
71,839,700✔
329
    int32_t midPos = (numOfRows >> 1u) + firstPos;
71,839,700✔
330

331
    if (uid < uidList[midPos]) {
71,839,700✔
332
      lastPos = midPos - 1;
13,954,910✔
333
    } else if (uid > uidList[midPos]) {
57,884,910✔
334
      firstPos = midPos + 1;
31,032,635✔
335
    } else {
336
      return findEarliestRow(midPos, uid, uidList, num, backward);
26,855,246✔
337
    }
338
  }
339
}
340

341
static int32_t extractSttBlockInfo(SLDataIter *pIter, const TSttBlkArray *pArray, SSttBlockLoadInfo *pBlockLoadInfo,
211,306,996✔
342
                                   uint64_t suid) {
343
  void   *px = NULL;
211,306,996✔
344
  int32_t code = TSDB_CODE_SUCCESS;
211,306,996✔
345
  if (TARRAY2_SIZE(pArray) <= 0) {
211,306,996✔
346
    return code;
149,468✔
347
  }
348

349
  SSttBlk *pStart = &pArray->data[0];
211,212,773✔
350
  SSttBlk *pEnd = &pArray->data[TARRAY2_SIZE(pArray) - 1];
211,202,124✔
351

352
  // all identical
353
  if (pStart->suid == pEnd->suid) {
211,153,375✔
354
    if (pStart->suid != suid) {  // no qualified stt block existed
181,262,247✔
355
      taosArrayClear(pBlockLoadInfo->aSttBlk);
51,493,601✔
356
      pIter->iSttBlk = -1;
51,484,525✔
357
      return TSDB_CODE_SUCCESS;
51,491,583✔
358
    } else {  // all blocks are qualified
359
      taosArrayClear(pBlockLoadInfo->aSttBlk);
129,767,767✔
360
      px = taosArrayAddBatch(pBlockLoadInfo->aSttBlk, pArray->data, pArray->size);
129,772,792✔
361
      if (px == NULL) {
129,814,500✔
UNCOV
362
        return terrno;
×
363
      }
364
    }
365
  } else {
366
    SArray *pTmp = taosArrayInit(TARRAY2_SIZE(pArray), sizeof(SSttBlk));
29,935,562✔
367
    if (pTmp == NULL) {
29,942,153✔
UNCOV
368
      return terrno;
×
369
    }
370

371
    for (int32_t i = 0; i < TARRAY2_SIZE(pArray); ++i) {
101,265,228✔
372
      SSttBlk *p = &pArray->data[i];
82,907,815✔
373
      if (p->suid < suid) {
82,905,695✔
374
        continue;
47,980,942✔
375
      }
376

377
      if (p->suid == suid) {
34,928,595✔
378
        void *px = taosArrayPush(pTmp, p);
23,342,307✔
379
        if (px == NULL) {
23,342,307✔
UNCOV
380
          code = terrno;
×
UNCOV
381
          break;
×
382
        }
383
      } else if (p->suid > suid) {
11,587,766✔
384
        break;
11,588,854✔
385
      }
386
    }
387

388
    taosArrayDestroy(pBlockLoadInfo->aSttBlk);
29,940,852✔
389
    pBlockLoadInfo->aSttBlk = pTmp;
29,940,793✔
390
  }
391

392
  return code;
159,688,294✔
393
}
394

395
static int32_t tValueDupPayload(SValue *pVal) {
37,926,464✔
396
  if (IS_VAR_DATA_TYPE(pVal->type) || pVal->type == TSDB_DATA_TYPE_DECIMAL) {
37,926,464✔
397
    char *p = (char *)pVal->pData;
13,174,029✔
398
    char *pBuf = taosMemoryMalloc(pVal->nData);
13,173,401✔
399
    if (pBuf == NULL) {
13,170,696✔
UNCOV
400
      return terrno;
×
401
    }
402

403
    memcpy(pBuf, p, pVal->nData);
13,170,696✔
404
    pVal->pData = (uint8_t *)pBuf;
13,170,404✔
405
  }
406

407
  return TSDB_CODE_SUCCESS;
37,927,789✔
408
}
409

410
static int32_t loadSttStatisticsBlockData(SSttFileReader *pSttFileReader, SSttBlockLoadInfo *pBlockLoadInfo,
211,017,554✔
411
                                          TStatisBlkArray *pStatisBlkArray, uint64_t suid, const char *id) {
412
  int32_t code = TSDB_CODE_SUCCESS;
211,017,554✔
413
  int32_t lino = 0;
211,017,554✔
414
  void   *px = NULL;
211,017,554✔
415
  int32_t startIndex = 0;
211,017,554✔
416
  int32_t ret = 0;
211,017,554✔
417

418
  int32_t numOfBlocks = TARRAY2_SIZE(pStatisBlkArray);
211,017,554✔
419
  if (numOfBlocks <= 0) {
211,016,781✔
420
    return code;
149,468✔
421
  }
422

423
  while ((startIndex < numOfBlocks) && (pStatisBlkArray->data[startIndex].maxTbid.suid < suid)) {
237,435,130✔
424
    ++startIndex;
26,567,817✔
425
  }
426

427
  if (startIndex >= numOfBlocks || pStatisBlkArray->data[startIndex].minTbid.suid > suid) {
210,900,117✔
428
    return 0;
59,642,309✔
429
  }
430

431
  int32_t endIndex = startIndex;
151,278,021✔
432
  while (endIndex < numOfBlocks && pStatisBlkArray->data[endIndex].minTbid.suid <= suid) {
305,218,602✔
433
    ++endIndex;
153,940,581✔
434
  }
435

436
  int32_t num = endIndex - startIndex;
151,272,638✔
437
  pBlockLoadInfo->cost.loadStatisBlocks += num;
151,272,638✔
438

439
  STbStatisBlock block;
151,281,805✔
440
  code = tStatisBlockInit(&block);
151,250,873✔
441
  QUERY_CHECK_CODE(code, lino, _end);
151,336,067✔
442

443
  int64_t st = taosGetTimestampUs();
151,335,191✔
444

445
  for (int32_t k = startIndex; k < endIndex; ++k) {
305,294,632✔
446
    code = tsdbSttFileReadStatisBlock(pSttFileReader, &pStatisBlkArray->data[k], &block);
153,920,697✔
447
    QUERY_CHECK_CODE(code, lino, _end);
153,994,011✔
448

449
    int32_t i = 0;
153,994,011✔
450
    int32_t rows = block.numOfRecords;
153,994,011✔
451
    while (i < rows && ((int64_t *)block.suids.data)[i] != suid) {
180,441,442✔
452
      ++i;
26,447,431✔
453
    }
454

455
    // existed
456
    if (i < rows) {
153,988,523✔
457
      SSttTableRowsInfo *pInfo = &pBlockLoadInfo->info;
153,079,204✔
458

459
      if (pInfo->pUid == NULL) {
153,071,125✔
460
        pInfo->pUid = taosArrayInit(rows, sizeof(int64_t));
150,420,008✔
461
        pInfo->pFirstTs = taosArrayInit(rows, sizeof(int64_t));
150,424,287✔
462
        pInfo->pLastTs = taosArrayInit(rows, sizeof(int64_t));
150,428,398✔
463
        pInfo->pCount = taosArrayInit(rows, sizeof(int64_t));
150,423,881✔
464

465
        pInfo->pFirstKey = taosArrayInit(rows, sizeof(SValue));
150,418,152✔
466
        pInfo->pLastKey = taosArrayInit(rows, sizeof(SValue));
150,389,155✔
467

468
        if (pInfo->pUid == NULL || pInfo->pFirstTs == NULL || pInfo->pLastTs == NULL || pInfo->pCount == NULL ||
150,408,185✔
469
            pInfo->pFirstKey == NULL || pInfo->pLastKey == NULL) {
150,403,196✔
470
          code = terrno;
30,498✔
UNCOV
471
          goto _end;
×
472
        }
473

474
        pInfo->memSize = sizeof(SSttTableRowsInfo) + sizeof(SArray) * 6;
150,397,677✔
475
      }
476

477
      if (pStatisBlkArray->data[k].maxTbid.suid == suid) {
153,078,708✔
478
        int32_t size = rows - i;
145,536,906✔
479
        int32_t offset = i * sizeof(int64_t);
145,536,906✔
480

481
        px = taosArrayAddBatch(pInfo->pUid, tBufferGetDataAt(&block.uids, offset), size);
145,536,906✔
482
        TSDB_CHECK_NULL(px, code, lino, _end, terrno);
145,533,854✔
483

484
        px = taosArrayAddBatch(pInfo->pFirstTs, tBufferGetDataAt(&block.firstKeyTimestamps, offset), size);
145,533,854✔
485
        TSDB_CHECK_NULL(px, code, lino, _end, terrno);
145,546,923✔
486

487
        px = taosArrayAddBatch(pInfo->pLastTs, tBufferGetDataAt(&block.lastKeyTimestamps, offset), size);
145,546,923✔
488
        TSDB_CHECK_NULL(px, code, lino, _end, terrno);
145,561,895✔
489

490
        px = taosArrayAddBatch(pInfo->pCount, tBufferGetDataAt(&block.counts, offset), size);
145,561,895✔
491
        TSDB_CHECK_NULL(px, code, lino, _end, terrno);
145,570,815✔
492

493
        pInfo->memSize += size * sizeof(int64_t) * 4;
145,570,815✔
494
        pInfo->memSize += size * sizeof(SValue) * 2;
145,552,529✔
495

496
        if (block.numOfPKs > 0) {
145,496,851✔
497
          SValue vFirst = {0}, vLast = {0};
10,643,257✔
498
          for (int32_t f = i; f < rows; ++f) {
25,727,082✔
499
            code = tValueColumnGet(&block.firstKeyPKs[0], f, &vFirst);
15,080,565✔
500
            TSDB_CHECK_CODE(code, lino, _end);
15,081,148✔
501

502
            code = tValueDupPayload(&vFirst);
15,081,148✔
503
            TSDB_CHECK_CODE(code, lino, _end);
15,089,001✔
504

505
            px = taosArrayPush(pInfo->pFirstKey, &vFirst);
15,089,001✔
506
            TSDB_CHECK_NULL(px, code, lino, _end, terrno);
15,090,385✔
507

508
            // todo add api to clone the original data
509
            code = tValueColumnGet(&block.lastKeyPKs[0], f, &vLast);
15,090,385✔
510
            TSDB_CHECK_CODE(code, lino, _end);
15,091,457✔
511

512
            code = tValueDupPayload(&vLast);
15,091,457✔
513
            TSDB_CHECK_CODE(code, lino, _end);
15,090,843✔
514

515
            px = taosArrayPush(pInfo->pLastKey, &vLast);
15,090,843✔
516
            TSDB_CHECK_NULL(px, code, lino, _end, terrno);
15,091,982✔
517

518
            pInfo->memSize += (IS_VAR_DATA_TYPE(vFirst.type) || vFirst.type == TSDB_DATA_TYPE_DECIMAL)? (vFirst.nData + vLast.nData):0;
15,091,982✔
519
          }
520
        } else {
521
          SValue vFirst = {0};
134,853,594✔
522
          for (int32_t j = 0; j < size; ++j) {
1,957,782,957✔
523
            px = taosArrayPush(pInfo->pFirstKey, &vFirst);
1,823,195,014✔
524
            TSDB_CHECK_NULL(px, code, lino, _end, terrno);
1,822,709,890✔
525

526
            px = taosArrayPush(pInfo->pLastKey, &vFirst);
1,822,709,890✔
527
            TSDB_CHECK_NULL(px, code, lino, _end, terrno);
1,822,939,279✔
528
          }
529
        }
530
      } else {
531
        STbStatisRecord record = {0};
7,510,322✔
532
        while (i < rows) {
23,575,922✔
533
          code = tStatisBlockGet(&block, i, &record);
23,578,777✔
534
          TSDB_CHECK_CODE(code, lino, _end);
23,578,910✔
535

536
          if (record.suid != suid) {
23,578,910✔
537
            break;
7,512,763✔
538
          }
539

540
          px = taosArrayPush(pInfo->pUid, &record.uid);
16,066,147✔
541
          TSDB_CHECK_NULL(px, code, lino, _end, terrno);
16,067,536✔
542

543
          px = taosArrayPush(pInfo->pCount, &record.count);
16,067,536✔
544
          TSDB_CHECK_NULL(px, code, lino, _end, terrno);
16,069,032✔
545

546
          px = taosArrayPush(pInfo->pFirstTs, &record.firstKey.ts);
16,069,032✔
547
          TSDB_CHECK_NULL(px, code, lino, _end, terrno);
16,068,411✔
548

549
          px = taosArrayPush(pInfo->pLastTs, &record.lastKey.ts);
16,068,411✔
550
          TSDB_CHECK_NULL(px, code, lino, _end, terrno);
16,066,780✔
551

552
          pInfo->memSize += (sizeof(int64_t) * 4 + sizeof(SValue) * 2);
16,066,780✔
553

554
          if (record.firstKey.numOfPKs > 0) {
16,063,401✔
555
            SValue first = record.firstKey.pks[0];
3,874,241✔
556
            code = tValueDupPayload(&first);
3,874,210✔
557
            TSDB_CHECK_CODE(code, lino, _end);
3,874,387✔
558

559
            px = taosArrayPush(pInfo->pFirstKey, &first);
3,874,387✔
560
            TSDB_CHECK_NULL(px, code, lino, _end, terrno);
3,874,387✔
561

562
            SValue last = record.lastKey.pks[0];
3,874,387✔
563
            code = tValueDupPayload(&last);
3,874,387✔
564
            TSDB_CHECK_CODE(code, lino, _end);
3,874,222✔
565

566
            px = taosArrayPush(pInfo->pLastKey, &last);
3,874,222✔
567
            TSDB_CHECK_NULL(px, code, lino, _end, terrno);
3,874,387✔
568

569
            pInfo->memSize += (IS_VAR_DATA_TYPE(first.type) || first.type == TSDB_DATA_TYPE_DECIMAL)? (first.nData + last.nData):0;
3,874,387✔
570
          } else {
571
            SValue v = {0};
12,189,160✔
572
            px = taosArrayPush(pInfo->pFirstKey, &v);
12,193,019✔
573
            TSDB_CHECK_NULL(px, code, lino, _end, terrno);
12,193,019✔
574

575
            px = taosArrayPush(pInfo->pLastKey, &v);
12,193,019✔
576
            TSDB_CHECK_NULL(px, code, lino, _end, terrno);
12,193,277✔
577
          }
578

579
          i += 1;
16,065,709✔
580
        }
581
      }
582
    }
583
  }
584

585
_end:
151,414,927✔
586
  tStatisBlockDestroy(&block);
151,294,956✔
587
  if (code != 0) {
151,341,279✔
UNCOV
588
    tsdbError("%s error happens at:%s line number: %d, code:%s", id, __func__, lino, tstrerror(code));
×
589
  } else {
590
    double el = (taosGetTimestampUs() - st) / 1000.0;
151,339,690✔
591
    pBlockLoadInfo->cost.statisElapsedTime += el;
151,339,690✔
592

593
    tsdbDebug("%s load %d statis blocks into buf, elapsed time:%.2fms", id, num, el);
151,356,523✔
594
  }
595
  return code;
151,341,246✔
596
}
597

598
static int32_t doLoadSttFilesBlk(SSttBlockLoadInfo *pBlockLoadInfo, SLDataIter *pIter, int64_t suid,
211,262,249✔
599
                                 _load_tomb_fn loadTombFn, void *pReader1, const char *idStr, bool loadFromDisk) {
600
  int64_t st = taosGetTimestampUs();
211,366,545✔
601

602
  const TSttBlkArray *pSttBlkArray = NULL;
211,366,545✔
603
  pBlockLoadInfo->sttBlockLoaded = true;
211,340,820✔
604

605
  // load the stt block info for each stt-block
606
  int32_t code = tsdbSttFileReadSttBlk(pIter->pReader, &pSttBlkArray);
211,350,347✔
607
  if (code != TSDB_CODE_SUCCESS) {
211,301,377✔
UNCOV
608
    tsdbError("load stt blk failed, code:%s, %s", tstrerror(code), idStr);
×
UNCOV
609
    return code;
×
610
  }
611

612
  // load the stt block info for each stt file block
613
  code = extractSttBlockInfo(pIter, pSttBlkArray, pBlockLoadInfo, suid);
211,301,377✔
614
  if (code != TSDB_CODE_SUCCESS) {
211,315,460✔
615
    tsdbError("load stt block info failed, code:%s, %s", tstrerror(code), idStr);
2,339✔
UNCOV
616
    return code;
×
617
  }
618

619
  if (loadFromDisk) {
211,314,734✔
620
    // load stt statistics block for all stt-blocks, to decide if the data of queried table exists in current stt file
621
    TStatisBlkArray *pStatisBlkArray = NULL;
211,057,804✔
622
    code = tsdbSttFileReadStatisBlk(pIter->pReader, (const TStatisBlkArray **)&pStatisBlkArray);
211,033,650✔
623
    if (code != TSDB_CODE_SUCCESS) {
211,050,791✔
UNCOV
624
      tsdbError("failed to load stt block statistics, code:%s, %s", tstrerror(code), idStr);
×
UNCOV
625
      return code;
×
626
    }
627

628
    // load statistics block for all tables in current stt file
629
    code = loadSttStatisticsBlockData(pIter->pReader, pIter->pBlockLoadInfo, pStatisBlkArray, suid, idStr);
211,050,791✔
630
    if (code != TSDB_CODE_SUCCESS) {
211,048,515✔
UNCOV
631
      tsdbError("failed to load stt statistics block data, code:%s, %s", tstrerror(code), idStr);
×
UNCOV
632
      return code;
×
633
    }
634
  } else {
635
    tsdbDebug("stt block statis info loaded from cache, %s", idStr);
256,930✔
636
  }
637

638
  code = loadTombFn(pReader1, pIter->pReader, pIter->pBlockLoadInfo);
211,380,454✔
639

640
  double el = (taosGetTimestampUs() - st) / 1000.0;
211,364,583✔
641
  tsdbDebug("load the stt file blk info completed, elapsed time:%.2fms, %s", el, idStr);
211,364,583✔
642
  return code;
211,340,894✔
643
}
644

645
static int32_t uidComparFn(const void *p1, const void *p2) {
295,157,057✔
646
  const uint64_t *pFirst = p1;
295,157,057✔
647
  const uint64_t *pVal = p2;
295,157,057✔
648

649
  if (*pFirst == *pVal) {
295,157,057✔
650
    return 0;
148,405,413✔
651
  } else {
652
    return *pFirst < *pVal ? -1 : 1;
146,875,445✔
653
  }
654
}
655

656
static void setSttInfoForCurrentTable(SSttBlockLoadInfo *pLoadInfo, uint64_t uid, SSttKeyRange *pRange,
297,225,099✔
657
                                      int64_t *numOfRows) {
658
  if (pRange == NULL || taosArrayGetSize(pLoadInfo->info.pUid) == 0) {
297,225,099✔
659
    return;
80,391,854✔
660
  }
661

662
  int32_t index = taosArraySearchIdx(pLoadInfo->info.pUid, &uid, uidComparFn, TD_EQ);
216,880,545✔
663
  if (index >= 0) {
216,850,784✔
664
    pRange->skey.ts = *(int64_t *)taosArrayGet(pLoadInfo->info.pFirstTs, index);
148,386,682✔
665
    pRange->ekey.ts = *(int64_t *)taosArrayGet(pLoadInfo->info.pLastTs, index);
148,417,681✔
666

667
    *numOfRows += *(int64_t *)taosArrayGet(pLoadInfo->info.pCount, index);
148,404,748✔
668

669
    if (pRange->skey.numOfPKs > 0) {
148,409,879✔
670
      memcpy(&pRange->skey.pks[0], taosArrayGet(pLoadInfo->info.pFirstKey, index), sizeof(SValue));
11,717,740✔
671
      memcpy(&pRange->ekey.pks[0], taosArrayGet(pLoadInfo->info.pLastKey, index), sizeof(SValue));
11,720,135✔
672
    }
673
  }
674
}
675

676
int32_t tLDataIterOpen2(SLDataIter *pIter, SSttFileReader *pSttFileReader, int32_t cid, int8_t backward,
297,274,459✔
677
                        SMergeTreeConf *pConf, SSttBlockLoadInfo *pBlockLoadInfo, SSttKeyRange *pKeyRange,
678
                        int64_t *numOfRows, const char *idStr, bool loadFromDisk) {
679
  int32_t code = TSDB_CODE_SUCCESS;
297,274,459✔
680

681
  pIter->uid = pConf->uid;
297,274,459✔
682
  pIter->cid = cid;
297,346,650✔
683
  pIter->backward = backward;
297,345,702✔
684
  pIter->verRange.minVer = pConf->verRange.minVer;
297,335,941✔
685
  pIter->verRange.maxVer = pConf->verRange.maxVer;
297,288,273✔
686
  pIter->timeWindow.skey = pConf->timewindow.skey;
297,304,517✔
687
  pIter->timeWindow.ekey = pConf->timewindow.ekey;
297,266,986✔
688

689
  pIter->pStartRowKey = pConf->pCurRowKey;
297,308,162✔
690
  pIter->pReader = pSttFileReader;
297,262,705✔
691
  pIter->pBlockLoadInfo = pBlockLoadInfo;
297,324,030✔
692

693
  // open stt file failed, ignore and continue
694
  if (pIter->pReader == NULL) {
297,321,906✔
UNCOV
695
    tsdbError("stt file reader is null, %s", idStr);
×
UNCOV
696
    pIter->pSttBlk = NULL;
×
UNCOV
697
    pIter->iSttBlk = -1;
×
698
    return TSDB_CODE_SUCCESS;
×
699
  }
700

701
  if (!pBlockLoadInfo->sttBlockLoaded) {
297,258,709✔
702
      code = doLoadSttFilesBlk(pBlockLoadInfo, pIter, pConf->suid, pConf->loadTombFn, pConf->pReader, idStr, loadFromDisk);
211,291,509✔
703
  }
704

705
  setSttInfoForCurrentTable(pBlockLoadInfo, pConf->uid, pKeyRange, numOfRows);
297,262,364✔
706

707
  // find the start block, actually we could load the position to avoid repeatly searching for the start position when
708
  // the skey is updated.
709
  size_t size = taosArrayGetSize(pBlockLoadInfo->aSttBlk);
297,242,406✔
710
  pIter->iSttBlk = binarySearchForStartBlock(pBlockLoadInfo->aSttBlk->pData, size, pConf->uid, backward);
297,282,694✔
711
  if (pIter->iSttBlk != -1) {
297,213,233✔
712
    pIter->pSttBlk = taosArrayGet(pBlockLoadInfo->aSttBlk, pIter->iSttBlk);
148,449,942✔
713
    pIter->iRow = (pIter->backward) ? pIter->pSttBlk->nRow : -1;
148,440,789✔
714

715
    if ((!backward) && ((pConf->strictTimeRange && pIter->pSttBlk->minKey >= pIter->timeWindow.ekey) ||
148,406,188✔
716
                        (!pConf->strictTimeRange && pIter->pSttBlk->minKey > pIter->timeWindow.ekey))) {
141,317,506✔
717
      pIter->pSttBlk = NULL;
65,751✔
718
    }
719

720
    if (backward && ((pConf->strictTimeRange && pIter->pSttBlk->maxKey <= pIter->timeWindow.skey) ||
148,385,702✔
721
                     (!pConf->strictTimeRange && pIter->pSttBlk->maxKey < pIter->timeWindow.skey))) {
7,121,410✔
722
      pIter->pSttBlk = NULL;
189,005✔
723
      pIter->ignoreEarlierTs = true;
186,683✔
724
    }
725
  }
726

727
  return code;
297,094,753✔
728
}
729

730
void tLDataIterClose2(SLDataIter *pIter) {
211,395,545✔
731
  tsdbSttFileReaderClose(&pIter->pReader);
211,395,545✔
732
  pIter->pReader = NULL;
211,365,522✔
733
}
211,375,614✔
734

735
void tLDataIterNextBlock(SLDataIter *pIter, const char *idStr) {
152,303,499✔
736
  int32_t step = pIter->backward ? -1 : 1;
152,303,499✔
737
  int32_t oldIndex = pIter->iSttBlk;
152,337,860✔
738

739
  pIter->iSttBlk += step;
152,344,766✔
740

741
  int32_t index = -1;
152,318,643✔
742
  size_t  size = pIter->pBlockLoadInfo->aSttBlk->size;
152,318,643✔
743
  for (int32_t i = pIter->iSttBlk; i < size && i >= 0; i += step) {
152,797,756✔
744
    SSttBlk *p = taosArrayGet(pIter->pBlockLoadInfo->aSttBlk, i);
16,117,380✔
745
    if ((!pIter->backward) && p->minUid > pIter->uid) {
16,117,749✔
746
      break;
7,670,102✔
747
    }
748

749
    if (pIter->backward && p->maxUid < pIter->uid) {
8,448,706✔
750
      break;
1,581,343✔
751
    }
752

753
    // check uid firstly
754
    if (p->minUid <= pIter->uid && p->maxUid >= pIter->uid) {
6,867,034✔
755
      if ((!pIter->backward) && p->minKey > pIter->timeWindow.ekey) {
6,866,832✔
756
        break;
83,479✔
757
      }
758

759
      if (pIter->backward && p->maxKey < pIter->timeWindow.skey) {
6,783,246✔
760
        break;
134✔
761
      }
762

763
      // check time range secondly
764
      if (p->minKey <= pIter->timeWindow.ekey && p->maxKey >= pIter->timeWindow.skey) {
6,783,219✔
765
        if ((!pIter->backward) && p->minVer > pIter->verRange.maxVer) {
6,293,155✔
UNCOV
766
          break;
×
767
        }
768

769
        if (pIter->backward && p->maxVer < pIter->verRange.minVer) {
6,292,941✔
UNCOV
770
          break;
×
771
        }
772

773
        if (p->minVer <= pIter->verRange.maxVer && p->maxVer >= pIter->verRange.minVer) {
6,293,155✔
774
          index = i;
6,293,155✔
775
          break;
6,293,155✔
776
        }
777
      }
778
    }
779
  }
780

781
  pIter->pSttBlk = NULL;
152,359,688✔
782
  if (index != -1) {
152,287,339✔
783
    SSttBlk *p = taosArrayGet(pIter->pBlockLoadInfo->aSttBlk, index);
6,293,048✔
784

785
    pIter->iSttBlk = index;
6,293,048✔
786
    pIter->pSttBlk = (SSttBlk *)taosArrayGet(pIter->pBlockLoadInfo->aSttBlk, pIter->iSttBlk);
6,293,048✔
787
    tsdbDebug("try next stt-file block:%d from %d, trigger by uid:%" PRIu64 ", stt-fileVer:%" PRId64
6,293,048✔
788
              ", uidRange:%" PRId64 "-%" PRId64 " %s",
789
              pIter->iSttBlk, oldIndex, pIter->uid, pIter->cid, p->minUid, p->maxUid, idStr);
790
  } else {
791
    tsdbDebug("no more last block qualified, uid:%" PRIu64 ", stt-file block:%d, %s", pIter->uid, oldIndex, idStr);
145,994,291✔
792
  }
793
}
152,287,339✔
794

795
static int32_t findNextValidRow(SLDataIter *pIter, const char *idStr) {
2,147,483,647✔
796
  bool        hasVal = false;
2,147,483,647✔
797
  int32_t     step = pIter->backward ? -1 : 1;
2,147,483,647✔
798
  int32_t     i = pIter->iRow;
2,147,483,647✔
799
  SBlockData *pData = NULL;
2,147,483,647✔
800

801
  int32_t code = loadLastBlock(pIter, idStr, &pData);
2,147,483,647✔
802
  if (code) {
2,147,483,647✔
UNCOV
803
    tsdbError("failed to load stt block, code:%s, %s", tstrerror(code), idStr);
×
UNCOV
804
    return code;
×
805
  }
806

807
  // mostly we only need to find the start position for a given table
808
  if ((((i == 0) && (!pIter->backward)) || (i == pData->nRow - 1 && pIter->backward)) && pData->aUid != NULL) {
2,147,483,647✔
809
    i = binarySearchForStartRowIndex((uint64_t *)pData->aUid, pData->nRow, pIter->uid, pIter->backward);
149,295,569✔
810
    if (i == -1) {
149,215,123✔
811
      tsdbDebug("failed to find the data in pBlockData, uid:%" PRIu64 " , %s", pIter->uid, idStr);
84,295✔
812
      pIter->iRow = -1;
84,295✔
813
      return code;
84,295✔
814
    }
815
  }
816

817
  for (; i < pData->nRow && i >= 0; i += step) {
2,147,483,647✔
818
    if (pData->aUid != NULL) {
2,147,483,647✔
819
      if (!pIter->backward) {
2,147,483,647✔
820
        if (pData->aUid[i] > pIter->uid) {
2,147,483,647✔
821
          break;
27,549,121✔
822
        }
823
      } else {
824
        if (pData->aUid[i] < pIter->uid) {
526,799,352✔
825
          break;
2,516,844✔
826
        }
827
      }
828
    }
829

830
    int64_t ts = pData->aTSKEY[i];
2,147,483,647✔
831
    if (!pIter->backward) {               // asc
2,147,483,647✔
832
      if (ts > pIter->timeWindow.ekey) {  // no more data
2,147,483,647✔
833
        break;
621,360✔
834
      } else {
835
        if (ts < pIter->timeWindow.skey) {
2,147,483,647✔
836
          continue;
1,609,710,303✔
837
        }
838

839
        if (ts == pIter->timeWindow.skey && pIter->pStartRowKey->numOfPKs > 0) {
2,147,483,647✔
840
          SRowKey key;
157,784✔
841
          tColRowGetKey(pData, i, &key);
157,784✔
842
          int32_t ret = pkCompEx(&key, pIter->pStartRowKey);
157,784✔
843
          if (ret < 0) {
157,784✔
UNCOV
844
            continue;
×
845
          }
846
        }
847
      }
848
    } else {
849
      if (ts < pIter->timeWindow.skey) {
541,275,141✔
850
        break;
802,200✔
851
      } else {
852
        if (ts > pIter->timeWindow.ekey) {
540,426,934✔
853
          continue;
92,644,953✔
854
        }
855

856
        if (ts == pIter->timeWindow.ekey && pIter->pStartRowKey->numOfPKs > 0) {
447,800,260✔
UNCOV
857
          SRowKey key;
×
UNCOV
858
          tColRowGetKey(pData, i, &key);
×
UNCOV
859
          int32_t ret = pkCompEx(&key, pIter->pStartRowKey);
×
860
          if (ret > 0) {
×
861
            continue;
×
862
          }
863
        }
864
      }
865
    }
866

867
    int64_t ver = pData->aVersion[i];
2,147,483,647✔
868
    if (ver < pIter->verRange.minVer) {
2,147,483,647✔
UNCOV
869
      continue;
×
870
    }
871

872
    // todo opt handle desc case
873
    if (ver > pIter->verRange.maxVer) {
2,147,483,647✔
UNCOV
874
      continue;
×
875
    }
876

877
    hasVal = true;
2,147,483,647✔
878
    break;
2,147,483,647✔
879
  }
880

881
  pIter->iRow = (hasVal) ? i : -1;
2,147,483,647✔
882
  return code;
2,147,483,647✔
883
}
884

885
int32_t tLDataIterNextRow(SLDataIter *pIter, const char *idStr, bool *hasNext) {
2,147,483,647✔
886
  int32_t     step = pIter->backward ? -1 : 1;
2,147,483,647✔
887
  int32_t     code = 0;
2,147,483,647✔
888
  int32_t     iBlockL = pIter->iSttBlk;
2,147,483,647✔
889
  SBlockData *pBlockData = NULL;
2,147,483,647✔
890
  int32_t     lino = 0;
2,147,483,647✔
891

892
  *hasNext = false;
2,147,483,647✔
893

894
  // no qualified last file block in current file, no need to fetch row
895
  if (pIter->pSttBlk == NULL) {
2,147,483,647✔
896
    return code;
149,060,103✔
897
  }
898

899
  code = loadLastBlock(pIter, idStr, &pBlockData);
2,147,483,647✔
900
  if (pBlockData == NULL || code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
UNCOV
901
    lino = __LINE__;
×
UNCOV
902
    goto _exit;
×
903
  }
904

905
  pIter->iRow += step;
2,147,483,647✔
906

907
  while (1) {
6,293,048✔
908
    bool skipBlock = false;
2,147,483,647✔
909
    code = findNextValidRow(pIter, idStr);
2,147,483,647✔
910
    TSDB_CHECK_CODE(code, lino, _exit);
2,147,483,647✔
911

912
    if (pIter->pBlockLoadInfo->checkRemainingRow) {
2,147,483,647✔
UNCOV
913
      skipBlock = true;
×
UNCOV
914
      int16_t *aCols = pIter->pBlockLoadInfo->colIds;
×
UNCOV
915
      int      nCols = pIter->pBlockLoadInfo->numOfCols;
×
916
      bool     isLast = pIter->pBlockLoadInfo->isLast;
×
917
      for (int inputColIndex = 0; inputColIndex < nCols; ++inputColIndex) {
×
918
        for (int colIndex = 0; colIndex < pBlockData->nColData; ++colIndex) {
×
919
          SColData *pColData = &pBlockData->aColData[colIndex];
×
920
          int16_t   cid = pColData->cid;
×
921

922
          if (cid == aCols[inputColIndex]) {
×
923
            if (isLast && (pColData->flag & HAS_VALUE)) {
×
UNCOV
924
              skipBlock = false;
×
925
              break;
×
926
            } else if (pColData->flag & (HAS_VALUE | HAS_NULL)) {
×
927
              skipBlock = false;
×
928
              break;
×
929
            }
930
          }
931
        }
932
      }
933
    }
934

935
    if (skipBlock || pIter->iRow >= pBlockData->nRow || pIter->iRow < 0) {
2,147,483,647✔
936
      tLDataIterNextBlock(pIter, idStr);
155,066,617✔
937
      if (pIter->pSttBlk == NULL) {  // no more data
152,284,091✔
938
        goto _exit;
146,034,929✔
939
      }
940
    } else {
941
      break;
942
    }
943

944
    if (iBlockL != pIter->iSttBlk) {
6,293,048✔
945
      code = loadLastBlock(pIter, idStr, &pBlockData);
6,293,048✔
946
      if ((pBlockData == NULL) || (code != 0)) {
6,293,155✔
UNCOV
947
        lino = __LINE__;
×
UNCOV
948
        goto _exit;
×
949
      }
950

951
      // set start row index
952
      pIter->iRow = pIter->backward ? pBlockData->nRow - 1 : 0;
6,293,155✔
953
    }
954
  }
955

956
  pIter->rInfo.suid = pBlockData->suid;
2,147,483,647✔
957
  pIter->rInfo.uid = pBlockData->uid;
2,147,483,647✔
958
  pIter->rInfo.row = tsdbRowFromBlockData(pBlockData, pIter->iRow);
2,147,483,647✔
959

960
_exit:
2,147,483,647✔
961
  if (code) {
2,147,483,647✔
UNCOV
962
    tsdbError("failed to exec stt-file nextIter, lino:%d, code:%s, %s", lino, tstrerror(code), idStr);
×
963
  }
964

965
  *hasNext = (code == TSDB_CODE_SUCCESS) && (pIter->pSttBlk != NULL) && (pBlockData != NULL);
2,147,483,647✔
966
  return code;
2,147,483,647✔
967
}
968

969
// SMergeTree =================================================
970
static FORCE_INLINE int32_t tLDataIterCmprFn(const SRBTreeNode *p1, const SRBTreeNode *p2) {
2,147,483,647✔
971
  SLDataIter *pIter1 = (SLDataIter *)(((uint8_t *)p1) - offsetof(SLDataIter, node));
2,147,483,647✔
972
  SLDataIter *pIter2 = (SLDataIter *)(((uint8_t *)p2) - offsetof(SLDataIter, node));
2,147,483,647✔
973

974
  SRowKey rkey1 = {0}, rkey2 = {0};
2,147,483,647✔
975
  tRowGetKeyEx(&pIter1->rInfo.row, &rkey1);
2,147,483,647✔
976
  tRowGetKeyEx(&pIter2->rInfo.row, &rkey2);
2,147,483,647✔
977

978
  int32_t ret = tRowKeyCompare(&rkey1, &rkey2);
2,147,483,647✔
979
  if (ret < 0) {
2,147,483,647✔
980
    return -1;
1,389,879,601✔
981
  } else if (ret > 0) {
2,147,483,647✔
982
    return 1;
1,871,762,971✔
983
  } else {
984
    int64_t ver1 = TSDBROW_VERSION(&pIter1->rInfo.row);
2,147,483,647✔
985
    int64_t ver2 = TSDBROW_VERSION(&pIter2->rInfo.row);
2,147,483,647✔
986

987
    if (ver1 < ver2) {
2,147,483,647✔
988
      return -1;
1,244,288,127✔
989
    } else if (ver1 > ver2) {
1,872,489,799✔
990
      return 1;
1,872,493,641✔
991
    } else {
UNCOV
992
      return 0;
×
993
    }
994
  }
995
}
996

997
static FORCE_INLINE int32_t tLDataIterDescCmprFn(const SRBTreeNode *p1, const SRBTreeNode *p2) {
27,099,127✔
998
  return -1 * tLDataIterCmprFn(p1, p2);
27,099,127✔
999
}
1000

1001
static void clearTableRowsInfoCache(void) {
135,731✔
1002
  int32_t items = (statisCacheInfo.pStatisFileCache != NULL)? taosLRUCacheGetElems(statisCacheInfo.pStatisFileCache):0;
135,731✔
1003
  tsdbInfo("start to free %d items in statisCache", items);
135,731✔
1004

1005
  taosLRUCacheCleanup(statisCacheInfo.pStatisFileCache);
135,731✔
1006
  (void)taosThreadMutexDestroy(&statisCacheInfo.lock);
135,731✔
1007
}
135,731✔
1008

1009
// init the statis file cache, 10MiB by default
1010
static void initTableRowsInfoCache(void) {
135,731✔
1011
  statisCacheInfo.pStatisFileCache = taosLRUCacheInit(40 * 1024 * 1024, -1, 0.5);
135,731✔
1012
  (void)taosThreadMutexInit(&statisCacheInfo.lock, NULL);
135,731✔
1013
  (void) atexit(clearTableRowsInfoCache);
135,731✔
1014
}
135,731✔
1015

1016
int32_t tMergeTreeOpen2(SMergeTree *pMTree, SMergeTreeConf *pConf, SSttDataInfoForTable *pSttDataInfo) {
302,374,765✔
1017
  int32_t               code = TSDB_CODE_SUCCESS;
302,374,765✔
1018
  STFileSet *           pFset = (STFileSet *)pConf->pCurrentFileset;
302,374,765✔
1019
  bool                  loadStatisFromDisk = true;
302,403,775✔
1020
  int32_t               lino = 0;
302,403,775✔
1021
  int32_t               numOfLevels = pFset->lvlArr->size;
302,403,775✔
1022
  SSttStatisCacheValue* pValue = NULL;
302,392,427✔
1023
  LRUHandle*            pHandle = NULL;
302,386,612✔
1024
  SSttStatisCacheKey    key = {.suid = pConf->suid, .fid = pFset->fid, .vgId = TD_VID(pConf->pTsdb->pVnode)};
302,390,109✔
1025

1026
  (void)taosThreadOnce(&tsCacheInit, initTableRowsInfoCache);
302,410,255✔
1027

1028
  pMTree->pIter = NULL;
302,328,290✔
1029
  pMTree->backward = pConf->backward;
302,373,099✔
1030
  pMTree->idStr = pConf->idstr;
302,284,874✔
1031

1032
  if (!pMTree->backward) {  // asc
302,340,224✔
1033
    tRBTreeCreate(&pMTree->rbt, tLDataIterCmprFn);
289,791,531✔
1034
  } else {  // desc
1035
    tRBTreeCreate(&pMTree->rbt, tLDataIterDescCmprFn);
12,563,274✔
1036
  }
1037

1038
  pMTree->ignoreEarlierTs = false;
302,323,743✔
1039

1040
  // no data exists, go to end
1041
  if (numOfLevels == 0) {
302,289,122✔
1042
    goto _end;
27,487,807✔
1043
  }
1044

1045
  code = adjustSttDataIters(pConf->pSttFileBlockIterArray, pConf->pCurrentFileset);
274,801,315✔
1046
  if (code) {
274,834,200✔
UNCOV
1047
    goto _end;
×
1048
  }
1049

1050
  if (pConf->cacheStatis) {
274,834,200✔
1051
    int32_t ret = getStatisInfoFromCache(statisCacheInfo.pStatisFileCache, &key, &pValue, &pHandle, pConf->idstr);
766,560✔
1052
    if (ret == TSDB_CODE_SUCCESS) {  // use cached statis info
766,920✔
1053
      if (pValue->commitTs == pFset->lastCommit) {
765,735✔
1054
        loadStatisFromDisk = false;
765,735✔
1055
      } else {  // release the handle ref, and then remove it from lru cache
UNCOV
1056
        int64_t ts = pValue->commitTs;
×
UNCOV
1057
        clearStatisInfoCache(statisCacheInfo.pStatisFileCache, &key, &pHandle);
×
UNCOV
1058
        tsdbInfo(
×
1059
            "cache expired since new commit occurs, remove the cache and load from disk, vgId:%d, fid:%d, suid:%" PRId64
1060
            ", commitTs:%" PRId64 ", new commitTs:%" PRId64,
1061
            key.vgId, key.fid, key.suid, ts, pFset->lastCommit);
1062
      }
1063
    }
1064
  }
1065

1066
  for (int32_t j = 0; j < numOfLevels; ++j) {
571,827,605✔
1067
    SSttLvl *pSttLevel = ((STFileSet *)pConf->pCurrentFileset)->lvlArr->data[j];
296,923,798✔
1068
    SArray  *pList = taosArrayGetP(pConf->pSttFileBlockIterArray, j);
296,995,122✔
1069

1070
    for (int32_t i = 0; i < TARRAY2_SIZE(pSttLevel->fobjArr); ++i) {  // open all last file
594,332,623✔
1071
      SLDataIter *pIter = taosArrayGetP(pList, i);
297,296,367✔
1072

1073
      SSttFileReader    *pSttFileReader = pIter->pReader;
297,320,871✔
1074
      SSttBlockLoadInfo *pLoadInfo = pIter->pBlockLoadInfo;
297,298,233✔
1075

1076
      // open stt file reader if not opened yet
1077
      // if failed to open this stt file, ignore the error and try next one
1078
      if (pSttFileReader == NULL) {
297,329,269✔
1079
        int32_t pgSize = pConf->pTsdb->pVnode->config.tsdbPageSize;
211,333,400✔
1080

1081
        SSttFileReaderConfig conf = {
422,761,508✔
1082
            .tsdb = pConf->pTsdb, .szPage = pgSize, .file[0] = *pSttLevel->fobjArr->data[i]->f};
211,373,659✔
1083

1084
        code = tsdbSttFileReaderOpen(pSttLevel->fobjArr->data[i]->fname, &conf, &pSttFileReader);
211,393,681✔
1085
        if (code != TSDB_CODE_SUCCESS) {
211,289,638✔
UNCOV
1086
          tsdbError("open stt file reader error. file name %s, code %s, %s", pSttLevel->fobjArr->data[i]->fname,
×
1087
                    tstrerror(code), pMTree->idStr);
1088
        }
1089
      }
1090

1091
      if (pLoadInfo == NULL) {
297,244,899✔
1092
        code = tCreateSttBlockLoadInfo(pConf->pSchema, pConf->pCols, pConf->numOfCols, &pLoadInfo);
211,260,990✔
1093
        if (code != TSDB_CODE_SUCCESS) {
211,363,207✔
UNCOV
1094
          goto _end;
×
1095
        }
1096
      }
1097

1098
      if (!loadStatisFromDisk && (pLoadInfo->info.pCount == NULL)) {
297,347,116✔
1099
          code = getSttTableRowsInfo(pValue, pConf->pCurRowKey->numOfPKs, j, i, &pLoadInfo->info);
257,840✔
1100
          if (code != TSDB_CODE_SUCCESS) {
257,840✔
UNCOV
1101
            loadStatisFromDisk = true;  // failed to get statis info from cache, load it from stt file
×
1102
          }
1103
      }
1104

1105
      memset(pIter, 0, sizeof(SLDataIter));
297,347,116✔
1106

1107
      SSttKeyRange range = {.skey.numOfPKs = pConf->pCurRowKey->numOfPKs, .ekey.numOfPKs = pConf->pCurRowKey->numOfPKs};
297,347,116✔
1108
      int64_t      numOfRows = 0;
297,329,421✔
1109
      int64_t      cid = pSttLevel->fobjArr->data[i]->f->cid;
297,322,466✔
1110

1111
      code = tLDataIterOpen2(pIter, pSttFileReader, cid, pMTree->backward, pConf, pLoadInfo, &range, &numOfRows,
297,363,609✔
1112
                             pMTree->idStr, loadStatisFromDisk);
1113
      if (code != TSDB_CODE_SUCCESS) {
297,166,433✔
UNCOV
1114
        goto _end;
×
1115
      }
1116

1117
      bool hasVal = NULL;
297,166,433✔
1118
      code = tLDataIterNextRow(pIter, pMTree->idStr, &hasVal);
297,228,221✔
1119
      if (code) {
297,131,019✔
UNCOV
1120
        goto _end;
×
1121
      }
1122

1123
      if (hasVal) {
297,131,019✔
1124
        tMergeTreeAddIter(pMTree, pIter);
146,782,007✔
1125

1126
        // let's record the time window for current table of uid in the stt files
1127
        if (pSttDataInfo != NULL && numOfRows > 0) {
146,768,246✔
1128
          void *px = taosArrayPush(pSttDataInfo->pKeyRangeList, &range);
146,794,586✔
1129
          QUERY_CHECK_NULL(px, code, lino, _end, terrno);
146,866,513✔
1130

1131
          pSttDataInfo->numOfRows += numOfRows;
146,866,513✔
1132
        }
1133
      } else {
1134
        if (!pMTree->ignoreEarlierTs) {
150,349,012✔
1135
          pMTree->ignoreEarlierTs = pIter->ignoreEarlierTs;
150,268,903✔
1136
        }
1137
      }
1138
    }
1139
  }
1140

1141
  if (pConf->cacheStatis && loadStatisFromDisk) {
274,903,807✔
1142
    SSttStatisCacheKey    k = {0};
1,084✔
1143
    SSttStatisCacheValue *pVal = NULL;
1,084✔
1144

1145
    code = buildSttTableRowsInfoKV(pConf, TD_VID(pConf->pTsdb->pVnode), &k, &pVal);
1,084✔
1146
    if (code == TSDB_CODE_SUCCESS) {
1,185✔
1147
      code = putStatisInfoIntoCache(statisCacheInfo.pStatisFileCache, &k, pVal, pConf->idstr);
1,185✔
1148
    }
1149
  }
1150

1151
  if (pHandle != NULL && pConf->cacheStatis) {
274,754,087✔
1152
    releaseCacheHandle(statisCacheInfo.pStatisFileCache, &pHandle, true);
765,561✔
1153
  }
1154

1155
  return code;
274,782,539✔
1156

1157
_end:
27,490,266✔
1158
  if (pHandle != NULL && pConf->cacheStatis) {
27,487,807✔
UNCOV
1159
    releaseCacheHandle(statisCacheInfo.pStatisFileCache, &pHandle, true);
×
1160
  }
1161

1162
  tMergeTreeClose(pMTree);
27,487,807✔
1163
  return code;
27,488,308✔
1164
}
1165

1166
void tMergeTreeAddIter(SMergeTree *pMTree, SLDataIter *pIter) {
146,788,770✔
1167
  SRBTreeNode *node = tRBTreePut(&pMTree->rbt, (SRBTreeNode *)pIter);
146,788,770✔
1168
}
146,771,245✔
1169

UNCOV
1170
bool tMergeTreeIgnoreEarlierTs(SMergeTree *pMTree) { return pMTree->ignoreEarlierTs; }
×
1171

1172
static void tLDataIterPinSttBlock(SLDataIter *pIter, const char *id) {
2,147,483,647✔
1173
  SSttBlockLoadInfo *pInfo = pIter->pBlockLoadInfo;
2,147,483,647✔
1174

1175
  if (pInfo->blockData[0].sttBlockIndex == pIter->iSttBlk) {
2,147,483,647✔
1176
    pInfo->blockData[0].pin = true;
2,147,483,647✔
1177
    tsdbTrace("pin stt-block, blockIndex:%d, stt-fileVer:%" PRId64 " %s", pIter->iSttBlk, pIter->cid, id);
2,147,483,647✔
1178
    return;
2,147,483,647✔
1179
  }
1180

1181
  if (pInfo->blockData[1].sttBlockIndex == pIter->iSttBlk) {
2,147,483,647✔
1182
    pInfo->blockData[1].pin = true;
2,147,483,647✔
1183
    tsdbTrace("pin stt-block, blockIndex:%d, stt-fileVer:%" PRId64 " %s", pIter->iSttBlk, pIter->cid, id);
2,147,483,647✔
1184
    return;
2,147,483,647✔
1185
  }
1186

UNCOV
1187
  tsdbError("failed to pin any stt block, sttBlock:%d stt-fileVer:%" PRId64 " %s", pIter->iSttBlk, pIter->cid, id);
×
1188
}
1189

1190
static void tLDataIterUnpinSttBlock(SLDataIter *pIter, const char *id) {
2,147,483,647✔
1191
  SSttBlockLoadInfo *pInfo = pIter->pBlockLoadInfo;
2,147,483,647✔
1192
  if (pInfo->blockData[0].pin) {
2,147,483,647✔
1193
    pInfo->blockData[0].pin = false;
2,147,483,647✔
1194
    tsdbTrace("unpin stt-block:%d, stt-fileVer:%" PRId64 " %s", pInfo->blockData[0].sttBlockIndex, pIter->cid, id);
2,147,483,647✔
1195
    return;
2,147,483,647✔
1196
  }
1197

1198
  if (pInfo->blockData[1].pin) {
2,147,483,647✔
1199
    pInfo->blockData[1].pin = false;
2,147,483,647✔
1200
    tsdbTrace("unpin stt-block:%d, stt-fileVer:%" PRId64 " %s", pInfo->blockData[1].sttBlockIndex, pIter->cid, id);
2,147,483,647✔
1201
    return;
2,147,483,647✔
1202
  }
1203

UNCOV
1204
  tsdbError("failed to unpin any stt block, sttBlock:%d stt-fileVer:%" PRId64 " %s", pIter->iSttBlk, pIter->cid, id);
×
1205
}
1206

1207
void tMergeTreePinSttBlock(SMergeTree *pMTree) {
2,147,483,647✔
1208
  if (pMTree->pIter == NULL) {
2,147,483,647✔
UNCOV
1209
    return;
×
1210
  }
1211

1212
  SLDataIter *pIter = pMTree->pIter;
2,147,483,647✔
1213
  pMTree->pPinnedBlockIter = pIter;
2,147,483,647✔
1214
  tLDataIterPinSttBlock(pIter, pMTree->idStr);
2,147,483,647✔
1215
}
1216

1217
void tMergeTreeUnpinSttBlock(SMergeTree *pMTree) {
2,147,483,647✔
1218
  if (pMTree->pPinnedBlockIter == NULL) {
2,147,483,647✔
UNCOV
1219
    return;
×
1220
  }
1221

1222
  SLDataIter *pIter = pMTree->pPinnedBlockIter;
2,147,483,647✔
1223
  pMTree->pPinnedBlockIter = NULL;
2,147,483,647✔
1224
  tLDataIterUnpinSttBlock(pIter, pMTree->idStr);
2,147,483,647✔
1225
}
1226

1227
int32_t tMergeTreeNext(SMergeTree *pMTree, bool *pHasNext) {
2,147,483,647✔
1228
  int32_t code = 0;
2,147,483,647✔
1229
  if (pHasNext == NULL) {
2,147,483,647✔
UNCOV
1230
    return TSDB_CODE_INVALID_PARA;
×
1231
  }
1232

1233
  *pHasNext = false;
2,147,483,647✔
1234
  while (pMTree->pIter) {
2,147,483,647✔
1235
    SLDataIter *pIter = pMTree->pIter;
2,147,483,647✔
1236
    bool        hasVal = false;
2,147,483,647✔
1237
    code = tLDataIterNextRow(pIter, pMTree->idStr, &hasVal);
2,147,483,647✔
1238
    if (!hasVal || (code != 0)) {
2,147,483,647✔
1239
      if (code == TSDB_CODE_FILE_CORRUPTED) {
143,727,017✔
UNCOV
1240
        code = 0;  // suppress the file corrupt error to enable all queries within this cluster can run without failed.
×
1241
      }
1242

1243
      pMTree->pIter = NULL;
143,727,017✔
1244
    }
1245

1246
    // compare with min in RB Tree
1247
    pIter = (SLDataIter *)tRBTreeMin(&pMTree->rbt);
2,147,483,647✔
1248
    if (pMTree->pIter && pIter) {
2,147,483,647✔
1249
      int32_t c = pMTree->rbt.cmprFn(&pMTree->pIter->node, &pIter->node);
1,380,975,113✔
1250
      if (c > 0) {
1,380,975,897✔
1251
        (void)tRBTreePut(&pMTree->rbt, (SRBTreeNode *)pMTree->pIter);
1,226,129,013✔
1252
        pMTree->pIter = NULL;
1,226,142,599✔
1253
      } else if (!c) {
154,846,884✔
UNCOV
1254
        continue;
×
1255
      }
1256
    }
1257

1258
    break;
2,147,483,647✔
1259
  }
1260

1261
  if (pMTree->pIter == NULL) {
2,147,483,647✔
1262
    pMTree->pIter = (SLDataIter *)tRBTreeMin(&pMTree->rbt);
1,670,996,258✔
1263
    if (pMTree->pIter) {
1,670,948,171✔
1264
      tRBTreeDrop(&pMTree->rbt, (SRBTreeNode *)pMTree->pIter);
1,370,819,216✔
1265
    }
1266
  }
1267

1268
  *pHasNext = (pMTree->pIter != NULL);
2,147,483,647✔
1269
  return code;
2,147,483,647✔
1270
}
1271

1272
void tMergeTreeClose(SMergeTree *pMTree) {
602,080,837✔
1273
  pMTree->pIter = NULL;
602,080,837✔
1274
  pMTree->pPinnedBlockIter = NULL;
602,179,948✔
1275
}
602,173,416✔
1276

1277
int32_t buildSttTableRowsInfoKV(SMergeTreeConf *pConf, int32_t vgId, SSttStatisCacheKey *pKey,
1,084✔
1278
                                SSttStatisCacheValue **pValue) {
1279
  *pValue = taosMemoryCalloc(1, sizeof(SSttStatisCacheValue));
1,084✔
1280
  if (*pValue == NULL) {
1,185✔
UNCOV
1281
    return terrno;
×
1282
  }
1283

1284
  memset(pKey, 0, sizeof(SSttStatisCacheKey));
1,185✔
1285

1286
  STFileSet *pFset = (STFileSet *)pConf->pCurrentFileset;
1,185✔
1287

1288
  pKey->suid = pConf->suid;
1,185✔
1289
  pKey->vgId = vgId;
1,185✔
1290
  pKey->fid = pFset->fid;
1,185✔
1291

1292
  (*pValue)->commitTs = pFset->lastCommit;
1,185✔
1293

1294
  int32_t numOfLevels = TARRAY2_SIZE(pFset->lvlArr);
1,185✔
1295

1296
  (*pValue)->pLevel = taosArrayInit(numOfLevels, sizeof(void *));
1,185✔
1297
  if ((*pValue)->pLevel == NULL) {
1,185✔
UNCOV
1298
    return terrno;
×
1299
  }
1300

1301
  for (int32_t j = 0; j < numOfLevels; ++j) {
2,370✔
1302
    SSttLvl *pSttLevel = pFset->lvlArr->data[j];
1,185✔
1303
    SArray * pIterList = taosArrayGetP(pConf->pSttFileBlockIterArray, j);
1,185✔
1304
    if (pIterList == NULL) {
1,084✔
UNCOV
1305
      return terrno;
×
1306
    }
1307

1308
    SArray *pRowsInfoArr = taosArrayInit(TARRAY2_SIZE(pSttLevel->fobjArr), sizeof(SSttTableRowsInfo));
1,084✔
1309
    if (pRowsInfoArr == NULL) {
1,185✔
UNCOV
1310
      return terrno;
×
1311
    }
1312

1313
    for (int32_t i = 0; i < TARRAY2_SIZE(pSttLevel->fobjArr); ++i) {  // open all stt file
2,370✔
1314
      SLDataIter *       pIter = taosArrayGetP(pIterList, i);
1,084✔
1315
      SSttBlockLoadInfo *pLoadInfo = pIter->pBlockLoadInfo;
1,084✔
1316

1317
      void *px = taosArrayPush(pRowsInfoArr, &pLoadInfo->info);
1,084✔
1318
      if (px == NULL) {
1,185✔
UNCOV
1319
        return terrno;
×
1320
      }
1321

1322
      memset(&pLoadInfo->info, 0, sizeof(SSttTableRowsInfo));
1,185✔
1323
    }
1324

1325
    void *px = taosArrayPush((*pValue)->pLevel, &pRowsInfoArr);
1,286✔
1326
    if (px == NULL) {
1,185✔
UNCOV
1327
      return terrno;
×
1328
    }
1329
  }
1330

1331
  // todo handle memory failure
1332

1333
  return TSDB_CODE_SUCCESS;
1,185✔
1334
}
1335

1336
int32_t getStatisInfoFromCache(SLRUCache *pCache, SSttStatisCacheKey *pKey, SSttStatisCacheValue **pValue,
766,920✔
1337
                               LRUHandle **pHandle, const char *id) {
1338
  *pValue = NULL;
766,920✔
1339
  *pHandle = NULL;
766,920✔
1340

1341
  (void)taosThreadMutexLock(&statisCacheInfo.lock);
766,920✔
1342
  LRUHandle *pItemHandle = taosLRUCacheLookup(pCache, pKey, sizeof(SSttStatisCacheKey));
766,920✔
1343
  if (pItemHandle == NULL) {
766,920✔
1344
    (void)taosThreadMutexUnlock(&statisCacheInfo.lock);
1,185✔
1345
    return TSDB_CODE_NOT_FOUND;
1,185✔
1346
  }
1347

1348
  void *p = taosLRUCacheValue(pCache, pItemHandle);
765,735✔
1349

1350
  *pValue = p;
765,735✔
1351
  *pHandle = pItemHandle;
765,735✔
1352

1353
  tsdbDebug("get statis info from cache suid:%" PRId64 ", vgId:%d, fid:%d, %s, commitTs:%" PRId64, pKey->suid,
765,735✔
1354
            pKey->vgId, pKey->fid, id, (*pValue)->commitTs);
1355

1356
  // (*pEntry)->hitTimes += 1;
1357
  (void)taosThreadMutexUnlock(&statisCacheInfo.lock);
765,735✔
1358
  return TSDB_CODE_SUCCESS;
765,735✔
1359
}
1360

1361
void releaseCacheHandle(SLRUCache *pCache, LRUHandle **pHandle, bool lock) {
765,735✔
1362
  if (lock) {
765,735✔
1363
    (void)taosThreadMutexLock(&statisCacheInfo.lock);
765,735✔
1364
  }
1365

1366
  bool ret = taosLRUCacheRelease(pCache, *pHandle, false);
765,735✔
1367
  *pHandle = NULL;
765,735✔
1368

1369
  if (lock) {
765,735✔
1370
    (void)taosThreadMutexUnlock(&statisCacheInfo.lock);
765,735✔
1371
  }
1372
}
765,735✔
1373

1374
void freeStatisFileItems(const void* key, size_t keyLen, void* value, void* ud) {
1,185✔
1375
  (void)ud;
1376

1377
  if (value == NULL) {
1,185✔
UNCOV
1378
    return;
×
1379
  }
1380

1381
  SSttStatisCacheKey *  pKey = (SSttStatisCacheKey *)key;
1,185✔
1382
  SSttStatisCacheValue *pVal = value;
1,185✔
1383

1384
  for(int32_t i = 0; i < taosArrayGetSize(pVal->pLevel); ++i) {
2,370✔
1385
    SArray* pInfos = taosArrayGetP(pVal->pLevel, i);
1,185✔
1386

1387
    for(int32_t j = 0; j < taosArrayGetSize(pInfos); ++j) {
2,370✔
1388
      SSttTableRowsInfo* p = taosArrayGet(pInfos, j);
1,185✔
1389
      taosArrayDestroy(p->pCount);
1,185✔
1390
      taosArrayDestroyEx(p->pFirstKey, freeItem);
1,185✔
1391
      taosArrayDestroyEx(p->pLastKey, freeItem);
1,185✔
1392
      taosArrayDestroy(p->pFirstTs);
1,185✔
1393
      taosArrayDestroy(p->pLastTs);
1,185✔
1394
      taosArrayDestroy(p->pUid);
1,185✔
1395
    }
1396

1397
    taosArrayDestroy(pInfos);
1,185✔
1398
  }
1399

1400
  taosArrayDestroy(pVal->pLevel);
1,185✔
1401
  taosMemoryFree(pVal);
1,185✔
1402
}
1403

1404
int32_t putStatisInfoIntoCache(SLRUCache *pCache, SSttStatisCacheKey *pKey, SSttStatisCacheValue *pValue,
1,185✔
1405
                               const char *id) {
1406
  (void)taosThreadMutexLock(&statisCacheInfo.lock);
1,185✔
1407

1408
  LRUStatus status = taosLRUCacheInsert(pCache, pKey, sizeof(SSttStatisCacheKey), pValue, getCacheValueSize(pValue),
1,185✔
1409
                                        freeStatisFileItems, NULL, NULL, TAOS_LRU_PRIORITY_LOW, NULL);
1410
  if (status != TAOS_LRU_STATUS_OK) {
1,185✔
UNCOV
1411
    if (status == TAOS_LRU_STATUS_FAIL) {
×
UNCOV
1412
      tsdbError("%s failed to insert items into statis cache, status:%d", id, status);
×
UNCOV
1413
      freeStatisFileItems(NULL, 0, pValue, NULL);
×
1414
    }
1415
  } else {
1416
    int32_t total = taosLRUCacheGetElems(pCache);
1,185✔
1417
    tsdbDebug("%s put statis info into cache, total:%d suid:%" PRId64 ", vgId:%d, fid:%d", id, total, pKey->suid,
1,185✔
1418
              pKey->vgId, pKey->fid);
1419
  }
1420

1421
  (void)taosThreadMutexUnlock(&statisCacheInfo.lock);
1,185✔
1422
  return TSDB_CODE_SUCCESS;
1,185✔
1423
}
1424

UNCOV
1425
void clearStatisInfoCache(SLRUCache *pStatisCache, SSttStatisCacheKey *pKey, LRUHandle** pHandle) {
×
UNCOV
1426
  (void)taosThreadMutexLock(&statisCacheInfo.lock);
×
UNCOV
1427
  releaseCacheHandle(statisCacheInfo.pStatisFileCache, pHandle, false);
×
1428
  taosLRUCacheErase(pStatisCache, pKey, sizeof(SSttStatisCacheKey));
×
1429
  (void)taosThreadMutexUnlock(&statisCacheInfo.lock);
×
1430
}
×
1431

1432
static int32_t dupPlayload(SValue *p){
×
1433
  if (p != NULL){
×
UNCOV
1434
    int32_t code = tValueDupPayload(p);
×
1435
    if (code != TSDB_CODE_SUCCESS) {
×
1436
      return code;
×
1437
    }
1438
  }
1439
  return 0;
×
1440
}
1441

1442
int32_t sttRowInfoDeepCopy(SSttTableRowsInfo *pDst, SSttTableRowsInfo *pInfo, int32_t numOfPKs) {
257,840✔
1443
  int32_t code = 0;
257,840✔
1444

1445
  pDst->pCount = taosArrayDup(pInfo->pCount, NULL);
257,840✔
1446
  pDst->pFirstKey = taosArrayDup(pInfo->pFirstKey, NULL);
257,840✔
1447
  pDst->pLastKey = taosArrayDup(pInfo->pLastKey, NULL);
257,840✔
1448
  pDst->pFirstTs = taosArrayDup(pInfo->pFirstTs, NULL);
257,840✔
1449
  pDst->pLastTs = taosArrayDup(pInfo->pLastTs, NULL);
257,840✔
1450
  pDst->pUid = taosArrayDup(pInfo->pUid, NULL);
257,840✔
1451

1452
  pDst->memSize = pInfo->memSize;
257,840✔
1453
  
1454
  if (numOfPKs > 0) {
257,840✔
UNCOV
1455
    int32_t len = taosArrayGetSize(pDst->pCount);
×
UNCOV
1456
    for (int32_t i = 0; i < len; ++i) {
×
UNCOV
1457
      SValue *p1 = (SValue *)taosArrayGet(pDst->pFirstKey, i);
×
UNCOV
1458
      if (p1 == NULL) {
×
UNCOV
1459
        return terrno;
×
1460
      }
1461
      code = tValueDupPayload(p1);
×
1462
      if (code != TSDB_CODE_SUCCESS) {
×
1463
        return code;
×
1464
      }
UNCOV
1465
      SValue *p2 = (SValue *)taosArrayGet(pDst->pLastKey, i);
×
1466
      if (p2 == NULL) {
×
1467
        return terrno;
×
1468
      }
UNCOV
1469
      code = tValueDupPayload(p2);
×
1470
      if (code != TSDB_CODE_SUCCESS) {
×
1471
        return code;
×
1472
      }
1473
    }
1474
  }
1475

1476
  return TSDB_CODE_SUCCESS;
257,840✔
1477
}
1478

1479
int32_t getSttTableRowsInfo(SSttStatisCacheValue *pValue, int32_t numOfPKs, int32_t levelIdx, int32_t fileIdx,
257,840✔
1480
                            SSttTableRowsInfo *pRowInfo) {
1481
  if (levelIdx >= taosArrayGetSize(pValue->pLevel)) {
257,840✔
UNCOV
1482
    return TSDB_CODE_INVALID_PARA;
×
1483
  }
1484

1485
  SArray *pRowsInfoArr = *(SArray **)taosArrayGet(pValue->pLevel, levelIdx);
257,480✔
1486
  if (pRowsInfoArr == NULL) {
257,840✔
1487
    return TSDB_CODE_INVALID_PARA;
×
1488
  }
1489

1490
  if (fileIdx >= taosArrayGetSize(pRowsInfoArr)) {
257,840✔
UNCOV
1491
    return TSDB_CODE_INVALID_PARA;
×
1492
  }
1493

1494
  void* p = (SSttTableRowsInfo *)taosArrayGet(pRowsInfoArr, fileIdx);
257,480✔
1495
  if (p == NULL) {
257,840✔
1496
    return TSDB_CODE_INVALID_PARA;
×
1497
  }
1498

1499
  return sttRowInfoDeepCopy(pRowInfo, p, numOfPKs);
257,840✔
1500
}
1501

1502
int32_t getCacheValueSize(const SSttStatisCacheValue *pValue) {
1,185✔
1503
  int32_t size = sizeof(SSttStatisCacheValue) + sizeof(SArray);
1,185✔
1504
  for (int32_t i = 0; i < taosArrayGetSize(pValue->pLevel); ++i) {
2,370✔
1505
    SArray *pRowsInfoArr = *(SArray **)taosArrayGet(pValue->pLevel, i);
1,185✔
1506
    
1507
    size += sizeof(SArray);
1,185✔
1508
    for (int32_t j = 0; j < taosArrayGetSize(pRowsInfoArr); ++j) {
2,370✔
1509
      SSttTableRowsInfo *p = (SSttTableRowsInfo *)taosArrayGet(pRowsInfoArr, j);
1,185✔
1510
      size += p->memSize;
1,185✔
1511
    }
1512
  }
1513

1514
  return size;
1,185✔
1515
}
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