walMeta.c 12.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"
L
Liu Jicong 已提交
19
#include "tref.h"
L
Liu Jicong 已提交
20 21 22 23 24
#include "walInt.h"

#include <libgen.h>
#include <regex.h>

L
Liu Jicong 已提交
25
int64_t inline walGetFirstVer(SWal* pWal) { return pWal->vers.firstVer; }
L
Liu Jicong 已提交
26

L
Liu Jicong 已提交
27
int64_t inline walGetSnaphostVer(SWal* pWal) { return pWal->vers.snapshotVer; }
L
Liu Jicong 已提交
28

L
Liu Jicong 已提交
29
int64_t inline walGetLastVer(SWal* pWal) { return pWal->vers.lastVer; }
L
Liu Jicong 已提交
30

L
Liu Jicong 已提交
31 32 33 34
static inline int walBuildMetaName(SWal* pWal, int metaVer, char* buf) {
  return sprintf(buf, "%s/meta-ver%d", pWal->path, metaVer);
}

L
Liu Jicong 已提交
35 36 37 38
void* tmemmem(char* haystack, int hlen, char* needle, int nlen) {
  char* limit;

  if (nlen == 0 || hlen < nlen) {
L
Liu Jicong 已提交
39
    return NULL;
L
Liu Jicong 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52
  }

  limit = haystack + hlen - nlen + 1;
  while ((haystack = (char*)memchr(
              haystack, needle[0], limit - haystack)) != NULL) {
    if (memcmp(haystack, needle, nlen) == 0) {
      return haystack;
    }
    haystack++;
  }
  return NULL;
}

L
Liu Jicong 已提交
53 54 55 56
static inline int64_t walScanLogGetLastVer(SWal* pWal) {
  ASSERT(pWal->fileInfoSet != NULL);
  int sz = taosArrayGetSize(pWal->fileInfoSet);
  ASSERT(sz > 0);
L
Liu Jicong 已提交
57
#if 0
L
Liu Jicong 已提交
58 59 60
  for (int i = 0; i < sz; i++) {
    SWalFileInfo* pFileInfo = taosArrayGet(pWal->fileInfoSet, i);
  }
L
Liu Jicong 已提交
61 62
#endif

L
Liu Jicong 已提交
63 64 65 66 67 68
  SWalFileInfo *pLastFileInfo = taosArrayGet(pWal->fileInfoSet, sz-1);
  char fnameStr[WAL_FILE_LEN];
  walBuildLogName(pWal, pLastFileInfo->firstVer, fnameStr);

  struct stat statbuf;
  stat(fnameStr, &statbuf);
L
Liu Jicong 已提交
69
  int readSize = MIN(WAL_MAX_SIZE + 2, statbuf.st_size);
L
Liu Jicong 已提交
70
  pLastFileInfo->fileSize = statbuf.st_size;
L
Liu Jicong 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

  FileFd fd = taosOpenFileRead(fnameStr);
  if (fd < 0) {
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }

  uint64_t magic = WAL_MAGIC;

  char* buf = malloc(readSize + 5);
  if (buf == NULL) {
    taosCloseFile(fd);
    terrno = TSDB_CODE_WAL_OUT_OF_MEMORY;
    return -1;
  }

L
Liu Jicong 已提交
87
  taosLSeekFile(fd, -readSize, SEEK_END);
L
Liu Jicong 已提交
88 89 90 91 92 93 94
  if (readSize != taosReadFile(fd, buf, readSize)) {
    free(buf);
    taosCloseFile(fd);
    terrno = TAOS_SYSTEM_ERROR(errno);
    return -1;
  }
  
L
Liu Jicong 已提交
95 96
  char* haystack = buf;
  char* found = NULL;
L
Liu Jicong 已提交
97
  char *candidate;
L
Liu Jicong 已提交
98
  while((candidate = tmemmem(haystack, readSize - (haystack - buf), (char*)&magic, sizeof(uint64_t))) != NULL) {
L
Liu Jicong 已提交
99
    // read and validate
L
Liu Jicong 已提交
100
    SWalHead *logContent = (SWalHead*)candidate;
L
Liu Jicong 已提交
101
    if (walValidHeadCksum(logContent) == 0 && walValidBodyCksum(logContent) == 0) {
L
Liu Jicong 已提交
102 103 104 105 106 107 108 109 110 111 112 113
      found = candidate;
    }
    haystack = candidate + 1;
  }
  if (found == buf) {
    SWalHead *logContent = (SWalHead*)found;
    if (walValidHeadCksum(logContent) != 0 || walValidBodyCksum(logContent) != 0) {
      // file has to be deleted
      free(buf);
      taosCloseFile(fd);
      terrno = TSDB_CODE_WAL_FILE_CORRUPTED;
      return -1;
L
Liu Jicong 已提交
114 115 116 117 118 119 120 121
    }
  }
  taosCloseFile(fd);
  SWalHead *lastEntry = (SWalHead*)found;

  return lastEntry->head.version;
}

L
Liu Jicong 已提交
122 123 124 125
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 已提交
126 127
  regex_t     logRegPattern;
  regex_t     idxRegPattern;
L
Liu Jicong 已提交
128
  SArray*     pLogInfoArray = taosArrayInit(8, sizeof(SWalFileInfo));
L
Liu Jicong 已提交
129 130 131

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

  DIR* dir = opendir(pWal->path);
  if (dir == NULL) {
L
Liu Jicong 已提交
135 136 137 138
    wError("vgId:%d, path:%s, failed to open since %s", pWal->cfg.vgId, pWal->path, strerror(errno));
    return -1;
  }

L
Liu Jicong 已提交
139
  // scan log files and build new meta
L
Liu Jicong 已提交
140
  struct dirent* ent;
L
Liu Jicong 已提交
141 142 143 144
  while ((ent = readdir(dir)) != NULL) {
    char* name = basename(ent->d_name);
    int   code = regexec(&logRegPattern, name, 0, NULL, 0);
    if (code == 0) {
L
Liu Jicong 已提交
145 146 147 148
      SWalFileInfo fileInfo;
      memset(&fileInfo, -1, sizeof(SWalFileInfo));
      sscanf(name, "%" PRId64 ".log", &fileInfo.firstVer);
      taosArrayPush(pLogInfoArray, &fileInfo);
L
Liu Jicong 已提交
149 150 151
    }
  }

L
Liu Jicong 已提交
152 153 154 155 156 157 158 159 160
  regfree(&logRegPattern);
  regfree(&idxRegPattern);

  taosArraySort(pLogInfoArray, compareWalFileInfo);
  int oldSz = 0;
  if (pWal->fileInfoSet) {
    oldSz = taosArrayGetSize(pWal->fileInfoSet);
  }
  int newSz = taosArrayGetSize(pLogInfoArray);
L
Liu Jicong 已提交
161 162 163 164

  if (oldSz > newSz) {
    taosArrayPopFrontBatch(pWal->fileInfoSet, oldSz - newSz); 
  } else if (oldSz < newSz) {
L
Liu Jicong 已提交
165 166 167 168
    for (int i = oldSz; i < newSz; i++) {
      SWalFileInfo *pFileInfo = taosArrayGet(pLogInfoArray, i);
      taosArrayPush(pWal->fileInfoSet, pFileInfo);
    }
L
Liu Jicong 已提交
169
  }
L
Liu Jicong 已提交
170
  taosArrayDestroy(pLogInfoArray);
L
Liu Jicong 已提交
171

L
Liu Jicong 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
  pWal->writeCur = newSz - 1;
  if (newSz > 0) {
    pWal->vers.firstVer = ((SWalFileInfo*)taosArrayGet(pWal->fileInfoSet, 0))->firstVer;

    SWalFileInfo *pLastFileInfo = taosArrayGet(pWal->fileInfoSet, newSz-1);
    char fnameStr[WAL_FILE_LEN];
    walBuildLogName(pWal, pLastFileInfo->firstVer, fnameStr);
    struct stat statbuf;
    stat(fnameStr, &statbuf);

    if (oldSz != newSz || pLastFileInfo->fileSize != statbuf.st_size) {
      pLastFileInfo->fileSize = statbuf.st_size;
      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) {
        taosArrayDestroy(pLogInfoArray);
        return -1;
L
Liu Jicong 已提交
192 193 194 195
      }
    }
  }

L
Liu Jicong 已提交
196 197
  //TODO: set fileSize and lastVer if necessary
  
L
Liu Jicong 已提交
198 199 200 201
  return 0;
}

int walCheckAndRepairIdx(SWal* pWal) {
L
Liu Jicong 已提交
202 203 204 205
  // TODO: iterate all log files
  // if idx not found, scan log and write idx
  // if found, check complete by first and last entry of each idx file
  // if idx incomplete, binary search last valid entry, and then build other part
L
Liu Jicong 已提交
206 207 208
  return 0;
}

L
Liu Jicong 已提交
209 210 211 212
int walRollFileInfo(SWal* pWal) {
  int64_t ts = taosGetTimestampSec();

  SArray* pArray = pWal->fileInfoSet;
L
Liu Jicong 已提交
213
  if (taosArrayGetSize(pArray) != 0) {
L
Liu Jicong 已提交
214
    SWalFileInfo* pInfo = taosArrayGetLast(pArray);
L
Liu Jicong 已提交
215
    pInfo->lastVer = pWal->vers.lastVer;
L
Liu Jicong 已提交
216 217 218
    pInfo->closeTs = ts;
  }

L
Liu Jicong 已提交
219
  // TODO: change to emplace back
L
Liu Jicong 已提交
220
  SWalFileInfo* pNewInfo = malloc(sizeof(SWalFileInfo));
L
Liu Jicong 已提交
221
  if (pNewInfo == NULL) {
L
Liu Jicong 已提交
222
    terrno = TSDB_CODE_WAL_OUT_OF_MEMORY;
L
Liu Jicong 已提交
223 224
    return -1;
  }
L
Liu Jicong 已提交
225
  pNewInfo->firstVer = pWal->vers.lastVer + 1;
L
Liu Jicong 已提交
226 227 228 229
  pNewInfo->lastVer = -1;
  pNewInfo->createTs = ts;
  pNewInfo->closeTs = -1;
  pNewInfo->fileSize = 0;
L
Liu Jicong 已提交
230
  taosArrayPush(pArray, pNewInfo);
L
Liu Jicong 已提交
231
  free(pNewInfo);
L
Liu Jicong 已提交
232 233 234
  return 0;
}

235
char* walMetaSerialize(SWal* pWal) {
L
Liu Jicong 已提交
236
  char buf[30];
L
Liu Jicong 已提交
237
  ASSERT(pWal->fileInfoSet);
L
Liu Jicong 已提交
238
  int    sz = pWal->fileInfoSet->size;
239 240 241 242
  cJSON* pRoot = cJSON_CreateObject();
  cJSON* pMeta = cJSON_CreateObject();
  cJSON* pFiles = cJSON_CreateArray();
  cJSON* pField;
L
Liu Jicong 已提交
243
  if (pRoot == NULL || pMeta == NULL || pFiles == NULL) {
L
Liu Jicong 已提交
244 245 246 247 248 249 250 251 252 253
    if(pRoot) {
      cJSON_Delete(pRoot);
    }
    if(pMeta) {
      cJSON_Delete(pMeta);
    }
    if(pFiles) {
      cJSON_Delete(pFiles);
    }
    terrno = TSDB_CODE_WAL_OUT_OF_MEMORY;
L
Liu Jicong 已提交
254 255
    return NULL;
  }
256
  cJSON_AddItemToObject(pRoot, "meta", pMeta);
L
Liu Jicong 已提交
257
  sprintf(buf, "%" PRId64, pWal->vers.firstVer);
258
  cJSON_AddStringToObject(pMeta, "firstVer", buf);
L
Liu Jicong 已提交
259
  sprintf(buf, "%" PRId64, pWal->vers.snapshotVer);
260
  cJSON_AddStringToObject(pMeta, "snapshotVer", buf);
L
Liu Jicong 已提交
261
  sprintf(buf, "%" PRId64, pWal->vers.commitVer);
262
  cJSON_AddStringToObject(pMeta, "commitVer", buf);
L
Liu Jicong 已提交
263
  sprintf(buf, "%" PRId64, pWal->vers.lastVer);
264 265 266
  cJSON_AddStringToObject(pMeta, "lastVer", buf);

  cJSON_AddItemToObject(pRoot, "files", pFiles);
L
Liu Jicong 已提交
267
  SWalFileInfo* pData = pWal->fileInfoSet->pData;
L
Liu Jicong 已提交
268
  for (int i = 0; i < sz; i++) {
L
Liu Jicong 已提交
269
    SWalFileInfo* pInfo = &pData[i];
270
    cJSON_AddItemToArray(pFiles, pField = cJSON_CreateObject());
L
Liu Jicong 已提交
271
    if (pField == NULL) {
272
      cJSON_Delete(pRoot);
L
Liu Jicong 已提交
273 274
      return NULL;
    }
L
Liu Jicong 已提交
275 276
    // cjson only support int32_t or double
    // string are used to prohibit the loss of precision
277 278 279 280 281 282 283 284 285 286
    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 已提交
287
  }
L
Liu Jicong 已提交
288 289 290
  char* serialized = cJSON_Print(pRoot);
  cJSON_Delete(pRoot);
  return serialized;
L
Liu Jicong 已提交
291 292
}

293 294 295 296 297 298
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 已提交
299
  pWal->vers.firstVer = atoll(cJSON_GetStringValue(pField));
300
  pField = cJSON_GetObjectItem(pMeta, "snapshotVer");
L
Liu Jicong 已提交
301
  pWal->vers.snapshotVer = atoll(cJSON_GetStringValue(pField));
302
  pField = cJSON_GetObjectItem(pMeta, "commitVer");
L
Liu Jicong 已提交
303
  pWal->vers.commitVer = atoll(cJSON_GetStringValue(pField));
304
  pField = cJSON_GetObjectItem(pMeta, "lastVer");
L
Liu Jicong 已提交
305
  pWal->vers.lastVer = atoll(cJSON_GetStringValue(pField));
306 307 308

  pFiles = cJSON_GetObjectItem(pRoot, "files");
  int sz = cJSON_GetArraySize(pFiles);
L
Liu Jicong 已提交
309
  // deserialize
L
Liu Jicong 已提交
310 311
  SArray* pArray = pWal->fileInfoSet;
  taosArrayEnsureCap(pArray, sz);
L
Liu Jicong 已提交
312
  SWalFileInfo* pData = pArray->pData;
L
Liu Jicong 已提交
313
  for (int i = 0; i < sz; i++) {
L
Liu Jicong 已提交
314 315
    cJSON*        pInfoJson = cJSON_GetArrayItem(pFiles, i);
    SWalFileInfo* pInfo = &pData[i];
L
Liu Jicong 已提交
316 317 318 319 320 321 322 323 324 325 326 327
    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);
328
  pWal->fileInfoSet = pArray;
L
Liu Jicong 已提交
329
  pWal->writeCur = sz - 1;
L
Liu Jicong 已提交
330
  cJSON_Delete(pRoot);
331
  return 0;
L
Liu Jicong 已提交
332 333 334
}

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

L
Liu Jicong 已提交
339 340
  DIR* dir = opendir(pWal->path);
  if (dir == NULL) {
L
Liu Jicong 已提交
341
    wError("vgId:%d, path:%s, failed to open since %s", pWal->cfg.vgId, pWal->path, strerror(errno));
L
Liu Jicong 已提交
342 343 344 345 346
    return -1;
  }

  struct dirent* ent;

L
Liu Jicong 已提交
347
  // find existing meta-ver[x].json
L
Liu Jicong 已提交
348
  int metaVer = -1;
L
Liu Jicong 已提交
349 350 351 352
  while ((ent = readdir(dir)) != NULL) {
    char* name = basename(ent->d_name);
    int   code = regexec(&walMetaRegexPattern, name, 0, NULL, 0);
    if (code == 0) {
L
Liu Jicong 已提交
353 354 355 356
      sscanf(name, "meta-ver%d", &metaVer);
      break;
    }
  }
L
Liu Jicong 已提交
357 358
  closedir(dir);
  regfree(&walMetaRegexPattern);
L
Liu Jicong 已提交
359 360 361
  return metaVer;
}

L
Liu Jicong 已提交
362
int walSaveMeta(SWal* pWal) {
L
Liu Jicong 已提交
363
  int  metaVer = walFindCurMetaVer(pWal);
L
Liu Jicong 已提交
364
  char fnameStr[WAL_FILE_LEN];
L
Liu Jicong 已提交
365
  walBuildMetaName(pWal, metaVer + 1, fnameStr);
L
Liu Jicong 已提交
366 367
  FileFd metaFd = taosOpenFileCreateWrite(fnameStr);
  if (metaFd < 0) {
L
Liu Jicong 已提交
368 369
    return -1;
  }
370
  char* serialized = walMetaSerialize(pWal);
L
Liu Jicong 已提交
371
  int   len = strlen(serialized);
L
Liu Jicong 已提交
372
  if (len != taosWriteFile(metaFd, serialized, len)) {
L
Liu Jicong 已提交
373
    // TODO:clean file
L
Liu Jicong 已提交
374 375
    return -1;
  }
L
Liu Jicong 已提交
376

L
Liu Jicong 已提交
377
  taosCloseFile(metaFd);
L
Liu Jicong 已提交
378 379
  // delete old file
  if (metaVer > -1) {
L
Liu Jicong 已提交
380 381 382
    walBuildMetaName(pWal, metaVer, fnameStr);
    remove(fnameStr);
  }
L
Liu Jicong 已提交
383
  free(serialized);
L
Liu Jicong 已提交
384 385 386
  return 0;
}

L
Liu Jicong 已提交
387
int walLoadMeta(SWal* pWal) {
L
Liu Jicong 已提交
388
  ASSERT(pWal->fileInfoSet->size == 0);
L
Liu Jicong 已提交
389
  // find existing meta file
L
Liu Jicong 已提交
390
  int metaVer = walFindCurMetaVer(pWal);
L
Liu Jicong 已提交
391
  if (metaVer == -1) {
L
Liu Jicong 已提交
392
    return -1;
L
Liu Jicong 已提交
393 394 395
  }
  char fnameStr[WAL_FILE_LEN];
  walBuildMetaName(pWal, metaVer, fnameStr);
L
Liu Jicong 已提交
396
  // read metafile
L
Liu Jicong 已提交
397 398
  struct stat statbuf;
  stat(fnameStr, &statbuf);
L
Liu Jicong 已提交
399
  int   size = statbuf.st_size;
L
Liu Jicong 已提交
400
  char* buf = malloc(size + 5);
L
Liu Jicong 已提交
401
  if (buf == NULL) {
L
Liu Jicong 已提交
402
    terrno = TSDB_CODE_WAL_OUT_OF_MEMORY;
L
Liu Jicong 已提交
403 404
    return -1;
  }
L
Liu Jicong 已提交
405
  memset(buf, 0, size + 5);
L
Liu Jicong 已提交
406
  FileFd fd = taosOpenFileRead(fnameStr);
L
Liu Jicong 已提交
407 408 409 410
  if (fd < 0) {
    terrno = TSDB_CODE_WAL_FILE_CORRUPTED;
    return -1;
  }
L
Liu Jicong 已提交
411 412 413
  if (taosReadFile(fd, buf, size) != size) {
    terrno = TAOS_SYSTEM_ERROR(errno);
    taosCloseFile(fd);
L
Liu Jicong 已提交
414 415 416
    free(buf);
    return -1;
  }
L
Liu Jicong 已提交
417
  // load into fileInfoSet
418
  int code = walMetaDeserialize(pWal, buf);
L
Liu Jicong 已提交
419
  taosCloseFile(fd);
L
Liu Jicong 已提交
420
  free(buf);
L
Liu Jicong 已提交
421
  return code;
L
Liu Jicong 已提交
422
}