walMeta.c 8.4 KB
Newer Older
L
Liu Jicong 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * 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/>.
 */

#define _DEFAULT_SOURCE
L
Liu Jicong 已提交
17
#include "cJSON.h"
L
Liu Jicong 已提交
18 19 20
#include "os.h"
#include "taoserror.h"
#include "tfile.h"
L
Liu Jicong 已提交
21
#include "tref.h"
L
Liu Jicong 已提交
22 23 24 25 26
#include "walInt.h"

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

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

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

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

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

L
Liu Jicong 已提交
37 38 39 40
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 已提交
41 42 43
  regex_t     logRegPattern;
  regex_t     idxRegPattern;
  SArray*     pLogArray = taosArrayInit(8, sizeof(int64_t));
L
Liu Jicong 已提交
44 45 46

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

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

  struct dirent* ent;
L
Liu Jicong 已提交
55 56 57 58
  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 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
      int64_t firstVer;
      sscanf(name, "%" PRId64 ".log", &firstVer);
      taosArrayPush(pLogArray, &firstVer);
    }
  }

  // load meta
  // if not match, or meta missing
  // rebuild meta
  return 0;
}

int walCheckAndRepairIdx(SWal* pWal) {
  // iterate all idx files
  // check first and last entry of each idx file valid
  return 0;
}

L
Liu Jicong 已提交
77 78 79 80
int walRollFileInfo(SWal* pWal) {
  int64_t ts = taosGetTimestampSec();

  SArray* pArray = pWal->fileInfoSet;
L
Liu Jicong 已提交
81
  if (taosArrayGetSize(pArray) != 0) {
L
Liu Jicong 已提交
82
    SWalFileInfo* pInfo = taosArrayGetLast(pArray);
L
Liu Jicong 已提交
83
    pInfo->lastVer = pWal->vers.lastVer;
L
Liu Jicong 已提交
84 85 86
    pInfo->closeTs = ts;
  }

L
Liu Jicong 已提交
87
  // TODO: change to emplace back
L
Liu Jicong 已提交
88
  SWalFileInfo* pNewInfo = malloc(sizeof(SWalFileInfo));
L
Liu Jicong 已提交
89
  if (pNewInfo == NULL) {
L
Liu Jicong 已提交
90 91
    return -1;
  }
L
Liu Jicong 已提交
92
  pNewInfo->firstVer = pWal->vers.lastVer + 1;
L
Liu Jicong 已提交
93 94 95 96 97
  pNewInfo->lastVer = -1;
  pNewInfo->createTs = ts;
  pNewInfo->closeTs = -1;
  pNewInfo->fileSize = 0;
  taosArrayPush(pWal->fileInfoSet, pNewInfo);
L
Liu Jicong 已提交
98
  free(pNewInfo);
L
Liu Jicong 已提交
99 100 101
  return 0;
}

102
char* walMetaSerialize(SWal* pWal) {
L
Liu Jicong 已提交
103
  char buf[30];
L
Liu Jicong 已提交
104
  ASSERT(pWal->fileInfoSet);
L
Liu Jicong 已提交
105
  int    sz = pWal->fileInfoSet->size;
106 107 108 109
  cJSON* pRoot = cJSON_CreateObject();
  cJSON* pMeta = cJSON_CreateObject();
  cJSON* pFiles = cJSON_CreateArray();
  cJSON* pField;
L
Liu Jicong 已提交
110 111
  if (pRoot == NULL || pMeta == NULL || pFiles == NULL) {
    // TODO
L
Liu Jicong 已提交
112 113
    return NULL;
  }
114
  cJSON_AddItemToObject(pRoot, "meta", pMeta);
L
Liu Jicong 已提交
115
  sprintf(buf, "%" PRId64, pWal->vers.firstVer);
116
  cJSON_AddStringToObject(pMeta, "firstVer", buf);
L
Liu Jicong 已提交
117
  sprintf(buf, "%" PRId64, pWal->vers.snapshotVer);
118
  cJSON_AddStringToObject(pMeta, "snapshotVer", buf);
L
Liu Jicong 已提交
119
  sprintf(buf, "%" PRId64, pWal->vers.commitVer);
120
  cJSON_AddStringToObject(pMeta, "commitVer", buf);
L
Liu Jicong 已提交
121
  sprintf(buf, "%" PRId64, pWal->vers.lastVer);
122 123 124
  cJSON_AddStringToObject(pMeta, "lastVer", buf);

  cJSON_AddItemToObject(pRoot, "files", pFiles);
L
Liu Jicong 已提交
125
  SWalFileInfo* pData = pWal->fileInfoSet->pData;
L
Liu Jicong 已提交
126
  for (int i = 0; i < sz; i++) {
L
Liu Jicong 已提交
127
    SWalFileInfo* pInfo = &pData[i];
128
    cJSON_AddItemToArray(pFiles, pField = cJSON_CreateObject());
L
Liu Jicong 已提交
129
    if (pField == NULL) {
130
      cJSON_Delete(pRoot);
L
Liu Jicong 已提交
131 132
      return NULL;
    }
L
Liu Jicong 已提交
133 134
    // cjson only support int32_t or double
    // string are used to prohibit the loss of precision
135 136 137 138 139 140 141 142 143 144
    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 已提交
145
  }
L
Liu Jicong 已提交
146 147 148
  char* serialized = cJSON_Print(pRoot);
  cJSON_Delete(pRoot);
  return serialized;
L
Liu Jicong 已提交
149 150
}

151 152 153 154 155 156
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 已提交
157
  pWal->vers.firstVer = atoll(cJSON_GetStringValue(pField));
158
  pField = cJSON_GetObjectItem(pMeta, "snapshotVer");
L
Liu Jicong 已提交
159
  pWal->vers.snapshotVer = atoll(cJSON_GetStringValue(pField));
160
  pField = cJSON_GetObjectItem(pMeta, "commitVer");
L
Liu Jicong 已提交
161
  pWal->vers.commitVer = atoll(cJSON_GetStringValue(pField));
162
  pField = cJSON_GetObjectItem(pMeta, "lastVer");
L
Liu Jicong 已提交
163
  pWal->vers.lastVer = atoll(cJSON_GetStringValue(pField));
164 165 166

  pFiles = cJSON_GetObjectItem(pRoot, "files");
  int sz = cJSON_GetArraySize(pFiles);
L
Liu Jicong 已提交
167
  // deserialize
L
Liu Jicong 已提交
168 169
  SArray* pArray = pWal->fileInfoSet;
  taosArrayEnsureCap(pArray, sz);
L
Liu Jicong 已提交
170
  SWalFileInfo* pData = pArray->pData;
L
Liu Jicong 已提交
171
  for (int i = 0; i < sz; i++) {
L
Liu Jicong 已提交
172 173
    cJSON*        pInfoJson = cJSON_GetArrayItem(pFiles, i);
    SWalFileInfo* pInfo = &pData[i];
L
Liu Jicong 已提交
174 175 176 177 178 179 180 181 182 183 184 185
    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);
186
  pWal->fileInfoSet = pArray;
L
Liu Jicong 已提交
187
  pWal->writeCur = sz - 1;
L
Liu Jicong 已提交
188
  cJSON_Delete(pRoot);
189
  return 0;
L
Liu Jicong 已提交
190 191 192
}

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

L
Liu Jicong 已提交
197 198
  DIR* dir = opendir(pWal->path);
  if (dir == NULL) {
L
Liu Jicong 已提交
199
    wError("vgId:%d, path:%s, failed to open since %s", pWal->cfg.vgId, pWal->path, strerror(errno));
L
Liu Jicong 已提交
200 201 202 203 204
    return -1;
  }

  struct dirent* ent;

L
Liu Jicong 已提交
205
  // find existing meta-ver[x].json
L
Liu Jicong 已提交
206
  int metaVer = -1;
L
Liu Jicong 已提交
207 208 209 210
  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 已提交
211 212 213 214
      sscanf(name, "meta-ver%d", &metaVer);
      break;
    }
  }
L
Liu Jicong 已提交
215 216
  closedir(dir);
  regfree(&walMetaRegexPattern);
L
Liu Jicong 已提交
217 218 219
  return metaVer;
}

L
Liu Jicong 已提交
220
int walSaveMeta(SWal* pWal) {
L
Liu Jicong 已提交
221
  int  metaVer = walFindCurMetaVer(pWal);
L
Liu Jicong 已提交
222
  char fnameStr[WAL_FILE_LEN];
L
Liu Jicong 已提交
223
  walBuildMetaName(pWal, metaVer + 1, fnameStr);
L
Liu Jicong 已提交
224
  int metaTfd = tfOpenCreateWrite(fnameStr);
L
Liu Jicong 已提交
225
  if (metaTfd < 0) {
L
Liu Jicong 已提交
226 227
    return -1;
  }
228
  char* serialized = walMetaSerialize(pWal);
L
Liu Jicong 已提交
229 230 231
  int   len = strlen(serialized);
  if (len != tfWrite(metaTfd, serialized, len)) {
    // TODO:clean file
L
Liu Jicong 已提交
232 233
    return -1;
  }
L
Liu Jicong 已提交
234

L
Liu Jicong 已提交
235
  tfClose(metaTfd);
L
Liu Jicong 已提交
236 237
  // delete old file
  if (metaVer > -1) {
L
Liu Jicong 已提交
238 239 240
    walBuildMetaName(pWal, metaVer, fnameStr);
    remove(fnameStr);
  }
L
Liu Jicong 已提交
241
  free(serialized);
L
Liu Jicong 已提交
242 243 244
  return 0;
}

L
Liu Jicong 已提交
245
int walLoadMeta(SWal* pWal) {
L
Liu Jicong 已提交
246
  ASSERT(pWal->fileInfoSet->size == 0);
L
Liu Jicong 已提交
247
  // find existing meta file
L
Liu Jicong 已提交
248
  int metaVer = walFindCurMetaVer(pWal);
L
Liu Jicong 已提交
249
  if (metaVer == -1) {
L
Liu Jicong 已提交
250 251 252 253
    return 0;
  }
  char fnameStr[WAL_FILE_LEN];
  walBuildMetaName(pWal, metaVer, fnameStr);
L
Liu Jicong 已提交
254
  // read metafile
L
Liu Jicong 已提交
255 256
  struct stat statbuf;
  stat(fnameStr, &statbuf);
L
Liu Jicong 已提交
257
  int   size = statbuf.st_size;
L
Liu Jicong 已提交
258
  char* buf = malloc(size + 5);
L
Liu Jicong 已提交
259
  if (buf == NULL) {
L
Liu Jicong 已提交
260 261
    return -1;
  }
L
Liu Jicong 已提交
262
  memset(buf, 0, size + 5);
L
Liu Jicong 已提交
263
  int tfd = tfOpenRead(fnameStr);
L
Liu Jicong 已提交
264
  if (tfRead(tfd, buf, size) != size) {
L
Liu Jicong 已提交
265
    tfClose(tfd);
L
Liu Jicong 已提交
266 267 268
    free(buf);
    return -1;
  }
L
Liu Jicong 已提交
269
  // load into fileInfoSet
270
  int code = walMetaDeserialize(pWal, buf);
L
Liu Jicong 已提交
271
  if (code != 0) {
L
Liu Jicong 已提交
272
    tfClose(tfd);
L
Liu Jicong 已提交
273 274 275
    free(buf);
    return -1;
  }
L
Liu Jicong 已提交
276
  tfClose(tfd);
L
Liu Jicong 已提交
277 278 279
  free(buf);
  return 0;
}