tfs.c 16.6 KB
Newer Older
H
Hongze Cheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * 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/>.
 */

S
Shengliang Guan 已提交
16 17
#define _DEFAULT_SOURCE
#include "tfsInt.h"
H
Hongze Cheng 已提交
18

S
Shengliang Guan 已提交
19 20 21 22 23 24 25 26 27
static int32_t   tfsMount(STfs *pTfs, SDiskCfg *pCfg);
static int32_t   tfsCheck(STfs *pTfs);
static int32_t   tfsCheckAndFormatCfg(STfs *pTfs, SDiskCfg *pCfg);
static int32_t   tfsFormatDir(char *idir, char *odir);
static STfsDisk *tfsGetDiskByName(STfs *pTfs, const char *dir);
static int32_t   tfsOpendirImpl(STfs *pTfs, STfsDir *pDir);
static STfsDisk *tfsNextDisk(STfs *pTfs, SDiskIter *pIter);

STfs *tfsOpen(SDiskCfg *pCfg, int32_t ndisk) {
S
Shengliang Guan 已提交
28
  if (ndisk <= 0 || ndisk > TFS_MAX_DISKS) {
29
    terrno = TSDB_CODE_INVALID_PARA;
S
Shengliang Guan 已提交
30
    return NULL;
31
  }
H
Hongze Cheng 已提交
32

wafwerar's avatar
wafwerar 已提交
33
  STfs *pTfs = taosMemoryCalloc(1, sizeof(STfs));
S
Shengliang Guan 已提交
34 35 36 37
  if (pTfs == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    return NULL;
  }
H
Hongze Cheng 已提交
38

wafwerar's avatar
wafwerar 已提交
39
  if (taosThreadSpinInit(&pTfs->lock, 0) != 0) {
S
Shengliang Guan 已提交
40 41 42 43
    terrno = TAOS_SYSTEM_ERROR(errno);
    tfsClose(pTfs);
    return NULL;
  }
H
Hongze Cheng 已提交
44

S
Shengliang Guan 已提交
45 46 47 48 49
  for (int32_t level = 0; level < TFS_MAX_TIERS; level++) {
    STfsTier *pTier = &pTfs->tiers[level];
    if (tfsInitTier(pTier, level) < 0) {
      tfsClose(pTfs);
      return NULL;
H
Hongze Cheng 已提交
50
    }
H
Hongze Cheng 已提交
51 52
  }

S
Shengliang Guan 已提交
53 54
  pTfs->hash = taosHashInit(TFS_MAX_DISKS * 2, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK);
  if (pTfs->hash == NULL) {
S
Shengliang Guan 已提交
55
    terrno = TSDB_CODE_OUT_OF_MEMORY;
S
Shengliang Guan 已提交
56 57
    tfsClose(pTfs);
    return NULL;
H
Hongze Cheng 已提交
58 59
  }

S
Shengliang Guan 已提交
60
  for (int32_t idisk = 0; idisk < ndisk; idisk++) {
S
Shengliang Guan 已提交
61 62 63
    if (tfsMount(pTfs, &pCfg[idisk]) < 0) {
      tfsClose(pTfs);
      return NULL;
H
Hongze Cheng 已提交
64 65 66
    }
  }

S
Shengliang Guan 已提交
67 68 69
  if (tfsCheck(pTfs) < 0) {
    tfsClose(pTfs);
    return NULL;
H
Hongze Cheng 已提交
70 71
  }

S
Shengliang Guan 已提交
72 73 74
  tfsUpdateSize(pTfs);
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
    tfsPosNextId(&pTfs->tiers[level]);
H
Hongze Cheng 已提交
75
  }
H
Hongze Cheng 已提交
76

S
Shengliang Guan 已提交
77
  return pTfs;
H
Hongze Cheng 已提交
78 79
}

S
Shengliang Guan 已提交
80 81
void tfsClose(STfs *pTfs) {
  if (pTfs == NULL) return;
H
Hongze Cheng 已提交
82

K
kailixu 已提交
83
  for (int32_t level = 0; level <= TFS_MAX_LEVEL; level++) {
S
Shengliang Guan 已提交
84
    tfsDestroyTier(&pTfs->tiers[level]);
H
Hongze Cheng 已提交
85
  }
S
Shengliang Guan 已提交
86 87

  taosHashCleanup(pTfs->hash);
wafwerar's avatar
wafwerar 已提交
88
  taosThreadSpinDestroy(&pTfs->lock);
wafwerar's avatar
wafwerar 已提交
89
  taosMemoryFree(pTfs);
H
Hongze Cheng 已提交
90 91
}

S
Shengliang Guan 已提交
92
void tfsUpdateSize(STfs *pTfs) {
93
  SDiskSize size = {0};
H
Hongze Cheng 已提交
94

S
Shengliang Guan 已提交
95 96
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
    STfsTier *pTier = &pTfs->tiers[level];
97
    tfsUpdateTierSize(pTier);
S
Shengliang Guan 已提交
98 99 100
    size.total += pTier->size.total;
    size.avail += pTier->size.avail;
    size.used += pTier->size.used;
H
Hongze Cheng 已提交
101 102
  }

S
Shengliang Guan 已提交
103 104 105
  tfsLock(pTfs);
  pTfs->size = size;
  tfsUnLock(pTfs);
H
Hongze Cheng 已提交
106 107
}

S
Shengliang Guan 已提交
108 109 110 111
SDiskSize tfsGetSize(STfs *pTfs) {
  tfsLock(pTfs);
  SDiskSize size = pTfs->size;
  tfsUnLock(pTfs);
H
Hongze Cheng 已提交
112

S
Shengliang Guan 已提交
113 114 115
  return size;
}

116 117 118 119 120 121 122 123 124
int32_t tfsGetDisksAtLevel(STfs *pTfs, int32_t level) {
  if (level < 0 || level >= pTfs->nlevel) {
    return 0;
  }

  STfsTier *pTier = TFS_TIER_AT(pTfs, level);
  return pTier->ndisk;
}

125 126
int32_t tfsGetLevel(STfs *pTfs) { return pTfs->nlevel; }

S
Shengliang Guan 已提交
127 128 129
int32_t tfsAllocDisk(STfs *pTfs, int32_t expLevel, SDiskID *pDiskId) {
  pDiskId->level = expLevel;
  pDiskId->id = -1;
H
Hongze Cheng 已提交
130

S
Shengliang Guan 已提交
131
  if (pDiskId->level >= pTfs->nlevel) {
S
Shengliang Guan 已提交
132 133 134 135 136
    pDiskId->level = pTfs->nlevel - 1;
  }

  if (pDiskId->level < 0) {
    pDiskId->level = 0;
H
Hongze Cheng 已提交
137 138
  }

S
Shengliang Guan 已提交
139 140 141 142
  while (pDiskId->level >= 0) {
    pDiskId->id = tfsAllocDiskOnTier(&pTfs->tiers[pDiskId->level]);
    if (pDiskId->id < 0) {
      pDiskId->level--;
H
Hongze Cheng 已提交
143 144 145
      continue;
    }

S
Shengliang Guan 已提交
146
    return 0;
H
Hongze Cheng 已提交
147 148
  }

S
Shengliang Guan 已提交
149 150
  terrno = TSDB_CODE_FS_NO_VALID_DISK;
  return -1;
H
Hongze Cheng 已提交
151 152
}

S
Shengliang Guan 已提交
153
const char *tfsGetPrimaryPath(STfs *pTfs) { return TFS_PRIMARY_DISK(pTfs)->path; }
H
Hongze Cheng 已提交
154

S
Shengliang Guan 已提交
155
const char *tfsGetDiskPath(STfs *pTfs, SDiskID diskId) { return TFS_DISK_AT(pTfs, diskId)->path; }
H
Hongze Cheng 已提交
156

S
Shengliang Guan 已提交
157 158
void tfsInitFile(STfs *pTfs, STfsFile *pFile, SDiskID diskId, const char *rname) {
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
S
Shengliang Guan 已提交
159
  if (pDisk == NULL) return;
H
Hongze Cheng 已提交
160

S
Shengliang Guan 已提交
161 162
  pFile->did = diskId;
  tstrncpy(pFile->rname, rname, TSDB_FILENAME_LEN);
S
TD-1207  
Shengliang Guan 已提交
163 164

  char tmpName[TMPNAME_LEN] = {0};
S
Shengliang Guan 已提交
165
  snprintf(tmpName, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
S
Shengliang Guan 已提交
166 167
  tstrncpy(pFile->aname, tmpName, TSDB_FILENAME_LEN);
  pFile->pTfs = pTfs;
H
Hongze Cheng 已提交
168 169
}

S
Shengliang Guan 已提交
170 171 172 173
bool tfsIsSameFile(const STfsFile *pFile1, const STfsFile *pFile2) {
  if (pFile1 == NULL || pFile2 == NULL || pFile1->pTfs != pFile2->pTfs) return false;
  if (pFile1->did.level != pFile2->did.level) return false;
  if (pFile1->did.id != pFile2->did.id) return false;
wafwerar's avatar
wafwerar 已提交
174
  char nameBuf1[TMPNAME_LEN], nameBuf2[TMPNAME_LEN];
wafwerar's avatar
wafwerar 已提交
175 176 177 178 179 180
  strncpy(nameBuf1, pFile1->rname, TMPNAME_LEN);
  strncpy(nameBuf2, pFile2->rname, TMPNAME_LEN);
  nameBuf1[TMPNAME_LEN - 1] = 0;
  nameBuf2[TMPNAME_LEN - 1] = 0;
  taosRealPath(nameBuf1, NULL, TMPNAME_LEN);
  taosRealPath(nameBuf2, NULL, TMPNAME_LEN);
wafwerar's avatar
wafwerar 已提交
181
  if (strncmp(nameBuf1, nameBuf2, TMPNAME_LEN) != 0) return false;
H
Hongze Cheng 已提交
182 183 184
  return true;
}

S
Shengliang Guan 已提交
185
int32_t tfsEncodeFile(void **buf, STfsFile *pFile) {
S
Shengliang Guan 已提交
186
  int32_t tlen = 0;
H
Hongze Cheng 已提交
187

S
Shengliang Guan 已提交
188 189 190
  tlen += taosEncodeVariantI32(buf, pFile->did.level);
  tlen += taosEncodeVariantI32(buf, pFile->did.id);
  tlen += taosEncodeString(buf, pFile->rname);
H
Hongze Cheng 已提交
191 192 193 194

  return tlen;
}

S
Shengliang Guan 已提交
195 196 197
void *tfsDecodeFile(STfs *pTfs, void *buf, STfsFile *pFile) {
  SDiskID diskId = {0};
  char   *rname = NULL;
H
Hongze Cheng 已提交
198

S
Shengliang Guan 已提交
199 200
  buf = taosDecodeVariantI32(buf, &diskId.level);
  buf = taosDecodeVariantI32(buf, &diskId.id);
H
Hongze Cheng 已提交
201 202
  buf = taosDecodeString(buf, &rname);

S
Shengliang Guan 已提交
203
  tfsInitFile(pTfs, pFile, diskId, rname);
H
Hongze Cheng 已提交
204

wafwerar's avatar
wafwerar 已提交
205
  taosMemoryFreeClear(rname);
H
Hongze Cheng 已提交
206 207 208
  return buf;
}

S
Shengliang Guan 已提交
209
void tfsBasename(const STfsFile *pFile, char *dest) {
H
Hongze Cheng 已提交
210 211
  char tname[TSDB_FILENAME_LEN] = "\0";

S
Shengliang Guan 已提交
212
  tstrncpy(tname, pFile->aname, TSDB_FILENAME_LEN);
wafwerar's avatar
wafwerar 已提交
213
  tstrncpy(dest, taosDirEntryBaseName(tname), TSDB_FILENAME_LEN);
H
Hongze Cheng 已提交
214 215
}

S
Shengliang Guan 已提交
216
void tfsDirname(const STfsFile *pFile, char *dest) {
H
Hongze Cheng 已提交
217 218
  char tname[TSDB_FILENAME_LEN] = "\0";

S
Shengliang Guan 已提交
219
  tstrncpy(tname, pFile->aname, TSDB_FILENAME_LEN);
wafwerar's avatar
wafwerar 已提交
220
  tstrncpy(dest, taosDirName(tname), TSDB_FILENAME_LEN);
H
Hongze Cheng 已提交
221 222
}

C
Cary Xu 已提交
223 224
void tfsAbsoluteName(STfs *pTfs, SDiskID diskId, const char *rname, char *aname) {
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
H
Hongze Cheng 已提交
225

226
  snprintf(aname, TSDB_FILENAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
C
Cary Xu 已提交
227 228
}

229
int32_t tfsRemoveFile(const STfsFile *pFile) { return taosRemoveFile(pFile->aname); }
S
Shengliang Guan 已提交
230 231 232 233 234

int32_t tfsCopyFile(const STfsFile *pFile1, const STfsFile *pFile2) {
  return taosCopyFile(pFile1->aname, pFile2->aname);
}

S
Shengliang Guan 已提交
235 236 237
int32_t tfsMkdirAt(STfs *pTfs, const char *rname, SDiskID diskId) {
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
  char      aname[TMPNAME_LEN];
H
Hongze Cheng 已提交
238

239 240 241
  if (pDisk == NULL) {
    return -1;
  }
S
Shengliang Guan 已提交
242
  snprintf(aname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
243
  if (taosMkDir(aname) != 0) {
H
Hongze Cheng 已提交
244 245 246 247 248 249 250
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }

  return 0;
}

S
Shengliang Guan 已提交
251 252
int32_t tfsMkdirRecurAt(STfs *pTfs, const char *rname, SDiskID diskId) {
  if (tfsMkdirAt(pTfs, rname, diskId) < 0) {
H
Hongze Cheng 已提交
253 254
    if (errno == ENOENT) {
      // Try to create upper
255
      char *s = taosStrdup(rname);
H
Hongze Cheng 已提交
256

J
Jun Li 已提交
257 258 259 260
      // Make a copy of dirname(s) because the implementation of 'dirname' differs on different platforms.
      // Some platform may modify the contents of the string passed into dirname(). Others may return a pointer to
      // internal static storage space that will be overwritten by next call. For case like that, we should not use
      // the pointer directly in this recursion.
H
Hongze Cheng 已提交
261 262
      // See
      // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dirname.3.html
263
      char *dir = taosStrdup(taosDirName(s));
J
Jun Li 已提交
264

S
Shengliang Guan 已提交
265
      if (tfsMkdirRecurAt(pTfs, dir, diskId) < 0) {
wafwerar's avatar
wafwerar 已提交
266 267
        taosMemoryFree(s);
        taosMemoryFree(dir);
H
Hongze Cheng 已提交
268 269
        return -1;
      }
wafwerar's avatar
wafwerar 已提交
270 271
      taosMemoryFree(s);
      taosMemoryFree(dir);
H
Hongze Cheng 已提交
272

S
Shengliang Guan 已提交
273
      if (tfsMkdirAt(pTfs, rname, diskId) < 0) {
H
Hongze Cheng 已提交
274 275 276 277 278 279 280 281 282 283
        return -1;
      }
    } else {
      return -1;
    }
  }

  return 0;
}

S
Shengliang Guan 已提交
284 285 286 287 288
int32_t tfsMkdir(STfs *pTfs, const char *rname) {
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
    STfsTier *pTier = TFS_TIER_AT(pTfs, level);
    for (int32_t id = 0; id < pTier->ndisk; id++) {
      SDiskID did = {.id = id, .level = level};
289
      if (tfsMkdirRecurAt(pTfs, rname, did) < 0) {
H
Hongze Cheng 已提交
290 291 292 293 294 295 296 297
        return -1;
      }
    }
  }

  return 0;
}

C
cadem 已提交
298 299 300 301 302 303 304 305
bool tfsDirExistAt(STfs *pTfs, const char *rname, SDiskID diskId) {
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, diskId);
  char      aname[TMPNAME_LEN];

  snprintf(aname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
  return taosDirExist(aname);
}

S
Shengliang Guan 已提交
306
int32_t tfsRmdir(STfs *pTfs, const char *rname) {
K
kailixu 已提交
307 308 309
  if (rname[0] == 0) {
    return 0;
  }
H
Hongze Cheng 已提交
310

S
TD-1207  
Shengliang Guan 已提交
311
  char aname[TMPNAME_LEN] = "\0";
H
Hongze Cheng 已提交
312

S
Shengliang Guan 已提交
313 314 315 316 317
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
    STfsTier *pTier = TFS_TIER_AT(pTfs, level);
    for (int32_t id = 0; id < pTier->ndisk; id++) {
      STfsDisk *pDisk = pTier->disks[id];
      snprintf(aname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, rname);
318
      uInfo("tfs remove dir:%s aname:%s rname:[%s]", pDisk->path, aname, rname);
H
Hongze Cheng 已提交
319
      taosRemoveDir(aname);
H
Hongze Cheng 已提交
320 321 322 323 324 325
    }
  }

  return 0;
}

326
int32_t tfsRename(STfs *pTfs, const char *orname, const char *nrname) {
S
TD-1207  
Shengliang Guan 已提交
327 328
  char oaname[TMPNAME_LEN] = "\0";
  char naname[TMPNAME_LEN] = "\0";
H
Hongze Cheng 已提交
329

330
  for (int32_t level = pTfs->nlevel - 1; level >= 0; level--) {
S
Shengliang Guan 已提交
331
    STfsTier *pTier = TFS_TIER_AT(pTfs, level);
332
    for (int32_t id = pTier->ndisk - 1; id >= 0; id--) {
S
Shengliang Guan 已提交
333
      STfsDisk *pDisk = pTier->disks[id];
S
Shengliang Guan 已提交
334 335
      snprintf(oaname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, orname);
      snprintf(naname, TMPNAME_LEN, "%s%s%s", pDisk->path, TD_DIRSEP, nrname);
S
Shengliang Guan 已提交
336
      if (taosRenameFile(oaname, naname) != 0 && errno != ENOENT) {
S
Shengliang Guan 已提交
337 338
        terrno = TAOS_SYSTEM_ERROR(errno);
        fError("failed to rename %s to %s since %s", oaname, naname, terrstr());
S
Shengliang Guan 已提交
339 340
        return -1;
      }
H
Hongze Cheng 已提交
341 342 343 344 345
    }
  }

  return 0;
}
S
Shengliang Guan 已提交
346

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
int32_t tfsSearch(STfs *pTfs, int32_t level, const char *fname) {
  if (level < 0 || level >= pTfs->nlevel) {
    return -1;
  }
  char      path[TMPNAME_LEN] = {0};
  STfsTier *pTier = TFS_TIER_AT(pTfs, level);

  for (int32_t id = 0; id < pTier->ndisk; id++) {
    STfsDisk *pDisk = pTier->disks[id];
    snprintf(path, TMPNAME_LEN - 1, "%s%s%s", pDisk->path, TD_DIRSEP, fname);
    if (taosCheckExistFile(path)) {
      return id;
    }
  }
  return -1;
}

S
Shengliang Guan 已提交
364
STfsDir *tfsOpendir(STfs *pTfs, const char *rname) {
wafwerar's avatar
wafwerar 已提交
365
  STfsDir *pDir = taosMemoryCalloc(1, sizeof(STfsDir));
S
Shengliang Guan 已提交
366
  if (pDir == NULL) {
367
    terrno = TSDB_CODE_OUT_OF_MEMORY;
H
Hongze Cheng 已提交
368 369 370
    return NULL;
  }

S
Shengliang Guan 已提交
371
  SDiskID diskId = {.id = 0, .level = 0};
S
Shengliang Guan 已提交
372
  pDir->iter.pDisk = TFS_DISK_AT(pTfs, diskId);
S
Shengliang Guan 已提交
373
  pDir->pTfs = pTfs;
C
Cary Xu 已提交
374
  tstrncpy(pDir->dirName, rname, TSDB_FILENAME_LEN);
H
Hongze Cheng 已提交
375

S
Shengliang Guan 已提交
376
  if (tfsOpendirImpl(pTfs, pDir) < 0) {
wafwerar's avatar
wafwerar 已提交
377
    taosMemoryFree(pDir);
H
Hongze Cheng 已提交
378 379 380
    return NULL;
  }

S
Shengliang Guan 已提交
381
  return pDir;
H
Hongze Cheng 已提交
382 383
}

wafwerar's avatar
wafwerar 已提交
384 385
const STfsFile *tfsReaddir(STfsDir *pTfsDir) {
  if (pTfsDir == NULL || pTfsDir->pDir == NULL) return NULL;
S
TD-1207  
Shengliang Guan 已提交
386
  char bname[TMPNAME_LEN * 2] = "\0";
H
Hongze Cheng 已提交
387 388

  while (true) {
wafwerar's avatar
wafwerar 已提交
389 390 391
    TdDirEntryPtr pDirEntry = NULL;
    pDirEntry = taosReadDir(pTfsDir->pDir);
    if (pDirEntry != NULL) {
392
      // Skip . and ..
wafwerar's avatar
wafwerar 已提交
393 394
      char *name = taosGetDirEntryName(pDirEntry);
      if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;
395

C
Cary Xu 已提交
396
      if (pTfsDir->dirName[0] == 0) {
wafwerar's avatar
wafwerar 已提交
397
        snprintf(bname, TMPNAME_LEN * 2, "%s", name);
S
Shengliang Guan 已提交
398
      } else {
C
Cary Xu 已提交
399
        snprintf(bname, TMPNAME_LEN * 2, "%s%s%s", pTfsDir->dirName, TD_DIRSEP, name);
S
Shengliang Guan 已提交
400 401
      }

wafwerar's avatar
wafwerar 已提交
402 403
      tfsInitFile(pTfsDir->pTfs, &pTfsDir->tfile, pTfsDir->did, bname);
      return &pTfsDir->tfile;
H
Hongze Cheng 已提交
404 405
    }

wafwerar's avatar
wafwerar 已提交
406
    if (tfsOpendirImpl(pTfsDir->pTfs, pTfsDir) < 0) {
H
Hongze Cheng 已提交
407 408 409
      return NULL;
    }

wafwerar's avatar
wafwerar 已提交
410
    if (pTfsDir->pDir == NULL) {
H
Hongze Cheng 已提交
411 412 413 414 415 416
      terrno = TSDB_CODE_SUCCESS;
      return NULL;
    }
  }
}

wafwerar's avatar
wafwerar 已提交
417 418 419
void tfsClosedir(STfsDir *pTfsDir) {
  if (pTfsDir) {
    if (pTfsDir->pDir != NULL) {
wafwerar's avatar
wafwerar 已提交
420
      taosCloseDir(&pTfsDir->pDir);
wafwerar's avatar
wafwerar 已提交
421
      pTfsDir->pDir = NULL;
H
Hongze Cheng 已提交
422
    }
wafwerar's avatar
wafwerar 已提交
423
    taosMemoryFree(pTfsDir);
H
Hongze Cheng 已提交
424 425 426
  }
}

S
Shengliang Guan 已提交
427 428 429 430
static int32_t tfsMount(STfs *pTfs, SDiskCfg *pCfg) {
  if (tfsCheckAndFormatCfg(pTfs, pCfg) < 0) {
    return -1;
  }
H
Hongze Cheng 已提交
431

S
Shengliang Guan 已提交
432 433
  SDiskID   did = {.level = pCfg->level};
  STfsDisk *pDisk = tfsMountDiskToTier(TFS_TIER_AT(pTfs, did.level), pCfg);
H
Hongze Cheng 已提交
434
  if (pDisk == NULL) {
S
Shengliang Guan 已提交
435
    fError("failed to mount disk %s to level %d since %s", pCfg->dir, pCfg->level, terrstr());
H
refact  
Hongze Cheng 已提交
436
    return -1;
H
Hongze Cheng 已提交
437
  }
438
  did.id = pDisk->id;
H
Hongze Cheng 已提交
439

S
Shengliang Guan 已提交
440 441 442 443
  taosHashPut(pTfs->hash, (void *)(pCfg->dir), strnlen(pCfg->dir, TSDB_FILENAME_LEN), (void *)(&did), sizeof(did));
  if (pTfs->nlevel < pCfg->level + 1) {
    pTfs->nlevel = pCfg->level + 1;
  }
H
Hongze Cheng 已提交
444 445 446 447

  return 0;
}

S
Shengliang Guan 已提交
448
static int32_t tfsCheckAndFormatCfg(STfs *pTfs, SDiskCfg *pCfg) {
S
shm  
Shengliang Guan 已提交
449
  char dirName[TSDB_FILENAME_LEN] = "\0";
H
Hongze Cheng 已提交
450

S
Shengliang Guan 已提交
451
  if (pCfg->level < 0 || pCfg->level >= TFS_MAX_TIERS) {
H
Hongze Cheng 已提交
452
    fError("failed to mount %s to FS since invalid level %d", pCfg->dir, pCfg->level);
H
Hongze Cheng 已提交
453 454 455 456
    terrno = TSDB_CODE_FS_INVLD_CFG;
    return -1;
  }

H
refact  
Hongze Cheng 已提交
457 458
  if (pCfg->primary) {
    if (pCfg->level != 0) {
H
Hongze Cheng 已提交
459
      fError("failed to mount %s to FS since disk is primary but level %d not 0", pCfg->dir, pCfg->level);
H
refact  
Hongze Cheng 已提交
460 461 462
      terrno = TSDB_CODE_FS_INVLD_CFG;
      return -1;
    }
H
Hongze Cheng 已提交
463

S
Shengliang Guan 已提交
464
    if (TFS_PRIMARY_DISK(pTfs) != NULL) {
H
Hongze Cheng 已提交
465
      fError("failed to mount %s to FS since duplicate primary mount", pCfg->dir);
H
refact  
Hongze Cheng 已提交
466 467 468 469
      terrno = TSDB_CODE_FS_DUP_PRIMARY;
      return -1;
    }
  }
H
Hongze Cheng 已提交
470

H
Hongze Cheng 已提交
471
  if (tfsFormatDir(pCfg->dir, dirName) < 0) {
S
Shengliang Guan 已提交
472
    fError("failed to mount %s to FS since %s", pCfg->dir, terrstr());
H
Hongze Cheng 已提交
473 474 475
    return -1;
  }

S
Shengliang Guan 已提交
476
  if (tfsGetDiskByName(pTfs, dirName) != NULL) {
H
Hongze Cheng 已提交
477
    fError("failed to mount %s to FS since duplicate mount", pCfg->dir);
H
Hongze Cheng 已提交
478 479 480 481
    terrno = TSDB_CODE_FS_INVLD_CFG;
    return -1;
  }

482
  if (!taosCheckAccessFile(dirName, TD_FILE_ACCESS_EXIST_OK | TD_FILE_ACCESS_READ_OK | TD_FILE_ACCESS_WRITE_OK)) {
H
Hongze Cheng 已提交
483
    fError("failed to mount %s to FS since no R/W access rights", pCfg->dir);
H
Hongze Cheng 已提交
484 485 486 487
    terrno = TSDB_CODE_FS_INVLD_CFG;
    return -1;
  }

488
  if (!taosIsDir(dirName)) {
H
Hongze Cheng 已提交
489
    fError("failed to mount %s to FS since not a directory", pCfg->dir);
H
Hongze Cheng 已提交
490 491 492 493 494 495 496 497 498
    terrno = TSDB_CODE_FS_INVLD_CFG;
    return -1;
  }

  strncpy(pCfg->dir, dirName, TSDB_FILENAME_LEN);

  return 0;
}

S
Shengliang Guan 已提交
499
static int32_t tfsFormatDir(char *idir, char *odir) {
H
Hongze Cheng 已提交
500 501
  wordexp_t wep = {0};

S
Shengliang Guan 已提交
502
  int32_t code = wordexp(idir, &wep, 0);
H
Hongze Cheng 已提交
503 504 505 506 507
  if (code != 0) {
    terrno = TAOS_SYSTEM_ERROR(code);
    return -1;
  }

508
  char tmp[PATH_MAX] = {0};
wafwerar's avatar
wafwerar 已提交
509
  if (taosRealPath(wep.we_wordv[0], tmp, PATH_MAX) != 0) {
H
Hongze Cheng 已提交
510 511 512 513
    terrno = TAOS_SYSTEM_ERROR(errno);
    wordfree(&wep);
    return -1;
  }
514
  strcpy(odir, tmp);
H
Hongze Cheng 已提交
515 516 517 518 519

  wordfree(&wep);
  return 0;
}

S
Shengliang Guan 已提交
520 521
static int32_t tfsCheck(STfs *pTfs) {
  if (TFS_PRIMARY_DISK(pTfs) == NULL) {
H
Hongze Cheng 已提交
522 523 524 525 526
    fError("no primary disk is set");
    terrno = TSDB_CODE_FS_NO_PRIMARY_DISK;
    return -1;
  }

S
Shengliang Guan 已提交
527 528
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
    if (TFS_TIER_AT(pTfs, level)->ndisk == 0) {
H
Hongze Cheng 已提交
529
      fError("no disk at level %d", level);
H
refact  
Hongze Cheng 已提交
530
      terrno = TSDB_CODE_FS_NO_MOUNT_AT_TIER;
H
Hongze Cheng 已提交
531 532
      return -1;
    }
H
Hongze Cheng 已提交
533
  }
H
Hongze Cheng 已提交
534

H
Hongze Cheng 已提交
535 536 537
  return 0;
}

S
Shengliang Guan 已提交
538 539
static STfsDisk *tfsGetDiskByName(STfs *pTfs, const char *dir) {
  void *pr = taosHashGet(pTfs->hash, (void *)dir, strnlen(dir, TSDB_FILENAME_LEN));
H
Hongze Cheng 已提交
540 541
  if (pr == NULL) return NULL;

S
Shengliang Guan 已提交
542 543
  SDiskID   did = *(SDiskID *)pr;
  STfsDisk *pDisk = TFS_DISK_AT(pTfs, did);
H
refact  
Hongze Cheng 已提交
544

H
Hongze Cheng 已提交
545
  return pDisk;
H
Hongze Cheng 已提交
546 547
}

wafwerar's avatar
wafwerar 已提交
548
static int32_t tfsOpendirImpl(STfs *pTfs, STfsDir *pTfsDir) {
S
Shengliang Guan 已提交
549 550
  STfsDisk *pDisk = NULL;
  char      adir[TMPNAME_LEN * 2] = "\0";
H
Hongze Cheng 已提交
551

wafwerar's avatar
wafwerar 已提交
552
  if (pTfsDir->pDir != NULL) {
wafwerar's avatar
wafwerar 已提交
553
    taosCloseDir(&pTfsDir->pDir);
wafwerar's avatar
wafwerar 已提交
554
    pTfsDir->pDir = NULL;
H
Hongze Cheng 已提交
555 556 557
  }

  while (true) {
wafwerar's avatar
wafwerar 已提交
558
    pDisk = tfsNextDisk(pTfs, &pTfsDir->iter);
H
Hongze Cheng 已提交
559 560
    if (pDisk == NULL) return 0;

wafwerar's avatar
wafwerar 已提交
561 562
    pTfsDir->did.level = pDisk->level;
    pTfsDir->did.id = pDisk->id;
H
Hongze Cheng 已提交
563

S
Shengliang Guan 已提交
564
    if (pDisk->path == NULL || pDisk->path[0] == 0) {
C
Cary Xu 已提交
565
      snprintf(adir, TMPNAME_LEN * 2, "%s", pTfsDir->dirName);
S
Shengliang Guan 已提交
566
    } else {
C
Cary Xu 已提交
567
      snprintf(adir, TMPNAME_LEN * 2, "%s%s%s", pDisk->path, TD_DIRSEP, pTfsDir->dirName);
S
Shengliang Guan 已提交
568
    }
wafwerar's avatar
wafwerar 已提交
569 570
    pTfsDir->pDir = taosOpenDir(adir);
    if (pTfsDir->pDir != NULL) break;
H
Hongze Cheng 已提交
571 572 573 574 575
  }

  return 0;
}

S
Shengliang Guan 已提交
576 577
static STfsDisk *tfsNextDisk(STfs *pTfs, SDiskIter *pIter) {
  if (pIter == NULL) return NULL;
H
Hongze Cheng 已提交
578

S
Shengliang Guan 已提交
579
  STfsDisk *pDisk = pIter->pDisk;
S
Shengliang Guan 已提交
580 581 582
  if (pDisk == NULL) return NULL;

  SDiskID did = {.level = pDisk->level, .id = pDisk->id + 1};
H
Hongze Cheng 已提交
583

S
Shengliang Guan 已提交
584 585
  if (did.id < TFS_TIER_AT(pTfs, did.level)->ndisk) {
    pIter->pDisk = TFS_DISK_AT(pTfs, did);
H
Hongze Cheng 已提交
586
  } else {
S
Shengliang Guan 已提交
587 588 589 590
    did.level++;
    did.id = 0;
    if (did.level < pTfs->nlevel) {
      pIter->pDisk = TFS_DISK_AT(pTfs, did);
H
Hongze Cheng 已提交
591 592 593 594 595 596 597
    } else {
      pIter->pDisk = NULL;
    }
  }

  return pDisk;
}
S
Shengliang Guan 已提交
598

S
shm  
Shengliang Guan 已提交
599
int32_t tfsGetMonitorInfo(STfs *pTfs, SMonDiskInfo *pInfo) {
S
Shengliang Guan 已提交
600
  pInfo->datadirs = taosArrayInit(32, sizeof(SMonDiskDesc));
S
shm  
Shengliang Guan 已提交
601
  if (pInfo->datadirs == NULL) return -1;
S
Shengliang Guan 已提交
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617

  tfsUpdateSize(pTfs);

  tfsLock(pTfs);
  for (int32_t level = 0; level < pTfs->nlevel; level++) {
    STfsTier *pTier = &pTfs->tiers[level];
    for (int32_t disk = 0; disk < pTier->ndisk; ++disk) {
      STfsDisk    *pDisk = pTier->disks[disk];
      SMonDiskDesc dinfo = {0};
      dinfo.size = pDisk->size;
      dinfo.level = pDisk->level;
      tstrncpy(dinfo.name, pDisk->path, sizeof(dinfo.name));
      taosArrayPush(pInfo->datadirs, &dinfo);
    }
  }
  tfsUnLock(pTfs);
S
shm  
Shengliang Guan 已提交
618 619

  return 0;
620
}