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

taosdata / TDengine / #4917

07 Jan 2026 03:52PM UTC coverage: 65.42% (+0.02%) from 65.402%
#4917

push

travis-ci

web-flow
merge: from main to 3.0 branch #34204

31 of 34 new or added lines in 2 files covered. (91.18%)

819 existing lines in 129 files now uncovered.

202679 of 309814 relevant lines covered (65.42%)

116724351.99 hits per line

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

83.72
/source/libs/sync/src/syncRaftCfg.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
#define _DEFAULT_SOURCE
17
#include "syncRaftCfg.h"
18
#include "syncUtil.h"
19
#include "tencrypt.h"
20
#include "tjson.h"
21

22
static const char *syncRoleToStr(ESyncRole role) {
6,658,442✔
23
  switch (role) {
6,658,442✔
24
    case TAOS_SYNC_ROLE_VOTER:
6,335,545✔
25
      return "true";
6,335,545✔
26
    case TAOS_SYNC_ROLE_LEARNER:
322,897✔
27
      return "false";
322,897✔
28
    default:
×
29
      return "unknown";
×
30
  }
31
}
32

33
static const ESyncRole syncStrToRole(char *str) {
3,049,000✔
34
  if (strcmp(str, "true") == 0) {
3,049,000✔
35
    return TAOS_SYNC_ROLE_VOTER;
2,749,186✔
36
  } else if (strcmp(str, "false") == 0) {
299,814✔
37
    return TAOS_SYNC_ROLE_LEARNER;
299,814✔
38
  } else {
UNCOV
39
    return TAOS_SYNC_ROLE_ERROR;
×
40
  }
41
}
42

43
static int32_t syncEncodeSyncCfg(const void *pObj, SJson *pJson) {
3,862,548✔
44
  SSyncCfg *pCfg = (SSyncCfg *)pObj;
3,862,548✔
45
  int32_t   code = 0, lino = 0;
3,862,548✔
46

47
  TAOS_CHECK_EXIT(tjsonAddDoubleToObject(pJson, "replicaNum", pCfg->replicaNum));
3,862,548✔
48
  TAOS_CHECK_EXIT(tjsonAddDoubleToObject(pJson, "myIndex", pCfg->myIndex));
3,862,548✔
49
  TAOS_CHECK_EXIT(tjsonAddDoubleToObject(pJson, "changeVersion", pCfg->changeVersion));
3,862,548✔
50

51
  SJson *nodeInfo = tjsonCreateArray();
3,862,548✔
52
  if (nodeInfo == NULL) {
3,862,548✔
53
    TAOS_CHECK_EXIT(terrno);
×
54
  }
55

56
  if ((code = tjsonAddItemToObject(pJson, "nodeInfo", nodeInfo)) < 0) {
3,862,548✔
57
    tjsonDelete(nodeInfo);
877✔
58
    TAOS_CHECK_EXIT(code);
×
59
  }
60

61
  for (int32_t i = 0; i < pCfg->totalReplicaNum; ++i) {
10,519,585✔
62
    SJson *info = tjsonCreateObject();
6,658,645✔
63
    if (info == NULL) {
6,657,914✔
64
      TAOS_CHECK_EXIT(terrno);
×
65
    }
66
    TAOS_CHECK_GOTO(tjsonAddDoubleToObject(info, "nodePort", pCfg->nodeInfo[i].nodePort), NULL, _err);
6,657,914✔
67
    TAOS_CHECK_GOTO(tjsonAddStringToObject(info, "nodeFqdn", pCfg->nodeInfo[i].nodeFqdn), NULL, _err);
6,658,645✔
68
    TAOS_CHECK_GOTO(tjsonAddIntegerToObject(info, "nodeId", pCfg->nodeInfo[i].nodeId), NULL, _err);
6,657,765✔
69
    TAOS_CHECK_GOTO(tjsonAddIntegerToObject(info, "clusterId", pCfg->nodeInfo[i].clusterId), NULL, _err);
6,658,645✔
70
    TAOS_CHECK_GOTO(tjsonAddStringToObject(info, "isReplica", syncRoleToStr(pCfg->nodeInfo[i].nodeRole)), NULL, _err);
6,658,645✔
71
    TAOS_CHECK_GOTO(tjsonAddItemToArray(nodeInfo, info), NULL, _err);
6,657,914✔
72
    continue;
6,657,914✔
73

74
  _err:
×
75
    tjsonDelete(info);
×
76
    break;
×
77
  }
78

79
_exit:
3,859,944✔
80
  if (code < 0) {
3,859,944✔
81
    sError("failed to encode sync cfg at line %d since %s", lino, tstrerror(code));
×
82
  }
83

84
  TAOS_RETURN(code);
3,859,944✔
85
}
86

87
static int32_t syncEncodeRaftCfg(const void *pObj, SJson *pJson) {
3,862,525✔
88
  SRaftCfg *pCfg = (SRaftCfg *)pObj;
3,862,525✔
89
  int32_t   code = 0;
3,862,525✔
90
  int32_t   lino = 0;
3,862,525✔
91

92
  TAOS_CHECK_EXIT(tjsonAddObject(pJson, "SSyncCfg", syncEncodeSyncCfg, (void *)&pCfg->cfg));
3,862,525✔
93
  TAOS_CHECK_EXIT(tjsonAddDoubleToObject(pJson, "isStandBy", pCfg->isStandBy));
3,862,548✔
94
  TAOS_CHECK_EXIT(tjsonAddDoubleToObject(pJson, "snapshotStrategy", pCfg->snapshotStrategy));
3,862,548✔
95
  TAOS_CHECK_EXIT(tjsonAddDoubleToObject(pJson, "batchSize", pCfg->batchSize));
3,862,548✔
96
  TAOS_CHECK_EXIT(tjsonAddIntegerToObject(pJson, "lastConfigIndex", pCfg->lastConfigIndex));
3,862,548✔
97
  TAOS_CHECK_EXIT(tjsonAddDoubleToObject(pJson, "configIndexCount", pCfg->configIndexCount));
3,862,283✔
98

99
  SJson *configIndexArr = tjsonCreateArray();
3,862,548✔
100
  if (configIndexArr == NULL) {
3,862,345✔
101
    TAOS_CHECK_EXIT(terrno);
×
102
  }
103

104
  if ((code = tjsonAddItemToObject(pJson, "configIndexArr", configIndexArr)) < 0) {
3,862,345✔
105
    tjsonDelete(configIndexArr);
203✔
106
    TAOS_CHECK_EXIT(code);
×
107
  }
108

109
  for (int32_t i = 0; i < pCfg->configIndexCount; ++i) {
7,814,277✔
110
    SJson *configIndex = tjsonCreateObject();
3,950,998✔
111
    if (configIndex == NULL) {
3,951,201✔
112
      TAOS_CHECK_EXIT(terrno);
×
113
    }
114
    TAOS_CHECK_EXIT(tjsonAddIntegerToObject(configIndex, "index", pCfg->configIndexArr[i]));
3,951,201✔
115
    TAOS_CHECK_EXIT(tjsonAddItemToArray(configIndexArr, configIndex));
3,951,932✔
116
    continue;
3,951,932✔
117

118
  _err:
119
    tjsonDelete(configIndex);
120
    break;
121
  }
122

123
_exit:
3,862,345✔
124
  if (code < 0) {
3,862,345✔
125
    sError("failed to encode raft cfg at line %d since %s", lino, tstrerror(code));
×
126
  }
127

128
  TAOS_RETURN(code);
3,862,345✔
129
}
130

131
int32_t syncWriteCfgFile(SSyncNode *pNode, const char *reason) {
3,862,283✔
132
  int32_t     code = 0, lino = 0;
3,862,283✔
133
  char       *buffer = NULL;
3,862,283✔
134
  SJson      *pJson = NULL;
3,862,283✔
135
  const char *realfile = pNode->configPath;
3,862,283✔
136
  SRaftCfg   *pCfg = &pNode->raftCfg;
3,862,548✔
137

138
  if ((pJson = tjsonCreateObject()) == NULL) {
3,862,548✔
139
    TAOS_CHECK_EXIT(terrno);
×
140
  }
141

142
  TAOS_CHECK_EXIT(tjsonAddObject(pJson, "RaftCfg", syncEncodeRaftCfg, pCfg));
3,862,548✔
143
  TAOS_CHECK_EXIT(tjsonAddStringToObject(pJson, "reason", reason));
3,862,345✔
144
  buffer = tjsonToString(pJson);
3,862,548✔
145
  if (buffer == NULL) {
3,862,548✔
146
    TAOS_CHECK_EXIT(terrno);
×
147
  }
148

149
  int32_t len = strlen(buffer);
3,862,548✔
150
  
151
  // Use encrypted write if tsCfgKey is enabled
152
  code = taosWriteCfgFile(realfile, buffer, len);
3,862,548✔
153
  if (code != 0) {
3,860,145✔
154
    lino = __LINE__;
×
155
    TAOS_CHECK_EXIT(code);
×
156
  }
157

158
  sInfo("vgId:%d, succeed to write sync cfg file:%s, len:%d, lastConfigIndex:%" PRId64 ", changeVersion:%d",
3,860,145✔
159
        pNode->vgId, realfile, len, pNode->raftCfg.lastConfigIndex, pNode->raftCfg.cfg.changeVersion);
160

161
_exit:
×
162
  if (pJson != NULL) tjsonDelete(pJson);
3,862,548✔
163
  if (buffer != NULL) taosMemoryFree(buffer);
3,862,548✔
164

165
  if (code != 0) {
3,862,548✔
166
    sError("vgId:%d, failed at line %d to write sync cfg file:%s since %s", pNode->vgId, lino, realfile,
×
167
           tstrerror(code));
168
  }
169

170
  TAOS_RETURN(code);
3,862,548✔
171
}
172

173
static int32_t syncDecodeSyncCfg(const SJson *pJson, void *pObj) {
1,204,796✔
174
  SSyncCfg *pCfg = (SSyncCfg *)pObj;
1,204,796✔
175
  int32_t   code = 0;
1,204,796✔
176

177
  tjsonGetInt32ValueFromDouble(pJson, "replicaNum", pCfg->replicaNum, code);
1,204,796✔
178
  if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
179
  tjsonGetInt32ValueFromDouble(pJson, "myIndex", pCfg->myIndex, code);
1,204,796✔
180
  if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
181
  tjsonGetInt32ValueFromDouble(pJson, "changeVersion", pCfg->changeVersion, code);
1,204,796✔
182
  if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
183

184
  SJson *nodeInfo = tjsonGetObjectItem(pJson, "nodeInfo");
1,204,796✔
185
  if (nodeInfo == NULL) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
186
  pCfg->totalReplicaNum = tjsonGetArraySize(nodeInfo);
1,204,796✔
187

188
  for (int32_t i = 0; i < pCfg->totalReplicaNum; ++i) {
4,253,796✔
189
    SJson *info = tjsonGetArrayItem(nodeInfo, i);
3,049,000✔
190
    if (info == NULL) return TSDB_CODE_INVALID_JSON_FORMAT;
3,049,000✔
191
    tjsonGetUInt16ValueFromDouble(info, "nodePort", pCfg->nodeInfo[i].nodePort, code);
3,049,000✔
192
    if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
3,049,000✔
193
    code = tjsonGetStringValue(info, "nodeFqdn", pCfg->nodeInfo[i].nodeFqdn);
3,049,000✔
194
    if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
3,049,000✔
195
    tjsonGetNumberValue(info, "nodeId", pCfg->nodeInfo[i].nodeId, code);
3,049,000✔
196
    tjsonGetNumberValue(info, "clusterId", pCfg->nodeInfo[i].clusterId, code);
3,049,000✔
197
    char role[10] = {0};
3,049,000✔
198
    code = tjsonGetStringValue(info, "isReplica", role);
3,049,000✔
199
    if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
3,049,000✔
200
    if (strlen(role) != 0) {
3,049,000✔
201
      pCfg->nodeInfo[i].nodeRole = syncStrToRole(role);
3,049,000✔
202
    } else {
203
      pCfg->nodeInfo[i].nodeRole = TAOS_SYNC_ROLE_VOTER;
×
204
    }
205
  }
206

207
  return 0;
1,204,796✔
208
}
209

210
static int32_t syncDecodeRaftCfg(const SJson *pJson, void *pObj) {
1,204,796✔
211
  SRaftCfg *pCfg = (SRaftCfg *)pObj;
1,204,796✔
212
  int32_t   code = 0;
1,204,796✔
213

214
  TAOS_CHECK_RETURN(tjsonToObject(pJson, "SSyncCfg", syncDecodeSyncCfg, (void *)&pCfg->cfg));
1,204,796✔
215

216
  tjsonGetInt8ValueFromDouble(pJson, "isStandBy", pCfg->isStandBy, code);
1,204,796✔
217
  if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
218
  tjsonGetInt8ValueFromDouble(pJson, "snapshotStrategy", pCfg->snapshotStrategy, code);
1,204,796✔
219
  if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
220
  tjsonGetInt32ValueFromDouble(pJson, "batchSize", pCfg->batchSize, code);
1,204,796✔
221
  if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
222
  tjsonGetNumberValue(pJson, "lastConfigIndex", pCfg->lastConfigIndex, code);
1,204,796✔
223
  if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
224
  tjsonGetInt32ValueFromDouble(pJson, "configIndexCount", pCfg->configIndexCount, code);
1,204,796✔
225
  if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
226

227
  SJson *configIndexArr = tjsonGetObjectItem(pJson, "configIndexArr");
1,204,796✔
228
  if (configIndexArr == NULL) return TSDB_CODE_INVALID_JSON_FORMAT;
1,204,796✔
229

230
  pCfg->configIndexCount = tjsonGetArraySize(configIndexArr);
1,204,796✔
231
  for (int32_t i = 0; i < pCfg->configIndexCount; ++i) {
2,435,850✔
232
    SJson *configIndex = tjsonGetArrayItem(configIndexArr, i);
1,231,054✔
233
    if (configIndex == NULL) return TSDB_CODE_INVALID_JSON_FORMAT;
1,231,054✔
234
    tjsonGetNumberValue(configIndex, "index", pCfg->configIndexArr[i], code);
1,231,054✔
235
    if (code < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
1,231,054✔
236
  }
237

238
  return 0;
1,204,796✔
239
}
240

241
int32_t syncReadCfgFile(SSyncNode *pNode) {
1,204,796✔
242
  int32_t     code = 0;
1,204,796✔
243
  char       *pData = NULL;
1,204,796✔
244
  int32_t     dataLen = 0;
1,204,796✔
245
  SJson      *pJson = NULL;
1,204,796✔
246
  const char *file = pNode->configPath;
1,204,796✔
247
  SRaftCfg   *pCfg = &pNode->raftCfg;
1,204,796✔
248

249
  // Use taosReadCfgFile for automatic decryption support (returns null-terminated string)
250
  code = taosReadCfgFile(file, &pData, &dataLen);
1,204,796✔
251
  if (code != 0) {
1,204,796✔
252
    sError("vgId:%d, failed to read sync cfg file:%s since %s", pNode->vgId, file, tstrerror(code));
×
253
    goto _OVER;
×
254
  }
255

256
  pJson = tjsonParse(pData);
1,204,796✔
257
  if (pJson == NULL) {
1,204,796✔
258
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
259
    goto _OVER;
×
260
  }
261

262
  if (tjsonToObject(pJson, "RaftCfg", syncDecodeRaftCfg, (void *)pCfg) < 0) {
1,204,796✔
263
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
264
    goto _OVER;
×
265
  }
266

267
  sInfo("vgId:%d, succceed to read sync cfg file %s, changeVersion:%d", pNode->vgId, file, pCfg->cfg.changeVersion);
1,204,796✔
268

269
_OVER:
1,204,644✔
270
  if (pData != NULL) taosMemoryFree(pData);
1,204,796✔
271
  if (pJson != NULL) cJSON_Delete(pJson);
1,204,796✔
272

273
  if (code != 0) {
1,204,796✔
274
    sError("vgId:%d, failed to read sync cfg file:%s since %s", pNode->vgId, file, tstrerror(code));
×
275
  }
276

277
  TAOS_RETURN(code);
1,204,796✔
278
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc