• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #5125

16 Sep 2026 01:31AM UTC coverage: 73.454% (+0.7%) from 72.781%
#5125

push

travis-ci

jbjia
test(coverage): sync from gitlab

311157 of 423608 relevant lines covered (73.45%)

66601041.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.92
/source/dnode/vnode/src/vnd/vnodeOpen.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15

16
#include "sync.h"
17
#include "tss.h"
18
#include "tq.h"
19
#include "tsdb.h"
20
#include "vnd.h"
21

22
void vnodeGetPrimaryDir(const char *relPath, int32_t diskPrimary, STfs *pTfs, char *buf, size_t bufLen) {
25,558,593 ✔
23
  if (pTfs) {
25,558,593 ✔
24
    SDiskID diskId = {0};
25,558,811 ✔
25
    diskId.id = diskPrimary;
25,558,811 ✔
26
    snprintf(buf, bufLen - 1, "%s%s%s", tfsGetDiskPath(pTfs, diskId), TD_DIRSEP, relPath);
25,558,811 ✔
27
  } else {
28
    snprintf(buf, bufLen - 1, "%s", relPath);
565 ✔
29
  }
30
  buf[bufLen - 1] = '\0';
25,572,037 ✔
31
}
25,572,037 ✔
32

33
void vnodeGetPrimaryPath(SVnode *pVnode, bool mount, char *buf, size_t bufLen) {
22,712,580 ✔
34
  if (pVnode->mounted) {
22,712,580 ✔
35
    if (mount) {  // mount path
8,184 ✔
36
      SDiskID diskId = {0};
×
37
      diskId.id = pVnode->diskPrimary;
×
38
      snprintf(buf, bufLen - 1, "%s%svnode%svnode%d", tfsGetDiskPath(pVnode->pMountTfs, diskId), TD_DIRSEP, TD_DIRSEP,
×
39
               pVnode->config.mountVgId);
40
    } else {  // host path
41
      vnodeGetPrimaryDir(pVnode->path, 0, pVnode->pTfs, buf, bufLen);
8,184 ✔
42
    }
43
    buf[bufLen - 1] = '\0';
8,184 ✔
44

45
  } else {
46
    vnodeGetPrimaryDir(pVnode->path, pVnode->diskPrimary, pVnode->pTfs, buf, bufLen);
22,704,396 ✔
47
  }
48
}
22,730,828 ✔
49

50
static int32_t vnodeMkDir(STfs *pTfs, const char *path) {
2,618,801 ✔
51
  if (pTfs) {
2,618,801 ✔
52
    return tfsMkdirRecur(pTfs, path);
2,620,236 ✔
53
  } else {
54
    return taosMkDir(path);
×
55
  }
56
}
57

58
int32_t vnodeCreate(const char *path, SVnodeCfg *pCfg, int32_t diskPrimary, STfs *pTfs) {
1,148,499 ✔
59
  int32_t    code = 0;
1,148,499 ✔
60
  SVnodeInfo info = {0};
1,148,499 ✔
61
  char       dir[TSDB_FILENAME_LEN] = {0};
1,148,817 ✔
62

63
  // check config
64
  if ((code = vnodeCheckCfg(pCfg)) < 0) {
1,148,817 ✔
65
    vError("vgId:%d, failed to create vnode since:%s", pCfg->vgId, tstrerror(code));
×
66
    return code;
×
67
  }
68

69
  // create vnode env
70
  if (vnodeMkDir(pTfs, path)) {
1,148,817 ✔
71
    vError("vgId:%d, failed to prepare vnode dir since %s, path: %s", pCfg->vgId, strerror(ERRNO), path);
×
72
    return TAOS_SYSTEM_ERROR(ERRNO);
×
73
  }
74
  vnodeGetPrimaryDir(path, diskPrimary, pTfs, dir, TSDB_FILENAME_LEN);
1,148,817 ✔
75

76
  if (pCfg) {
1,148,817 ✔
77
    info.config = *pCfg;
1,148,817 ✔
78
  } else {
79
    info.config = vnodeCfgDefault;
×
80
  }
81
  info.state.committed = -1;
1,148,817 ✔
82
  info.state.applied = -1;
1,148,817 ✔
83
  info.state.commitID = 0;
1,148,817 ✔
84

85
  SVnodeInfo oldInfo = {0};
1,148,817 ✔
86
  oldInfo.config = vnodeCfgDefault;
1,148,817 ✔
87
  if (vnodeLoadInfo(dir, &oldInfo) == 0) {
1,148,817 ✔
88
    code = (oldInfo.config.dbId == info.config.dbId) ? 0 : TSDB_CODE_VND_ALREADY_EXIST_BUT_NOT_MATCH;
280 ✔
89
    if (code == 0) {
280 ✔
90
      vWarn("vgId:%d, vnode config info already exists at %s.", oldInfo.config.vgId, dir);
280 ✔
91
    } else {
92
      vError("vgId:%d, vnode config info already exists at %s. oldDbId:%" PRId64 "(%s) at cluster:%" PRId64
×
93
             ", newDbId:%" PRId64 "(%s) at cluser:%" PRId64 ", code:%s",
94
             oldInfo.config.vgId, dir, oldInfo.config.dbId, oldInfo.config.dbname,
95
             oldInfo.config.syncCfg.nodeInfo[oldInfo.config.syncCfg.myIndex].clusterId, info.config.dbId,
96
             info.config.dbname, info.config.syncCfg.nodeInfo[info.config.syncCfg.myIndex].clusterId, tstrerror(code));
97
    }
98
    return code;
280 ✔
99
  }
100

101
  vInfo("vgId:%d, save config while create", info.config.vgId);
1,148,537 ✔
102
  if ((code = vnodeSaveInfo(dir, &info)) < 0 || (code = vnodeCommitInfo(dir)) < 0) {
1,148,537 ✔
103
    vError("vgId:%d, failed to save vnode config since %s", pCfg ? pCfg->vgId : 0, tstrerror(code));
243 ✔
104
    return code;
28 ✔
105
  }
106

107
  vInfo("vgId:%d, vnode is created", info.config.vgId);
1,148,509 ✔
108
  return 0;
1,147,468 ✔
109
}
110

111
bool vnodeShouldRemoveWal(SVnode *pVnode) { return pVnode->config.walCfg.clearFiles == 1; }
222,395 ✔
112

113
int32_t vnodeAlterReplica(const char *path, SAlterVnodeReplicaReq *pReq, int32_t diskPrimary, STfs *pTfs) {
222,395 ✔
114
  SVnodeInfo info = {0};
222,395 ✔
115
  char       dir[TSDB_FILENAME_LEN] = {0};
222,395 ✔
116
  int32_t    ret = 0;
222,395 ✔
117

118
  vnodeGetPrimaryDir(path, diskPrimary, pTfs, dir, TSDB_FILENAME_LEN);
222,395 ✔
119

120
  ret = vnodeLoadInfo(dir, &info);
222,395 ✔
121
  if (ret < 0) {
222,395 ✔
122
    vError("vgId:%d, failed to read vnode config from %s since %s", pReq->vgId, path, tstrerror(terrno));
×
123
    return ret;
×
124
  }
125

126
  SSyncCfg *pCfg = &info.config.syncCfg;
222,395 ✔
127

128
  pCfg->replicaNum = 0;
222,395 ✔
129
  pCfg->totalReplicaNum = 0;
222,395 ✔
130
  memset(&pCfg->nodeInfo, 0, sizeof(pCfg->nodeInfo));
222,395 ✔
131

132
  for (int i = 0; i < pReq->replica; ++i) {
878,165 ✔
133
    SNodeInfo *pNode = &pCfg->nodeInfo[i];
655,770 ✔
134
    pNode->nodeId = pReq->replicas[i].id;
655,770 ✔
135
    pNode->nodePort = pReq->replicas[i].port;
655,770 ✔
136
    tstrncpy(pNode->nodeFqdn, pReq->replicas[i].fqdn, sizeof(pNode->nodeFqdn));
655,770 ✔
137
    pNode->nodeRole = TAOS_SYNC_ROLE_VOTER;
655,770 ✔
138
    bool ret = tmsgUpdateDnodeInfo(&pNode->nodeId, &pNode->clusterId, pNode->nodeFqdn, &pNode->nodePort);
655,770 ✔
139
    vInfo("vgId:%d, replica:%d ep:%s:%u dnode:%d", pReq->vgId, i, pNode->nodeFqdn, pNode->nodePort, pNode->nodeId);
655,770 ✔
140
    pCfg->replicaNum++;
655,770 ✔
141
  }
142
  if (pReq->selfIndex != -1) {
222,395 ✔
143
    pCfg->myIndex = pReq->selfIndex;
222,395 ✔
144
  }
145
  for (int i = pCfg->replicaNum; i < pReq->replica + pReq->learnerReplica; ++i) {
278,771 ✔
146
    SNodeInfo *pNode = &pCfg->nodeInfo[i];
56,376 ✔
147
    pNode->nodeId = pReq->learnerReplicas[pCfg->totalReplicaNum].id;
56,376 ✔
148
    pNode->nodePort = pReq->learnerReplicas[pCfg->totalReplicaNum].port;
56,376 ✔
149
    pNode->nodeRole = TAOS_SYNC_ROLE_LEARNER;
56,376 ✔
150
    tstrncpy(pNode->nodeFqdn, pReq->learnerReplicas[pCfg->totalReplicaNum].fqdn, sizeof(pNode->nodeFqdn));
56,376 ✔
151
    bool ret = tmsgUpdateDnodeInfo(&pNode->nodeId, &pNode->clusterId, pNode->nodeFqdn, &pNode->nodePort);
56,376 ✔
152
    vInfo("vgId:%d, replica:%d ep:%s:%u dnode:%d", pReq->vgId, i, pNode->nodeFqdn, pNode->nodePort, pNode->nodeId);
56,376 ✔
153
    pCfg->totalReplicaNum++;
56,376 ✔
154
  }
155
  pCfg->totalReplicaNum += pReq->replica;
222,395 ✔
156
  if (pReq->learnerSelfIndex != -1) {
222,395 ✔
157
    pCfg->myIndex = pReq->replica + pReq->learnerSelfIndex;
×
158
  }
159
  pCfg->changeVersion = pReq->changeVersion;
222,395 ✔
160

161
  if (info.config.walCfg.clearFiles) {
222,395 ✔
162
    info.config.walCfg.clearFiles = 0;
×
163

164
    vInfo("vgId:%d, reset wal clearFiles", pReq->vgId);
×
165
  }
166

167
  vInfo("vgId:%d, save config while alter, replicas:%d totalReplicas:%d selfIndex:%d changeVersion:%d", pReq->vgId,
222,395 ✔
168
        pCfg->replicaNum, pCfg->totalReplicaNum, pCfg->myIndex, pCfg->changeVersion);
169

170
  info.config.syncCfg = *pCfg;
222,395 ✔
171
  ret = vnodeSaveInfo(dir, &info);
222,395 ✔
172
  if (ret < 0) {
222,395 ✔
173
    vError("vgId:%d, failed to save vnode config since %s", pReq->vgId, tstrerror(terrno));
×
174
    return ret;
×
175
  }
176

177
  ret = vnodeCommitInfo(dir);
222,395 ✔
178
  if (ret < 0) {
222,395 ✔
179
    vError("vgId:%d, failed to commit vnode config since %s", pReq->vgId, tstrerror(terrno));
×
180
    return ret;
×
181
  }
182

183
  vInfo("vgId:%d, vnode config is saved", info.config.vgId);
222,395 ✔
184
  return 0;
222,395 ✔
185
}
186

187
static int32_t vnodeVgroupIdLen(int32_t vgId) {
7,363 ✔
188
  char tmp[TSDB_FILENAME_LEN];
7,363 ✔
189
  (void)snprintf(tmp, TSDB_FILENAME_LEN, "%d", vgId);
7,363 ✔
190
  return strlen(tmp);
7,363 ✔
191
}
192

193
int32_t vnodeRenameVgroupId(const char *srcPath, const char *dstPath, int32_t srcVgId, int32_t dstVgId,
2,881 ✔
194
                            int32_t diskPrimary, STfs *pTfs) {
195
  int32_t ret = 0;
2,881 ✔
196

197
  char oldRname[TSDB_FILENAME_LEN] = {0};
2,881 ✔
198
  char newRname[TSDB_FILENAME_LEN] = {0};
2,881 ✔
199
  char tsdbPath[TSDB_FILENAME_LEN] = {0};
2,881 ✔
200
  char tsdbFilePrefix[TSDB_FILENAME_LEN] = {0};
2,881 ✔
201
  snprintf(tsdbPath, TSDB_FILENAME_LEN, "%s%stsdb", srcPath, TD_DIRSEP);
2,881 ✔
202
  snprintf(tsdbFilePrefix, TSDB_FILENAME_LEN, "tsdb%sv", TD_DIRSEP);
2,881 ✔
203
  int32_t prefixLen = strlen(tsdbFilePrefix);
2,881 ✔
204

205
  STfsDir *tsdbDir = NULL;
2,881 ✔
206
  int32_t  tret = tfsOpendir(pTfs, tsdbPath, &tsdbDir);
2,881 ✔
207
  if (tsdbDir == NULL) {
2,881 ✔
208
    return 0;
×
209
  }
210

211
  while (1) {
13,125 ✔
212
    const STfsFile *tsdbFile = tfsReaddir(tsdbDir);
16,006 ✔
213
    if (tsdbFile == NULL) break;
16,006 ✔
214
    if (tsdbFile->rname[0] == '\0') continue;
13,125 ✔
215
    tstrncpy(oldRname, tsdbFile->rname, TSDB_FILENAME_LEN);
13,125 ✔
216

217
    char *tsdbFilePrefixPos = strstr(oldRname, tsdbFilePrefix);
13,125 ✔
218
    if (tsdbFilePrefixPos == NULL) continue;
13,125 ✔
219

220
    int32_t tsdbFileVgId = 0;
7,363 ✔
221
    ret = taosStr2int32(tsdbFilePrefixPos + prefixLen, &tsdbFileVgId);
7,363 ✔
222
    if (ret != 0) {
7,363 ✔
223
      vError("vgId:%d, failed to get tsdb file vgid since %s", dstVgId, tstrerror(ret));
×
224
      tfsClosedir(tsdbDir);
×
225
      return ret;
×
226
    }
227

228
    if (tsdbFileVgId == srcVgId) {
7,363 ✔
229
      char *tsdbFileSurfixPos = tsdbFilePrefixPos + prefixLen + vnodeVgroupIdLen(srcVgId);
7,363 ✔
230

231
      tsdbFilePrefixPos[prefixLen] = 0;
7,363 ✔
232
      snprintf(newRname, TSDB_FILENAME_LEN, "%s%d%s", oldRname, dstVgId, tsdbFileSurfixPos);
7,363 ✔
233
      vInfo("vgId:%d, rename file from %s to %s", dstVgId, tsdbFile->rname, newRname);
7,363 ✔
234

235
      ret = tfsRename(pTfs, diskPrimary, tsdbFile->rname, newRname);
7,363 ✔
236
      if (ret != 0) {
7,363 ✔
237
        vError("vgId:%d, failed to rename file from %s to %s since %s", dstVgId, tsdbFile->rname, newRname, terrstr());
×
238
        tfsClosedir(tsdbDir);
×
239
        return ret;
×
240
      }
241
    }
242
  }
243

244
  tfsClosedir(tsdbDir);
2,881 ✔
245

246
  vInfo("vgId:%d, rename dir from %s to %s", dstVgId, srcPath, dstPath);
2,881 ✔
247
  ret = tfsRename(pTfs, diskPrimary, srcPath, dstPath);
2,881 ✔
248
  if (ret != 0) {
2,881 ✔
249
    vError("vgId:%d, failed to rename dir from %s to %s since %s", dstVgId, srcPath, dstPath, terrstr());
×
250
  }
251
  return ret;
2,881 ✔
252
}
253

254
int32_t vnodeAlterHashRange(const char *srcPath, const char *dstPath, SAlterVnodeHashRangeReq *pReq,
2,881 ✔
255
                            int32_t diskPrimary, STfs *pTfs) {
256
  SVnodeInfo info = {0};
2,881 ✔
257
  char       dir[TSDB_FILENAME_LEN] = {0};
2,881 ✔
258
  int32_t    ret = 0;
2,881 ✔
259

260
  vnodeGetPrimaryDir(srcPath, diskPrimary, pTfs, dir, TSDB_FILENAME_LEN);
2,881 ✔
261

262
  ret = vnodeLoadInfo(dir, &info);
2,881 ✔
263
  if (ret < 0) {
2,881 ✔
264
    vError("vgId:%d, failed to read vnode config from %s since %s", pReq->srcVgId, srcPath, tstrerror(terrno));
×
265
    return ret;
×
266
  }
267

268
  vInfo("vgId:%d, alter hashrange from [%u, %u] to [%u, %u]", pReq->srcVgId, info.config.hashBegin, info.config.hashEnd,
2,881 ✔
269
        pReq->hashBegin, pReq->hashEnd);
270
  info.config.vgId = pReq->dstVgId;
2,881 ✔
271
  info.config.hashBegin = pReq->hashBegin;
2,881 ✔
272
  info.config.hashEnd = pReq->hashEnd;
2,881 ✔
273
  info.config.hashChange = true;
2,881 ✔
274
  info.config.walCfg.vgId = pReq->dstVgId;
2,881 ✔
275
  info.config.syncCfg.changeVersion = pReq->changeVersion;
2,881 ✔
276

277
  SSyncCfg *pCfg = &info.config.syncCfg;
2,881 ✔
278
  pCfg->myIndex = 0;
2,881 ✔
279
  pCfg->replicaNum = 1;
2,881 ✔
280
  pCfg->totalReplicaNum = 1;
2,881 ✔
281
  memset(&pCfg->nodeInfo, 0, sizeof(pCfg->nodeInfo));
2,881 ✔
282

283
  vInfo("vgId:%d, alter vnode replicas to 1", pReq->srcVgId);
2,881 ✔
284
  SNodeInfo *pNode = &pCfg->nodeInfo[0];
2,881 ✔
285
  pNode->nodePort = tsServerPort;
2,881 ✔
286
  tstrncpy(pNode->nodeFqdn, tsLocalFqdn, TSDB_FQDN_LEN);
2,881 ✔
287
  bool ret1 = tmsgUpdateDnodeInfo(&pNode->nodeId, &pNode->clusterId, pNode->nodeFqdn, &pNode->nodePort);
2,881 ✔
288
  vInfo("vgId:%d, ep:%s:%u dnode:%d", pReq->srcVgId, pNode->nodeFqdn, pNode->nodePort, pNode->nodeId);
2,881 ✔
289

290
  info.config.syncCfg = *pCfg;
2,881 ✔
291

292
  ret = vnodeSaveInfo(dir, &info);
2,881 ✔
293
  if (ret < 0) {
2,881 ✔
294
    vError("vgId:%d, failed to save vnode config since %s", pReq->dstVgId, tstrerror(terrno));
×
295
    return ret;
×
296
  }
297

298
  ret = vnodeCommitInfo(dir);
2,881 ✔
299
  if (ret < 0) {
2,881 ✔
300
    vError("vgId:%d, failed to commit vnode config since %s", pReq->dstVgId, tstrerror(terrno));
×
301
    return ret;
×
302
  }
303

304
  vInfo("vgId:%d, rename %s to %s", pReq->dstVgId, srcPath, dstPath);
2,881 ✔
305
  ret = vnodeRenameVgroupId(srcPath, dstPath, pReq->srcVgId, pReq->dstVgId, diskPrimary, pTfs);
2,881 ✔
306
  if (ret < 0) {
2,881 ✔
307
    vError("vgId:%d, failed to rename vnode from %s to %s since %s", pReq->dstVgId, srcPath, dstPath,
×
308
           tstrerror(terrno));
309
    return ret;
×
310
  }
311

312
  vInfo("vgId:%d, vnode hashrange is altered", info.config.vgId);
2,881 ✔
313
  return 0;
2,881 ✔
314
}
315

316
int32_t vnodeRestoreVgroupId(const char *srcPath, const char *dstPath, int32_t srcVgId, int32_t dstVgId,
×
317
                             int32_t diskPrimary, STfs *pTfs) {
318
  SVnodeInfo info = {0};
×
319
  char       dir[TSDB_FILENAME_LEN] = {0};
×
320
  int32_t    code = 0;
×
321

322
  vnodeGetPrimaryDir(dstPath, diskPrimary, pTfs, dir, TSDB_FILENAME_LEN);
×
323
  if (vnodeLoadInfo(dir, &info) == 0) {
×
324
    if (info.config.vgId != dstVgId) {
×
325
      vError("vgId:%d, unexpected vnode config.vgId:%d", dstVgId, info.config.vgId);
×
326
      return TSDB_CODE_FAILED;
×
327
    }
328
    return dstVgId;
×
329
  }
330

331
  vnodeGetPrimaryDir(srcPath, diskPrimary, pTfs, dir, TSDB_FILENAME_LEN);
×
332
  if ((code = vnodeLoadInfo(dir, &info)) < 0) {
×
333
    vError("vgId:%d, failed to read vnode config from %s since %s", srcVgId, srcPath, tstrerror(terrno));
×
334
    return code;
×
335
  }
336

337
  if (info.config.vgId == srcVgId) {
×
338
    vInfo("vgId:%d, rollback alter hashrange", srcVgId);
×
339
    return srcVgId;
×
340
  } else if (info.config.vgId != dstVgId) {
×
341
    vError("vgId:%d, unexpected vnode config.vgId:%d", dstVgId, info.config.vgId);
×
342
    return TSDB_CODE_FAILED;
×
343
  }
344

345
  vInfo("vgId:%d, rename %s to %s", dstVgId, srcPath, dstPath);
×
346
  if (vnodeRenameVgroupId(srcPath, dstPath, srcVgId, dstVgId, diskPrimary, pTfs) < 0) {
×
347
    vError("vgId:%d, failed to rename vnode from %s to %s since %s", dstVgId, srcPath, dstPath, tstrerror(terrno));
×
348
    return TSDB_CODE_FAILED;
×
349
  }
350

351
  return dstVgId;
×
352
}
353

354
void vnodeDestroy(int32_t vgId, const char *path, STfs *pTfs, int32_t nodeId) {
623,237 ✔
355
  vInfo("path:%s is removed while destroy vnode", path);
623,237 ✔
356
  if (tfsRmdir(pTfs, path) < 0) {
623,237 ✔
357
    vError("failed to remove path:%s since %s", path, tstrerror(terrno));
×
358
  }
359

360
#ifdef USE_SHARED_STORAGE
361
  if (nodeId > 0 && vgId > 0 && tsSsEnabled) {
623,237 ✔
362
    // we should only do this on the leader node, but it is ok to do this on all nodes
363
    char prefix[TSDB_FILENAME_LEN];
7,470 ✔
364
    snprintf(prefix, TSDB_FILENAME_LEN, "vnode%d/", vgId);
7,470 ✔
365
    int32_t code = tssDeleteFileByPrefixFromDefault(prefix);
7,470 ✔
366
    if (code < 0) {
7,470 ✔
367
      vError("vgId:%d, failed to remove vnode files from shared storage since %s", vgId, tstrerror(code));
7,243 ✔
368
    } else {
369
      vInfo("vgId:%d, removed vnode files from shared storage", vgId);
227 ✔
370
    }
371
  }
372
#endif
373
}
623,237 ✔
374

375
static int32_t vnodeCheckDisk(int32_t diskPrimary, STfs *pTfs) {
1,472,621 ✔
376
  int32_t ndisk = 1;
1,472,621 ✔
377
  if (pTfs) {
1,472,621 ✔
378
    ndisk = tfsGetDisksAtLevel(pTfs, 0);
1,475,191 ✔
379
  }
380
  if (diskPrimary < 0 || diskPrimary >= ndisk) {
1,470,110 ✔
381
    vError("disk:%d is unavailable from the %d disks mounted at level 0", diskPrimary, ndisk);
×
382
    return terrno = TSDB_CODE_FS_INVLD_CFG;
×
383
  }
384
  return 0;
1,472,099 ✔
385
}
386

387
SVnode *vnodeOpen(const char *path, int32_t diskPrimary, STfs *pTfs, STfs *pMountTfs, SMsgCb msgCb, bool force) {
1,468,085 ✔
388
  SVnode    *pVnode = NULL;
1,468,085 ✔
389
  SVnodeInfo info = {0};
1,468,085 ✔
390
  char       dir[TSDB_FILENAME_LEN] = {0};
1,475,395 ✔
391
  char       tdir[TSDB_FILENAME_LEN * 2] = {0};
1,475,418 ✔
392
  int32_t    ret = 0;
1,475,379 ✔
393
  bool       mounted = pMountTfs != NULL;
1,475,379 ✔
394
  terrno = TSDB_CODE_SUCCESS;
1,475,379 ✔
395

396
  if (vnodeCheckDisk(diskPrimary, pTfs)) {
1,474,337 ✔
397
    vError("failed to open vnode from %s since %s. diskPrimary:%d", path, terrstr(), diskPrimary);
×
398
    return NULL;
×
399
  }
400
  vnodeGetPrimaryDir(path, diskPrimary, pTfs, dir, TSDB_FILENAME_LEN);
1,470,961 ✔
401

402
  info.config = vnodeCfgDefault;
1,474,657 ✔
403

404
  // load vnode info
405
  vInfo("vgId:%d, start to vnode load info %s", info.config.vgId, dir);
1,474,657 ✔
406
  ret = vnodeLoadInfo(dir, &info);
1,478,500 ✔
407
  if (ret < 0) {
1,472,664 ✔
408
    vError("failed to open vnode from %s since %s", path, tstrerror(terrno));
×
409
    terrno = TSDB_CODE_NEED_RETRY;
×
410
    return NULL;
×
411
  }
412

413
  if (!mounted && vnodeMkDir(pTfs, path)) {
1,472,664 ✔
414
    vError("vgId:%d, failed to prepare vnode dir since %s, path: %s", info.config.vgId, strerror(ERRNO), path);
5,665 ✔
415
    return NULL;
×
416
  }
417
  // save vnode info on dnode ep changed
418
  bool      updated = false;
1,467,607 ✔
419
  SSyncCfg *pCfg = &info.config.syncCfg;
1,467,607 ✔
420
  for (int32_t i = 0; i < pCfg->totalReplicaNum; ++i) {
3,788,547 ✔
421
    SNodeInfo *pNode = &pCfg->nodeInfo[i];
2,317,241 ✔
422
    if (tmsgUpdateDnodeInfo(&pNode->nodeId, &pNode->clusterId, pNode->nodeFqdn, &pNode->nodePort)) {
2,317,241 ✔
423
      updated = true;
×
424
    }
425
  }
426
  if (updated) {
1,471,306 ✔
427
    vInfo("vgId:%d, save vnode info since dnode info changed", info.config.vgId);
×
428
    if (vnodeSaveInfo(dir, &info) < 0) {
×
429
      vError("vgId:%d, failed to save vnode info since %s", info.config.vgId, tstrerror(terrno));
×
430
    }
431

432
    if (vnodeCommitInfo(dir) < 0) {
×
433
      vError("vgId:%d, failed to commit vnode info since %s", info.config.vgId, tstrerror(terrno));
×
434
    }
435
  }
436

437
  // create handle
438
  pVnode = taosMemoryCalloc(1, sizeof(*pVnode) + strlen(path) + 1);
1,469,254 ✔
439
  if (pVnode == NULL) {
1,472,044 ✔
440
    terrno = TSDB_CODE_OUT_OF_MEMORY;
×
441
    vError("vgId:%d, failed to open vnode since %s", info.config.vgId, tstrerror(terrno));
×
442
    return NULL;
×
443
  }
444

445
  pVnode->path = (char *)&pVnode[1];
1,472,044 ✔
446
  memcpy(pVnode->path, path, strlen(path) + 1);
1,472,044 ✔
447
  pVnode->config = info.config;
1,472,044 ✔
448
  pVnode->state.committed = info.state.committed;
1,472,044 ✔
449
  pVnode->state.commitTerm = info.state.commitTerm;
1,472,044 ✔
450
  pVnode->state.commitID = info.state.commitID;
1,472,044 ✔
451
  pVnode->state.applied = info.state.committed;
1,472,044 ✔
452
  pVnode->state.applyTerm = info.state.commitTerm;
1,472,044 ✔
453
  pVnode->pTfs = pTfs;
1,472,044 ✔
454
  pVnode->pMountTfs = pMountTfs;
1,472,044 ✔
455
  pVnode->mounted = mounted;
1,472,044 ✔
456
  pVnode->diskPrimary = diskPrimary;
1,472,044 ✔
457
  pVnode->msgCb = msgCb;
1,472,044 ✔
458
  (void)taosThreadMutexInit(&pVnode->lock, NULL);
1,472,044 ✔
459
  pVnode->blocked = false;
1,474,097 ✔
460
  pVnode->disableWrite = false;
1,474,097 ✔
461
  pVnode->closing = 0;
1,474,097 ✔
462
  pVnode->vacuumRunning = 0;
1,474,097 ✔
463

464
  if (tsem_init(&pVnode->syncSem, 0, 0) != 0) {
1,474,097 ✔
465
    vError("vgId:%d, failed to init semaphore", TD_VID(pVnode));
×
466
    goto _err;
×
467
  }
468
  (void)taosThreadMutexInit(&pVnode->mutex, NULL);
1,471,555 ✔
469
  (void)taosThreadCondInit(&pVnode->poolNotEmpty, NULL);
1,473,912 ✔
470

471
  vInfo("vgId:%d, finished vnode load info %s, vnode committed:%" PRId64, info.config.vgId, dir,
1,473,690 ✔
472
        pVnode->state.committed);
473

474
  int8_t rollback = vnodeShouldRollback(pVnode);
1,474,499 ✔
475

476
  // open buffer pool
477
  vInfo("vgId:%d, start to open vnode buffer pool", TD_VID(pVnode));
1,474,669 ✔
478
  if (vnodeOpenBufPool(pVnode) < 0) {
1,475,628 ✔
479
    vError("vgId:%d, failed to open vnode buffer pool since %s", TD_VID(pVnode), tstrerror(terrno));
×
480
    goto _err;
×
481
  }
482

483
  // open meta
484
  (void)taosThreadRwlockInit(&pVnode->metaRWLock, NULL);
1,475,733 ✔
485
  vInfo("vgId:%d, start to open vnode meta", TD_VID(pVnode));
1,475,733 ✔
486
  if (metaOpen(pVnode, &pVnode->pMeta, rollback) < 0) {
1,475,733 ✔
487
    vError("vgId:%d, failed to open vnode meta since %s", TD_VID(pVnode), tstrerror(terrno));
220 ✔
488
    goto _err;
220 ✔
489
  }
490

491
  vInfo("vgId:%d, start to upgrade meta", TD_VID(pVnode));
1,474,933 ✔
492
  if (!mounted && metaUpgrade(pVnode, &pVnode->pMeta) < 0) {
1,475,402 ✔
493
    vError("vgId:%d, failed to upgrade meta since %s", TD_VID(pVnode), tstrerror(terrno));
×
494
  }
495

496
  // init txn manager and rebuild in-memory txn state from B+ tree
497
  vInfo("vgId:%d, start to init vnode txn manager", TD_VID(pVnode));
1,473,573 ✔
498
  if (vnodeTxnInit(pVnode) < 0) {
1,475,489 ✔
499
    vError("vgId:%d, failed to init txn manager since %s", TD_VID(pVnode), tstrerror(terrno));
×
500
    goto _err;
×
501
  }
502
  if (vnodeTxnRebuildFromMeta(pVnode) < 0) {
1,475,513 ✔
503
    vError("vgId:%d, failed to rebuild txn state from meta since %s", TD_VID(pVnode), tstrerror(terrno));
×
504
    goto _err;
×
505
  }
506

507
  // open tsdb
508
  vInfo("vgId:%d, start to open vnode tsdb", TD_VID(pVnode));
1,475,513 ✔
509
  if ((terrno = tsdbOpen(pVnode, &VND_TSDB(pVnode), VNODE_TSDB_DIR, NULL, rollback, force)) < 0) {
1,475,518 ✔
510
    vError("vgId:%d, failed to open vnode tsdb since %s", TD_VID(pVnode), tstrerror(terrno));
364 ✔
511
    goto _err;
364 ✔
512
  }
513

514
  if (TSDB_CACHE_RESET(pVnode->config)) {
1,472,260 ✔
515
    // flag vnode tsdb cache
516
    vInfo("vgId:%d, start to flag vnode tsdb cache", TD_VID(pVnode));
×
517

518
    if (metaFlagCache(pVnode) < 0) {
×
519
      vError("vgId:%d, failed to flag tsdb cache since %s", TD_VID(pVnode), tstrerror(terrno));
×
520
      goto _err;
×
521
    }
522
  }
523

524
  // open wal
525
  (void)snprintf(tdir, sizeof(tdir), "%s%s%s", dir, TD_DIRSEP, VNODE_WAL_DIR);
1,472,260 ✔
526
  ret = taosRealPath(tdir, NULL, sizeof(tdir));
1,472,260 ✔
527
  TAOS_UNUSED(ret);
1,181 ✔
528

529
  vInfo("vgId:%d, start to open vnode wal", TD_VID(pVnode));
1,471,709 ✔
530
  pVnode->config.walCfg.enableTxnFile = 1;  // vnode WAL: enable .txn files for CDC lazy load
1,475,491 ✔
531
  // Bind the dnode-shared tfs handle *before* walOpen() so its one-time repair pass
532
  // (walCheckAndRepairMeta/walCheckAndRepairIdx) already knows about every mount point a
533
  // historical segment might live on -- binding after walOpen() returns is too late: that
534
  // pass would only look under tdir (the primary mount) and drop every segment it can't
535
  // find there, permanently losing WAL data on the next walSaveMeta(). No-op when
536
  // pVnode->pTfs is NULL (single mount point).
537
  // relDir must be the wal directory's path *relative to a mount point root*, i.e.
538
  // "<path>/wal" (e.g. "vnode/vnode2/wal") -- NOT just VNODE_WAL_DIR ("wal") on its own,
539
  // otherwise every vnode on this dnode would collide on the same "<mount>/wal/" directory
540
  // and reuse the same version-numbered segment file names.
541
  pVnode->config.walCfg.pTfs = pVnode->pTfs;
1,475,491 ✔
542
  if (pVnode->pTfs != NULL) {
1,475,491 ✔
543
    (void)snprintf(pVnode->config.walCfg.relDir, sizeof(pVnode->config.walCfg.relDir), "%s%s%s", path, TD_DIRSEP,
1,475,149 ✔
544
                   VNODE_WAL_DIR);
545
  }
546
  pVnode->pWal = walOpen(tdir, &(pVnode->config.walCfg));
1,475,491 ✔
547
  if (pVnode->pWal == NULL) {
1,470,269 ✔
548
    vError("vgId:%d, failed to open vnode wal since %s. wal:%s", TD_VID(pVnode), tstrerror(terrno), tdir);
×
549
    goto _err;
×
550
  }
551

552
  // open tq
553
  (void)snprintf(tdir, sizeof(tdir), "%s%s%s", dir, TD_DIRSEP, VNODE_TQ_DIR);
1,470,269 ✔
554
  ret = taosRealPath(tdir, NULL, sizeof(tdir));
1,470,269 ✔
555
  TAOS_UNUSED(ret);
1,156 ✔
556

557
  // open query
558
  vInfo("vgId:%d, start to open vnode query", TD_VID(pVnode));
1,472,080 ✔
559
  if (vnodeQueryOpen(pVnode)) {
1,472,664 ✔
560
    vError("vgId:%d, failed to open vnode query since %s", TD_VID(pVnode), tstrerror(terrno));
×
561
    terrno = TSDB_CODE_OUT_OF_MEMORY;
×
562
    goto _err;
×
563
  }
564

565
  // sma required the tq is initialized before the vnode open
566
  vInfo("vgId:%d, start to open vnode tq", TD_VID(pVnode));
1,475,149 ✔
567
  if (tqOpen(tdir, pVnode)) {
1,475,538 ✔
568
    vError("vgId:%d, failed to open vnode tq since %s", TD_VID(pVnode), tstrerror(terrno));
168 ✔
569
    goto _err;
168 ✔
570
  }
571

572
  // open txn WAL manager (CDC txn-atomic cache)
573
  vInfo("vgId:%d, start to open txn WAL manager", TD_VID(pVnode));
1,471,144 ✔
574
  pVnode->pTxnWalMgr = txnMgrOpen(pVnode->pWal, pVnode, info.lastTxnConsumeTs);
1,475,162 ✔
575
  if (pVnode->pTxnWalMgr == NULL) {
1,474,981 ✔
576
    vError("vgId:%d, failed to open txn WAL manager since %s", TD_VID(pVnode), tstrerror(terrno));
×
577
    goto _err;
×
578
  }
579
  // Rebuild cache from WAL for any txns that were in-flight before restart.
580
  {
581
    int64_t minTxnVer = walGetFirstVer(pVnode->pWal);
1,474,981 ✔
582
    int64_t appliedVer = pVnode->state.applied;
1,474,981 ✔
583
    if (minTxnVer > 0 && minTxnVer <= appliedVer) {
1,474,981 ✔
584
      (void)txnMgrReloadFromWal(pVnode->pTxnWalMgr, pVnode->pWal, minTxnVer, appliedVer);
6,069 ✔
585
    }
586
  }
587
  // Set initial WAL keep-version based on slots loaded from WAL restart scan.
588
  txnMgrRefreshWalKeepVersion(pVnode->pTxnWalMgr, pVnode->pWal, pVnode);
1,474,981 ✔
589

590
  // open blob store engine
591
  vInfo("vgId:%d, start to open blob store engine", TD_VID(pVnode));
1,474,957 ✔
592
  (void)snprintf(tdir, sizeof(tdir), "%s%s%s", dir, TD_DIRSEP, VNODE_BSE_DIR);
1,474,957 ✔
593

594
  SBseCfg cfg = {
1,474,957 ✔
595
      .vgId = pVnode->config.vgId,
1,474,981 ✔
596
      .keepDays = pVnode->config.tsdbCfg.days,
1,474,981 ✔
597
      .keeps = pVnode->config.tsdbCfg.keep0,
1,474,981 ✔
598
      .retention = pVnode->config.tsdbCfg.retentions[0],
599
      .precision = pVnode->config.tsdbCfg.precision,
1,474,981 ✔
600
  };
601
  tstrncpy(cfg.encryptAlgrName, pVnode->config.tdbEncryptData.encryptAlgrName, TSDB_ENCRYPT_ALGR_NAME_LEN);
1,474,981 ✔
602
  tstrncpy(cfg.encryptKey, tsDataKey, ENCRYPT_KEY_LEN + 1);
1,474,981 ✔
603

604
  ret = bseOpen(tdir, &cfg, &pVnode->pBse);
1,474,981 ✔
605
  if (ret != 0) {
1,474,981 ✔
606
    vError("vgId:%d, failed to open blob store engine since %s", TD_VID(pVnode), tstrerror(ret));
×
607
    terrno = ret;
×
608
    goto _err;
×
609
  }
610

611
  // vnode begin
612
  vInfo("vgId:%d, start to begin vnode", TD_VID(pVnode));
1,474,981 ✔
613
  if (vnodeBegin(pVnode) < 0) {
1,474,981 ✔
614
    vError("vgId:%d, failed to begin since %s", TD_VID(pVnode), tstrerror(terrno));
×
615
    terrno = TSDB_CODE_OUT_OF_MEMORY;
×
616
    goto _err;
×
617
  }
618

619
  // open sync
620
  vInfo("vgId:%d, start to open sync, changeVersion:%d", TD_VID(pVnode), info.config.syncCfg.changeVersion);
1,473,276 ✔
621
  if (vnodeSyncOpen(pVnode, dir, info.config.syncCfg.changeVersion)) {
1,475,150 ✔
622
    vError("vgId:%d, failed to open sync since %s", TD_VID(pVnode), tstrerror(terrno));
56 ✔
623
    goto _err;
56 ✔
624
  }
625

626
  if (rollback) {
1,474,925 ✔
627
    vnodeRollback(pVnode);
×
628
  }
629

630
  snprintf(pVnode->monitor.strClusterId, TSDB_CLUSTER_ID_LEN, "%" PRId64, pVnode->config.syncCfg.nodeInfo[0].clusterId);
1,474,925 ✔
631
  snprintf(pVnode->monitor.strDnodeId, TSDB_NODE_ID_LEN, "%" PRId32, pVnode->config.syncCfg.nodeInfo[0].nodeId);
1,474,925 ✔
632
  snprintf(pVnode->monitor.strVgId, TSDB_VGROUP_ID_LEN, "%" PRId32, pVnode->config.vgId);
1,474,925 ✔
633

634
  return pVnode;
1,474,925 ✔
635

636
_err:
808 ✔
637
  if (pVnode->pQuery) vnodeQueryClose(pVnode);
808 ✔
638
  if (pVnode->pTq) tqClose(pVnode->pTq);
808 ✔
639
  if (pVnode->pTxnWalMgr) {
808 ✔
640
    txnMgrClose(pVnode->pTxnWalMgr);
56 ✔
641
    pVnode->pTxnWalMgr = NULL;
56 ✔
642
  }
643
  if (pVnode->pWal) walClose(pVnode->pWal);
808 ✔
644
  if (pVnode->pTsdb) tsdbClose(&pVnode->pTsdb);
808 ✔
645
  vnodeTxnCleanup(pVnode);
808 ✔
646
  if (pVnode->pMeta) metaClose(&pVnode->pMeta);
808 ✔
647
  if (pVnode->pBse) {
808 ✔
648
    bseClose(pVnode->pBse);
56 ✔
649
    pVnode->pBse = NULL;
56 ✔
650
  }
651
  if (pVnode->freeList) vnodeCloseBufPool(pVnode);
808 ✔
652

653
  (void)taosThreadRwlockDestroy(&pVnode->metaRWLock);
808 ✔
654
  taosMemoryFree(pVnode);
808 ✔
655
  return NULL;
808 ✔
656
}
657

658
void vnodePreClose(SVnode *pVnode) {
1,474,869 ✔
659
  streamRemoveVnodeLeader(pVnode->config.vgId);
1,474,869 ✔
660
  vnodeSyncPreClose(pVnode);
1,474,869 ✔
661
  vnodeQueryPreClose(pVnode);
1,474,552 ✔
662
}
1,474,869 ✔
663

664
void vnodePostClose(SVnode *pVnode) { vnodeSyncPostClose(pVnode); }
1,474,869 ✔
665

666
void vnodeClose(SVnode *pVnode) {
1,475,653 ✔
667
  if (pVnode) {
1,475,653 ✔
668
    vInfo("start to close vnode");
1,474,869 ✔
669
    atomic_store_8(&pVnode->closing, 1);
1,474,869 ✔
670
    vnodeAWait(&pVnode->commitTask2);
1,474,869 ✔
671
    vnodeAWait(&pVnode->commitTask);
1,474,869 ✔
672

673
    // Vacuum may submit follow-up vacuum tasks (chained submission inside
674
    // vnodeTxnVacuumExecute when more entries remain). Loop until vacuumRunning
675
    // settles to 0 with no in-flight task. Bounded by the fact that
676
    // vnodeTxnSubmitVacuumAsync rejects new submissions once closing==1, so
677
    // at most one extra task can be queued past the closing barrier.
678
    vnodeAWait(&pVnode->vacuumTask);
1,474,869 ✔
679
    if (atomic_load_8(&pVnode->vacuumRunning)) {
1,474,869 ✔
680
      vnodeAWait(&pVnode->vacuumTask);
×
681
    }
682
    vnodeSyncClose(pVnode);
1,474,869 ✔
683
    vnodeQueryClose(pVnode);
1,474,856 ✔
684
    tqClose(pVnode->pTq);
1,474,869 ✔
685
    if (pVnode->pTxnWalMgr) {
1,474,642 ✔
686
      txnMgrClose(pVnode->pTxnWalMgr);
1,474,642 ✔
687
      pVnode->pTxnWalMgr = NULL;
1,474,869 ✔
688
    }
689
    walClose(pVnode->pWal);
1,474,869 ✔
690
    if (pVnode->pTsdb) tsdbClose(&pVnode->pTsdb);
1,472,796 ✔
691
    vnodeTxnCleanup(pVnode);
1,472,880 ✔
692
    if (pVnode->pMeta) metaClose(&pVnode->pMeta);
1,474,869 ✔
693
    vnodeCloseBufPool(pVnode);
1,474,869 ✔
694

695
    if (pVnode->pBse) {
1,474,869 ✔
696
      bseClose(pVnode->pBse);
1,474,869 ✔
697
    }
698

699
    // destroy handle
700
    if (tsem_destroy(&pVnode->syncSem) != 0) {
1,474,730 ✔
701
      vError("vgId:%d, failed to destroy semaphore", TD_VID(pVnode));
×
702
    }
703
    (void)taosThreadCondDestroy(&pVnode->poolNotEmpty);
1,474,869 ✔
704
    (void)taosThreadMutexDestroy(&pVnode->mutex);
1,474,869 ✔
705
    (void)taosThreadMutexDestroy(&pVnode->lock);
1,474,869 ✔
706
    taosMemoryFree(pVnode);
1,474,869 ✔
707
  }
708
}
1,475,384 ✔
709

710
// start the sync timer after the queue is ready
711
int32_t vnodeStart(SVnode *pVnode) {
1,473,691 ✔
712
  if (pVnode == NULL) {
1,473,691 ✔
713
    return TSDB_CODE_INVALID_PARA;
×
714
  }
715
  return vnodeSyncStart(pVnode);
1,473,691 ✔
716
}
717

718
int32_t vnodeIsCatchUp(SVnode *pVnode) { return syncIsCatchUp(pVnode->sync); }
563,237 ✔
719

720
ESyncRole vnodeGetRole(SVnode *pVnode) { return syncGetRole(pVnode->sync); }
563,237 ✔
721

722
int32_t vnodeUpdateArbTerm(SVnode *pVnode, int64_t arbTerm) { return syncUpdateArbTerm(pVnode->sync, arbTerm); }
70,339 ✔
723
int32_t vnodeGetArbToken(SVnode *pVnode, char *outToken) { return syncGetArbToken(pVnode->sync, outToken); }
79,920 ✔
724

725
int32_t vnodeSetWalKeepVersion(SVnode *pVnode, int64_t keepVersion) {
930 ✔
726
  if (pVnode == NULL || pVnode->pWal == NULL) {
930 ✔
727
    return TSDB_CODE_INVALID_PARA;
×
728
  }
729
  return walSetKeepVersion(pVnode->pWal, keepVersion);
930 ✔
730
}
731

732
void vnodeStop(SVnode *pVnode) {}
×
733

734
int64_t vnodeGetSyncHandle(SVnode *pVnode) { return pVnode->sync; }
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc