walMeta.c 30.5 KB
Newer Older
L
Liu Jicong 已提交
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/>.
 */

L
Liu Jicong 已提交
16
#include "cJSON.h"
L
Liu Jicong 已提交
17 18
#include "os.h"
#include "taoserror.h"
19
#include "tglobal.h"
L
Liu Jicong 已提交
20
#include "tutil.h"
L
Liu Jicong 已提交
21 22
#include "walInt.h"

23 24 25 26
bool FORCE_INLINE walLogExist(SWal* pWal, int64_t ver) {
  return !walIsEmpty(pWal) && walGetFirstVer(pWal) <= ver && walGetLastVer(pWal) >= ver;
}

27
bool FORCE_INLINE walIsEmpty(SWal* pWal) {
L
Liu Jicong 已提交
28
  return (pWal->vers.firstVer == -1 || pWal->vers.lastVer < pWal->vers.firstVer);  // [firstVer, lastVer + 1)
29
}
L
Liu Jicong 已提交
30

L
Liu Jicong 已提交
31
int64_t FORCE_INLINE walGetFirstVer(SWal* pWal) { return pWal->vers.firstVer; }
L
Liu Jicong 已提交
32

L
Liu Jicong 已提交
33
int64_t FORCE_INLINE walGetSnapshotVer(SWal* pWal) { return pWal->vers.snapshotVer; }
L
Liu Jicong 已提交
34

L
Liu Jicong 已提交
35
int64_t FORCE_INLINE walGetLastVer(SWal* pWal) { return pWal->vers.lastVer; }
L
Liu Jicong 已提交
36

L
Liu Jicong 已提交
37 38
int64_t FORCE_INLINE walGetCommittedVer(SWal* pWal) { return pWal->vers.commitVer; }

L
Liu Jicong 已提交
39 40
int64_t FORCE_INLINE walGetAppliedVer(SWal* pWal) { return pWal->vers.appliedVer; }

41 42 43 44 45 46
static FORCE_INLINE int walBuildMetaName(SWal* pWal, int metaVer, char* buf) {
  return sprintf(buf, "%s/meta-ver%d", pWal->path, metaVer);
}

static FORCE_INLINE int walBuildTmpMetaName(SWal* pWal, char* buf) {
  return sprintf(buf, "%s/meta-ver.tmp", pWal->path);
L
Liu Jicong 已提交
47 48
}

49
static FORCE_INLINE int64_t walScanLogGetLastVer(SWal* pWal, int32_t fileIdx) {
50
  int32_t       sz = taosArrayGetSize(pWal->fileInfoSet);
51
  SWalFileInfo* pFileInfo = taosArrayGet(pWal->fileInfoSet, fileIdx);
L
Liu Jicong 已提交
52
  char          fnameStr[WAL_FILE_LEN];
53
  walBuildLogName(pWal, pFileInfo->firstVer, fnameStr);
L
Liu Jicong 已提交
54

L
Liu Jicong 已提交
55 56
  int64_t fileSize = 0;
  taosStatFile(fnameStr, &fileSize, NULL);
L
Liu Jicong 已提交
57

58
  TdFilePtr pFile = taosOpenFile(fnameStr, TD_FILE_READ | TD_FILE_WRITE);
59
  if (pFile == NULL) {
60
    wError("vgId:%d, failed to open file due to %s. file:%s", pWal->cfg.vgId, strerror(errno), fnameStr);
L
Liu Jicong 已提交
61 62 63 64
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }

65 66 67
  // ensure size as non-negative
  pFileInfo->fileSize = TMAX(0, pFileInfo->fileSize);

68
  int64_t  stepSize = WAL_SCAN_BUF_SIZE;
L
Liu Jicong 已提交
69
  uint64_t magic = WAL_MAGIC;
70 71
  int64_t  walCkHeadSz = sizeof(SWalCkHead);
  int64_t  end = fileSize;
72 73
  int64_t  capacity = 0;
  int64_t  readSize = 0;
74
  char*    buf = NULL;
75
  int64_t  offset = TMIN(pFileInfo->fileSize, fileSize);
76 77 78
  int64_t  retVer = -1;
  int64_t  lastEntryBeginOffset = 0;
  int64_t  lastEntryEndOffset = 0;
79 80
  int64_t  recordLen = 0;
  bool     forwardStage = false;
81

82 83
  // check recover size
  if (2 * tsWalFsyncDataSizeLimit + offset < end) {
84 85 86
    wWarn("vgId:%d, possibly corrupted WAL range exceeds size limit (i.e. %" PRId64 " bytes). offset:%" PRId64
          ", end:%" PRId64 ", file:%s",
          pWal->cfg.vgId, 2 * tsWalFsyncDataSizeLimit, offset, end, fnameStr);
87
  }
88 89 90

  // search for the valid last WAL entry, e.g. block by block
  while (1) {
91
    offset = (lastEntryEndOffset > 0) ? offset : TMAX(0, offset - stepSize + walCkHeadSz - 1);
92 93
    end = TMIN(offset + stepSize, fileSize);

94 95 96 97 98
    readSize = end - offset;
    capacity = readSize + sizeof(magic);

    void* ptr = taosMemoryRealloc(buf, capacity);
    if (ptr == NULL) {
S
Shengliang Guan 已提交
99
      terrno = TSDB_CODE_OUT_OF_MEMORY;
100 101 102
      goto _err;
    }
    buf = ptr;
L
Liu Jicong 已提交
103

104 105 106 107 108 109 110 111 112 113 114 115 116
    int64_t ret = taosLSeekFile(pFile, offset, SEEK_SET);
    if (ret < 0) {
      wError("vgId:%d, failed to lseek file due to %s. offset:%" PRId64 "", pWal->cfg.vgId, strerror(errno), offset);
      terrno = TAOS_SYSTEM_ERROR(errno);
      goto _err;
    }

    if (readSize != taosReadFile(pFile, buf, readSize)) {
      wError("vgId:%d, failed to read file due to %s. readSize:%" PRId64 ", file:%s", pWal->cfg.vgId, strerror(errno),
             readSize, fnameStr);
      terrno = TAOS_SYSTEM_ERROR(errno);
      goto _err;
    }
L
Liu Jicong 已提交
117

118 119
    char*       candidate = NULL;
    char*       haystack = buf;
120 121
    int64_t     pos = 0;
    SWalCkHead* logContent = NULL;
122

123 124 125 126 127 128 129 130 131 132
    while (true) {
      forwardStage = (lastEntryEndOffset > 0 || offset == 0);
      terrno = TSDB_CODE_SUCCESS;
      if (forwardStage) {
        candidate = (readSize - (haystack - buf)) > 0 ? haystack : NULL;
      } else {
        candidate = tmemmem(haystack, readSize - (haystack - buf), (char*)&magic, sizeof(magic));
      }

      if (candidate == NULL) break;
133 134
      pos = candidate - buf;

135
      // validate head
136
      int64_t len = readSize - pos;
137
      if (len < walCkHeadSz) {
138
        break;
139
      }
140

141
      logContent = (SWalCkHead*)(buf + pos);
142
      if (walValidHeadCksum(logContent) != 0) {
143
        terrno = TSDB_CODE_WAL_CHKSUM_MISMATCH;
144
        wWarn("vgId:%d, failed to validate checksum of wal entry header. offset:%" PRId64 ", file:%s", pWal->cfg.vgId,
145 146
              offset + pos, fnameStr);
        haystack = buf + pos + 1;
147
        if (forwardStage) {
148 149 150 151 152 153 154
          break;
        } else {
          continue;
        }
      }

      // validate body
155 156 157
      recordLen = walCkHeadSz + logContent->head.bodyLen;
      if (len < recordLen) {
        int64_t extraSize = recordLen - len;
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
        if (capacity < readSize + extraSize + sizeof(magic)) {
          capacity += extraSize;
          void* ptr = taosMemoryRealloc(buf, capacity);
          if (ptr == NULL) {
            terrno = TSDB_CODE_OUT_OF_MEMORY;
            goto _err;
          }
          buf = ptr;
        }
        int64_t ret = taosLSeekFile(pFile, offset + readSize, SEEK_SET);
        if (ret < 0) {
          wError("vgId:%d, failed to lseek file due to %s. offset:%" PRId64 "", pWal->cfg.vgId, strerror(errno),
                 offset);
          terrno = TAOS_SYSTEM_ERROR(errno);
          break;
        }
        if (extraSize != taosReadFile(pFile, buf + readSize, extraSize)) {
          wError("vgId:%d, failed to read file due to %s. offset:%" PRId64 ", extraSize:%" PRId64 ", file:%s",
                 pWal->cfg.vgId, strerror(errno), offset + readSize, extraSize, fnameStr);
          terrno = TAOS_SYSTEM_ERROR(errno);
          break;
        }
180
      }
181 182

      logContent = (SWalCkHead*)(buf + pos);
183 184
      if (walValidBodyCksum(logContent) != 0) {
        terrno = TSDB_CODE_WAL_CHKSUM_MISMATCH;
185
        wWarn("vgId:%d, failed to validate checksum of wal entry body. offset:%" PRId64 ", file:%s", pWal->cfg.vgId,
186 187
              offset + pos, fnameStr);
        haystack = buf + pos + 1;
188
        if (forwardStage) {
189 190 191 192 193 194 195
          break;
        } else {
          continue;
        }
      }

      // found one
196 197
      retVer = logContent->head.version;
      lastEntryBeginOffset = offset + pos;
198
      lastEntryEndOffset = offset + pos + recordLen;
199 200

      // try next
201
      haystack = buf + pos + recordLen;
L
Liu Jicong 已提交
202
    }
203

204 205
    offset = (lastEntryEndOffset > 0) ? lastEntryEndOffset : offset;
    if (forwardStage && (terrno != TSDB_CODE_SUCCESS || end == fileSize)) break;
206 207
  }

208
  if (retVer < 0) {
209
    terrno = TSDB_CODE_WAL_LOG_NOT_EXIST;
L
Liu Jicong 已提交
210
  }
L
Liu Jicong 已提交
211 212 213

  // truncate file
  if (lastEntryEndOffset != fileSize) {
214 215
    wWarn("vgId:%d, repair meta truncate file %s to %" PRId64 ", orig size %" PRId64, pWal->cfg.vgId, fnameStr,
          lastEntryEndOffset, fileSize);
216

217
    if (taosFtruncateFile(pFile, lastEntryEndOffset) < 0) {
218 219 220
      wError("failed to truncate file due to %s. file:%s", strerror(errno), fnameStr);
      terrno = TAOS_SYSTEM_ERROR(errno);
      goto _err;
221
    }
222

223
    if (taosFsyncFile(pFile) < 0) {
224 225 226
      wError("failed to fsync file due to %s. file:%s", strerror(errno), fnameStr);
      terrno = TAOS_SYSTEM_ERROR(errno);
      goto _err;
227
    }
L
Liu Jicong 已提交
228
  }
229

230
  pFileInfo->fileSize = lastEntryEndOffset;
L
Liu Jicong 已提交
231

232 233
  taosCloseFile(&pFile);
  taosMemoryFree(buf);
L
Liu Jicong 已提交
234
  return retVer;
235 236 237 238 239

_err:
  taosCloseFile(&pFile);
  taosMemoryFree(buf);
  return -1;
L
Liu Jicong 已提交
240 241
}

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
static void walRebuildFileInfoSet(SArray* metaLogList, SArray* actualLogList) {
  int metaFileNum = taosArrayGetSize(metaLogList);
  int actualFileNum = taosArrayGetSize(actualLogList);
  int j = 0;

  // both of the lists in asc order
  for (int i = 0; i < actualFileNum; i++) {
    SWalFileInfo* pLogInfo = taosArrayGet(actualLogList, i);
    while (j < metaFileNum) {
      SWalFileInfo* pMetaInfo = taosArrayGet(metaLogList, j);
      if (pMetaInfo->firstVer < pLogInfo->firstVer) {
        j++;
      } else if (pMetaInfo->firstVer == pLogInfo->firstVer) {
        (*pLogInfo) = *pMetaInfo;
        j++;
        break;
      } else {
        break;
      }
    }
  }

  taosArrayClear(metaLogList);

  for (int i = 0; i < actualFileNum; i++) {
    SWalFileInfo* pFileInfo = taosArrayGet(actualLogList, i);
    taosArrayPush(metaLogList, pFileInfo);
  }
}

void walAlignVersions(SWal* pWal) {
273 274
  if (pWal->vers.firstVer > pWal->vers.snapshotVer + 1) {
    wWarn("vgId:%d, firstVer:%" PRId64 " is larger than snapshotVer:%" PRId64 " + 1. align with it.", pWal->cfg.vgId,
275
          pWal->vers.firstVer, pWal->vers.snapshotVer);
276
    pWal->vers.firstVer = pWal->vers.snapshotVer + 1;
277 278
  }
  if (pWal->vers.lastVer < pWal->vers.snapshotVer) {
279
    wWarn("vgId:%d, lastVer:%" PRId64 " is less than snapshotVer:%" PRId64 ". align with it.", pWal->cfg.vgId,
280
          pWal->vers.lastVer, pWal->vers.snapshotVer);
281 282 283
    if (pWal->vers.lastVer < pWal->vers.firstVer) {
      pWal->vers.firstVer = pWal->vers.snapshotVer + 1;
    }
284 285
    pWal->vers.lastVer = pWal->vers.snapshotVer;
  }
286 287 288
  // reset commitVer and appliedVer
  pWal->vers.commitVer = pWal->vers.snapshotVer;
  pWal->vers.appliedVer = pWal->vers.snapshotVer;
289
  wInfo("vgId:%d, reset commitVer to %" PRId64, pWal->cfg.vgId, pWal->vers.commitVer);
290 291
}

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
int walRepairLogFileTs(SWal* pWal, bool* updateMeta) {
  int32_t sz = taosArrayGetSize(pWal->fileInfoSet);
  int32_t fileIdx = -1;
  int32_t lastCloseTs = 0;
  char    fnameStr[WAL_FILE_LEN] = {0};

  while (++fileIdx < sz - 1) {
    SWalFileInfo* pFileInfo = taosArrayGet(pWal->fileInfoSet, fileIdx);
    if (pFileInfo->closeTs != -1) {
      lastCloseTs = pFileInfo->closeTs;
      continue;
    }

    walBuildLogName(pWal, pFileInfo->firstVer, fnameStr);
    int32_t mtime = 0;
    if (taosStatFile(fnameStr, NULL, &mtime) < 0) {
      terrno = TAOS_SYSTEM_ERROR(errno);
      wError("vgId:%d, failed to stat file due to %s, file:%s", pWal->cfg.vgId, strerror(errno), fnameStr);
      return -1;
    }

    if (updateMeta != NULL) *updateMeta = true;
    if (pFileInfo->createTs == -1) pFileInfo->createTs = lastCloseTs;
    pFileInfo->closeTs = mtime;
    lastCloseTs = pFileInfo->closeTs;
  }

  return 0;
}

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
bool walLogEntriesComplete(const SWal* pWal) {
  int32_t sz = taosArrayGetSize(pWal->fileInfoSet);
  bool    complete = true;
  int32_t fileIdx = -1;
  int64_t index = pWal->vers.firstVer;

  while (++fileIdx < sz) {
    SWalFileInfo* pFileInfo = taosArrayGet(pWal->fileInfoSet, fileIdx);
    if (pFileInfo->firstVer != index) {
      break;
    }
    index = pFileInfo->lastVer + ((fileIdx + 1 < sz) ? 1 : 0);
  }
  // empty is regarded as complete
  if (sz != 0) {
    complete = (index == pWal->vers.lastVer);
  }

  if (!complete) {
    wError("vgId:%d, WAL log entries incomplete in range [%" PRId64 ", %" PRId64 "], aligned with snaphotVer:%" PRId64,
           pWal->cfg.vgId, pWal->vers.firstVer, pWal->vers.lastVer, pWal->vers.snapshotVer);
    terrno = TSDB_CODE_WAL_LOG_INCOMPLETE;
  }

  return complete;
}

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
int walTrimIdxFile(SWal* pWal, int32_t fileIdx) {
  SWalFileInfo* pFileInfo = taosArrayGet(pWal->fileInfoSet, fileIdx);
  ASSERT(pFileInfo != NULL);
  char fnameStr[WAL_FILE_LEN];
  walBuildIdxName(pWal, pFileInfo->firstVer, fnameStr);

  int64_t fileSize = 0;
  taosStatFile(fnameStr, &fileSize, NULL);
  int64_t records = TMAX(0, pFileInfo->lastVer - pFileInfo->firstVer + 1);
  int64_t lastEndOffset = records * sizeof(SWalIdxEntry);

  if (fileSize <= lastEndOffset) {
    return 0;
  }

  TdFilePtr pFile = taosOpenFile(fnameStr, TD_FILE_READ | TD_FILE_WRITE);
  if (pFile == NULL) {
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }

  wInfo("vgId:%d, trim idx file. file: %s, size: %" PRId64 ", offset: %" PRId64, pWal->cfg.vgId, fnameStr, fileSize,
        lastEndOffset);

  taosFtruncateFile(pFile, lastEndOffset);
  taosCloseFile(&pFile);
  return 0;
}

L
Liu Jicong 已提交
378 379 380 381
int walCheckAndRepairMeta(SWal* pWal) {
  // load log files, get first/snapshot/last version info
  const char* logPattern = "^[0-9]+.log$";
  const char* idxPattern = "^[0-9]+.idx$";
L
Liu Jicong 已提交
382 383
  regex_t     logRegPattern;
  regex_t     idxRegPattern;
L
Liu Jicong 已提交
384 385 386

  regcomp(&logRegPattern, logPattern, REG_EXTENDED);
  regcomp(&idxRegPattern, idxPattern, REG_EXTENDED);
L
Liu Jicong 已提交
387

wafwerar's avatar
wafwerar 已提交
388 389
  TdDirPtr pDir = taosOpenDir(pWal->path);
  if (pDir == NULL) {
L
Liu Jicong 已提交
390 391
    regfree(&logRegPattern);
    regfree(&idxRegPattern);
L
Liu Jicong 已提交
392 393 394 395
    wError("vgId:%d, path:%s, failed to open since %s", pWal->cfg.vgId, pWal->path, strerror(errno));
    return -1;
  }

396 397
  SArray* actualLog = taosArrayInit(8, sizeof(SWalFileInfo));

L
Liu Jicong 已提交
398
  // scan log files and build new meta
wafwerar's avatar
wafwerar 已提交
399 400 401
  TdDirEntryPtr pDirEntry;
  while ((pDirEntry = taosReadDir(pDir)) != NULL) {
    char* name = taosDirEntryBaseName(taosGetDirEntryName(pDirEntry));
L
Liu Jicong 已提交
402 403
    int   code = regexec(&logRegPattern, name, 0, NULL, 0);
    if (code == 0) {
L
Liu Jicong 已提交
404 405 406
      SWalFileInfo fileInfo;
      memset(&fileInfo, -1, sizeof(SWalFileInfo));
      sscanf(name, "%" PRId64 ".log", &fileInfo.firstVer);
407
      taosArrayPush(actualLog, &fileInfo);
L
Liu Jicong 已提交
408 409 410
    }
  }

wafwerar's avatar
wafwerar 已提交
411
  taosCloseDir(&pDir);
L
Liu Jicong 已提交
412 413 414
  regfree(&logRegPattern);
  regfree(&idxRegPattern);

415
  taosArraySort(actualLog, compareWalFileInfo);
L
Liu Jicong 已提交
416

417 418 419 420 421 422 423 424 425 426 427 428
  int     metaFileNum = taosArrayGetSize(pWal->fileInfoSet);
  int     actualFileNum = taosArrayGetSize(actualLog);
  int64_t firstVerPrev = pWal->vers.firstVer;
  int64_t lastVerPrev = pWal->vers.lastVer;
  int64_t totSize = 0;
  bool    updateMeta = (metaFileNum != actualFileNum);

  // rebuild meta of file info
  walRebuildFileInfoSet(pWal->fileInfoSet, actualLog);
  taosArrayDestroy(actualLog);

  int32_t sz = taosArrayGetSize(pWal->fileInfoSet);
L
Liu Jicong 已提交
429

430 431 432 433
  // scan and determine the lastVer
  int32_t fileIdx = sz;

  while (--fileIdx >= 0) {
L
Liu Jicong 已提交
434
    char          fnameStr[WAL_FILE_LEN];
435 436 437
    int64_t       fileSize = 0;
    SWalFileInfo* pFileInfo = taosArrayGet(pWal->fileInfoSet, fileIdx);

L
Liu Jicong 已提交
438
    walBuildLogName(pWal, pFileInfo->firstVer, fnameStr);
439 440 441 442 443
    int32_t code = taosStatFile(fnameStr, &fileSize, NULL);
    if (code < 0) {
      terrno = TAOS_SYSTEM_ERROR(errno);
      wError("failed to stat file since %s. file:%s", terrstr(), fnameStr);
      return -1;
L
Liu Jicong 已提交
444 445
    }

446 447 448
    if (pFileInfo->lastVer >= pFileInfo->firstVer && fileSize == pFileInfo->fileSize) {
      totSize += pFileInfo->fileSize;
      continue;
L
Liu Jicong 已提交
449
    }
450
    updateMeta = true;
L
Liu Jicong 已提交
451

452 453
    (void)walTrimIdxFile(pWal, fileIdx);

454 455 456 457 458
    int64_t lastVer = walScanLogGetLastVer(pWal, fileIdx);
    if (lastVer < 0) {
      if (terrno != TSDB_CODE_WAL_LOG_NOT_EXIST) {
        wError("failed to scan wal last ver since %s", terrstr());
        return -1;
L
Liu Jicong 已提交
459
      }
460 461
      // empty log file
      lastVer = pFileInfo->firstVer - 1;
L
Liu Jicong 已提交
462 463
    }

464 465 466
    // update lastVer
    pFileInfo->lastVer = lastVer;
    totSize += pFileInfo->fileSize;
L
Liu Jicong 已提交
467
  }
L
Liu Jicong 已提交
468

469
  // reset vers info and so on
L
Liu Jicong 已提交
470
  actualFileNum = taosArrayGetSize(pWal->fileInfoSet);
L
Liu Jicong 已提交
471
  pWal->writeCur = actualFileNum - 1;
472 473
  pWal->totSize = totSize;
  pWal->vers.lastVer = -1;
L
Liu Jicong 已提交
474
  if (actualFileNum > 0) {
475 476
    pWal->vers.firstVer = ((SWalFileInfo*)taosArrayGet(pWal->fileInfoSet, 0))->firstVer;
    pWal->vers.lastVer = ((SWalFileInfo*)taosArrayGetLast(pWal->fileInfoSet))->lastVer;
L
Liu Jicong 已提交
477
  }
478
  (void)walAlignVersions(pWal);
L
Liu Jicong 已提交
479

480 481 482 483 484
  // repair ts of files
  if (walRepairLogFileTs(pWal, &updateMeta) < 0) {
    return -1;
  }

485 486 487 488
  // update meta file
  if (updateMeta) {
    (void)walSaveMeta(pWal);
  }
489 490 491 492 493

  if (!walLogEntriesComplete(pWal)) {
    return -1;
  }

494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
  return 0;
}

int walReadLogHead(TdFilePtr pLogFile, int64_t offset, SWalCkHead* pCkHead) {
  if (taosLSeekFile(pLogFile, offset, SEEK_SET) < 0) {
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }

  if (taosReadFile(pLogFile, pCkHead, sizeof(SWalCkHead)) != sizeof(SWalCkHead)) {
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }

  if (walValidHeadCksum(pCkHead) != 0) {
    terrno = TSDB_CODE_WAL_CHKSUM_MISMATCH;
    return -1;
L
Liu Jicong 已提交
511 512
  }

L
Liu Jicong 已提交
513 514 515
  return 0;
}

516
int walCheckAndRepairIdxFile(SWal* pWal, int32_t fileIdx) {
L
Liu Jicong 已提交
517
  int32_t       sz = taosArrayGetSize(pWal->fileInfoSet);
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
  SWalFileInfo* pFileInfo = taosArrayGet(pWal->fileInfoSet, fileIdx);
  char          fnameStr[WAL_FILE_LEN];
  walBuildIdxName(pWal, pFileInfo->firstVer, fnameStr);
  char fLogNameStr[WAL_FILE_LEN];
  walBuildLogName(pWal, pFileInfo->firstVer, fLogNameStr);
  int64_t fileSize = 0;

  if (taosStatFile(fnameStr, &fileSize, NULL) < 0 && errno != ENOENT) {
    wError("vgId:%d, failed to stat file due to %s. file:%s", pWal->cfg.vgId, strerror(errno), fnameStr);
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }

  if (fileSize == (pFileInfo->lastVer - pFileInfo->firstVer + 1) * sizeof(SWalIdxEntry)) {
    return 0;
  }

  // start to repair
  int64_t      offset = fileSize - fileSize % sizeof(SWalIdxEntry);
  TdFilePtr    pLogFile = NULL;
  TdFilePtr    pIdxFile = NULL;
  SWalIdxEntry idxEntry = {.ver = pFileInfo->firstVer - 1, .offset = -sizeof(SWalCkHead)};
  SWalCkHead   ckHead;
  memset(&ckHead, 0, sizeof(ckHead));
  ckHead.head.version = idxEntry.ver;

  pIdxFile = taosOpenFile(fnameStr, TD_FILE_READ | TD_FILE_WRITE | TD_FILE_CREATE);
  if (pIdxFile == NULL) {
    wError("vgId:%d, failed to open file due to %s. file:%s", pWal->cfg.vgId, strerror(errno), fnameStr);
    terrno = TAOS_SYSTEM_ERROR(errno);
    goto _err;
  }

  pLogFile = taosOpenFile(fLogNameStr, TD_FILE_READ);
  if (pLogFile == NULL) {
    terrno = TAOS_SYSTEM_ERROR(errno);
    wError("vgId:%d, cannot open file %s, since %s", pWal->cfg.vgId, fLogNameStr, terrstr());
    goto _err;
  }

  // determine the last valid entry end, i.e. offset
  while ((offset -= sizeof(SWalIdxEntry)) >= 0) {
    if (taosLSeekFile(pIdxFile, offset, SEEK_SET) < 0) {
561
      wError("vgId:%d, failed to seek file due to %s. offset:%" PRId64 ", file:%s", pWal->cfg.vgId, strerror(errno),
562
             offset, fnameStr);
L
Liu Jicong 已提交
563
      terrno = TAOS_SYSTEM_ERROR(errno);
564 565 566 567 568 569 570 571
      goto _err;
    }

    if (taosReadFile(pIdxFile, &idxEntry, sizeof(SWalIdxEntry)) != sizeof(SWalIdxEntry)) {
      wError("vgId:%d, failed to read file due to %s. offset:%" PRId64 ", file:%s", pWal->cfg.vgId, strerror(errno),
             offset, fnameStr);
      terrno = TAOS_SYSTEM_ERROR(errno);
      goto _err;
L
Liu Jicong 已提交
572 573
    }

574
    if (idxEntry.ver > pFileInfo->lastVer) {
L
Liu Jicong 已提交
575 576
      continue;
    }
L
Liu Jicong 已提交
577

578 579 580 581
    if (offset != (idxEntry.ver - pFileInfo->firstVer) * sizeof(SWalIdxEntry)) {
      continue;
    }

582 583 584 585
    if (walReadLogHead(pLogFile, idxEntry.offset, &ckHead) < 0) {
      wWarn("vgId:%d, failed to read log file since %s. file:%s, offset:%" PRId64 ", idx entry ver:%" PRId64 "",
            pWal->cfg.vgId, terrstr(), fLogNameStr, idxEntry.offset, idxEntry.ver);
      continue;
L
Liu Jicong 已提交
586 587
    }

588 589
    if (idxEntry.ver == ckHead.head.version) {
      break;
L
Liu Jicong 已提交
590
    }
591 592
  }
  offset += sizeof(SWalIdxEntry);
L
Liu Jicong 已提交
593

L
Liu Jicong 已提交
594
  /*A(offset == (idxEntry.ver - pFileInfo->firstVer + 1) * sizeof(SWalIdxEntry));*/
595

596 597 598 599 600 601 602 603 604 605 606 607
  // ftruncate idx file
  if (offset < fileSize) {
    if (taosFtruncateFile(pIdxFile, offset) < 0) {
      wError("vgId:%d, failed to ftruncate file due to %s. offset:%" PRId64 ", file:%s", pWal->cfg.vgId,
             strerror(errno), offset, fnameStr);
      terrno = TAOS_SYSTEM_ERROR(errno);
      goto _err;
    }
  }

  // rebuild idx file
  if (taosLSeekFile(pIdxFile, 0, SEEK_END) < 0) {
608
    wError("vgId:%d, failed to seek file due to %s. offset:%" PRId64 ", file:%s", pWal->cfg.vgId, strerror(errno),
609 610 611 612 613
           offset, fnameStr);
    terrno = TAOS_SYSTEM_ERROR(errno);
    goto _err;
  }

614
  int64_t count = 0;
615
  while (idxEntry.ver < pFileInfo->lastVer) {
L
Liu Jicong 已提交
616
    /*A(idxEntry.ver == ckHead.head.version);*/
617 618 619 620 621 622 623 624 625 626 627 628 629

    idxEntry.ver += 1;
    idxEntry.offset += sizeof(SWalCkHead) + ckHead.head.bodyLen;

    if (walReadLogHead(pLogFile, idxEntry.offset, &ckHead) < 0) {
      wError("vgId:%d, failed to read wal log head since %s. offset:%" PRId64 ", file:%s", pWal->cfg.vgId, terrstr(),
             idxEntry.offset, fLogNameStr);
      goto _err;
    }
    if (taosWriteFile(pIdxFile, &idxEntry, sizeof(SWalIdxEntry)) < 0) {
      wError("vgId:%d, failed to append file since %s. file:%s", pWal->cfg.vgId, terrstr(), fnameStr);
      goto _err;
    }
630
    count++;
631 632 633 634 635 636 637
  }

  if (taosFsyncFile(pIdxFile) < 0) {
    wError("vgId:%d, faild to fsync file since %s. file:%s", pWal->cfg.vgId, terrstr(), fnameStr);
    goto _err;
  }

638 639 640 641 642
  if (count > 0) {
    wInfo("vgId:%d, rebuilt %" PRId64 " wal idx entries until lastVer: %" PRId64, pWal->cfg.vgId, count,
          pFileInfo->lastVer);
  }

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
  (void)taosCloseFile(&pLogFile);
  (void)taosCloseFile(&pIdxFile);
  return 0;

_err:
  (void)taosCloseFile(&pLogFile);
  (void)taosCloseFile(&pIdxFile);
  return -1;
}

int walCheckAndRepairIdx(SWal* pWal) {
  int32_t sz = taosArrayGetSize(pWal->fileInfoSet);
  int32_t fileIdx = sz;
  while (--fileIdx >= 0) {
    if (walCheckAndRepairIdxFile(pWal, fileIdx) < 0) {
      wError("vgId:%d, failed to repair idx file since %s. fileIdx:%d", pWal->cfg.vgId, terrstr(), fileIdx);
      return -1;
L
Liu Jicong 已提交
660 661
    }
  }
L
Liu Jicong 已提交
662 663 664
  return 0;
}

L
Liu Jicong 已提交
665 666 667 668
int walRollFileInfo(SWal* pWal) {
  int64_t ts = taosGetTimestampSec();

  SArray* pArray = pWal->fileInfoSet;
L
Liu Jicong 已提交
669
  if (taosArrayGetSize(pArray) != 0) {
L
Liu Jicong 已提交
670
    SWalFileInfo* pInfo = taosArrayGetLast(pArray);
L
Liu Jicong 已提交
671
    pInfo->lastVer = pWal->vers.lastVer;
L
Liu Jicong 已提交
672 673 674
    pInfo->closeTs = ts;
  }

L
Liu Jicong 已提交
675
  // TODO: change to emplace back
wafwerar's avatar
wafwerar 已提交
676
  SWalFileInfo* pNewInfo = taosMemoryMalloc(sizeof(SWalFileInfo));
L
Liu Jicong 已提交
677
  if (pNewInfo == NULL) {
S
Shengliang Guan 已提交
678
    terrno = TSDB_CODE_OUT_OF_MEMORY;
L
Liu Jicong 已提交
679 680
    return -1;
  }
L
Liu Jicong 已提交
681
  pNewInfo->firstVer = pWal->vers.lastVer + 1;
L
Liu Jicong 已提交
682 683 684 685
  pNewInfo->lastVer = -1;
  pNewInfo->createTs = ts;
  pNewInfo->closeTs = -1;
  pNewInfo->fileSize = 0;
686
  pNewInfo->syncedOffset = 0;
L
Liu Jicong 已提交
687
  taosArrayPush(pArray, pNewInfo);
wafwerar's avatar
wafwerar 已提交
688
  taosMemoryFree(pNewInfo);
L
Liu Jicong 已提交
689 690 691
  return 0;
}

692
char* walMetaSerialize(SWal* pWal) {
L
Liu Jicong 已提交
693
  char   buf[30];
L
Liu Jicong 已提交
694
  int    sz = taosArrayGetSize(pWal->fileInfoSet);
695 696 697 698
  cJSON* pRoot = cJSON_CreateObject();
  cJSON* pMeta = cJSON_CreateObject();
  cJSON* pFiles = cJSON_CreateArray();
  cJSON* pField;
L
Liu Jicong 已提交
699
  if (pRoot == NULL || pMeta == NULL || pFiles == NULL) {
L
Liu Jicong 已提交
700
    if (pRoot) {
L
Liu Jicong 已提交
701 702
      cJSON_Delete(pRoot);
    }
L
Liu Jicong 已提交
703
    if (pMeta) {
L
Liu Jicong 已提交
704 705
      cJSON_Delete(pMeta);
    }
L
Liu Jicong 已提交
706
    if (pFiles) {
L
Liu Jicong 已提交
707 708
      cJSON_Delete(pFiles);
    }
S
Shengliang Guan 已提交
709
    terrno = TSDB_CODE_OUT_OF_MEMORY;
L
Liu Jicong 已提交
710 711
    return NULL;
  }
712
  cJSON_AddItemToObject(pRoot, "meta", pMeta);
L
Liu Jicong 已提交
713
  sprintf(buf, "%" PRId64, pWal->vers.firstVer);
714
  cJSON_AddStringToObject(pMeta, "firstVer", buf);
L
Liu Jicong 已提交
715
  sprintf(buf, "%" PRId64, pWal->vers.snapshotVer);
716
  cJSON_AddStringToObject(pMeta, "snapshotVer", buf);
L
Liu Jicong 已提交
717
  sprintf(buf, "%" PRId64, pWal->vers.commitVer);
718
  cJSON_AddStringToObject(pMeta, "commitVer", buf);
L
Liu Jicong 已提交
719
  sprintf(buf, "%" PRId64, pWal->vers.lastVer);
720 721 722
  cJSON_AddStringToObject(pMeta, "lastVer", buf);

  cJSON_AddItemToObject(pRoot, "files", pFiles);
L
Liu Jicong 已提交
723
  SWalFileInfo* pData = pWal->fileInfoSet->pData;
L
Liu Jicong 已提交
724
  for (int i = 0; i < sz; i++) {
L
Liu Jicong 已提交
725
    SWalFileInfo* pInfo = &pData[i];
726
    cJSON_AddItemToArray(pFiles, pField = cJSON_CreateObject());
L
Liu Jicong 已提交
727
    if (pField == NULL) {
728
      cJSON_Delete(pRoot);
L
Liu Jicong 已提交
729 730
      return NULL;
    }
L
Liu Jicong 已提交
731 732
    // cjson only support int32_t or double
    // string are used to prohibit the loss of precision
733 734 735 736 737 738 739 740 741 742
    sprintf(buf, "%" PRId64, pInfo->firstVer);
    cJSON_AddStringToObject(pField, "firstVer", buf);
    sprintf(buf, "%" PRId64, pInfo->lastVer);
    cJSON_AddStringToObject(pField, "lastVer", buf);
    sprintf(buf, "%" PRId64, pInfo->createTs);
    cJSON_AddStringToObject(pField, "createTs", buf);
    sprintf(buf, "%" PRId64, pInfo->closeTs);
    cJSON_AddStringToObject(pField, "closeTs", buf);
    sprintf(buf, "%" PRId64, pInfo->fileSize);
    cJSON_AddStringToObject(pField, "fileSize", buf);
L
Liu Jicong 已提交
743
  }
L
Liu Jicong 已提交
744 745 746
  char* serialized = cJSON_Print(pRoot);
  cJSON_Delete(pRoot);
  return serialized;
L
Liu Jicong 已提交
747 748
}

749
int walMetaDeserialize(SWal* pWal, const char* bytes) {
L
Liu Jicong 已提交
750
  /*A(taosArrayGetSize(pWal->fileInfoSet) == 0);*/
751 752
  cJSON *pRoot, *pMeta, *pFiles, *pInfoJson, *pField;
  pRoot = cJSON_Parse(bytes);
753
  if (!pRoot) goto _err;
754
  pMeta = cJSON_GetObjectItem(pRoot, "meta");
755
  if (!pMeta) goto _err;
756
  pField = cJSON_GetObjectItem(pMeta, "firstVer");
757
  if (!pField) goto _err;
L
Liu Jicong 已提交
758
  pWal->vers.firstVer = atoll(cJSON_GetStringValue(pField));
759
  pField = cJSON_GetObjectItem(pMeta, "snapshotVer");
760
  if (!pField) goto _err;
L
Liu Jicong 已提交
761
  pWal->vers.snapshotVer = atoll(cJSON_GetStringValue(pField));
762
  pField = cJSON_GetObjectItem(pMeta, "commitVer");
763
  if (!pField) goto _err;
L
Liu Jicong 已提交
764
  pWal->vers.commitVer = atoll(cJSON_GetStringValue(pField));
765
  pField = cJSON_GetObjectItem(pMeta, "lastVer");
766
  if (!pField) goto _err;
L
Liu Jicong 已提交
767
  pWal->vers.lastVer = atoll(cJSON_GetStringValue(pField));
768 769 770

  pFiles = cJSON_GetObjectItem(pRoot, "files");
  int sz = cJSON_GetArraySize(pFiles);
L
Liu Jicong 已提交
771
  // deserialize
L
Liu Jicong 已提交
772 773
  SArray* pArray = pWal->fileInfoSet;
  taosArrayEnsureCap(pArray, sz);
774

L
Liu Jicong 已提交
775
  for (int i = 0; i < sz; i++) {
776
    pInfoJson = cJSON_GetArrayItem(pFiles, i);
777
    if (!pInfoJson) goto _err;
778 779 780

    SWalFileInfo info = {0};

L
Liu Jicong 已提交
781
    pField = cJSON_GetObjectItem(pInfoJson, "firstVer");
782
    if (!pField) goto _err;
783
    info.firstVer = atoll(cJSON_GetStringValue(pField));
L
Liu Jicong 已提交
784
    pField = cJSON_GetObjectItem(pInfoJson, "lastVer");
785
    if (!pField) goto _err;
786
    info.lastVer = atoll(cJSON_GetStringValue(pField));
L
Liu Jicong 已提交
787
    pField = cJSON_GetObjectItem(pInfoJson, "createTs");
788
    if (!pField) goto _err;
789
    info.createTs = atoll(cJSON_GetStringValue(pField));
L
Liu Jicong 已提交
790
    pField = cJSON_GetObjectItem(pInfoJson, "closeTs");
791
    if (!pField) goto _err;
792
    info.closeTs = atoll(cJSON_GetStringValue(pField));
L
Liu Jicong 已提交
793
    pField = cJSON_GetObjectItem(pInfoJson, "fileSize");
794
    if (!pField) goto _err;
795 796
    info.fileSize = atoll(cJSON_GetStringValue(pField));
    taosArrayPush(pArray, &info);
L
Liu Jicong 已提交
797
  }
798
  pWal->fileInfoSet = pArray;
L
Liu Jicong 已提交
799
  pWal->writeCur = sz - 1;
L
Liu Jicong 已提交
800
  cJSON_Delete(pRoot);
801
  return 0;
802 803 804 805

_err:
  cJSON_Delete(pRoot);
  return -1;
L
Liu Jicong 已提交
806 807 808
}

static int walFindCurMetaVer(SWal* pWal) {
L
Liu Jicong 已提交
809 810
  const char* pattern = "^meta-ver[0-9]+$";
  regex_t     walMetaRegexPattern;
L
Liu Jicong 已提交
811 812
  regcomp(&walMetaRegexPattern, pattern, REG_EXTENDED);

wafwerar's avatar
wafwerar 已提交
813 814
  TdDirPtr pDir = taosOpenDir(pWal->path);
  if (pDir == NULL) {
L
Liu Jicong 已提交
815
    wError("vgId:%d, path:%s, failed to open since %s", pWal->cfg.vgId, pWal->path, strerror(errno));
L
Liu Jicong 已提交
816 817 818
    return -1;
  }

wafwerar's avatar
wafwerar 已提交
819
  TdDirEntryPtr pDirEntry;
L
Liu Jicong 已提交
820

L
Liu Jicong 已提交
821
  // find existing meta-ver[x].json
L
Liu Jicong 已提交
822
  int metaVer = -1;
wafwerar's avatar
wafwerar 已提交
823 824
  while ((pDirEntry = taosReadDir(pDir)) != NULL) {
    char* name = taosDirEntryBaseName(taosGetDirEntryName(pDirEntry));
L
Liu Jicong 已提交
825 826
    int   code = regexec(&walMetaRegexPattern, name, 0, NULL, 0);
    if (code == 0) {
L
Liu Jicong 已提交
827
      sscanf(name, "meta-ver%d", &metaVer);
L
Liu Jicong 已提交
828
      wDebug("vgId:%d, wal find current meta: %s is the meta file, ver %d", pWal->cfg.vgId, name, metaVer);
L
Liu Jicong 已提交
829 830
      break;
    }
L
Liu Jicong 已提交
831
    wDebug("vgId:%d, wal find current meta: %s is not meta file", pWal->cfg.vgId, name);
L
Liu Jicong 已提交
832
  }
wafwerar's avatar
wafwerar 已提交
833
  taosCloseDir(&pDir);
L
Liu Jicong 已提交
834
  regfree(&walMetaRegexPattern);
L
Liu Jicong 已提交
835 836 837
  return metaVer;
}

838 839 840 841 842 843
void walUpdateSyncedOffset(SWal* pWal) {
  SWalFileInfo* pFileInfo = walGetCurFileInfo(pWal);
  if (pFileInfo == NULL) return;
  pFileInfo->syncedOffset = pFileInfo->fileSize;
}

L
Liu Jicong 已提交
844
int walSaveMeta(SWal* pWal) {
L
Liu Jicong 已提交
845
  int  metaVer = walFindCurMetaVer(pWal);
L
Liu Jicong 已提交
846
  char fnameStr[WAL_FILE_LEN];
847
  char tmpFnameStr[WAL_FILE_LEN];
848 849 850 851 852 853 854 855 856 857 858 859 860 861
  int  n;

  // fsync the idx and log file at first to ensure validity of meta
  if (taosFsyncFile(pWal->pIdxFile) < 0) {
    wError("vgId:%d, failed to sync idx file due to %s", pWal->cfg.vgId, strerror(errno));
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }

  if (taosFsyncFile(pWal->pLogFile) < 0) {
    wError("vgId:%d, failed to sync log file due to %s", pWal->cfg.vgId, strerror(errno));
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }
862

863 864 865
  // update synced offset
  (void)walUpdateSyncedOffset(pWal);

866 867
  // flush to a tmpfile
  n = walBuildTmpMetaName(pWal, tmpFnameStr);
L
Liu Jicong 已提交
868
  if (n >= sizeof(tmpFnameStr)) {
L
Liu Jicong 已提交
869 870
    return -1;
  }
871 872

  TdFilePtr pMetaFile = taosOpenFile(tmpFnameStr, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
L
Liu Jicong 已提交
873
  if (pMetaFile == NULL) {
874
    wError("vgId:%d, failed to open file due to %s. file:%s", pWal->cfg.vgId, strerror(errno), tmpFnameStr);
875
    terrno = TAOS_SYSTEM_ERROR(errno);
L
Liu Jicong 已提交
876 877
    return -1;
  }
878

879
  char* serialized = walMetaSerialize(pWal);
L
Liu Jicong 已提交
880
  int   len = strlen(serialized);
L
Liu Jicong 已提交
881
  if (len != taosWriteFile(pMetaFile, serialized, len)) {
882
    wError("vgId:%d, failed to write file due to %s. file:%s", pWal->cfg.vgId, strerror(errno), tmpFnameStr);
883 884 885
    terrno = TAOS_SYSTEM_ERROR(errno);
    goto _err;
  }
L
Liu Jicong 已提交
886

887
  if (taosFsyncFile(pMetaFile) < 0) {
888
    wError("vgId:%d, failed to sync file due to %s. file:%s", pWal->cfg.vgId, strerror(errno), tmpFnameStr);
889 890 891 892 893
    terrno = TAOS_SYSTEM_ERROR(errno);
    goto _err;
  }

  if (taosCloseFile(&pMetaFile) < 0) {
894
    wError("vgId:%d, failed to close file due to %s. file:%s", pWal->cfg.vgId, strerror(errno), tmpFnameStr);
895 896 897 898 899 900
    terrno = TAOS_SYSTEM_ERROR(errno);
    goto _err;
  }

  // rename it
  n = walBuildMetaName(pWal, metaVer + 1, fnameStr);
L
Liu Jicong 已提交
901
  if (n >= sizeof(fnameStr)) {
L
Liu Jicong 已提交
902 903
    goto _err;
  }
904 905 906 907 908

  if (taosRenameFile(tmpFnameStr, fnameStr) < 0) {
    wError("failed to rename file due to %s. dest:%s", strerror(errno), fnameStr);
    terrno = TAOS_SYSTEM_ERROR(errno);
    goto _err;
L
Liu Jicong 已提交
909
  }
L
Liu Jicong 已提交
910 911 912

  // delete old file
  if (metaVer > -1) {
L
Liu Jicong 已提交
913
    walBuildMetaName(pWal, metaVer, fnameStr);
914
    taosRemoveFile(fnameStr);
L
Liu Jicong 已提交
915
  }
wafwerar's avatar
wafwerar 已提交
916
  taosMemoryFree(serialized);
L
Liu Jicong 已提交
917
  return 0;
918 919 920 921 922

_err:
  taosCloseFile(&pMetaFile);
  taosMemoryFree(serialized);
  return -1;
L
Liu Jicong 已提交
923 924
}

L
Liu Jicong 已提交
925
int walLoadMeta(SWal* pWal) {
L
Liu Jicong 已提交
926
  // find existing meta file
L
Liu Jicong 已提交
927
  int metaVer = walFindCurMetaVer(pWal);
L
Liu Jicong 已提交
928
  if (metaVer == -1) {
S
Shengliang Guan 已提交
929
    wDebug("vgId:%d, wal find meta ver %d", pWal->cfg.vgId, metaVer);
L
Liu Jicong 已提交
930
    return -1;
L
Liu Jicong 已提交
931 932 933
  }
  char fnameStr[WAL_FILE_LEN];
  walBuildMetaName(pWal, metaVer, fnameStr);
L
Liu Jicong 已提交
934
  // read metafile
L
Liu Jicong 已提交
935 936
  int64_t fileSize = 0;
  taosStatFile(fnameStr, &fileSize, NULL);
L
Liu Jicong 已提交
937
  if (fileSize == 0) {
938
    (void)taosRemoveFile(fnameStr);
S
Shengliang Guan 已提交
939
    wDebug("vgId:%d, wal find empty meta ver %d", pWal->cfg.vgId, metaVer);
L
Liu Jicong 已提交
940 941
    return -1;
  }
L
Liu Jicong 已提交
942
  int   size = (int)fileSize;
wafwerar's avatar
wafwerar 已提交
943
  char* buf = taosMemoryMalloc(size + 5);
L
Liu Jicong 已提交
944
  if (buf == NULL) {
S
Shengliang Guan 已提交
945
    terrno = TSDB_CODE_OUT_OF_MEMORY;
L
Liu Jicong 已提交
946 947
    return -1;
  }
L
Liu Jicong 已提交
948
  memset(buf, 0, size + 5);
949 950
  TdFilePtr pFile = taosOpenFile(fnameStr, TD_FILE_READ);
  if (pFile == NULL) {
L
Liu Jicong 已提交
951
    terrno = TSDB_CODE_WAL_FILE_CORRUPTED;
L
Liu Jicong 已提交
952
    taosMemoryFree(buf);
L
Liu Jicong 已提交
953 954
    return -1;
  }
955
  if (taosReadFile(pFile, buf, size) != size) {
L
Liu Jicong 已提交
956
    terrno = TAOS_SYSTEM_ERROR(errno);
957
    taosCloseFile(&pFile);
wafwerar's avatar
wafwerar 已提交
958
    taosMemoryFree(buf);
L
Liu Jicong 已提交
959 960
    return -1;
  }
L
Liu Jicong 已提交
961
  // load into fileInfoSet
962
  int code = walMetaDeserialize(pWal, buf);
963 964 965 966
  if (code < 0) {
    wError("failed to deserialize wal meta. file:%s", fnameStr);
    terrno = TSDB_CODE_WAL_FILE_CORRUPTED;
  }
967
  taosCloseFile(&pFile);
wafwerar's avatar
wafwerar 已提交
968
  taosMemoryFree(buf);
L
Liu Jicong 已提交
969
  return code;
L
Liu Jicong 已提交
970
}
971 972 973 974 975 976

int walRemoveMeta(SWal* pWal) {
  int metaVer = walFindCurMetaVer(pWal);
  if (metaVer == -1) return 0;
  char fnameStr[WAL_FILE_LEN];
  walBuildMetaName(pWal, metaVer, fnameStr);
L
Liu Jicong 已提交
977
  return taosRemoveFile(fnameStr);
978
}