You need to sign in or sign up before continuing.
walMeta.c 18.2 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"
L
Liu Jicong 已提交
19
#include "tutil.h"
L
Liu Jicong 已提交
20 21
#include "walInt.h"

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

L
Liu Jicong 已提交
26 27
bool FORCE_INLINE walIsEmpty(SWal* pWal) { return pWal->vers.firstVer == -1; }

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

L
Liu Jicong 已提交
30
int64_t FORCE_INLINE walGetSnaphostVer(SWal* pWal) { return pWal->vers.snapshotVer; }
L
Liu Jicong 已提交
31

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

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

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

L
Liu Jicong 已提交
38
static FORCE_INLINE int walBuildMetaName(SWal* pWal, int metaVer, char* buf) {
L
Liu Jicong 已提交
39 40 41
  return sprintf(buf, "%s/meta-ver%d", pWal->path, metaVer);
}

L
Liu Jicong 已提交
42
static FORCE_INLINE int64_t walScanLogGetLastVer(SWal* pWal) {
L
Liu Jicong 已提交
43
  int32_t sz = taosArrayGetSize(pWal->fileInfoSet);
L
Liu Jicong 已提交
44
  ASSERT(sz > 0);
L
Liu Jicong 已提交
45
#if 0
L
Liu Jicong 已提交
46 47 48
  for (int i = 0; i < sz; i++) {
    SWalFileInfo* pFileInfo = taosArrayGet(pWal->fileInfoSet, i);
  }
L
Liu Jicong 已提交
49 50
#endif

L
Liu Jicong 已提交
51 52
  SWalFileInfo* pLastFileInfo = taosArrayGet(pWal->fileInfoSet, sz - 1);
  char          fnameStr[WAL_FILE_LEN];
L
Liu Jicong 已提交
53 54
  walBuildLogName(pWal, pLastFileInfo->firstVer, fnameStr);

L
Liu Jicong 已提交
55 56
  int64_t fileSize = 0;
  taosStatFile(fnameStr, &fileSize, NULL);
57
  int32_t readSize = TMIN(WAL_SCAN_BUF_SIZE, fileSize);
L
Liu Jicong 已提交
58
  pLastFileInfo->fileSize = fileSize;
L
Liu Jicong 已提交
59

60 61
  TdFilePtr pFile = taosOpenFile(fnameStr, TD_FILE_READ);
  if (pFile == NULL) {
L
Liu Jicong 已提交
62 63 64 65 66 67
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }

  uint64_t magic = WAL_MAGIC;

wafwerar's avatar
wafwerar 已提交
68
  char* buf = taosMemoryMalloc(readSize + 5);
L
Liu Jicong 已提交
69
  if (buf == NULL) {
70
    taosCloseFile(&pFile);
L
Liu Jicong 已提交
71 72 73 74
    terrno = TSDB_CODE_WAL_OUT_OF_MEMORY;
    return -1;
  }

75 76
  int64_t offset;
  offset = taosLSeekFile(pFile, -readSize, SEEK_END);
77
  if (readSize != taosReadFile(pFile, buf, readSize)) {
wafwerar's avatar
wafwerar 已提交
78
    taosMemoryFree(buf);
79
    taosCloseFile(&pFile);
L
Liu Jicong 已提交
80 81 82
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }
L
Liu Jicong 已提交
83

L
Liu Jicong 已提交
84
  char* found = NULL;
85 86 87 88 89 90 91 92 93 94
  while (1) {
    char* haystack = buf;
    char* candidate;
    while ((candidate = tmemmem(haystack, readSize - (haystack - buf), (char*)&magic, sizeof(uint64_t))) != NULL) {
      // read and validate
      SWalCkHead* logContent = (SWalCkHead*)candidate;
      if (walValidHeadCksum(logContent) == 0 && walValidBodyCksum(logContent) == 0) {
        found = candidate;
      }
      haystack = candidate + 1;
L
Liu Jicong 已提交
95
    }
96
    if (found || offset == 0) break;
L
Liu Jicong 已提交
97
    offset = TMIN(0, offset - readSize + sizeof(uint64_t));
98 99 100
    int64_t offset2 = taosLSeekFile(pFile, offset, SEEK_SET);
    ASSERT(offset == offset2);
    if (readSize != taosReadFile(pFile, buf, readSize)) {
wafwerar's avatar
wafwerar 已提交
101
      taosMemoryFree(buf);
102
      taosCloseFile(&pFile);
103
      terrno = TAOS_SYSTEM_ERROR(errno);
L
Liu Jicong 已提交
104
      return -1;
L
Liu Jicong 已提交
105
    }
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
#if 0
    if (found == buf) {
      SWalCkHead* logContent = (SWalCkHead*)found;
      if (walValidHeadCksum(logContent) != 0 || walValidBodyCksum(logContent) != 0) {
        // file has to be deleted
        taosMemoryFree(buf);
        taosCloseFile(&pFile);
        terrno = TSDB_CODE_WAL_FILE_CORRUPTED;
        return -1;
      }
    }
#endif
  }

  if (found == NULL) {
    // file corrupted, no complete log
    // TODO delete and search in previous files
123
    /*ASSERT(0);*/
124 125
    terrno = TSDB_CODE_WAL_FILE_CORRUPTED;
    return -1;
L
Liu Jicong 已提交
126
  }
L
Liu Jicong 已提交
127 128

  // truncate file
L
Liu Jicong 已提交
129
  SWalCkHead* lastEntry = (SWalCkHead*)found;
L
Liu Jicong 已提交
130
  int64_t     retVer = lastEntry->head.version;
L
Liu Jicong 已提交
131 132 133 134 135 136 137 138 139 140
  int64_t     lastEntryBeginOffset = offset + (int64_t)((char*)found - (char*)buf);
  int64_t     lastEntryEndOffset = lastEntryBeginOffset + sizeof(SWalCkHead) + lastEntry->head.bodyLen;
  if (lastEntryEndOffset != fileSize) {
    wWarn("vgId:%d repair meta truncate file %s to %ld, orig size %ld", pWal->cfg.vgId, fnameStr, lastEntryEndOffset,
          fileSize);
    taosFtruncateFile(pFile, lastEntryEndOffset);
    ((SWalFileInfo*)taosArrayGetLast(pWal->fileInfoSet))->fileSize = lastEntryEndOffset;
    pWal->totSize -= (fileSize - lastEntryEndOffset);
  }

141 142
  taosCloseFile(&pFile);
  taosMemoryFree(buf);
L
Liu Jicong 已提交
143

L
Liu Jicong 已提交
144
  return retVer;
L
Liu Jicong 已提交
145 146
}

L
Liu Jicong 已提交
147 148 149 150
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 已提交
151 152
  regex_t     logRegPattern;
  regex_t     idxRegPattern;
153
  SArray*     actualLog = taosArrayInit(8, sizeof(SWalFileInfo));
L
Liu Jicong 已提交
154 155 156

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

wafwerar's avatar
wafwerar 已提交
158 159
  TdDirPtr pDir = taosOpenDir(pWal->path);
  if (pDir == NULL) {
L
Liu Jicong 已提交
160 161 162 163
    wError("vgId:%d, path:%s, failed to open since %s", pWal->cfg.vgId, pWal->path, strerror(errno));
    return -1;
  }

L
Liu Jicong 已提交
164
  // scan log files and build new meta
wafwerar's avatar
wafwerar 已提交
165 166 167
  TdDirEntryPtr pDirEntry;
  while ((pDirEntry = taosReadDir(pDir)) != NULL) {
    char* name = taosDirEntryBaseName(taosGetDirEntryName(pDirEntry));
L
Liu Jicong 已提交
168 169
    int   code = regexec(&logRegPattern, name, 0, NULL, 0);
    if (code == 0) {
L
Liu Jicong 已提交
170 171 172
      SWalFileInfo fileInfo;
      memset(&fileInfo, -1, sizeof(SWalFileInfo));
      sscanf(name, "%" PRId64 ".log", &fileInfo.firstVer);
173
      taosArrayPush(actualLog, &fileInfo);
L
Liu Jicong 已提交
174 175 176
    }
  }

wafwerar's avatar
wafwerar 已提交
177
  taosCloseDir(&pDir);
L
Liu Jicong 已提交
178 179 180
  regfree(&logRegPattern);
  regfree(&idxRegPattern);

181
  taosArraySort(actualLog, compareWalFileInfo);
L
Liu Jicong 已提交
182

L
Liu Jicong 已提交
183
  int metaFileNum = taosArrayGetSize(pWal->fileInfoSet);
184
  int actualFileNum = taosArrayGetSize(actualLog);
L
Liu Jicong 已提交
185

L
Liu Jicong 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
#if 0
  for (int32_t fileNo = actualFileNum - 1; fileNo >= 0; fileNo--) {
    SWalFileInfo* pFileInfo = taosArrayGet(pLogInfoArray, fileNo);
    char          fnameStr[WAL_FILE_LEN];
    walBuildLogName(pWal, pFileInfo->firstVer, fnameStr);
    int64_t fileSize = 0;
    taosStatFile(fnameStr, &fileSize, NULL);
    if (fileSize == 0) {
      taosRemoveFile(fnameStr);
      walBuildIdxName(pWal, pFileInfo->firstVer, fnameStr);
      taosRemoveFile(fnameStr);
      taosArrayPop(pLogInfoArray);
    } else {
      break;
    }
  }

  actualFileNum = taosArrayGetSize(pLogInfoArray);
#endif

L
Liu Jicong 已提交
206 207 208 209
  if (metaFileNum > actualFileNum) {
    taosArrayPopFrontBatch(pWal->fileInfoSet, metaFileNum - actualFileNum);
  } else if (metaFileNum < actualFileNum) {
    for (int i = metaFileNum; i < actualFileNum; i++) {
210
      SWalFileInfo* pFileInfo = taosArrayGet(actualLog, i);
L
Liu Jicong 已提交
211 212
      taosArrayPush(pWal->fileInfoSet, pFileInfo);
    }
L
Liu Jicong 已提交
213
  }
214
  taosArrayDestroy(actualLog);
L
Liu Jicong 已提交
215

L
Liu Jicong 已提交
216 217
  pWal->writeCur = actualFileNum - 1;
  if (actualFileNum > 0) {
L
Liu Jicong 已提交
218 219
    pWal->vers.firstVer = ((SWalFileInfo*)taosArrayGet(pWal->fileInfoSet, 0))->firstVer;

L
Liu Jicong 已提交
220
    SWalFileInfo* pLastFileInfo = taosArrayGet(pWal->fileInfoSet, actualFileNum - 1);
L
Liu Jicong 已提交
221
    char          fnameStr[WAL_FILE_LEN];
L
Liu Jicong 已提交
222
    walBuildLogName(pWal, pLastFileInfo->firstVer, fnameStr);
L
Liu Jicong 已提交
223 224
    int64_t fileSize = 0;
    taosStatFile(fnameStr, &fileSize, NULL);
L
Liu Jicong 已提交
225
    /*ASSERT(fileSize != 0);*/
L
Liu Jicong 已提交
226

L
Liu Jicong 已提交
227 228
    if (metaFileNum != actualFileNum || pLastFileInfo->fileSize != fileSize) {
      pLastFileInfo->fileSize = fileSize;
L
Liu Jicong 已提交
229 230 231 232 233 234 235
      pWal->vers.lastVer = walScanLogGetLastVer(pWal);
      ((SWalFileInfo*)taosArrayGetLast(pWal->fileInfoSet))->lastVer = pWal->vers.lastVer;
      ASSERT(pWal->vers.lastVer != -1);

      int code = walSaveMeta(pWal);
      if (code < 0) {
        return -1;
L
Liu Jicong 已提交
236 237 238 239
      }
    }
  }

L
Liu Jicong 已提交
240 241 242 243
  return 0;
}

int walCheckAndRepairIdx(SWal* pWal) {
L
Liu Jicong 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
  int32_t sz = taosArrayGetSize(pWal->fileInfoSet);
  for (int32_t i = 0; i < sz; i++) {
    SWalFileInfo* pFileInfo = taosArrayGet(pWal->fileInfoSet, i);

    char fnameStr[WAL_FILE_LEN];
    walBuildIdxName(pWal, pFileInfo->firstVer, fnameStr);
    int64_t   fsize;
    TdFilePtr pIdxFile = taosOpenFile(fnameStr, TD_FILE_READ | TD_FILE_WRITE | TD_FILE_CREATE);
    if (pIdxFile == NULL) {
      ASSERT(0);
      terrno = TAOS_SYSTEM_ERROR(errno);
      wError("vgId:%d, cannot open file %s, since %s", pWal->cfg.vgId, fnameStr, terrstr());
      return -1;
    }

    taosFStatFile(pIdxFile, &fsize, NULL);
L
Liu Jicong 已提交
260 261 262 263
    if (fsize == (pFileInfo->lastVer - pFileInfo->firstVer + 1) * sizeof(SWalIdxEntry)) {
      taosCloseFile(&pIdxFile);
      continue;
    }
L
Liu Jicong 已提交
264 265 266 267 268 269 270 271 272 273

    int32_t left = fsize % sizeof(SWalIdxEntry);
    int64_t offset = taosLSeekFile(pIdxFile, -left, SEEK_END);
    if (left != 0) {
      taosFtruncateFile(pIdxFile, offset);
      wWarn("vgId:%d wal truncate file %s to offset %ld since size invalid, file size %ld", pWal->cfg.vgId, fnameStr,
            offset, fsize);
    }
    offset -= sizeof(SWalIdxEntry);

L
Liu Jicong 已提交
274
    SWalIdxEntry idxEntry = {.ver = pFileInfo->firstVer};
L
Liu Jicong 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
    while (1) {
      if (offset < 0) {
        taosLSeekFile(pIdxFile, 0, SEEK_SET);
        taosWriteFile(pIdxFile, &idxEntry, sizeof(SWalIdxEntry));
        break;
      }
      taosLSeekFile(pIdxFile, offset, SEEK_SET);
      int64_t contLen = taosReadFile(pIdxFile, &idxEntry, sizeof(SWalIdxEntry));
      if (contLen < 0 || contLen != sizeof(SWalIdxEntry)) {
        terrno = TAOS_SYSTEM_ERROR(errno);
        return -1;
      }
      if ((idxEntry.ver - pFileInfo->firstVer) * sizeof(SWalIdxEntry) != offset) {
        taosFtruncateFile(pIdxFile, offset);
        wWarn("vgId:%d wal truncate file %s to offset %ld since entry invalid, entry ver %ld, entry offset %ld",
              pWal->cfg.vgId, fnameStr, offset, idxEntry.ver, idxEntry.offset);
        offset -= sizeof(SWalIdxEntry);
      } else {
        break;
      }
    }

    if (idxEntry.ver < pFileInfo->lastVer) {
      char fLogNameStr[WAL_FILE_LEN];
      walBuildLogName(pWal, pFileInfo->firstVer, fLogNameStr);
      TdFilePtr 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());
        return -1;
      }
      while (idxEntry.ver < pFileInfo->lastVer) {
        taosLSeekFile(pLogFile, idxEntry.offset, SEEK_SET);
        SWalCkHead ckHead;
        taosReadFile(pLogFile, &ckHead, sizeof(SWalCkHead));
        if (idxEntry.ver != ckHead.head.version) {
          // todo truncate this idx also
          taosCloseFile(&pLogFile);
L
Liu Jicong 已提交
313 314
          wError("vgId:%d, invalid repair case, log seek to %ld to find ver %ld, actual ver %ld", pWal->cfg.vgId,
                 idxEntry.offset, idxEntry.ver, ckHead.head.version);
L
Liu Jicong 已提交
315 316 317 318 319 320 321 322 323 324 325
          return -1;
        }
        idxEntry.ver = ckHead.head.version + 1;
        idxEntry.offset = idxEntry.offset + sizeof(SWalCkHead) + ckHead.head.bodyLen;
        wWarn("vgId:%d wal idx append new entry %ld %ld", pWal->cfg.vgId, idxEntry.ver, idxEntry.offset);
        taosWriteFile(pIdxFile, &idxEntry, sizeof(SWalIdxEntry));
      }
      taosCloseFile(&pLogFile);
    }
    taosCloseFile(&pIdxFile);
  }
L
Liu Jicong 已提交
326 327 328
  return 0;
}

L
Liu Jicong 已提交
329 330 331 332
int walRollFileInfo(SWal* pWal) {
  int64_t ts = taosGetTimestampSec();

  SArray* pArray = pWal->fileInfoSet;
L
Liu Jicong 已提交
333
  if (taosArrayGetSize(pArray) != 0) {
L
Liu Jicong 已提交
334
    SWalFileInfo* pInfo = taosArrayGetLast(pArray);
L
Liu Jicong 已提交
335
    pInfo->lastVer = pWal->vers.lastVer;
L
Liu Jicong 已提交
336 337 338
    pInfo->closeTs = ts;
  }

L
Liu Jicong 已提交
339
  // TODO: change to emplace back
wafwerar's avatar
wafwerar 已提交
340
  SWalFileInfo* pNewInfo = taosMemoryMalloc(sizeof(SWalFileInfo));
L
Liu Jicong 已提交
341
  if (pNewInfo == NULL) {
L
Liu Jicong 已提交
342
    terrno = TSDB_CODE_WAL_OUT_OF_MEMORY;
L
Liu Jicong 已提交
343 344
    return -1;
  }
L
Liu Jicong 已提交
345
  pNewInfo->firstVer = pWal->vers.lastVer + 1;
L
Liu Jicong 已提交
346 347 348 349
  pNewInfo->lastVer = -1;
  pNewInfo->createTs = ts;
  pNewInfo->closeTs = -1;
  pNewInfo->fileSize = 0;
L
Liu Jicong 已提交
350
  taosArrayPush(pArray, pNewInfo);
wafwerar's avatar
wafwerar 已提交
351
  taosMemoryFree(pNewInfo);
L
Liu Jicong 已提交
352 353 354
  return 0;
}

355
char* walMetaSerialize(SWal* pWal) {
L
Liu Jicong 已提交
356
  char buf[30];
L
Liu Jicong 已提交
357
  ASSERT(pWal->fileInfoSet);
L
Liu Jicong 已提交
358
  int    sz = taosArrayGetSize(pWal->fileInfoSet);
359 360 361 362
  cJSON* pRoot = cJSON_CreateObject();
  cJSON* pMeta = cJSON_CreateObject();
  cJSON* pFiles = cJSON_CreateArray();
  cJSON* pField;
L
Liu Jicong 已提交
363
  if (pRoot == NULL || pMeta == NULL || pFiles == NULL) {
L
Liu Jicong 已提交
364
    if (pRoot) {
L
Liu Jicong 已提交
365 366
      cJSON_Delete(pRoot);
    }
L
Liu Jicong 已提交
367
    if (pMeta) {
L
Liu Jicong 已提交
368 369
      cJSON_Delete(pMeta);
    }
L
Liu Jicong 已提交
370
    if (pFiles) {
L
Liu Jicong 已提交
371 372 373
      cJSON_Delete(pFiles);
    }
    terrno = TSDB_CODE_WAL_OUT_OF_MEMORY;
L
Liu Jicong 已提交
374 375
    return NULL;
  }
376
  cJSON_AddItemToObject(pRoot, "meta", pMeta);
L
Liu Jicong 已提交
377
  sprintf(buf, "%" PRId64, pWal->vers.firstVer);
378
  cJSON_AddStringToObject(pMeta, "firstVer", buf);
L
Liu Jicong 已提交
379
  sprintf(buf, "%" PRId64, pWal->vers.snapshotVer);
380
  cJSON_AddStringToObject(pMeta, "snapshotVer", buf);
L
Liu Jicong 已提交
381
  sprintf(buf, "%" PRId64, pWal->vers.commitVer);
382
  cJSON_AddStringToObject(pMeta, "commitVer", buf);
L
Liu Jicong 已提交
383
  sprintf(buf, "%" PRId64, pWal->vers.lastVer);
384 385 386
  cJSON_AddStringToObject(pMeta, "lastVer", buf);

  cJSON_AddItemToObject(pRoot, "files", pFiles);
L
Liu Jicong 已提交
387
  SWalFileInfo* pData = pWal->fileInfoSet->pData;
L
Liu Jicong 已提交
388
  for (int i = 0; i < sz; i++) {
L
Liu Jicong 已提交
389
    SWalFileInfo* pInfo = &pData[i];
390
    cJSON_AddItemToArray(pFiles, pField = cJSON_CreateObject());
L
Liu Jicong 已提交
391
    if (pField == NULL) {
392
      cJSON_Delete(pRoot);
L
Liu Jicong 已提交
393 394
      return NULL;
    }
L
Liu Jicong 已提交
395 396
    // cjson only support int32_t or double
    // string are used to prohibit the loss of precision
397 398 399 400 401 402 403 404 405 406
    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 已提交
407
  }
L
Liu Jicong 已提交
408 409 410
  char* serialized = cJSON_Print(pRoot);
  cJSON_Delete(pRoot);
  return serialized;
L
Liu Jicong 已提交
411 412
}

413 414 415 416 417 418
int walMetaDeserialize(SWal* pWal, const char* bytes) {
  ASSERT(taosArrayGetSize(pWal->fileInfoSet) == 0);
  cJSON *pRoot, *pMeta, *pFiles, *pInfoJson, *pField;
  pRoot = cJSON_Parse(bytes);
  pMeta = cJSON_GetObjectItem(pRoot, "meta");
  pField = cJSON_GetObjectItem(pMeta, "firstVer");
L
Liu Jicong 已提交
419
  pWal->vers.firstVer = atoll(cJSON_GetStringValue(pField));
420
  pField = cJSON_GetObjectItem(pMeta, "snapshotVer");
L
Liu Jicong 已提交
421
  pWal->vers.snapshotVer = atoll(cJSON_GetStringValue(pField));
422
  pField = cJSON_GetObjectItem(pMeta, "commitVer");
L
Liu Jicong 已提交
423
  pWal->vers.commitVer = atoll(cJSON_GetStringValue(pField));
424
  pField = cJSON_GetObjectItem(pMeta, "lastVer");
L
Liu Jicong 已提交
425
  pWal->vers.lastVer = atoll(cJSON_GetStringValue(pField));
426 427 428

  pFiles = cJSON_GetObjectItem(pRoot, "files");
  int sz = cJSON_GetArraySize(pFiles);
L
Liu Jicong 已提交
429
  // deserialize
L
Liu Jicong 已提交
430 431
  SArray* pArray = pWal->fileInfoSet;
  taosArrayEnsureCap(pArray, sz);
L
Liu Jicong 已提交
432
  SWalFileInfo* pData = pArray->pData;
L
Liu Jicong 已提交
433
  for (int i = 0; i < sz; i++) {
L
Liu Jicong 已提交
434 435
    cJSON*        pInfoJson = cJSON_GetArrayItem(pFiles, i);
    SWalFileInfo* pInfo = &pData[i];
L
Liu Jicong 已提交
436 437 438 439 440 441 442 443 444 445 446 447
    pField = cJSON_GetObjectItem(pInfoJson, "firstVer");
    pInfo->firstVer = atoll(cJSON_GetStringValue(pField));
    pField = cJSON_GetObjectItem(pInfoJson, "lastVer");
    pInfo->lastVer = atoll(cJSON_GetStringValue(pField));
    pField = cJSON_GetObjectItem(pInfoJson, "createTs");
    pInfo->createTs = atoll(cJSON_GetStringValue(pField));
    pField = cJSON_GetObjectItem(pInfoJson, "closeTs");
    pInfo->closeTs = atoll(cJSON_GetStringValue(pField));
    pField = cJSON_GetObjectItem(pInfoJson, "fileSize");
    pInfo->fileSize = atoll(cJSON_GetStringValue(pField));
  }
  taosArraySetSize(pArray, sz);
448
  pWal->fileInfoSet = pArray;
L
Liu Jicong 已提交
449
  pWal->writeCur = sz - 1;
L
Liu Jicong 已提交
450
  cJSON_Delete(pRoot);
451
  return 0;
L
Liu Jicong 已提交
452 453 454
}

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

wafwerar's avatar
wafwerar 已提交
459 460
  TdDirPtr pDir = taosOpenDir(pWal->path);
  if (pDir == NULL) {
L
Liu Jicong 已提交
461
    wError("vgId:%d, path:%s, failed to open since %s", pWal->cfg.vgId, pWal->path, strerror(errno));
L
Liu Jicong 已提交
462 463 464
    return -1;
  }

wafwerar's avatar
wafwerar 已提交
465
  TdDirEntryPtr pDirEntry;
L
Liu Jicong 已提交
466

L
Liu Jicong 已提交
467
  // find existing meta-ver[x].json
L
Liu Jicong 已提交
468
  int metaVer = -1;
wafwerar's avatar
wafwerar 已提交
469 470
  while ((pDirEntry = taosReadDir(pDir)) != NULL) {
    char* name = taosDirEntryBaseName(taosGetDirEntryName(pDirEntry));
L
Liu Jicong 已提交
471 472
    int   code = regexec(&walMetaRegexPattern, name, 0, NULL, 0);
    if (code == 0) {
L
Liu Jicong 已提交
473
      sscanf(name, "meta-ver%d", &metaVer);
L
Liu Jicong 已提交
474
      wDebug("vgId:%d, wal find current meta: %s is the meta file, ver %d", pWal->cfg.vgId, name, metaVer);
L
Liu Jicong 已提交
475 476
      break;
    }
L
Liu Jicong 已提交
477
    wDebug("vgId:%d, wal find current meta: %s is not meta file", pWal->cfg.vgId, name);
L
Liu Jicong 已提交
478
  }
wafwerar's avatar
wafwerar 已提交
479
  taosCloseDir(&pDir);
L
Liu Jicong 已提交
480
  regfree(&walMetaRegexPattern);
L
Liu Jicong 已提交
481 482 483
  return metaVer;
}

L
Liu Jicong 已提交
484
int walSaveMeta(SWal* pWal) {
L
Liu Jicong 已提交
485
  int  metaVer = walFindCurMetaVer(pWal);
L
Liu Jicong 已提交
486
  char fnameStr[WAL_FILE_LEN];
L
Liu Jicong 已提交
487
  walBuildMetaName(pWal, metaVer + 1, fnameStr);
488
  TdFilePtr pMataFile = taosOpenFile(fnameStr, TD_FILE_CREATE | TD_FILE_WRITE);
489
  if (pMataFile == NULL) {
L
Liu Jicong 已提交
490 491
    return -1;
  }
492
  char* serialized = walMetaSerialize(pWal);
L
Liu Jicong 已提交
493
  int   len = strlen(serialized);
494
  if (len != taosWriteFile(pMataFile, serialized, len)) {
L
Liu Jicong 已提交
495
    // TODO:clean file
L
Liu Jicong 已提交
496 497
    return -1;
  }
L
Liu Jicong 已提交
498

499
  taosCloseFile(&pMataFile);
L
Liu Jicong 已提交
500 501
  // delete old file
  if (metaVer > -1) {
L
Liu Jicong 已提交
502
    walBuildMetaName(pWal, metaVer, fnameStr);
503
    taosRemoveFile(fnameStr);
L
Liu Jicong 已提交
504
  }
wafwerar's avatar
wafwerar 已提交
505
  taosMemoryFree(serialized);
L
Liu Jicong 已提交
506 507 508
  return 0;
}

L
Liu Jicong 已提交
509
int walLoadMeta(SWal* pWal) {
L
Liu Jicong 已提交
510
  ASSERT(pWal->fileInfoSet->size == 0);
L
Liu Jicong 已提交
511
  // find existing meta file
L
Liu Jicong 已提交
512
  int metaVer = walFindCurMetaVer(pWal);
L
Liu Jicong 已提交
513
  if (metaVer == -1) {
L
Liu Jicong 已提交
514
    wDebug("vgId:%d wal find meta ver %d", pWal->cfg.vgId, metaVer);
L
Liu Jicong 已提交
515
    return -1;
L
Liu Jicong 已提交
516 517 518
  }
  char fnameStr[WAL_FILE_LEN];
  walBuildMetaName(pWal, metaVer, fnameStr);
L
Liu Jicong 已提交
519
  // read metafile
L
Liu Jicong 已提交
520 521 522
  int64_t fileSize = 0;
  taosStatFile(fnameStr, &fileSize, NULL);
  int   size = (int)fileSize;
wafwerar's avatar
wafwerar 已提交
523
  char* buf = taosMemoryMalloc(size + 5);
L
Liu Jicong 已提交
524
  if (buf == NULL) {
L
Liu Jicong 已提交
525
    terrno = TSDB_CODE_WAL_OUT_OF_MEMORY;
L
Liu Jicong 已提交
526 527
    return -1;
  }
L
Liu Jicong 已提交
528
  memset(buf, 0, size + 5);
529 530
  TdFilePtr pFile = taosOpenFile(fnameStr, TD_FILE_READ);
  if (pFile == NULL) {
L
Liu Jicong 已提交
531 532 533
    terrno = TSDB_CODE_WAL_FILE_CORRUPTED;
    return -1;
  }
534
  if (taosReadFile(pFile, buf, size) != size) {
L
Liu Jicong 已提交
535
    terrno = TAOS_SYSTEM_ERROR(errno);
536
    taosCloseFile(&pFile);
wafwerar's avatar
wafwerar 已提交
537
    taosMemoryFree(buf);
L
Liu Jicong 已提交
538 539
    return -1;
  }
L
Liu Jicong 已提交
540
  // load into fileInfoSet
541
  int code = walMetaDeserialize(pWal, buf);
542
  taosCloseFile(&pFile);
wafwerar's avatar
wafwerar 已提交
543
  taosMemoryFree(buf);
L
Liu Jicong 已提交
544
  return code;
L
Liu Jicong 已提交
545
}
546 547 548 549 550 551 552 553 554

int walRemoveMeta(SWal* pWal) {
  int metaVer = walFindCurMetaVer(pWal);
  if (metaVer == -1) return 0;
  char fnameStr[WAL_FILE_LEN];
  walBuildMetaName(pWal, metaVer, fnameStr);
  taosRemoveFile(fnameStr);
  return 0;
}