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

taosdata / TDengine / #4473

08 Jul 2025 09:38AM UTC coverage: 62.922% (+0.7%) from 62.22%
#4473

push

travis-ci

web-flow
Merge pull request #31712 from taosdata/merge/mainto3.0

merge: from main to 3.0 branch

158525 of 321496 branches covered (49.31%)

Branch coverage included in aggregate %.

56 of 60 new or added lines in 13 files covered. (93.33%)

1333 existing lines in 67 files now uncovered.

245526 of 320647 relevant lines covered (76.57%)

17689640.25 hits per line

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

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

16
#define _DEFAULT_SOURCE
17
#include "osEnv.h"
18
#include "tfsInt.h"
19

20
static int32_t   tfsMount(STfs *pTfs, SDiskCfg *pCfg);
21
static int32_t   tfsCheck(STfs *pTfs);
22
static int32_t   tfsFormatDir(char *idir, char *odir);
23
static int32_t   tfsGetDiskByName(STfs *pTfs, const char *dir, STfsDisk **ppDisk);
24
static int32_t   tfsOpendirImpl(STfs *pTfs, STfsDir *pDir);
25
static STfsDisk *tfsNextDisk(STfs *pTfs, SDiskIter *pIter);
26

27
int32_t tfsOpen(SDiskCfg *pCfg, int32_t ndisk, STfs **ppTfs) {
3,128✔
28
  int32_t code = 0;
3,128✔
29
  int32_t lino = 0;
3,128✔
30
  STfs   *pTfs = NULL;
3,128✔
31

32
  if (ndisk <= 0 || ndisk > TFS_MAX_DISKS) {
3,128!
33
    TAOS_CHECK_GOTO(TSDB_CODE_INVALID_PARA, &lino, _exit);
×
34
  }
35

36
  pTfs = taosMemoryCalloc(1, sizeof(STfs));
3,128!
37
  if (pTfs == NULL) {
3,128!
38
    TAOS_CHECK_GOTO(terrno, &lino, _exit);
×
39
  }
40

41
  if (taosThreadSpinInit(&pTfs->lock, 0) != 0) {
3,128!
42
    TAOS_CHECK_GOTO(TAOS_SYSTEM_ERROR(ERRNO), &lino, _exit);
×
43
  }
44

45
  for (int32_t level = 0; level < TFS_MAX_TIERS; level++) {
12,512✔
46
    STfsTier *pTier = &pTfs->tiers[level];
9,384✔
47
    TAOS_CHECK_GOTO(tfsInitTier(pTier, level), &lino, _exit);
9,384!
48
  }
49

50
  pTfs->hash = taosHashInit(TFS_MAX_DISKS * 2, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK);
3,128✔
51
  if (pTfs->hash == NULL) {
3,128!
52
    TAOS_CHECK_GOTO(terrno, &lino, _exit);
×
53
  }
54

55
  for (int32_t idisk = 0; idisk < ndisk; idisk++) {
6,312✔
56
    TAOS_CHECK_GOTO(tfsMount(pTfs, &pCfg[idisk]), &lino, _exit);
3,195✔
57
  }
58

59
  TAOS_CHECK_GOTO(tfsCheck(pTfs) < 0, &lino, _exit);
3,117✔
60

61
  tfsUpdateSize(pTfs);
3,116✔
62
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
6,246✔
63
    tfsPosNextId(&pTfs->tiers[level]);
3,130✔
64
  }
65

66
_exit:
3,116✔
67
  if (code != 0) {
3,128✔
68
    tfsClose(pTfs);
12✔
69
    pTfs = NULL;
12✔
70
  }
71
  *ppTfs = pTfs;
3,128✔
72
  TAOS_RETURN(code);
3,128✔
73
}
74

75
void tfsClose(STfs *pTfs) {
3,120✔
76
  if (pTfs == NULL) return;
3,120!
77

78
  for (int32_t level = 0; level <= TFS_MAX_LEVEL; level++) {
12,480✔
79
    tfsDestroyTier(&pTfs->tiers[level]);
9,360✔
80
  }
81

82
  taosHashCleanup(pTfs->hash);
3,120✔
83
  (void)taosThreadSpinDestroy(&pTfs->lock);
3,120✔
84
  taosMemoryFree(pTfs);
3,120!
85
}
86

87
void tfsUpdateSize(STfs *pTfs) {
139,868✔
88
  SDiskSize size = {0};
139,868✔
89

90
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
280,972✔
91
    STfsTier *pTier = &pTfs->tiers[level];
141,104✔
92
    tfsUpdateTierSize(pTier);
141,104✔
93
    size.total += pTier->size.total;
141,104✔
94
    size.avail += pTier->size.avail;
141,104✔
95
    size.used += pTier->size.used;
141,104✔
96
  }
97

98
  TAOS_UNUSED(tfsLock(pTfs));
139,868✔
99
  pTfs->size = size;
139,868✔
100
  TAOS_UNUSED(tfsUnLock(pTfs));
139,868✔
101
}
139,868✔
102

103
SDiskSize tfsGetSize(STfs *pTfs) {
2✔
104
  TAOS_UNUSED(tfsLock(pTfs));
2✔
105
  SDiskSize size = pTfs->size;
2✔
106
  TAOS_UNUSED(tfsUnLock(pTfs));
2✔
107

108
  return size;
2✔
109
}
110

111
bool tfsDiskSpaceAvailable(STfs *pTfs, int32_t level) {
3,111✔
112
  if (level < 0 || level >= pTfs->nlevel) {
3,111!
113
    return false;
×
114
  }
115
  STfsTier *pTier = TFS_TIER_AT(pTfs, level);
3,111✔
116
  for (int32_t id = 0; id < pTier->ndisk; id++) {
6,237✔
117
    SDiskID   diskId = {.level = level, .id = id};
3,126✔
118
    STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
3,126✔
119
    if (pDisk == NULL) {
3,126!
120
      return false;
×
121
    }
122
    if (pDisk->size.avail <= 0) {
3,126!
123
      fError("tfs disk space unavailable. level:%d, disk:%d, path:%s", level, id, pDisk->path);
×
124
      return false;
×
125
    }
126
  }
127
  return true;
3,111✔
128
}
129

130
bool tfsDiskSpaceSufficient(STfs *pTfs, int32_t level, int32_t disk) {
10,955,104✔
131
  if (level < 0 || level >= pTfs->nlevel) {
10,955,104!
UNCOV
132
    return false;
×
133
  }
134

135
  STfsTier *pTier = TFS_TIER_AT(pTfs, level);
10,961,039✔
136
  if (disk < 0 || disk >= pTier->ndisk) {
10,961,039!
137
    return false;
×
138
  }
139
  SDiskID   diskId = {.level = level, .id = disk};
10,963,524✔
140
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
10,963,524✔
141
  return pDisk->size.avail >= tsDataSpace.reserved;
10,963,524✔
142
}
143

144
int32_t tfsGetDisksAtLevel(STfs *pTfs, int32_t level) {
27,852✔
145
  if (level < 0 || level >= pTfs->nlevel) {
27,852!
146
    TAOS_RETURN(0);
×
147
  }
148

149
  STfsTier *pTier = TFS_TIER_AT(pTfs, level);
27,867✔
150
  return pTier->ndisk;
27,867✔
151
}
152

153
int32_t tfsGetLevel(STfs *pTfs) { return pTfs->nlevel; }
×
154

155
int32_t tfsAllocDisk(STfs *pTfs, int32_t expLevel, const char *label, SDiskID *pDiskId) {
359,808✔
156
  if (expLevel >= pTfs->nlevel || expLevel < 0) {
359,808!
157
    expLevel = pTfs->nlevel - 1;
6✔
158
  }
159

160
  for (; expLevel >= 0; expLevel--) {
359,808!
161
    if (tfsAllocDiskAtLevel(pTfs, expLevel, label, pDiskId) == 0) {
359,853!
162
      TAOS_RETURN(0);
359,887✔
163
    }
164
  }
165

166
  TAOS_RETURN(TSDB_CODE_FS_NO_VALID_DISK);
×
167
}
168

169
int32_t tfsAllocDiskAtLevel(STfs *pTfs, int32_t level, const char *label, SDiskID *pDiskId) {
359,865✔
170
  if (level < 0 || level >= pTfs->nlevel) {
359,865!
171
    TAOS_RETURN(TSDB_CODE_FS_NO_VALID_DISK);
×
172
  }
173

174
  pDiskId->level = level;
359,876✔
175
  pDiskId->id = -1;
359,876✔
176

177
  pDiskId->id = tfsAllocDiskOnTier(&pTfs->tiers[pDiskId->level], label);
359,876✔
178
  if (pDiskId->id < 0) {
359,896!
179
    TAOS_RETURN(TSDB_CODE_FS_NO_VALID_DISK);
×
180
  }
181

182
  TAOS_RETURN(0);
359,896✔
183
}
184

185
const char *tfsGetPrimaryPath(STfs *pTfs) { return TFS_PRIMARY_DISK(pTfs)->path; }
2✔
186

187
const char *tfsGetDiskPath(STfs *pTfs, SDiskID diskId) { return TFS_DISK_AT(pTfs, diskId)->path; }
1,516,735✔
188

189
void tfsInitFile(STfs *pTfs, STfsFile *pFile, SDiskID diskId, const char *rname) {
10,726✔
190
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
10,726✔
191
  if (pDisk == NULL) return;
10,726✔
192

193
  pFile->did = diskId;
10,724✔
194
  tstrncpy(pFile->rname, rname, TSDB_FILENAME_LEN);
10,724✔
195

196
  char tmpName[TMPNAME_LEN] = {0};
10,724✔
197
  (void)snprintf(tmpName, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
10,724✔
198
  tstrncpy(pFile->aname, tmpName, TSDB_FILENAME_LEN);
10,724✔
199
  pFile->pTfs = pTfs;
10,724✔
200
}
201

202
bool tfsIsSameFile(const STfsFile *pFile1, const STfsFile *pFile2) {
8✔
203
  if (pFile1 == NULL || pFile2 == NULL || pFile1->pTfs != pFile2->pTfs) return false;
8!
204
  if (pFile1->did.level != pFile2->did.level) return false;
6✔
205
  if (pFile1->did.id != pFile2->did.id) return false;
5✔
206
  char nameBuf1[TMPNAME_LEN], nameBuf2[TMPNAME_LEN];
207
  tstrncpy(nameBuf1, pFile1->rname, TMPNAME_LEN);
4✔
208
  tstrncpy(nameBuf2, pFile2->rname, TMPNAME_LEN);
4✔
209
  TAOS_UNUSED(taosRealPath(nameBuf1, NULL, TMPNAME_LEN));
4✔
210
  TAOS_UNUSED(taosRealPath(nameBuf2, NULL, TMPNAME_LEN));
4✔
211
  if (strncmp(nameBuf1, nameBuf2, TMPNAME_LEN) != 0) return false;
4✔
212
  return true;
2✔
213
}
214

215
int32_t tfsEncodeFile(void **buf, STfsFile *pFile) {
1✔
216
  int32_t tlen = 0;
1✔
217

218
  tlen += taosEncodeVariantI32(buf, pFile->did.level);
1✔
219
  tlen += taosEncodeVariantI32(buf, pFile->did.id);
1✔
220
  tlen += taosEncodeString(buf, pFile->rname);
1✔
221

222
  return tlen;
1✔
223
}
224

225
void *tfsDecodeFile(STfs *pTfs, void *buf, STfsFile *pFile) {
1✔
226
  SDiskID diskId = {0};
1✔
227
  char   *rname = NULL;
1✔
228

229
  buf = taosDecodeVariantI32(buf, &diskId.level);
1✔
230
  buf = taosDecodeVariantI32(buf, &diskId.id);
1✔
231
  buf = taosDecodeString(buf, &rname);
1✔
232

233
  tfsInitFile(pTfs, pFile, diskId, rname);
1✔
234

235
  taosMemoryFreeClear(rname);
1!
236
  return buf;
1✔
237
}
238

239
void tfsBasename(const STfsFile *pFile, char *dest) {
2✔
240
  char tname[TSDB_FILENAME_LEN] = "\0";
2✔
241

242
  tstrncpy(tname, pFile->aname, TSDB_FILENAME_LEN);
2✔
243
  tstrncpy(dest, taosDirEntryBaseName(tname), TSDB_FILENAME_LEN);
2✔
244
}
2✔
245

246
void tfsDirname(const STfsFile *pFile, char *dest) {
2✔
247
  char tname[TSDB_FILENAME_LEN] = "\0";
2✔
248

249
  tstrncpy(tname, pFile->aname, TSDB_FILENAME_LEN);
2✔
250
  tstrncpy(dest, taosDirName(tname), TSDB_FILENAME_LEN);
2✔
251
}
2✔
252
#if 0
253
void tfsAbsoluteName(STfs *pTfs, SDiskID diskId, const char *rname, char *aname) {
254
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
255

256
  (void)snprintf(aname, TSDB_FILENAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
257
}
258
#endif
259
int32_t tfsRemoveFile(const STfsFile *pFile) { return taosRemoveFile(pFile->aname); }
2✔
260

261
int32_t tfsCopyFile(const STfsFile *pFile1, const STfsFile *pFile2) {
4✔
262
  return taosCopyFile(pFile1->aname, pFile2->aname);
4✔
263
}
264

265
int32_t tfsMkdirAt(STfs *pTfs, const char *rname, SDiskID diskId) {
404,212✔
266
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
404,212✔
267
  char      aname[TMPNAME_LEN];
268

269
  if (pDisk == NULL) {
404,212!
270
    TAOS_RETURN(TSDB_CODE_FS_INVLD_CFG);
×
271
  }
272
  (void)snprintf(aname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
404,212✔
273
  if (taosMkDir(aname) != 0) {
404,212✔
274
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
45✔
275
  }
276

277
  TAOS_RETURN(0);
404,107✔
278
}
279

280
int32_t tfsMkdirRecurAt(STfs *pTfs, const char *rname, SDiskID diskId) {
388,148✔
281
  int32_t code = 0;
388,148✔
282
  int32_t lino = 0;
388,148✔
283
  char   *s = NULL;
388,148✔
284
  char   *dir = NULL;
388,148✔
285
  if ((code = tfsMkdirAt(pTfs, rname, diskId)) < 0) {
388,148✔
286
    if (ERRNO == ENOENT) {
41!
287
      // Try to create upper
288
      if ((s = taosStrdup(rname)) == NULL) {
41!
289
        TAOS_CHECK_GOTO(terrno, &lino, _exit);
×
290
      }
291

292
      // Make a copy of dirname(s) because the implementation of 'dirname' differs on different platforms.
293
      // Some platform may modify the contents of the string passed into dirname(). Others may return a pointer to
294
      // internal static storage space that will be overwritten by next call. For case like that, we should not use
295
      // the pointer directly in this recursion.
296
      // See
297
      // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dirname.3.html
298

299
      if ((dir = taosStrdup(taosDirName(s))) == NULL) {
41!
300
        TAOS_CHECK_GOTO(terrno, &lino, _exit);
×
301
      }
302

303
      if (strlen(dir) >= strlen(rname)) {  // TODO: check if it is necessary for equal length
41!
304
        TAOS_CHECK_GOTO(TSDB_CODE_APP_ERROR, &lino, _exit);
×
305
      }
306
      TAOS_CHECK_GOTO(tfsMkdirRecurAt(pTfs, dir, diskId), &lino, _exit);
41!
307
      TAOS_CHECK_GOTO(tfsMkdirAt(pTfs, rname, diskId), &lino, _exit);
41!
308
    } else {
309
      TAOS_CHECK_GOTO(code, &lino, _exit);
×
310
    }
311
  } else {
312
    TAOS_RETURN(code);
388,051✔
313
  }
314

315
_exit:
41✔
316
  if (code != 0) {
41!
317
    fError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
318
  }
319
  taosMemoryFree(s);
41!
320
  taosMemoryFree(dir);
41!
321
  TAOS_RETURN(code);
41✔
322
}
323

324
int32_t tfsMkdirRecur(STfs *pTfs, const char *rname) {
27,859✔
325
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
55,787✔
326
    STfsTier *pTier = TFS_TIER_AT(pTfs, level);
27,936✔
327
    for (int32_t id = 0; id < pTier->ndisk; id++) {
56,155✔
328
      SDiskID did = {.id = id, .level = level};
28,227✔
329
      TAOS_CHECK_RETURN(tfsMkdirRecurAt(pTfs, rname, did));
28,227!
330
    }
331
  }
332

333
  TAOS_RETURN(0);
27,851✔
334
}
335

336
int32_t tfsMkdir(STfs *pTfs, const char *rname) {
15,760✔
337
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
31,582✔
338
    STfsTier *pTier = TFS_TIER_AT(pTfs, level);
15,827✔
339
    for (int32_t id = 0; id < pTier->ndisk; id++) {
31,844✔
340
      SDiskID did = {.id = id, .level = level};
16,022✔
341
      TAOS_CHECK_RETURN(tfsMkdirAt(pTfs, rname, did));
16,022✔
342
    }
343
  }
344

345
  TAOS_RETURN(0);
15,755✔
346
}
347
#if 0
348
bool tfsDirExistAt(STfs *pTfs, const char *rname, SDiskID diskId) {
349
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
350
  char      aname[TMPNAME_LEN];
351

352
  (void)snprintf(aname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
353
  return taosDirExist(aname);
354
}
355
#endif
356
int32_t tfsRmdir(STfs *pTfs, const char *rname) {
5,603✔
357
  if (rname[0] == 0) {
5,603!
358
    TAOS_RETURN(0);
×
359
  }
360

361
  char aname[TMPNAME_LEN] = "\0";
5,603✔
362

363
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
11,224✔
364
    STfsTier *pTier = TFS_TIER_AT(pTfs, level);
5,621✔
365
    for (int32_t id = 0; id < pTier->ndisk; id++) {
11,278✔
366
      STfsDisk *pDisk = pTier->disks[id];
5,657✔
367
      (void)snprintf(aname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
5,657✔
368
      uInfo("tfs remove dir:%s aname:%s rname:[%s]", pDisk->path, aname, rname);
5,657!
369
      taosRemoveDir(aname);
5,657✔
370
    }
371
  }
372

373
  TAOS_RETURN(0);
5,603✔
374
}
375

376
static int32_t tfsRenameAt(STfs *pTfs, SDiskID diskId, const char *orname, const char *nrname) {
376✔
377
  char oaname[TMPNAME_LEN] = "\0";
376✔
378
  char naname[TMPNAME_LEN] = "\0";
376✔
379

380
  int32_t   level = diskId.level;
376✔
381
  int32_t   id = diskId.id;
376✔
382
  STfsTier *pTier = TFS_TIER_AT(pTfs, level);
376✔
383
  STfsDisk *pDisk = pTier->disks[id];
376✔
384
  (void)snprintf(oaname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, orname);
376✔
385
  (void)snprintf(naname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, nrname);
376✔
386

387
  if (taosRenameFile(oaname, naname) != 0 && ERRNO != ENOENT) {
376!
388
    int32_t code = TAOS_SYSTEM_ERROR(ERRNO);  // TODO: use return value of taosRenameFile directly
×
389
    fError("%s failed to rename %s to %s since %s", __func__, oaname, naname, tstrerror(code));
×
390
    TAOS_RETURN(code);
×
391
  }
392

393
  TAOS_RETURN(0);
376✔
394
}
395

396
int32_t tfsRename(STfs *pTfs, int32_t diskPrimary, const char *orname, const char *nrname) {
238✔
397
  for (int32_t level = pTfs->nlevel - 1; level >= 0; level--) {
530✔
398
    STfsTier *pTier = TFS_TIER_AT(pTfs, level);
292✔
399
    for (int32_t id = pTier->ndisk - 1; id >= 0; id--) {
668✔
400
      if (level == 0 && id == diskPrimary) {
376✔
401
        continue;
238✔
402
      }
403

404
      SDiskID diskId = {.level = level, .id = id};
138✔
405
      TAOS_CHECK_RETURN(tfsRenameAt(pTfs, diskId, orname, nrname));
138!
406
    }
407
  }
408

409
  SDiskID diskId = {.level = 0, .id = diskPrimary};
238✔
410
  TAOS_RETURN(tfsRenameAt(pTfs, diskId, orname, nrname));
238✔
411
}
412

413
int32_t tfsSearch(STfs *pTfs, int32_t level, const char *fname) {
24,308✔
414
  if (level < 0 || level >= pTfs->nlevel) {
24,308!
415
    return -1;
20✔
416
  }
417
  char      path[TMPNAME_LEN] = {0};
24,288✔
418
  STfsTier *pTier = TFS_TIER_AT(pTfs, level);
24,288✔
419

420
  for (int32_t id = 0; id < pTier->ndisk; id++) {
48,847✔
421
    STfsDisk *pDisk = pTier->disks[id];
24,481✔
422
    (void)snprintf(path, TMPNAME_LEN - 1, "%s%s%s", pDisk->path, TD_DIRSEP, fname);
24,481✔
423
    if (taosCheckExistFile(path)) {
24,481!
424
      return id;
×
425
    }
426
  }
427
  return -1;
24,366✔
428
}
429

430
int32_t tfsOpendir(STfs *pTfs, const char *rname, STfsDir **ppDir) {
3,533✔
431
  int32_t  code = 0;
3,533✔
432
  STfsDir *pDir = taosMemoryCalloc(1, sizeof(STfsDir));
3,533!
433
  if (pDir == NULL) {
3,535!
434
    TAOS_CHECK_GOTO(terrno, NULL, _exit);
×
435
  }
436

437
  SDiskID diskId = {.id = 0, .level = 0};
3,535✔
438
  pDir->iter.pDisk = TFS_DISK_AT(pTfs, diskId);
3,535✔
439
  pDir->pTfs = pTfs;
3,535✔
440
  tstrncpy(pDir->dirName, rname, TSDB_FILENAME_LEN);
3,535✔
441

442
  TAOS_CHECK_GOTO(tfsOpendirImpl(pTfs, pDir), NULL, _exit);
3,535!
443

444
_exit:
3,537✔
445
  if (code != 0) {
3,537!
446
    taosMemoryFreeClear(pDir);
×
447
  }
448
  *ppDir = pDir;
3,537✔
449
  TAOS_RETURN(code);
3,537✔
450
}
451

452
const STfsFile *tfsReaddir(STfsDir *pTfsDir) {
14,248✔
453
  if (pTfsDir == NULL || pTfsDir->pDir == NULL) return NULL;
14,248!
454
  char bname[TMPNAME_LEN * 2] = "\0";
14,250✔
455

456
  while (true) {
7,456✔
457
    TdDirEntryPtr pDirEntry = NULL;
21,706✔
458
    pDirEntry = taosReadDir(pTfsDir->pDir);
21,706✔
459
    if (pDirEntry != NULL) {
21,705✔
460
      // Skip . and ..
461
      char *name = taosGetDirEntryName(pDirEntry);
18,041✔
462
      if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;
18,041✔
463

464
      if (pTfsDir->dirName[0] == 0) {
10,711!
465
        (void)snprintf(bname, TMPNAME_LEN * 2, "%s", name);
×
466
      } else {
467
        (void)snprintf(bname, TMPNAME_LEN * 2, "%s%s%s", pTfsDir->dirName, TD_DIRSEP, name);
10,711✔
468
      }
469

470
      tfsInitFile(pTfsDir->pTfs, &pTfsDir->tfile, pTfsDir->did, bname);
10,711✔
471
      return &pTfsDir->tfile;
10,710✔
472
    }
473

474
    if (tfsOpendirImpl(pTfsDir->pTfs, pTfsDir) < 0) {
3,664!
475
      return NULL;
×
476
    }
477

478
    if (pTfsDir->pDir == NULL) {
3,666✔
479
      terrno = TSDB_CODE_SUCCESS;
3,540✔
480
      return NULL;
3,540✔
481
    }
482
  }
483
}
484

485
void tfsClosedir(STfsDir *pTfsDir) {
3,539✔
486
  if (pTfsDir) {
3,539!
487
    if (pTfsDir->pDir != NULL) {
3,539✔
488
      TAOS_UNUSED(taosCloseDir(&pTfsDir->pDir));
1✔
489
      pTfsDir->pDir = NULL;
1✔
490
    }
491
    taosMemoryFree(pTfsDir);
3,539!
492
  }
493
}
3,540✔
494

495
static int32_t tfsMount(STfs *pTfs, SDiskCfg *pCfg) {
3,195✔
496
  int32_t code = 0;
3,195✔
497
  int32_t lino = 0;
3,195✔
498

499
  TAOS_CHECK_GOTO(tfsCheckAndFormatCfg(pTfs, pCfg), &lino, _exit);
3,195✔
500

501
  SDiskID   did = {.level = pCfg->level};
3,184✔
502
  STfsDisk *pDisk = NULL;
3,184✔
503

504
  TAOS_CHECK_GOTO(tfsMountDiskToTier(TFS_TIER_AT(pTfs, did.level), pCfg, &pDisk), &lino, _exit);
3,184!
505
  did.id = pDisk->id;
3,184✔
506

507
  if (taosHashPut(pTfs->hash, (void *)(pCfg->dir), strnlen(pCfg->dir, TSDB_FILENAME_LEN), (void *)(&did),
3,184!
508
                  sizeof(did)) != 0) {
509
    TAOS_CHECK_GOTO(TSDB_CODE_OUT_OF_MEMORY, &lino, _exit);
×
510
  }
511
  if (pTfs->nlevel < pCfg->level + 1) {
3,184✔
512
    pTfs->nlevel = pCfg->level + 1;
3,144✔
513
  }
514

515
_exit:
40✔
516
  if (code != 0) {
3,195✔
517
    fError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
11!
518
  }
519
  TAOS_RETURN(code);
3,195✔
520
}
521

522
int32_t tfsCheckAndFormatCfg(STfs *pTfs, SDiskCfg *pCfg) {
3,195✔
523
  int32_t code = 0;
3,195✔
524
  char    dirName[TSDB_FILENAME_LEN] = "\0";
3,195✔
525

526
  if (pCfg->level < 0 || pCfg->level >= TFS_MAX_TIERS) {
3,195✔
527
    fError("failed to mount %s to FS since invalid level %d", pCfg->dir, pCfg->level);
3!
528
    TAOS_RETURN(TSDB_CODE_FS_INVLD_CFG);
3✔
529
  }
530

531
  if (pCfg->primary < 0 || pCfg->primary > 1) {
3,192!
532
    fError("failed to mount %s to FS since invalid primary %d", pCfg->dir, pCfg->primary);
×
533
    TAOS_RETURN(TSDB_CODE_FS_INVLD_CFG);
×
534
  }
535

536
  if (pCfg->disable < 0 || pCfg->disable > 1) {
3,192!
537
    fError("failed to mount %s to FS since invalid disable %" PRIi8, pCfg->dir, pCfg->disable);
×
538
    TAOS_RETURN(TSDB_CODE_FS_INVLD_CFG);
×
539
  }
540

541
  if (pCfg->primary) {
3,192✔
542
    if (pCfg->level != 0) {
3,133✔
543
      fError("failed to mount %s to FS since disk is primary but level %d not 0", pCfg->dir, pCfg->level);
2!
544
      TAOS_RETURN(TSDB_CODE_FS_INVLD_CFG);
2✔
545
    }
546

547
    if (TFS_PRIMARY_DISK(pTfs) != NULL) {
3,131✔
548
      fError("failed to mount %s to FS since duplicate primary mount", pCfg->dir);
4!
549
      TAOS_RETURN(TSDB_CODE_FS_DUP_PRIMARY);
4✔
550
    }
551
  }
552

553
  if ((code = tfsFormatDir(pCfg->dir, dirName)) < 0) {
3,186✔
554
    fError("failed to mount %s to FS since %s", pCfg->dir, tstrerror(code));
1!
555
    TAOS_RETURN(code);
1✔
556
  }
557

558
  STfsDisk *pDisk = NULL;
3,185✔
559
  if ((code = tfsGetDiskByName(pTfs, dirName, &pDisk)) != 0) {
3,185!
560
    fError("failed to mount %s to FS since %s", pCfg->dir, tstrerror(code));
×
561
    TAOS_RETURN(code);
×
562
  }
563
  if (pDisk != NULL) {
3,185✔
564
    fError("failed to mount %s to FS since duplicate mount", pCfg->dir);
1!
565
    TAOS_RETURN(TSDB_CODE_FS_INVLD_CFG);
1✔
566
  }
567

568
#ifndef TD_ASTRA
569
  if (!taosCheckAccessFile(dirName, TD_FILE_ACCESS_EXIST_OK | TD_FILE_ACCESS_READ_OK | TD_FILE_ACCESS_WRITE_OK)) {
3,184!
570
    fError("failed to mount %s to FS since no R/W access rights", pCfg->dir);
×
571
    TAOS_RETURN(TSDB_CODE_FS_INVLD_CFG);
×
572
  }
573
#else  // TD_ASTRA_TODO
574
  if (!taosCheckAccessFile(dirName, TD_FILE_ACCESS_EXIST_OK)) {
575
    fError("failed to mount %s to FS since no access rights", pCfg->dir);
576
    TAOS_RETURN(TSDB_CODE_FS_INVLD_CFG);
577
  }
578
#endif
579

580
  if (!taosIsDir(dirName)) {
3,184!
581
    fError("failed to mount %s to FS since not a directory", pCfg->dir);
×
582
    TAOS_RETURN(TSDB_CODE_FS_INVLD_CFG);
×
583
  }
584

585
  tstrncpy(pCfg->dir, dirName, TSDB_FILENAME_LEN);
3,184✔
586

587
  TAOS_RETURN(0);
3,184✔
588
}
589

590
static int32_t tfsFormatDir(char *idir, char *odir) {
3,186✔
591
#ifndef TD_ASTRA
592
  int32_t   code = 0, lino = 0;
3,186✔
593
  wordexp_t wep = {0};
3,186✔
594
  int32_t   dirLen = 0;
3,186✔
595
  char      tmp[PATH_MAX] = {0};
3,186✔
596

597
  code = wordexp(idir, &wep, 0);
3,186✔
598
  if (code != 0) {
3,186!
599
    TAOS_CHECK_EXIT(TAOS_SYSTEM_ERROR(code));
×
600
  }
601

602
  TAOS_CHECK_EXIT(taosRealPath(wep.we_wordv[0], tmp, PATH_MAX));
3,186✔
603

604
  dirLen = strlen(tmp);
3,185✔
605
  if (dirLen < 0 || dirLen >= TSDB_FILENAME_LEN) {
3,185!
606
    TAOS_CHECK_EXIT(TSDB_CODE_OUT_OF_RANGE);
×
607
  }
608

609
  tstrncpy(odir, tmp, TSDB_FILENAME_LEN);
3,185✔
610

611
_exit:
3,186✔
612
  wordfree(&wep);
3,186✔
613
  if (code != 0) {
3,186✔
614
    fError("failed to mount %s to FS at line %d since %s, real path:%s, len:%d", idir, lino, tstrerror(code), tmp,
1!
615
           dirLen);
616
  }
617
  TAOS_RETURN(code);
3,186✔
618
#else
619
  tstrncpy(odir, idir, TSDB_FILENAME_LEN);
620
  TAOS_RETURN(0);
621
#endif
622
}
623

624
static int32_t tfsCheck(STfs *pTfs) {
3,117✔
625
  if (TFS_PRIMARY_DISK(pTfs) == NULL) {
3,117✔
626
    fError("no primary disk is set");
1!
627
    TAOS_RETURN(TSDB_CODE_FS_NO_PRIMARY_DISK);
1✔
628
  }
629

630
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
6,246✔
631
    if (TFS_TIER_AT(pTfs, level)->ndisk == 0) {
3,130!
632
      fError("no disk at level %d", level);
×
633
      TAOS_RETURN(TSDB_CODE_FS_NO_MOUNT_AT_TIER);
×
634
    }
635

636
    if (level == 0) {
3,130✔
637
      tfsUpdateTierSize(TFS_TIER_AT(pTfs, level));
3,116✔
638
      if (TFS_TIER_AT(pTfs, level)->nAvailDisks == 0) {
3,116!
639
        fError("no disk to create new file at level %d", level);
×
640
        TAOS_RETURN(TSDB_CODE_FS_NO_VALID_DISK);
×
641
      }
642
    }
643
  }
644

645
  TAOS_RETURN(0);
3,116✔
646
}
647

648
static int32_t tfsGetDiskByName(STfs *pTfs, const char *dir, STfsDisk **ppDisk) {
3,185✔
649
  void *pr = taosHashGet(pTfs->hash, (void *)dir, strnlen(dir, TSDB_FILENAME_LEN));
3,185✔
650
  if (pr == NULL) {
3,185✔
651
    TAOS_RETURN(terrno);
3,184✔
652
  }
653

654
  SDiskID did = *(SDiskID *)pr;
1✔
655
  *ppDisk = TFS_DISK_AT(pTfs, did);
1✔
656

657
  TAOS_RETURN(0);
1✔
658
}
659

660
static int32_t tfsOpendirImpl(STfs *pTfs, STfsDir *pTfsDir) {
7,196✔
661
  STfsDisk *pDisk = NULL;
7,196✔
662
  char      adir[TMPNAME_LEN * 2] = "\0";
7,196✔
663
  int32_t   code = 0;
7,196✔
664

665
  if (pTfsDir->pDir != NULL) {
7,196✔
666
    if ((code = taosCloseDir(&pTfsDir->pDir)) != 0) {
3,666!
667
      fError("%s failed to close dir since %s", __func__, tstrerror(code));
×
668
      TAOS_RETURN(code);
×
669
    }
670
    pTfsDir->pDir = NULL;
3,666✔
671
  }
672

673
  while (true) {
674
    pDisk = tfsNextDisk(pTfs, &pTfsDir->iter);
7,196✔
675
    if (pDisk == NULL) TAOS_RETURN(0);
7,200✔
676

677
    pTfsDir->did.level = pDisk->level;
3,659✔
678
    pTfsDir->did.id = pDisk->id;
3,659✔
679

680
    if (pDisk->path == NULL || pDisk->path[0] == 0) {
3,659!
681
      (void)snprintf(adir, TMPNAME_LEN * 2, "%s", pTfsDir->dirName);
×
682
    } else {
683
      (void)snprintf(adir, TMPNAME_LEN * 2, "%s%s%s", pDisk->path, TD_DIRSEP, pTfsDir->dirName);
3,659✔
684
    }
685
    pTfsDir->pDir = taosOpenDir(adir);
3,659✔
686
    if (pTfsDir->pDir != NULL) break;
3,663!
687
    fWarn("%s failed to open dir %s since %s", __func__, adir, tstrerror(TAOS_SYSTEM_ERROR(ERRNO)));
×
688
  }
689

690
  TAOS_RETURN(0);
3,663✔
691
}
692

693
static STfsDisk *tfsNextDisk(STfs *pTfs, SDiskIter *pIter) {
7,197✔
694
  if (pIter == NULL) return NULL;
7,197!
695

696
  STfsDisk *pDisk = pIter->pDisk;
7,197✔
697
  if (pDisk == NULL) return NULL;
7,197✔
698

699
  SDiskID did = {.level = pDisk->level, .id = pDisk->id + 1};
3,657✔
700

701
  if (did.id < TFS_TIER_AT(pTfs, did.level)->ndisk) {
3,657✔
702
    pIter->pDisk = TFS_DISK_AT(pTfs, did);
78✔
703
  } else {
704
    did.level++;
3,579✔
705
    did.id = 0;
3,579✔
706
    if (did.level < pTfs->nlevel) {
3,579✔
707
      pIter->pDisk = TFS_DISK_AT(pTfs, did);
48✔
708
    } else {
709
      pIter->pDisk = NULL;
3,531✔
710
    }
711
  }
712

713
  return pDisk;
3,657✔
714
}
715

716
int32_t tfsGetMonitorInfo(STfs *pTfs, SMonDiskInfo *pInfo) {
16✔
717
  pInfo->datadirs = taosArrayInit(32, sizeof(SMonDiskDesc));
16✔
718
  if (pInfo->datadirs == NULL) {
16!
719
    TAOS_RETURN(terrno);
×
720
  }
721

722
  tfsUpdateSize(pTfs);
16✔
723

724
  TAOS_UNUSED(tfsLock(pTfs));
16✔
725
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
32✔
726
    STfsTier *pTier = &pTfs->tiers[level];
16✔
727
    for (int32_t disk = 0; disk < pTier->ndisk; ++disk) {
32✔
728
      STfsDisk    *pDisk = pTier->disks[disk];
16✔
729
      SMonDiskDesc dinfo = {0};
16✔
730
      dinfo.size = pDisk->size;
16✔
731
      dinfo.level = pDisk->level;
16✔
732
      tstrncpy(dinfo.name, pDisk->path, sizeof(dinfo.name));
16✔
733
      if (taosArrayPush(pInfo->datadirs, &dinfo) == NULL) {
32!
734
        TAOS_UNUSED(tfsUnLock(pTfs));
×
735
        taosArrayDestroy(pInfo->datadirs);
×
736
        pInfo->datadirs = NULL;
×
737
        TAOS_RETURN(terrno);
×
738
      }
739
    }
740
  }
741
  TAOS_UNUSED(tfsUnLock(pTfs));
16✔
742

743
  TAOS_RETURN(0);
16✔
744
}
745

746
int32_t tfsUpdateDiskDisable(STfs *pTfs, const char *dir, int8_t disable) {
×
747
  TAOS_UNUSED(tfsLock(pTfs));
×
748
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
×
749
    STfsTier *pTier = &pTfs->tiers[level];
×
750
    for (int32_t disk = 0; disk < pTier->ndisk; ++disk) {
×
751
      STfsDisk *pDisk = pTier->disks[disk];
×
752
      if (strcmp(pDisk->path, dir) == 0) {
×
753
        pDisk->disable = disable;
×
754
        TAOS_UNUSED(tfsUnLock(pTfs));
×
755
        fInfo("disk %s is %s", dir, disable ? "disabled" : "enabled");
×
756
        TAOS_RETURN(TSDB_CODE_SUCCESS);
×
757
      }
758
    }
759
  }
760
  TAOS_UNUSED(tfsUnLock(pTfs));
×
761
  fError("failed to update disk disable since %s not found", dir);
×
762
  TAOS_RETURN(TSDB_CODE_FS_NO_VALID_DISK);
×
763
}
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

© 2025 Coveralls, Inc