tsdbMergeTree.c 18.6 KB
Newer Older
H
Hongze Cheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "tsdb.h"

18
// SLDataIter =================================================
H
Hongze Cheng 已提交
19
struct SLDataIter {
H
Hongze Cheng 已提交
20 21 22 23 24 25 26 27 28 29 30 31
  SRBTreeNode        node;
  SSttBlk           *pSttBlk;
  SDataFReader      *pReader;
  int32_t            iStt;
  int8_t             backward;
  int32_t            iSttBlk;
  int32_t            iRow;
  SRowInfo           rInfo;
  uint64_t           uid;
  STimeWindow        timeWindow;
  SVersionRange      verRange;
  SSttBlockLoadInfo *pBlockLoadInfo;
H
Hongze Cheng 已提交
32
};
H
Hongze Cheng 已提交
33

H
Hongze Cheng 已提交
34 35
SSttBlockLoadInfo *tCreateLastBlockLoadInfo(STSchema *pSchema, int16_t *colList, int32_t numOfCols) {
  SSttBlockLoadInfo *pLoadInfo = taosMemoryCalloc(TSDB_DEFAULT_STT_FILE, sizeof(SSttBlockLoadInfo));
36
  if (pLoadInfo == NULL) {
H
Hongze Cheng 已提交
37
    terrno = TSDB_CODE_OUT_OF_MEMORY;
38 39 40
    return NULL;
  }

H
Hongze Cheng 已提交
41
  for (int32_t i = 0; i < TSDB_DEFAULT_STT_FILE; ++i) {
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
    pLoadInfo[i].blockIndex[0] = -1;
    pLoadInfo[i].blockIndex[1] = -1;
    pLoadInfo[i].currentLoadBlockIndex = 1;

    int32_t code = tBlockDataCreate(&pLoadInfo[i].blockData[0]);
    if (code) {
      terrno = code;
    }

    code = tBlockDataCreate(&pLoadInfo[i].blockData[1]);
    if (code) {
      terrno = code;
    }

    pLoadInfo[i].aSttBlk = taosArrayInit(4, sizeof(SSttBlk));
H
Haojun Liao 已提交
57 58 59
    pLoadInfo[i].pSchema = pSchema;
    pLoadInfo[i].colIds = colList;
    pLoadInfo[i].numOfCols = numOfCols;
60 61 62 63 64
  }

  return pLoadInfo;
}

H
Hongze Cheng 已提交
65 66
void resetLastBlockLoadInfo(SSttBlockLoadInfo *pLoadInfo) {
  for (int32_t i = 0; i < TSDB_DEFAULT_STT_FILE; ++i) {
67 68 69
    pLoadInfo[i].currentLoadBlockIndex = 1;
    pLoadInfo[i].blockIndex[0] = -1;
    pLoadInfo[i].blockIndex[1] = -1;
70

71
    taosArrayClear(pLoadInfo[i].aSttBlk);
H
Haojun Liao 已提交
72 73 74 75 76 77

    pLoadInfo[i].elapsedTime = 0;
    pLoadInfo[i].loadBlocks = 0;
  }
}

H
Hongze Cheng 已提交
78 79
void getLastBlockLoadInfo(SSttBlockLoadInfo *pLoadInfo, int64_t *blocks, double *el) {
  for (int32_t i = 0; i < TSDB_DEFAULT_STT_FILE; ++i) {
H
Haojun Liao 已提交
80 81
    *el += pLoadInfo[i].elapsedTime;
    *blocks += pLoadInfo[i].loadBlocks;
82 83 84
  }
}

H
Hongze Cheng 已提交
85 86
void *destroyLastBlockLoadInfo(SSttBlockLoadInfo *pLoadInfo) {
  for (int32_t i = 0; i < TSDB_DEFAULT_STT_FILE; ++i) {
87 88 89 90 91 92 93 94 95 96 97 98 99 100
    pLoadInfo[i].currentLoadBlockIndex = 1;
    pLoadInfo[i].blockIndex[0] = -1;
    pLoadInfo[i].blockIndex[1] = -1;

    tBlockDataDestroy(&pLoadInfo[i].blockData[0], true);
    tBlockDataDestroy(&pLoadInfo[i].blockData[1], true);

    taosArrayDestroy(pLoadInfo[i].aSttBlk);
  }

  taosMemoryFree(pLoadInfo);
  return NULL;
}

H
Hongze Cheng 已提交
101
static SBlockData *loadLastBlock(SLDataIter *pIter, const char *idStr) {
102 103
  int32_t code = 0;

H
Hongze Cheng 已提交
104 105
  SSttBlockLoadInfo *pInfo = pIter->pBlockLoadInfo;
  if (pInfo->blockIndex[0] == pIter->iSttBlk) {
106 107 108 109 110
    if (pInfo->currentLoadBlockIndex != 0) {
      tsdbDebug("current load index is set to 0, block index:%d, file index:%d, due to uid:%" PRIu64 ", load data, %s",
                pIter->iSttBlk, pIter->iStt, pIter->uid, idStr);
      pInfo->currentLoadBlockIndex = 0;
    }
111 112 113
    return &pInfo->blockData[0];
  }

114
  if (pInfo->blockIndex[1] == pIter->iSttBlk) {
115
    if (pInfo->currentLoadBlockIndex != 1) {
H
Hongze Cheng 已提交
116
      tsdbDebug("current load index is set to 1, block index:%d, file index:%d, due to uid:%" PRIu64 ", load data, %s",
117 118 119
                pIter->iSttBlk, pIter->iStt, pIter->uid, idStr);
      pInfo->currentLoadBlockIndex = 1;
    }
120 121 122
    return &pInfo->blockData[1];
  }

H
Haojun Liao 已提交
123 124 125 126 127
  if (pIter->pSttBlk == NULL) {
    return NULL;
  }

  // current block not loaded yet
128
  pInfo->currentLoadBlockIndex ^= 1;
H
Haojun Liao 已提交
129
  int64_t st = taosGetTimestampUs();
130

H
Haojun Liao 已提交
131
  SBlockData *pBlock = &pInfo->blockData[pInfo->currentLoadBlockIndex];
H
Haojun Liao 已提交
132

H
Haojun Liao 已提交
133 134 135 136 137 138
  TABLEID id = {0};
  if (pIter->pSttBlk->suid != 0) {
    id.suid = pIter->pSttBlk->suid;
  } else {
    id.uid = pIter->uid;
  }
H
Haojun Liao 已提交
139

H
Haojun Liao 已提交
140 141 142 143
  code = tBlockDataInit(pBlock, &id, pInfo->pSchema, pInfo->colIds, pInfo->numOfCols);
  if (code != TSDB_CODE_SUCCESS) {
    goto _exit;
  }
144

H
Haojun Liao 已提交
145 146 147 148
  code = tsdbReadSttBlock(pIter->pReader, pIter->iStt, pIter->pSttBlk, pBlock);
  if (code != TSDB_CODE_SUCCESS) {
    goto _exit;
  }
H
Haojun Liao 已提交
149

H
Haojun Liao 已提交
150 151 152
  double el = (taosGetTimestampUs() - st) / 1000.0;
  pInfo->elapsedTime += el;
  pInfo->loadBlocks += 1;
153

H
Haojun Liao 已提交
154
  tsdbDebug("read last block, total load:%d, trigger by uid:%" PRIu64
155 156
            ", last file index:%d, last block index:%d, entry:%d, rows:%d, %p, elapsed time:%.2f ms, %s",
            pInfo->loadBlocks, pIter->uid, pIter->iStt, pIter->iSttBlk, pInfo->currentLoadBlockIndex, pBlock->nRow, pBlock, el,
H
Haojun Liao 已提交
157
            idStr);
158

H
Haojun Liao 已提交
159 160
  pInfo->blockIndex[pInfo->currentLoadBlockIndex] = pIter->iSttBlk;
  tsdbDebug("last block index list:%d, %d, %s", pInfo->blockIndex[0], pInfo->blockIndex[1], idStr);
161

H
Haojun Liao 已提交
162
  pIter->iRow = (pIter->backward) ? pInfo->blockData[pInfo->currentLoadBlockIndex].nRow : -1;
163 164
  return &pInfo->blockData[pInfo->currentLoadBlockIndex];

H
Hongze Cheng 已提交
165
_exit:
166 167 168 169 170
  if (code != TSDB_CODE_SUCCESS) {
    terrno = code;
  }

  return NULL;
171 172
}

173
// find the earliest block that contains the required records
H
Hongze Cheng 已提交
174 175
static FORCE_INLINE int32_t findEarliestIndex(int32_t index, uint64_t uid, const SSttBlk *pBlockList, int32_t num,
                                              int32_t backward) {
176
  int32_t i = index;
H
Hongze Cheng 已提交
177
  int32_t step = backward ? 1 : -1;
H
Haojun Liao 已提交
178
  while (i >= 0 && i < num && uid >= pBlockList[i].minUid && uid <= pBlockList[i].maxUid) {
179 180 181 182 183
    i += step;
  }
  return i - step;
}

H
Hongze Cheng 已提交
184
static int32_t binarySearchForStartBlock(SSttBlk *pBlockList, int32_t num, uint64_t uid, int32_t backward) {
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
  int32_t midPos = -1;
  if (num <= 0) {
    return -1;
  }

  int32_t firstPos = 0;
  int32_t lastPos = num - 1;

  // find the first position which is bigger than the key
  if ((uid > pBlockList[lastPos].maxUid) || (uid < pBlockList[firstPos].minUid)) {
    return -1;
  }

  while (1) {
    if (uid >= pBlockList[firstPos].minUid && uid <= pBlockList[firstPos].maxUid) {
200
      return findEarliestIndex(firstPos, uid, pBlockList, num, backward);
201 202 203 204 205 206 207 208 209 210 211 212 213 214
    }

    if (uid > pBlockList[lastPos].maxUid || uid < pBlockList[firstPos].minUid) {
      return -1;
    }

    int32_t numOfRows = lastPos - firstPos + 1;
    midPos = (numOfRows >> 1u) + firstPos;

    if (uid < pBlockList[midPos].minUid) {
      lastPos = midPos - 1;
    } else if (uid > pBlockList[midPos].maxUid) {
      firstPos = midPos + 1;
    } else {
215
      return findEarliestIndex(midPos, uid, pBlockList, num, backward);
216 217 218 219
    }
  }
}

H
Hongze Cheng 已提交
220 221
static FORCE_INLINE int32_t findEarliestRow(int32_t index, uint64_t uid, const uint64_t *uidList, int32_t num,
                                            int32_t backward) {
222
  int32_t i = index;
H
Hongze Cheng 已提交
223
  int32_t step = backward ? 1 : -1;
H
Haojun Liao 已提交
224
  while (i >= 0 && i < num && uid == uidList[i]) {
225 226 227 228 229
    i += step;
  }
  return i - step;
}

H
Hongze Cheng 已提交
230
static int32_t binarySearchForStartRowIndex(uint64_t *uidList, int32_t num, uint64_t uid, int32_t backward) {
231 232 233 234 235 236 237 238 239 240
  int32_t firstPos = 0;
  int32_t lastPos = num - 1;

  // find the first position which is bigger than the key
  if ((uid > uidList[lastPos]) || (uid < uidList[firstPos])) {
    return -1;
  }

  while (1) {
    if (uid == uidList[firstPos]) {
241
      return findEarliestRow(firstPos, uid, uidList, num, backward);
242 243 244 245 246 247 248 249 250 251 252 253 254 255
    }

    if (uid > uidList[lastPos] || uid < uidList[firstPos]) {
      return -1;
    }

    int32_t numOfRows = lastPos - firstPos + 1;
    int32_t midPos = (numOfRows >> 1u) + firstPos;

    if (uid < uidList[midPos]) {
      lastPos = midPos - 1;
    } else if (uid > uidList[midPos]) {
      firstPos = midPos + 1;
    } else {
256
      return findEarliestRow(midPos, uid, uidList, num, backward);
257 258 259 260
    }
  }
}

H
Haojun Liao 已提交
261
int32_t tLDataIterOpen(struct SLDataIter **pIter, SDataFReader *pReader, int32_t iStt, int8_t backward, uint64_t suid,
H
Hongze Cheng 已提交
262 263
                       uint64_t uid, STimeWindow *pTimeWindow, SVersionRange *pRange, SSttBlockLoadInfo *pBlockLoadInfo,
                       const char *idStr) {
H
Haojun Liao 已提交
264 265
  int32_t code = TSDB_CODE_SUCCESS;

266
  *pIter = taosMemoryCalloc(1, sizeof(SLDataIter));
267 268 269 270
  if (*pIter == NULL) {
    code = TSDB_CODE_OUT_OF_MEMORY;
    goto _exit;
  }
H
Hongze Cheng 已提交
271

272
  (*pIter)->uid = uid;
273
  (*pIter)->pReader = pReader;
H
Hongze Cheng 已提交
274
  (*pIter)->iStt = iStt;
275
  (*pIter)->backward = backward;
H
Haojun Liao 已提交
276 277
  (*pIter)->verRange = *pRange;
  (*pIter)->timeWindow = *pTimeWindow;
H
Hongze Cheng 已提交
278

279
  (*pIter)->pBlockLoadInfo = pBlockLoadInfo;
280 281 282

  size_t size = taosArrayGetSize(pBlockLoadInfo->aSttBlk);
  if (size == 0) {
283 284
    int64_t st = taosGetTimestampUs();

285 286 287
    code = tsdbReadSttBlk(pReader, iStt, pBlockLoadInfo->aSttBlk);
    if (code) {
      goto _exit;
288 289 290
    }

    // only apply to the child tables, ordinary tables will not incur this filter procedure.
291
    size = taosArrayGetSize(pBlockLoadInfo->aSttBlk);
292

H
Haojun Liao 已提交
293 294 295 296 297 298 299 300 301 302 303
    if (size > 1) {
      SSttBlk *pStart = taosArrayGet(pBlockLoadInfo->aSttBlk, 0);
      SSttBlk *pEnd = taosArrayGet(pBlockLoadInfo->aSttBlk, size - 1);

      // all identical
      if (pStart->suid == pEnd->suid) {
        if (pStart->suid == suid) {
          // do nothing
        } else if (pStart->suid != suid) {
          // no qualified stt block existed
          (*pIter)->iSttBlk = -1;
H
Hongze Cheng 已提交
304
          double el = (taosGetTimestampUs() - st) / 1000.0;
H
Haojun Liao 已提交
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
          tsdbDebug("load the last file info completed, elapsed time:%.2fms, %s", el, idStr);
          return code;
        }
      } else {
        SArray *pTmp = taosArrayInit(size, sizeof(SSttBlk));
        for (int32_t i = 0; i < size; ++i) {
          SSttBlk *p = taosArrayGet(pBlockLoadInfo->aSttBlk, i);
          uint64_t s = p->suid;
          if (s < suid) {
            continue;
          }

          if (s == suid) {
            taosArrayPush(pTmp, p);
          } else if (s > suid) {
            break;
          }
        }

        taosArrayDestroy(pBlockLoadInfo->aSttBlk);
        pBlockLoadInfo->aSttBlk = pTmp;
326
      }
327
    }
328

H
Hongze Cheng 已提交
329
    double el = (taosGetTimestampUs() - st) / 1000.0;
330
    tsdbDebug("load the last file info completed, elapsed time:%.2fms, %s", el, idStr);
331
  }
H
Hongze Cheng 已提交
332

333
  size = taosArrayGetSize(pBlockLoadInfo->aSttBlk);
334 335

  // find the start block
H
Haojun Liao 已提交
336 337
  (*pIter)->iSttBlk = binarySearchForStartBlock(pBlockLoadInfo->aSttBlk->pData, size, uid, backward);
  if ((*pIter)->iSttBlk != -1) {
338
    (*pIter)->pSttBlk = taosArrayGet(pBlockLoadInfo->aSttBlk, (*pIter)->iSttBlk);
H
Haojun Liao 已提交
339
    (*pIter)->iRow = ((*pIter)->backward) ? (*pIter)->pSttBlk->nRow : -1;
H
Hongze Cheng 已提交
340 341
  }

H
Haojun Liao 已提交
342 343
  return code;

H
Hongze Cheng 已提交
344
_exit:
H
Haojun Liao 已提交
345
  taosMemoryFree(*pIter);
H
Hongze Cheng 已提交
346 347 348
  return code;
}

H
Hongze Cheng 已提交
349
void tLDataIterClose(SLDataIter *pIter) { taosMemoryFree(pIter); }
H
Hongze Cheng 已提交
350

H
Hongze Cheng 已提交
351
void tLDataIterNextBlock(SLDataIter *pIter, const char *idStr) {
H
Hongze Cheng 已提交
352
  int32_t step = pIter->backward ? -1 : 1;
353 354
  int32_t oldIndex = pIter->iSttBlk;

H
Hongze Cheng 已提交
355
  pIter->iSttBlk += step;
H
Hongze Cheng 已提交
356

357
  int32_t index = -1;
H
Haojun Liao 已提交
358
  size_t  size = pIter->pBlockLoadInfo->aSttBlk->size;
H
Hongze Cheng 已提交
359
  for (int32_t i = pIter->iSttBlk; i < size && i >= 0; i += step) {
360
    SSttBlk *p = taosArrayGet(pIter->pBlockLoadInfo->aSttBlk, i);
361 362 363 364 365
    if ((!pIter->backward) && p->minUid > pIter->uid) {
      break;
    }

    if (pIter->backward && p->maxUid < pIter->uid) {
366 367 368
      break;
    }

369
    // check uid firstly
370
    if (p->minUid <= pIter->uid && p->maxUid >= pIter->uid) {
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
      if ((!pIter->backward) && p->minKey > pIter->timeWindow.ekey) {
        break;
      }

      if (pIter->backward && p->maxKey < pIter->timeWindow.skey) {
        break;
      }

      // check time range secondly
      if (p->minKey <= pIter->timeWindow.ekey && p->maxKey >= pIter->timeWindow.skey) {
        if ((!pIter->backward) && p->minVer > pIter->verRange.maxVer) {
          break;
        }

        if (pIter->backward && p->maxVer < pIter->verRange.minVer) {
          break;
        }

        if (p->minVer <= pIter->verRange.maxVer && p->maxVer >= pIter->verRange.minVer) {
          index = i;
          break;
        }
      }
394 395 396
    }
  }

397 398
  pIter->pSttBlk = NULL;
  if (index != -1) {
H
Haojun Liao 已提交
399
    pIter->iSttBlk = index;
400
    pIter->pSttBlk = (SSttBlk *)taosArrayGet(pIter->pBlockLoadInfo->aSttBlk, pIter->iSttBlk);
H
Hongze Cheng 已提交
401 402
    tsdbDebug("try next last file block:%d from %d, trigger by uid:%" PRIu64 ", file index:%d, %s", pIter->iSttBlk,
              oldIndex, pIter->uid, pIter->iStt, idStr);
403
  } else {
H
Hongze Cheng 已提交
404
    tsdbDebug("no more last block qualified, uid:%" PRIu64 ", file index::%d, %s", pIter->uid, oldIndex, idStr);
405 406 407
  }
}

H
Hongze Cheng 已提交
408
static void findNextValidRow(SLDataIter *pIter, const char *idStr) {
H
Hongze Cheng 已提交
409
  int32_t step = pIter->backward ? -1 : 1;
410

H
Hongze Cheng 已提交
411 412
  bool    hasVal = false;
  int32_t i = pIter->iRow;
413

H
Haojun Liao 已提交
414
  SBlockData *pBlockData = loadLastBlock(pIter, idStr);
415

416
  // mostly we only need to find the start position for a given table
H
Hongze Cheng 已提交
417 418 419
  if ((((i == 0) && (!pIter->backward)) || (i == pBlockData->nRow - 1 && pIter->backward)) &&
      pBlockData->aUid != NULL) {
    i = binarySearchForStartRowIndex((uint64_t *)pBlockData->aUid, pBlockData->nRow, pIter->uid, pIter->backward);
H
Haojun Liao 已提交
420 421 422 423
    if (i == -1) {
      pIter->iRow = -1;
      return;
    }
424 425
  }

426 427
  for (; i < pBlockData->nRow && i >= 0; i += step) {
    if (pBlockData->aUid != NULL) {
428
      if (!pIter->backward) {
429
        if (pBlockData->aUid[i] > pIter->uid) {
430 431 432
          break;
        }
      } else {
433
        if (pBlockData->aUid[i] < pIter->uid) {
434 435 436 437 438
          break;
        }
      }
    }

439
    int64_t ts = pBlockData->aTSKEY[i];
H
Hongze Cheng 已提交
440
    if (!pIter->backward) {               // asc
441 442 443 444 445 446 447 448 449 450 451
      if (ts > pIter->timeWindow.ekey) {  // no more data
        break;
      } else if (ts < pIter->timeWindow.skey) {
        continue;
      }
    } else {
      if (ts < pIter->timeWindow.skey) {
        break;
      } else if (ts > pIter->timeWindow.ekey) {
        continue;
      }
452 453
    }

454
    int64_t ver = pBlockData->aVersion[i];
455 456 457 458 459 460 461 462 463 464 465
    if (ver < pIter->verRange.minVer) {
      continue;
    }

    // todo opt handle desc case
    if (ver > pIter->verRange.maxVer) {
      continue;
    }

    hasVal = true;
    break;
H
Hongze Cheng 已提交
466
  }
467

H
Hongze Cheng 已提交
468
  pIter->iRow = (hasVal) ? i : -1;
H
Hongze Cheng 已提交
469 470
}

H
Hongze Cheng 已提交
471
bool tLDataIterNextRow(SLDataIter *pIter, const char *idStr) {
H
Hongze Cheng 已提交
472
  int32_t step = pIter->backward ? -1 : 1;
H
Haojun Liao 已提交
473
  terrno = TSDB_CODE_SUCCESS;
474 475

  // no qualified last file block in current file, no need to fetch row
H
Hongze Cheng 已提交
476
  if (pIter->pSttBlk == NULL) {
477 478
    return false;
  }
H
Hongze Cheng 已提交
479

H
Hongze Cheng 已提交
480
  int32_t     iBlockL = pIter->iSttBlk;
H
Haojun Liao 已提交
481
  SBlockData *pBlockData = loadLastBlock(pIter, idStr);
H
Haojun Liao 已提交
482
  if (pBlockData == NULL || terrno != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
483 484 485
    goto _exit;
  }

486 487
  pIter->iRow += step;

H
Hongze Cheng 已提交
488
  while (1) {
H
Haojun Liao 已提交
489
    findNextValidRow(pIter, idStr);
490

491
    if (pIter->iRow >= pBlockData->nRow || pIter->iRow < 0) {
492
      tLDataIterNextBlock(pIter, idStr);
H
Hongze Cheng 已提交
493
      if (pIter->pSttBlk == NULL) {  // no more data
494 495 496 497
        goto _exit;
      }
    } else {
      break;
H
Hongze Cheng 已提交
498 499
    }

H
Hongze Cheng 已提交
500
    if (iBlockL != pIter->iSttBlk) {
H
Haojun Liao 已提交
501
      pBlockData = loadLastBlock(pIter, idStr);
H
Haojun Liao 已提交
502
      pIter->iRow += step;
H
Hongze Cheng 已提交
503 504 505
    }
  }

506 507 508
  pIter->rInfo.suid = pBlockData->suid;
  pIter->rInfo.uid = pBlockData->uid;
  pIter->rInfo.row = tsdbRowFromBlockData(pBlockData, pIter->iRow);
H
Hongze Cheng 已提交
509 510

_exit:
H
Haojun Liao 已提交
511
  return (terrno == TSDB_CODE_SUCCESS) && (pIter->pSttBlk != NULL);
H
Hongze Cheng 已提交
512 513
}

H
Hongze Cheng 已提交
514
SRowInfo *tLDataIterGet(SLDataIter *pIter) { return &pIter->rInfo; }
H
Hongze Cheng 已提交
515 516

// SMergeTree =================================================
H
Hongze Cheng 已提交
517 518 519
static FORCE_INLINE int32_t tLDataIterCmprFn(const SRBTreeNode *p1, const SRBTreeNode *p2) {
  SLDataIter *pIter1 = (SLDataIter *)(((uint8_t *)p1) - offsetof(SLDataIter, node));
  SLDataIter *pIter2 = (SLDataIter *)(((uint8_t *)p2) - offsetof(SLDataIter, node));
H
Hongze Cheng 已提交
520

521 522
  TSDBKEY key1 = TSDBROW_KEY(&pIter1->rInfo.row);
  TSDBKEY key2 = TSDBROW_KEY(&pIter2->rInfo.row);
H
Hongze Cheng 已提交
523

524 525 526 527 528 529 530 531 532 533 534 535 536
  if (key1.ts < key2.ts) {
    return -1;
  } else if (key1.ts > key2.ts) {
    return 1;
  } else {
    if (key1.version < key2.version) {
      return -1;
    } else if (key1.version > key2.version) {
      return 1;
    } else {
      return 0;
    }
  }
H
Hongze Cheng 已提交
537 538
}

539 540 541 542
static FORCE_INLINE int32_t tLDataIterDescCmprFn(const SRBTreeNode *p1, const SRBTreeNode *p2) {
  return -1 * tLDataIterCmprFn(p1, p2);
}

543
int32_t tMergeTreeOpen(SMergeTree *pMTree, int8_t backward, SDataFReader *pFReader, uint64_t suid, uint64_t uid,
544 545
                       STimeWindow *pTimeWindow, SVersionRange *pVerRange, SSttBlockLoadInfo *pBlockLoadInfo,
                       bool destroyLoadInfo, const char *idStr) {
H
Hongze Cheng 已提交
546
  pMTree->backward = backward;
547
  pMTree->pIter = NULL;
548
  pMTree->pIterList = taosArrayInit(4, POINTER_BYTES);
549 550 551
  if (pMTree->pIterList == NULL) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
552

H
Haojun Liao 已提交
553
  pMTree->idStr = idStr;
554 555 556 557 558
  if (!pMTree->backward) { // asc
    tRBTreeCreate(&pMTree->rbt, tLDataIterCmprFn);
  } else { // desc
    tRBTreeCreate(&pMTree->rbt, tLDataIterDescCmprFn);
  }
559 560
  int32_t code = TSDB_CODE_SUCCESS;

561 562
  pMTree->pLoadInfo = pBlockLoadInfo;
  pMTree->destroyLoadInfo = destroyLoadInfo;
563
  ASSERT(pMTree->pLoadInfo != NULL);
564

H
Hongze Cheng 已提交
565
  for (int32_t i = 0; i < pFReader->pSet->nSttF; ++i) {  // open all last file
H
Hongze Cheng 已提交
566 567 568
    struct SLDataIter *pIter = NULL;
    code = tLDataIterOpen(&pIter, pFReader, i, pMTree->backward, suid, uid, pTimeWindow, pVerRange,
                          &pMTree->pLoadInfo[i], pMTree->idStr);
569 570 571 572
    if (code != TSDB_CODE_SUCCESS) {
      goto _end;
    }

H
Haojun Liao 已提交
573
    bool hasVal = tLDataIterNextRow(pIter, pMTree->idStr);
574
    if (hasVal) {
575 576
      taosArrayPush(pMTree->pIterList, &pIter);
      tMergeTreeAddIter(pMTree, pIter);
577
    } else {
578
      tLDataIterClose(pIter);
579 580
    }
  }
581 582 583

  return code;

H
Hongze Cheng 已提交
584
_end:
585 586
  tMergeTreeClose(pMTree);
  return code;
H
Hongze Cheng 已提交
587
}
H
Hongze Cheng 已提交
588

589 590
void tMergeTreeAddIter(SMergeTree *pMTree, SLDataIter *pIter) { tRBTreePut(&pMTree->rbt, (SRBTreeNode *)pIter); }

H
Hongze Cheng 已提交
591
bool tMergeTreeNext(SMergeTree *pMTree) {
592 593 594 595
  int32_t code = TSDB_CODE_SUCCESS;
  if (pMTree->pIter) {
    SLDataIter *pIter = pMTree->pIter;

H
Haojun Liao 已提交
596
    bool hasVal = tLDataIterNextRow(pIter, pMTree->idStr);
597 598 599 600 601 602 603
    if (!hasVal) {
      pMTree->pIter = NULL;
    }

    // compare with min in RB Tree
    pIter = (SLDataIter *)tRBTreeMin(&pMTree->rbt);
    if (pMTree->pIter && pIter) {
H
Hongze Cheng 已提交
604
      int32_t c = pMTree->rbt.cmprFn(&pMTree->pIter->node, &pIter->node);
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
      if (c > 0) {
        tRBTreePut(&pMTree->rbt, (SRBTreeNode *)pMTree->pIter);
        pMTree->pIter = NULL;
      } else {
        ASSERT(c);
      }
    }
  }

  if (pMTree->pIter == NULL) {
    pMTree->pIter = (SLDataIter *)tRBTreeMin(&pMTree->rbt);
    if (pMTree->pIter) {
      tRBTreeDrop(&pMTree->rbt, (SRBTreeNode *)pMTree->pIter);
    }
  }

  return pMTree->pIter != NULL;
}

H
Hongze Cheng 已提交
624
TSDBROW tMergeTreeGetRow(SMergeTree *pMTree) { return pMTree->pIter->rInfo.row; }
625

H
Hongze Cheng 已提交
626
void tMergeTreeClose(SMergeTree *pMTree) {
627
  size_t size = taosArrayGetSize(pMTree->pIterList);
H
Hongze Cheng 已提交
628 629
  for (int32_t i = 0; i < size; ++i) {
    SLDataIter *pIter = taosArrayGetP(pMTree->pIterList, i);
630 631
    tLDataIterClose(pIter);
  }
632

633 634
  pMTree->pIterList = taosArrayDestroy(pMTree->pIterList);
  pMTree->pIter = NULL;
635 636 637 638 639

  if (pMTree->destroyLoadInfo) {
    pMTree->pLoadInfo = destroyLastBlockLoadInfo(pMTree->pLoadInfo);
    pMTree->destroyLoadInfo = false;
  }
640
}