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

taosdata / TDengine / #4987

16 Mar 2026 12:26PM UTC coverage: 73.883% (+36.6%) from 37.305%
#4987

push

travis-ci

web-flow
feat: support secure delete option. (#34591)

209 of 391 new or added lines in 24 files covered. (53.45%)

3062 existing lines in 140 files now uncovered.

261133 of 353439 relevant lines covered (73.88%)

121262425.02 hits per line

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

1.83
/source/dnode/vnode/src/tsdb/tsdbFS.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 "tsdb.h"
17
#include "vnd.h"
18

19
// =================================================================================================
20
static int32_t tsdbFSToBinary(uint8_t *p, STsdbFS *pFS) {
×
21
  int32_t  n = 0;
×
22
  int8_t   hasDel = pFS->pDelFile ? 1 : 0;
×
23
  uint32_t nSet = taosArrayGetSize(pFS->aDFileSet);
×
24

25
  // version
26
  n += tPutI8(p ? p + n : p, 0);
×
27

28
  // SDelFile
29
  n += tPutI8(p ? p + n : p, hasDel);
×
30
  if (hasDel) {
×
31
    n += tPutDelFile(p ? p + n : p, pFS->pDelFile);
×
32
  }
33

34
  // SArray<SDFileSet>
35
  n += tPutU32v(p ? p + n : p, nSet);
×
36
  for (uint32_t iSet = 0; iSet < nSet; iSet++) {
×
37
    n += tPutDFileSet(p ? p + n : p, (SDFileSet *)taosArrayGet(pFS->aDFileSet, iSet));
×
38
  }
39

40
  return n;
×
41
}
42

43
static int32_t tsdbBinaryToFS(uint8_t *pData, int64_t nData, STsdbFS *pFS) {
×
44
  int32_t code = 0;
×
45
  int32_t n = 0;
×
46

47
  // version
48
  n += tGetI8(pData + n, NULL);
×
49

50
  // SDelFile
51
  int8_t hasDel = 0;
×
52
  n += tGetI8(pData + n, &hasDel);
×
53
  if (hasDel) {
×
54
    pFS->pDelFile = (SDelFile *)taosMemoryCalloc(1, sizeof(SDelFile));
×
55
    if (pFS->pDelFile == NULL) {
×
56
      code = terrno;
×
57
      goto _exit;
×
58
    }
59

60
    n += tGetDelFile(pData + n, pFS->pDelFile);
×
61
    pFS->pDelFile->nRef = 1;
×
62
  } else {
63
    pFS->pDelFile = NULL;
×
64
  }
65

66
  // aDFileSet
67
  taosArrayClear(pFS->aDFileSet);
×
68
  uint32_t nSet = 0;
×
69
  n += tGetU32v(pData + n, &nSet);
×
70
  for (uint32_t iSet = 0; iSet < nSet; iSet++) {
×
71
    SDFileSet fSet = {0};
×
72

73
    int32_t nt = tGetDFileSet(pData + n, &fSet);
×
74
    if (nt < 0) {
×
75
      code = terrno;
×
76
      goto _exit;
×
77
    }
78

79
    n += nt;
×
80
    if (taosArrayPush(pFS->aDFileSet, &fSet) == NULL) {
×
81
      code = terrno;
×
82
      goto _exit;
×
83
    }
84
  }
85

86
  if (n + sizeof(TSCKSUM) != nData) {
×
87
    code = TSDB_CODE_FILE_CORRUPTED;
×
88
    goto _exit;
×
89
  }
90

91
_exit:
×
92
  return code;
×
93
}
94

95
static int32_t tsdbSaveFSToFile(STsdbFS *pFS, const char *fname) {
×
96
  int32_t   code = 0;
×
97
  int32_t   lino = 0;
×
98
  TdFilePtr pFD = NULL;
×
99
  uint8_t  *pData = NULL;
×
100

101
  // encode to binary
102
  int32_t size = tsdbFSToBinary(NULL, pFS) + sizeof(TSCKSUM);
×
103
  pData = taosMemoryMalloc(size);
×
104
  if (pData == NULL) {
×
105
    code = terrno;
×
106
    TSDB_CHECK_CODE(code, lino, _exit);
×
107
  }
108
  int32_t tsize = tsdbFSToBinary(pData, pFS);
×
109

110
  code = taosCalcChecksumAppend(0, pData, size);
×
111
  TSDB_CHECK_CODE(code, lino, _exit);
×
112

113
  // save to file
114
  pFD = taosOpenFile(fname, TD_FILE_WRITE | TD_FILE_CREATE | TD_FILE_TRUNC | TD_FILE_WRITE_THROUGH);
×
115
  if (pFD == NULL) {
×
116
    TSDB_CHECK_CODE(code = terrno, lino, _exit);
×
117
  }
118

119
  int64_t n = taosWriteFile(pFD, pData, size);
×
120
  if (n < 0) {
×
121
    TSDB_CHECK_CODE(code = terrno, lino, _exit);
×
122
  }
123

124
  if (taosFsyncFile(pFD) < 0) {
×
125
    TSDB_CHECK_CODE(code = TAOS_SYSTEM_ERROR(ERRNO), lino, _exit);
×
126
  }
127

128
_exit:
×
129
  if (code) {
×
130
    tsdbError("%s failed at line %d since %s, fname:%s", __func__, lino, tstrerror(code), fname);
×
131
  }
132
  taosMemoryFree(pData);
×
133
  taosCloseFileWithLog(&pFD);
×
134
  return code;
×
135
}
136

137
int32_t tsdbFSCreate(STsdbFS *pFS) {
×
138
  int32_t code = 0;
×
139

140
  pFS->pDelFile = NULL;
×
141
  pFS->aDFileSet = taosArrayInit(0, sizeof(SDFileSet));
×
142
  if (pFS->aDFileSet == NULL) {
×
143
    code = terrno;
×
144
    goto _exit;
×
145
  }
146

147
_exit:
×
148
  return code;
×
149
}
150

151
void tsdbFSDestroy(STsdbFS *pFS) {
×
152
  if (pFS->pDelFile) {
×
153
    taosMemoryFree(pFS->pDelFile);
×
154
    pFS->pDelFile = NULL;
×
155
  }
156

157
  for (int32_t iSet = 0; iSet < taosArrayGetSize(pFS->aDFileSet); iSet++) {
×
158
    SDFileSet *pSet = (SDFileSet *)taosArrayGet(pFS->aDFileSet, iSet);
×
159
    taosMemoryFree(pSet->pHeadF);
×
160
    taosMemoryFree(pSet->pDataF);
×
161
    taosMemoryFree(pSet->pSmaF);
×
162
    for (int32_t iStt = 0; iStt < pSet->nSttF; iStt++) {
×
163
      taosMemoryFree(pSet->aSttF[iStt]);
×
164
    }
165
  }
166

167
  taosArrayDestroy(pFS->aDFileSet);
×
168
  pFS->aDFileSet = NULL;
×
169
}
×
170

171
static int32_t tsdbScanAndTryFixFS(STsdb *pTsdb) {
×
172
  int32_t code = 0;
×
173
  int32_t lino = 0;
×
174
  int64_t size = 0;
×
175
  char    fname[TSDB_FILENAME_LEN] = {0};
×
176

177
  // SDelFile
178
  if (pTsdb->fs.pDelFile) {
×
179
    tsdbDelFileName(pTsdb, pTsdb->fs.pDelFile, fname);
×
180
    if (taosStatFile(fname, &size, NULL, NULL)) {
×
181
      code = terrno;
×
182
      TSDB_CHECK_CODE(code, lino, _exit);
×
183
    }
184
  }
185

186
  // SArray<SDFileSet>
187
  int32_t fid = 0;
×
188
  for (int32_t iSet = 0; iSet < taosArrayGetSize(pTsdb->fs.aDFileSet); iSet++) {
×
189
    SDFileSet *pSet = (SDFileSet *)taosArrayGet(pTsdb->fs.aDFileSet, iSet);
×
190
    fid = pSet->fid;
×
191

192
    // head =========
193
    tsdbHeadFileName(pTsdb, pSet->diskId, pSet->fid, pSet->pHeadF, fname);
×
194
    if (taosStatFile(fname, &size, NULL, NULL)) {
×
195
      code = terrno;
×
196
      TSDB_CHECK_CODE(code, lino, _exit);
×
197
    }
198
    // if (size != tsdbLogicToFileSize(pSet->pHeadF->size, pTsdb->pVnode->config.tsdbPageSize)) {
199
    //   code = TSDB_CODE_FILE_CORRUPTED;
200
    //   TSDB_CHECK_CODE(code, lino, _exit);
201
    // }
202

203
    // data =========
204
    tsdbDataFileName(pTsdb, pSet->diskId, pSet->fid, pSet->pDataF, fname);
×
205
    if (taosStatFile(fname, &size, NULL, NULL)) {
×
206
      code = terrno;
×
207
      TSDB_CHECK_CODE(code, lino, _exit);
×
208
    }
209
    // if (size < tsdbLogicToFileSize(pSet->pDataF->size, pTsdb->pVnode->config.tsdbPageSize)) {
210
    //   code = TSDB_CODE_FILE_CORRUPTED;
211
    //   TSDB_CHECK_CODE(code, lino, _exit);
212
    // }
213
    // else if (size > tsdbLogicToFileSize(pSet->pDataF->size, pTsdb->pVnode->config.tsdbPageSize)) {
214
    //   code = tsdbDFileRollback(pTsdb, pSet, TSDB_DATA_FILE);
215
    //   TSDB_CHECK_CODE(code, lino, _exit);
216
    // }
217

218
    // sma =============
219
    tsdbSmaFileName(pTsdb, pSet->diskId, pSet->fid, pSet->pSmaF, fname);
×
220
    if (taosStatFile(fname, &size, NULL, NULL)) {
×
221
      code = terrno;
×
222
      TSDB_CHECK_CODE(code, lino, _exit);
×
223
    }
224
    // if (size < tsdbLogicToFileSize(pSet->pSmaF->size, pTsdb->pVnode->config.tsdbPageSize)) {
225
    //   code = TSDB_CODE_FILE_CORRUPTED;
226
    //   TSDB_CHECK_CODE(code, lino, _exit);
227
    // }
228
    // else if (size > tsdbLogicToFileSize(pSet->pSmaF->size, pTsdb->pVnode->config.tsdbPageSize)) {
229
    //   code = tsdbDFileRollback(pTsdb, pSet, TSDB_SMA_FILE);
230
    //   TSDB_CHECK_CODE(code, lino, _exit);
231
    // }
232

233
    // stt ===========
234
    for (int32_t iStt = 0; iStt < pSet->nSttF; iStt++) {
×
235
      tsdbSttFileName(pTsdb, pSet->diskId, pSet->fid, pSet->aSttF[iStt], fname);
×
236
      if (taosStatFile(fname, &size, NULL, NULL)) {
×
237
        code = terrno;
×
238
        TSDB_CHECK_CODE(code, lino, _exit);
×
239
      }
240
      // if (size != tsdbLogicToFileSize(pSet->aSttF[iStt]->size, pTsdb->pVnode->config.tsdbPageSize)) {
241
      //   code = TSDB_CODE_FILE_CORRUPTED;
242
      //   TSDB_CHECK_CODE(code, lino, _exit);
243
      // }
244
    }
245
  }
246

247
  {
248
    // remove those invalid files (todo)
249
  }
250

251
_exit:
×
252
  if (code) {
×
253
    tsdbError("vgId:%d, %s failed at line %d since %s, fid:%d", TD_VID(pTsdb->pVnode), __func__, lino, tstrerror(code),
×
254
              fid);
255
  }
256
  return code;
×
257
}
258

259
int32_t tDFileSetCmprFn(const void *p1, const void *p2) {
×
260
  if (((SDFileSet *)p1)->fid < ((SDFileSet *)p2)->fid) {
×
261
    return -1;
×
262
  } else if (((SDFileSet *)p1)->fid > ((SDFileSet *)p2)->fid) {
×
263
    return 1;
×
264
  }
265

266
  return 0;
×
267
}
268

269
void tsdbGetCurrentFName(STsdb *pTsdb, char *current, char *current_t) {
4,198,540✔
270
  SVnode *pVnode = pTsdb->pVnode;
4,198,540✔
271
  int32_t offset = 0;
4,208,679✔
272

273
  // CURRENT
274
  if (current) {
4,208,679✔
275
    vnodeGetPrimaryPath(pVnode, false, current, TSDB_FILENAME_LEN);
4,208,775✔
276
    offset = strlen(current);
4,207,891✔
277
    snprintf(current + offset, TSDB_FILENAME_LEN - offset - 1, "%s%s%sCURRENT", TD_DIRSEP, pTsdb->name, TD_DIRSEP);
4,207,891✔
278
  }
279

280
  // CURRENT.t
281
  if (current_t) {
4,208,303✔
282
    vnodeGetPrimaryPath(pVnode, false, current_t, TSDB_FILENAME_LEN);
×
283
    offset = strlen(current_t);
×
284
    snprintf(current_t + offset, TSDB_FILENAME_LEN - offset - 1, "%s%s%sCURRENT.t", TD_DIRSEP, pTsdb->name, TD_DIRSEP);
×
285
  }
286
}
4,208,303✔
287

288
static int32_t load_fs(const char *fname, STsdbFS *pFS) {
×
289
  int32_t  code = 0;
×
290
  int32_t  lino = 0;
×
291
  uint8_t *pData = NULL;
×
292

293
  // load binary
294
  TdFilePtr pFD = taosOpenFile(fname, TD_FILE_READ);
×
295
  if (pFD == NULL) {
×
296
    code = terrno;
×
297
    TSDB_CHECK_CODE(code, lino, _exit);
×
298
  }
299

UNCOV
300
  int64_t size;
×
301
  code = taosFStatFile(pFD, &size, NULL);
×
302
  if (code != 0) {
×
303
    taosCloseFileWithLog(&pFD);
×
304
    TSDB_CHECK_CODE(code, lino, _exit);
×
305
  }
306

307
  pData = taosMemoryMalloc(size);
×
308
  if (pData == NULL) {
×
309
    code = terrno;
×
310
    taosCloseFileWithLog(&pFD);
×
311
    TSDB_CHECK_CODE(code, lino, _exit);
×
312
  }
313

314
  if (taosReadFile(pFD, pData, size) < 0) {
×
315
    code = terrno;
×
316
    taosCloseFileWithLog(&pFD);
×
317
    TSDB_CHECK_CODE(code, lino, _exit);
×
318
  }
319

320
  if (!taosCheckChecksumWhole(pData, size)) {
×
321
    code = TSDB_CODE_FILE_CORRUPTED;
×
322
    taosCloseFileWithLog(&pFD);
×
323
    TSDB_CHECK_CODE(code, lino, _exit);
×
324
  }
325

326
  code = tsdbBinaryToFS(pData, size, pFS);
×
327
  TSDB_CHECK_CODE(code, lino, _exit);
×
328

329
_exit:
×
330
  if (code) {
×
331
    tsdbError("%s failed at line %d since %s, fname:%s", __func__, lino, tstrerror(code), fname);
×
332
  }
333
  taosMemoryFree(pData);
×
334
  taosCloseFileWithLog(&pFD);
×
335
  return code;
×
336
}
337

338
static int32_t tsdbRemoveFileSet(STsdb *pTsdb, SDFileSet *pSet) {
×
339
  int32_t code = 0;
×
340
  char    fname[TSDB_FILENAME_LEN] = {0};
×
341

342
  int32_t nRef = atomic_sub_fetch_32(&pSet->pHeadF->nRef, 1);
×
343
  if (nRef == 0) {
×
344
    tsdbHeadFileName(pTsdb, pSet->diskId, pSet->fid, pSet->pHeadF, fname);
×
345
    tsdbRemoveFile(fname);
×
346
    taosMemoryFree(pSet->pHeadF);
×
347
  }
348

349
  nRef = atomic_sub_fetch_32(&pSet->pDataF->nRef, 1);
×
350
  if (nRef == 0) {
×
351
    tsdbDataFileName(pTsdb, pSet->diskId, pSet->fid, pSet->pDataF, fname);
×
352
    tsdbRemoveFile(fname);
×
353
    taosMemoryFree(pSet->pDataF);
×
354
  }
355

356
  nRef = atomic_sub_fetch_32(&pSet->pSmaF->nRef, 1);
×
357
  if (nRef == 0) {
×
358
    tsdbSmaFileName(pTsdb, pSet->diskId, pSet->fid, pSet->pSmaF, fname);
×
359
    tsdbRemoveFile(fname);
×
360
    taosMemoryFree(pSet->pSmaF);
×
361
  }
362

363
  for (int8_t iStt = 0; iStt < pSet->nSttF; iStt++) {
×
364
    nRef = atomic_sub_fetch_32(&pSet->aSttF[iStt]->nRef, 1);
×
365
    if (nRef == 0) {
×
366
      tsdbSttFileName(pTsdb, pSet->diskId, pSet->fid, pSet->aSttF[iStt], fname);
×
367
      tsdbRemoveFile(fname);
×
368
      taosMemoryFree(pSet->aSttF[iStt]);
×
369
    }
370
  }
371

372
_exit:
×
373
  return code;
×
374
}
375

376
static int32_t tsdbNewFileSet(STsdb *pTsdb, SDFileSet *pSetTo, SDFileSet *pSetFrom) {
×
377
  int32_t code = 0;
×
378
  int32_t lino = 0;
×
379

380
  *pSetTo = (SDFileSet){
×
381
      .diskId = pSetFrom->diskId,
×
382
      .fid = pSetFrom->fid,
×
383
      .nSttF = 0,
384
  };
385

386
  // head
387
  pSetTo->pHeadF = (SHeadFile *)taosMemoryMalloc(sizeof(SHeadFile));
×
388
  if (pSetTo->pHeadF == NULL) {
×
389
    code = terrno;
×
390
    TSDB_CHECK_CODE(code, lino, _exit);
×
391
  }
392
  *pSetTo->pHeadF = *pSetFrom->pHeadF;
×
393
  pSetTo->pHeadF->nRef = 1;
×
394

395
  // data
396
  pSetTo->pDataF = (SDataFile *)taosMemoryMalloc(sizeof(SDataFile));
×
397
  if (pSetTo->pDataF == NULL) {
×
398
    code = terrno;
×
399
    TSDB_CHECK_CODE(code, lino, _exit);
×
400
  }
401
  *pSetTo->pDataF = *pSetFrom->pDataF;
×
402
  pSetTo->pDataF->nRef = 1;
×
403

404
  // sma
405
  pSetTo->pSmaF = (SSmaFile *)taosMemoryMalloc(sizeof(SSmaFile));
×
406
  if (pSetTo->pSmaF == NULL) {
×
407
    code = terrno;
×
408
    TSDB_CHECK_CODE(code, lino, _exit);
×
409
  }
410
  *pSetTo->pSmaF = *pSetFrom->pSmaF;
×
411
  pSetTo->pSmaF->nRef = 1;
×
412

413
  // stt
414
  for (int32_t iStt = 0; iStt < pSetFrom->nSttF; iStt++) {
×
415
    pSetTo->aSttF[iStt] = (SSttFile *)taosMemoryMalloc(sizeof(SSttFile));
×
416
    if (pSetTo->aSttF[iStt] == NULL) {
×
417
      code = terrno;
×
418
      TSDB_CHECK_CODE(code, lino, _exit);
×
419
    }
420

421
    pSetTo->nSttF++;
×
422
    *pSetTo->aSttF[iStt] = *pSetFrom->aSttF[iStt];
×
423
    pSetTo->aSttF[iStt]->nRef = 1;
×
424
  }
425

426
_exit:
×
427
  if (code) {
×
428
    tsdbError("vgId:%d, %s failed at line %d since %s", TD_VID(pTsdb->pVnode), __func__, lino, tstrerror(code));
×
429
  }
430
  return code;
×
431
}
432

433
static int32_t tsdbMergeFileSet(STsdb *pTsdb, SDFileSet *pSetOld, SDFileSet *pSetNew) {
×
434
  int32_t code = 0;
×
435
  int32_t lino = 0;
×
436
  int32_t nRef = 0;
×
437
  bool    sameDisk = ((pSetOld->diskId.level == pSetNew->diskId.level) && (pSetOld->diskId.id == pSetNew->diskId.id));
×
438
  char    fname[TSDB_FILENAME_LEN] = {0};
×
439

440
  // head
441
  SHeadFile *pHeadF = pSetOld->pHeadF;
×
442
  if ((!sameDisk) || (pHeadF->commitID != pSetNew->pHeadF->commitID)) {
×
443
    pSetOld->pHeadF = (SHeadFile *)taosMemoryMalloc(sizeof(SHeadFile));
×
444
    if (pSetOld->pHeadF == NULL) {
×
445
      code = terrno;
×
446
      TSDB_CHECK_CODE(code, lino, _exit);
×
447
    }
448
    *pSetOld->pHeadF = *pSetNew->pHeadF;
×
449
    pSetOld->pHeadF->nRef = 1;
×
450

451
    nRef = atomic_sub_fetch_32(&pHeadF->nRef, 1);
×
452
    if (nRef == 0) {
×
453
      tsdbHeadFileName(pTsdb, pSetOld->diskId, pSetOld->fid, pHeadF, fname);
×
454
      tsdbRemoveFile(fname);
×
455
      taosMemoryFree(pHeadF);
×
456
    }
457
  } else {
458
    if (pHeadF->offset != pSetNew->pHeadF->offset || pHeadF->size != pSetNew->pHeadF->size) {
×
459
      TSDB_CHECK_CODE(code = TSDB_CODE_FILE_CORRUPTED, lino, _exit);
×
460
    }
461
  }
462

463
  // data
464
  SDataFile *pDataF = pSetOld->pDataF;
×
465
  if ((!sameDisk) || (pDataF->commitID != pSetNew->pDataF->commitID)) {
×
466
    pSetOld->pDataF = (SDataFile *)taosMemoryMalloc(sizeof(SDataFile));
×
467
    if (pSetOld->pDataF == NULL) {
×
468
      code = terrno;
×
469
      TSDB_CHECK_CODE(code, lino, _exit);
×
470
    }
471
    *pSetOld->pDataF = *pSetNew->pDataF;
×
472
    pSetOld->pDataF->nRef = 1;
×
473

474
    nRef = atomic_sub_fetch_32(&pDataF->nRef, 1);
×
475
    if (nRef == 0) {
×
476
      tsdbDataFileName(pTsdb, pSetOld->diskId, pSetOld->fid, pDataF, fname);
×
477
      tsdbRemoveFile(fname);
×
478
      taosMemoryFree(pDataF);
×
479
    }
480
  } else {
481
    pDataF->size = pSetNew->pDataF->size;
×
482
  }
483

484
  // sma
485
  SSmaFile *pSmaF = pSetOld->pSmaF;
×
486
  if ((!sameDisk) || (pSmaF->commitID != pSetNew->pSmaF->commitID)) {
×
487
    pSetOld->pSmaF = (SSmaFile *)taosMemoryMalloc(sizeof(SSmaFile));
×
488
    if (pSetOld->pSmaF == NULL) {
×
489
      code = terrno;
×
490
      TSDB_CHECK_CODE(code, lino, _exit);
×
491
    }
492
    *pSetOld->pSmaF = *pSetNew->pSmaF;
×
493
    pSetOld->pSmaF->nRef = 1;
×
494

495
    nRef = atomic_sub_fetch_32(&pSmaF->nRef, 1);
×
496
    if (nRef == 0) {
×
497
      tsdbSmaFileName(pTsdb, pSetOld->diskId, pSetOld->fid, pSmaF, fname);
×
498
      tsdbRemoveFile(fname);
×
499
      taosMemoryFree(pSmaF);
×
500
    }
501
  } else {
502
    pSmaF->size = pSetNew->pSmaF->size;
×
503
  }
504

505
  // stt
506
  if (sameDisk) {
×
507
    if (pSetNew->nSttF > pSetOld->nSttF) {
×
508
      pSetOld->aSttF[pSetOld->nSttF] = (SSttFile *)taosMemoryMalloc(sizeof(SSttFile));
×
509
      if (pSetOld->aSttF[pSetOld->nSttF] == NULL) {
×
510
        code = terrno;
×
511
        TSDB_CHECK_CODE(code, lino, _exit);
×
512
      }
513
      *pSetOld->aSttF[pSetOld->nSttF] = *pSetNew->aSttF[pSetOld->nSttF];
×
514
      pSetOld->aSttF[pSetOld->nSttF]->nRef = 1;
×
515
      pSetOld->nSttF++;
×
516
    } else if (pSetNew->nSttF < pSetOld->nSttF) {
×
517
      for (int32_t iStt = 0; iStt < pSetOld->nSttF; iStt++) {
×
518
        SSttFile *pSttFile = pSetOld->aSttF[iStt];
×
519
        nRef = atomic_sub_fetch_32(&pSttFile->nRef, 1);
×
520
        if (nRef == 0) {
×
521
          tsdbSttFileName(pTsdb, pSetOld->diskId, pSetOld->fid, pSttFile, fname);
×
522
          tsdbRemoveFile(fname);
×
523
          taosMemoryFree(pSttFile);
×
524
        }
525
        pSetOld->aSttF[iStt] = NULL;
×
526
      }
527

528
      pSetOld->nSttF = 1;
×
529
      pSetOld->aSttF[0] = (SSttFile *)taosMemoryMalloc(sizeof(SSttFile));
×
530
      if (pSetOld->aSttF[0] == NULL) {
×
531
        code = terrno;
×
532
        TSDB_CHECK_CODE(code, lino, _exit);
×
533
      }
534
      *pSetOld->aSttF[0] = *pSetNew->aSttF[0];
×
535
      pSetOld->aSttF[0]->nRef = 1;
×
536
    } else {
537
      for (int32_t iStt = 0; iStt < pSetOld->nSttF; iStt++) {
×
538
        if (pSetOld->aSttF[iStt]->commitID != pSetNew->aSttF[iStt]->commitID) {
×
539
          SSttFile *pSttFile = pSetOld->aSttF[iStt];
×
540
          nRef = atomic_sub_fetch_32(&pSttFile->nRef, 1);
×
541
          if (nRef == 0) {
×
542
            tsdbSttFileName(pTsdb, pSetOld->diskId, pSetOld->fid, pSttFile, fname);
×
543
            tsdbRemoveFile(fname);
×
544
            taosMemoryFree(pSttFile);
×
545
          }
546

547
          pSetOld->aSttF[iStt] = (SSttFile *)taosMemoryMalloc(sizeof(SSttFile));
×
548
          if (pSetOld->aSttF[iStt] == NULL) {
×
549
            code = terrno;
×
550
            TSDB_CHECK_CODE(code, lino, _exit);
×
551
          }
552
          *pSetOld->aSttF[iStt] = *pSetNew->aSttF[iStt];
×
553
          pSetOld->aSttF[iStt]->nRef = 1;
×
554
        } else {
555
          if (pSetOld->aSttF[iStt]->size != pSetOld->aSttF[iStt]->size ||
556
              pSetOld->aSttF[iStt]->offset == pSetOld->aSttF[iStt]->offset) {
557
            TSDB_CHECK_CODE(code = TSDB_CODE_FILE_CORRUPTED, lino, _exit);
×
558
          }
559
        }
560
      }
561
    }
562
  } else {
563
    for (int32_t iStt = 0; iStt < pSetOld->nSttF; iStt++) {
×
564
      SSttFile *pSttFile = pSetOld->aSttF[iStt];
×
565
      nRef = atomic_sub_fetch_32(&pSttFile->nRef, 1);
×
566
      if (nRef == 0) {
×
567
        tsdbSttFileName(pTsdb, pSetOld->diskId, pSetOld->fid, pSttFile, fname);
×
568
        tsdbRemoveFile(fname);
×
569
        taosMemoryFree(pSttFile);
×
570
      }
571
    }
572

573
    pSetOld->nSttF = 0;
×
574
    for (int32_t iStt = 0; iStt < pSetNew->nSttF; iStt++) {
×
575
      pSetOld->aSttF[iStt] = (SSttFile *)taosMemoryMalloc(sizeof(SSttFile));
×
576
      if (pSetOld->aSttF[iStt] == NULL) {
×
577
        code = terrno;
×
578
        TSDB_CHECK_CODE(code, lino, _exit);
×
579
      }
580

581
      *pSetOld->aSttF[iStt] = *pSetNew->aSttF[iStt];
×
582
      pSetOld->aSttF[iStt]->nRef = 1;
×
583

584
      pSetOld->nSttF++;
×
585
    }
586
  }
587

588
  if (!sameDisk) {
×
589
    pSetOld->diskId = pSetNew->diskId;
×
590
  }
591

592
_exit:
×
593
  if (code) {
×
594
    tsdbError("vgId:%d, %s failed at line %d since %s", TD_VID(pTsdb->pVnode), __func__, lino, tstrerror(code));
×
595
  }
596
  return code;
×
597
}
598

599
static int32_t tsdbFSApplyChange(STsdb *pTsdb, STsdbFS *pFS) {
×
600
  int32_t code = 0;
×
601
  int32_t lino = 0;
×
602

603
  int32_t nRef = 0;
×
604
  char    fname[TSDB_FILENAME_LEN] = {0};
×
605

606
  // SDelFile
607
  if (pFS->pDelFile) {
×
608
    SDelFile *pDelFile = pTsdb->fs.pDelFile;
×
609

610
    if (pDelFile == NULL || (pDelFile->commitID != pFS->pDelFile->commitID)) {
×
611
      pTsdb->fs.pDelFile = (SDelFile *)taosMemoryMalloc(sizeof(SDelFile));
×
612
      if (pTsdb->fs.pDelFile == NULL) {
×
613
        code = terrno;
×
614
        TSDB_CHECK_CODE(code, lino, _exit);
×
615
      }
616

617
      *pTsdb->fs.pDelFile = *pFS->pDelFile;
×
618
      pTsdb->fs.pDelFile->nRef = 1;
×
619

620
      if (pDelFile) {
×
621
        nRef = atomic_sub_fetch_32(&pDelFile->nRef, 1);
×
622
        if (nRef == 0) {
×
623
          tsdbDelFileName(pTsdb, pDelFile, fname);
×
624
          tsdbRemoveFile(fname);
×
625
          taosMemoryFree(pDelFile);
×
626
        }
627
      }
628
    }
629
  } else {
630
    if (pTsdb->fs.pDelFile) {
×
631
      nRef = atomic_sub_fetch_32(&pTsdb->fs.pDelFile->nRef, 1);
×
632
      if (nRef == 0) {
×
633
        tsdbDelFileName(pTsdb, pTsdb->fs.pDelFile, fname);
×
634
        tsdbRemoveFile(fname);
×
635
        taosMemoryFree(pTsdb->fs.pDelFile);
×
636
      }
637
      pTsdb->fs.pDelFile = NULL;
×
638
    }
639
  }
640

641
  // aDFileSet
642
  int32_t iOld = 0;
×
643
  int32_t iNew = 0;
×
644
  while (true) {
×
645
    int32_t   nOld = taosArrayGetSize(pTsdb->fs.aDFileSet);
×
646
    int32_t   nNew = taosArrayGetSize(pFS->aDFileSet);
×
647
    SDFileSet fSet = {0};
×
648
    int8_t    sameDisk = 0;
×
649

650
    if (iOld >= nOld && iNew >= nNew) break;
×
651

652
    SDFileSet *pSetOld = (iOld < nOld) ? taosArrayGet(pTsdb->fs.aDFileSet, iOld) : NULL;
×
653
    SDFileSet *pSetNew = (iNew < nNew) ? taosArrayGet(pFS->aDFileSet, iNew) : NULL;
×
654

655
    if (pSetOld && pSetNew) {
×
656
      if (pSetOld->fid == pSetNew->fid) {
×
657
        code = tsdbMergeFileSet(pTsdb, pSetOld, pSetNew);
×
658
        TSDB_CHECK_CODE(code, lino, _exit);
×
659

660
        iOld++;
×
661
        iNew++;
×
662
      } else if (pSetOld->fid < pSetNew->fid) {
×
663
        code = tsdbRemoveFileSet(pTsdb, pSetOld);
×
664
        TSDB_CHECK_CODE(code, lino, _exit);
×
665
        taosArrayRemove(pTsdb->fs.aDFileSet, iOld);
×
666
      } else {
667
        code = tsdbNewFileSet(pTsdb, &fSet, pSetNew);
×
668
        TSDB_CHECK_CODE(code, lino, _exit);
×
669

670
        if (taosArrayInsert(pTsdb->fs.aDFileSet, iOld, &fSet) == NULL) {
×
671
          code = terrno;
×
672
          TSDB_CHECK_CODE(code, lino, _exit);
×
673
        }
674

675
        iOld++;
×
676
        iNew++;
×
677
      }
678
    } else if (pSetOld) {
×
679
      code = tsdbRemoveFileSet(pTsdb, pSetOld);
×
680
      TSDB_CHECK_CODE(code, lino, _exit);
×
681
      taosArrayRemove(pTsdb->fs.aDFileSet, iOld);
×
682
    } else {
683
      code = tsdbNewFileSet(pTsdb, &fSet, pSetNew);
×
684
      TSDB_CHECK_CODE(code, lino, _exit);
×
685

686
      if (taosArrayInsert(pTsdb->fs.aDFileSet, iOld, &fSet) == NULL) {
×
687
        code = terrno;
×
688
        TSDB_CHECK_CODE(code, lino, _exit);
×
689
      }
690

691
      iOld++;
×
692
      iNew++;
×
693
    }
694
  }
695

696
_exit:
×
697
  if (code) {
×
698
    tsdbError("vgId:%d, %s failed at line %d since %s", TD_VID(pTsdb->pVnode), __func__, lino, tstrerror(code));
×
699
  }
700
  return code;
×
701
}
702

703
// EXPOSED APIS ====================================================================================
704
static int32_t tsdbFSCommit(STsdb *pTsdb) {
×
705
  int32_t code = 0;
×
706
  int32_t lino = 0;
×
707
  STsdbFS fs = {0};
×
708

709
  char current[TSDB_FILENAME_LEN] = {0};
×
710
  char current_t[TSDB_FILENAME_LEN] = {0};
×
711
  tsdbGetCurrentFName(pTsdb, current, current_t);
×
712

713
  if (!taosCheckExistFile(current_t)) goto _exit;
×
714

715
  // rename the file
716
  TSDB_CHECK_CODE(taosRenameFile(current_t, current), lino, _exit);
×
717

718
  // Load the new FS
719
  code = tsdbFSCreate(&fs);
×
720
  TSDB_CHECK_CODE(code, lino, _exit);
×
721

722
  code = load_fs(current, &fs);
×
723
  TSDB_CHECK_CODE(code, lino, _exit);
×
724

725
  // apply file change
726
  code = tsdbFSApplyChange(pTsdb, &fs);
×
727
  TSDB_CHECK_CODE(code, lino, _exit);
×
728

729
_exit:
×
730
  tsdbFSDestroy(&fs);
×
731
  if (code) {
×
732
    tsdbError("vgId:%d, %s failed at line %d since %s", TD_VID(pTsdb->pVnode), __func__, lino, tstrerror(code));
×
733
  }
734
  return code;
×
735
}
736

737
static int32_t tsdbFSRollback(STsdb *pTsdb) {
×
738
  int32_t code = 0;
×
739
  int32_t lino = 0;
×
740

741
  char current_t[TSDB_FILENAME_LEN] = {0};
×
742
  tsdbGetCurrentFName(pTsdb, NULL, current_t);
×
743
  tsdbRemoveFile(current_t);
×
744

745
_exit:
×
746
  if (code) {
×
747
    tsdbError("vgId:%d, %s failed at line %d since %s", TD_VID(pTsdb->pVnode), __func__, lino, tstrerror(ERRNO));
×
748
  }
749
  return code;
×
750
}
751

752
int32_t tsdbFSOpen(STsdb *pTsdb, int8_t rollback) {
×
753
  int32_t code = 0;
×
754
  int32_t lino = 0;
×
755
  SVnode *pVnode = pTsdb->pVnode;
×
756

757
  // open handle
758
  code = tsdbFSCreate(&pTsdb->fs);
×
759
  TSDB_CHECK_CODE(code, lino, _exit);
×
760

761
  // open impl
762
  char current[TSDB_FILENAME_LEN] = {0};
×
763
  char current_t[TSDB_FILENAME_LEN] = {0};
×
764
  tsdbGetCurrentFName(pTsdb, current, current_t);
×
765

766
  if (taosCheckExistFile(current)) {
×
767
    code = load_fs(current, &pTsdb->fs);
×
768
    TSDB_CHECK_CODE(code, lino, _exit);
×
769

770
    if (taosCheckExistFile(current_t)) {
×
771
      if (rollback) {
×
772
        code = tsdbFSRollback(pTsdb);
×
773
        TSDB_CHECK_CODE(code, lino, _exit);
×
774
      } else {
775
        code = tsdbFSCommit(pTsdb);
×
776
        TSDB_CHECK_CODE(code, lino, _exit);
×
777
      }
778
    }
779
  } else {
780
    // empty one
781
    code = tsdbSaveFSToFile(&pTsdb->fs, current);
×
782
    TSDB_CHECK_CODE(code, lino, _exit);
×
783
  }
784

785
  // scan and fix FS
786
  code = tsdbScanAndTryFixFS(pTsdb);
×
787
  TSDB_CHECK_CODE(code, lino, _exit);
×
788

789
_exit:
×
790
  if (code) {
×
791
    tsdbError("vgId:%d, %s failed at line %d since %s", TD_VID(pTsdb->pVnode), __func__, lino, tstrerror(code));
×
792
  }
793
  return code;
×
794
}
795

796
int32_t tsdbFSClose(STsdb *pTsdb) {
×
797
  int32_t code = 0;
×
798

799
  if (pTsdb->fs.pDelFile) {
×
800
    taosMemoryFree(pTsdb->fs.pDelFile);
×
801
  }
802

803
  for (int32_t iSet = 0; iSet < taosArrayGetSize(pTsdb->fs.aDFileSet); iSet++) {
×
804
    SDFileSet *pSet = (SDFileSet *)taosArrayGet(pTsdb->fs.aDFileSet, iSet);
×
805

806
    // head
807
    taosMemoryFree(pSet->pHeadF);
×
808

809
    // data
810
    taosMemoryFree(pSet->pDataF);
×
811

812
    // sma
813
    taosMemoryFree(pSet->pSmaF);
×
814

815
    // stt
816
    for (int32_t iStt = 0; iStt < pSet->nSttF; iStt++) {
×
817
      taosMemoryFree(pSet->aSttF[iStt]);
×
818
    }
819
  }
820

821
  taosArrayDestroy(pTsdb->fs.aDFileSet);
×
822

823
  return code;
×
824
}
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