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

taosdata / TDengine / #4881

14 Dec 2025 03:48AM UTC coverage: 60.617% (+0.5%) from 60.092%
#4881

push

travis-ci

web-flow
test: update coverage workflow time (#33918)

156854 of 258761 relevant lines covered (60.62%)

75258957.81 hits per line

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

70.25
/source/dnode/mgmt/node_mgmt/src/dmEnv.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
// clang-format off
18
//#include "storageapi.h"
19
#include "dmMgmt.h"
20
#include "audit.h"
21
#include "libs/function/tudf.h"
22
#include "metrics.h"
23
#include "tgrant.h"
24
#include "tcompare.h"
25
#include "tss.h"
26
#include "tanalytics.h"
27
#include "stream.h"
28
// clang-format on
29

30
extern void cryptUnloadProviders();
31

32
#define DM_INIT_AUDIT()                       \
33
  do {                                        \
34
    auditCfg.port = tsMonitorPort;            \
35
    auditCfg.server = tsMonitorFqdn;          \
36
    auditCfg.comp = tsMonitorComp;            \
37
    if ((code = auditInit(&auditCfg)) != 0) { \
38
      return code;                            \
39
    }                                         \
40
  } while (0)
41

42
static SDnode globalDnode = {0};
43

44
SDnode *dmInstance() { return &globalDnode; }
210,698,394✔
45

46
static int32_t dmCheckRepeatInit(SDnode *pDnode) {
319,223✔
47
  int32_t code = 0;
319,223✔
48
  if (atomic_val_compare_exchange_8(&pDnode->once, DND_ENV_INIT, DND_ENV_READY) != DND_ENV_INIT) {
319,223✔
49
    dError("env is already initialized");
×
50
    code = TSDB_CODE_REPEAT_INIT;
×
51
    return code;
×
52
  }
53
  return 0;
319,223✔
54
}
55

56
static int32_t dmInitSystem() {
319,223✔
57
  if (taosIgnSIGPIPE() != 0) {
319,223✔
58
    dError("failed to ignore SIGPIPE");
×
59
  }
60

61
  if (taosBlockSIGPIPE() != 0) {
319,223✔
62
    dError("failed to block SIGPIPE");
×
63
  }
64

65
  taosResolveCRC();
319,223✔
66
  return 0;
319,223✔
67
}
68

69
static int32_t dmInitMonitor() {
319,223✔
70
  int32_t code = 0;
319,223✔
71
  SMonCfg monCfg = {0};
319,223✔
72

73
  monCfg.maxLogs = tsMonitorMaxLogs;
319,223✔
74
  monCfg.port = tsMonitorPort;
319,223✔
75
  monCfg.server = tsMonitorFqdn;
319,223✔
76
  monCfg.comp = tsMonitorComp;
319,223✔
77
  if ((code = monInit(&monCfg)) != 0) {
319,223✔
78
    dError("failed to init monitor since %s", tstrerror(code));
×
79
  }
80
  return code;
319,223✔
81
}
82

83
static int32_t dmInitMetrics() {
319,223✔
84
  int32_t code = 0;
319,223✔
85
  if ((code = initMetricsManager()) != 0) {
319,223✔
86
    dError("failed to init metrics since %s", tstrerror(code));
×
87
  }
88
  return code;
319,223✔
89
}
90

91
static int32_t dmInitAudit() {
319,223✔
92
  SAuditCfg auditCfg = {0};
319,223✔
93
  int32_t   code = 0;
319,223✔
94

95
  DM_INIT_AUDIT();
319,223✔
96

97
  return 0;
319,223✔
98
}
99

100
static bool dmDataSpaceAvailable() {
319,223✔
101
  SDnode *pDnode = dmInstance();
319,223✔
102
  if (pDnode->pTfs) {
319,223✔
103
    return tfsDiskSpaceAvailable(pDnode->pTfs, 0);
319,223✔
104
  }
105
  if (!osDataSpaceAvailable()) {
×
106
    dError("data disk space unavailable, i.e. %s", tsDataDir);
×
107
    return false;
×
108
  }
109
  return true;
×
110
}
111

112
static int32_t dmCheckDiskSpace() {
319,223✔
113
  // availability
114
  int32_t code = 0;
319,223✔
115
  code = osUpdate();
319,223✔
116
  if (code != 0) {
319,223✔
117
    dError("failed to update os info since %s", tstrerror(code));
×
118
    code = 0;  // ignore the error, just log it
×
119
  }
120
  if (!dmDataSpaceAvailable()) {
319,223✔
121
    code = TSDB_CODE_NO_DISKSPACE;
×
122
    return code;
×
123
  }
124
  if (!osLogSpaceAvailable()) {
319,223✔
125
    dError("log disk space unavailable, i.e. %s", tsLogDir);
×
126
    code = TSDB_CODE_NO_DISKSPACE;
×
127
    return code;
×
128
  }
129
  if (!osTempSpaceAvailable()) {
319,223✔
130
    dError("temp disk space unavailable, i.e. %s", tsTempDir);
×
131
    code = TSDB_CODE_NO_DISKSPACE;
×
132
    return code;
×
133
  }
134
  return code;
319,223✔
135
}
136

137
int32_t dmDiskInit() {
323,680✔
138
  SDnode  *pDnode = dmInstance();
323,680✔
139
  SDiskCfg dCfg = {.level = 0, .primary = 1, .disable = 0};
323,680✔
140
  tstrncpy(dCfg.dir, tsDataDir, TSDB_FILENAME_LEN);
323,680✔
141
  SDiskCfg *pDisks = tsDiskCfg;
323,680✔
142
  int32_t   numOfDisks = tsDiskCfgNum;
323,680✔
143
  if (numOfDisks <= 0 || pDisks == NULL) {
323,680✔
144
    pDisks = &dCfg;
×
145
    numOfDisks = 1;
×
146
  }
147

148
  int32_t code = tfsOpen(pDisks, numOfDisks, &pDnode->pTfs);
323,680✔
149
  if (code != 0) {
323,680✔
150
    dError("failed to init tfs since %s", tstrerror(code));
4,457✔
151
    TAOS_RETURN(code);
4,457✔
152
  }
153
  return 0;
319,223✔
154
}
155

156
int32_t dmDiskClose() {
315,601✔
157
  SDnode *pDnode = dmInstance();
315,601✔
158
  tfsClose(pDnode->pTfs);
315,601✔
159
  pDnode->pTfs = NULL;
315,601✔
160
  return 0;
315,601✔
161
}
162

163
static bool dmCheckDataDirVersion() {
319,223✔
164
  char checkDataDirJsonFileName[PATH_MAX] = {0};
319,223✔
165
  snprintf(checkDataDirJsonFileName, PATH_MAX, "%s/dnode/dnodeCfg.json", tsDataDir);
319,223✔
166
  if (taosCheckExistFile(checkDataDirJsonFileName)) {
319,223✔
167
    dError("The default data directory %s contains old data of tdengine 2.x, please clear it before running!",
×
168
           tsDataDir);
169
    return false;
×
170
  }
171
  return true;
319,223✔
172
}
173

174
static int32_t dmCheckDataDirVersionWrapper() {
×
175
  if (!dmCheckDataDirVersion()) {
×
176
    return TSDB_CODE_INVALID_DATA_FMT;
×
177
  }
178
  return 0;
×
179
}
180

181
int32_t dmInit() {
323,680✔
182
  dInfo("start to init dnode env");
323,680✔
183
  int32_t code = 0;
323,680✔
184

185
#ifdef USE_SHARED_STORAGE
186
  if (tsSsEnabled) {
323,680✔
187
    if ((code = tssInit()) != 0) return code;
×
188
    if ((code = tssCreateDefaultInstance()) != 0) return code;
×
189
  }
190
#endif
191

192
  if ((code = dmDiskInit()) != 0) return code;
323,680✔
193
  if (!dmCheckDataDirVersion()) {
319,223✔
194
    code = TSDB_CODE_INVALID_DATA_FMT;
×
195
    return code;
×
196
  }
197
  SDnode* pDnode = dmInstance();
319,223✔
198
  if ((code = dmCheckDiskSpace()) != 0) return code;
319,223✔
199
  if ((code = dmCheckRepeatInit(pDnode)) != 0) return code;
319,223✔
200
  if ((code = dmInitSystem()) != 0) return code;
319,223✔
201
  if ((code = dmInitMonitor()) != 0) return code;
319,223✔
202
  if ((code = dmInitMetrics()) != 0) return code;
319,223✔
203
  if ((code = dmInitAudit()) != 0) return code;
319,223✔
204
  if ((code = dmInitDnode(pDnode)) != 0) return code;
319,223✔
205
  if ((code = InitRegexCache() != 0)) return code;
315,601✔
206

207
  gExecInfoInit(&pDnode->data, (getDnodeId_f)dmGetDnodeId, dmGetMnodeEpSet);
315,601✔
208
  if ((code = streamInit(&pDnode->data, (getDnodeId_f)dmGetDnodeId, dmGetMnodeEpSet, dmGetSynEpset)) != 0) return code;
315,601✔
209

210
  dInfo("dnode env is initialized");
315,601✔
211
  return 0;
315,601✔
212
}
213

214
static int32_t dmCheckRepeatCleanup(SDnode *pDnode) {
315,601✔
215
  if (atomic_val_compare_exchange_8(&pDnode->once, DND_ENV_READY, DND_ENV_CLEANUP) != DND_ENV_READY) {
315,601✔
216
    dError("dnode env is already cleaned up");
×
217
    return -1;
×
218
  }
219
  return 0;
315,601✔
220
}
221

222
void dmCleanup() {
315,601✔
223
  dDebug("start to cleanup dnode env");
315,601✔
224
  SDnode *pDnode = dmInstance();
315,601✔
225

226
#if defined(TD_ENTERPRISE) && defined(LINUX)
227
  cryptUnloadProviders();
315,601✔
228
#endif
229

230
  if (dmCheckRepeatCleanup(pDnode) != 0) return;
315,601✔
231
  dmCleanupDnode(pDnode);
315,601✔
232
  monCleanup();
315,601✔
233
  auditCleanup();
315,601✔
234
  syncCleanUp();
315,601✔
235
  walCleanUp();
315,601✔
236
  cleanupMetrics();
315,601✔
237
  if (udfcClose() != 0) {
315,601✔
238
    dError("failed to close udfc");
×
239
  }
240
  udfStopUdfd();
315,601✔
241
  taosAnalyticsCleanup();
315,601✔
242
  taosStopCacheRefreshWorker();
315,601✔
243
  (void)dmDiskClose();
315,601✔
244
  DestroyRegexCache();
315,601✔
245

246
#ifdef USE_SHARED_STORAGE
247
  if (tsSsEnabled) {
315,601✔
248
    (void)tssCloseDefaultInstance();
×
249
    (void)tssUninit();
×
250
  }
251
#endif
252

253
  dInfo("dnode env is cleaned up");
315,601✔
254

255
  taosMemPoolClose(gMemPoolHandle);
315,601✔
256
  taosCleanupCfg();
315,601✔
257
  taosCloseLog();
315,601✔
258
}
259

260
void dmStop() {
327,391✔
261
  SDnode *pDnode = dmInstance();
327,391✔
262
  pDnode->stop = true;
327,391✔
263
}
327,391✔
264

265
int32_t dmRun() {
315,601✔
266
  SDnode *pDnode = dmInstance();
315,601✔
267
  return dmRunDnode(pDnode);
315,601✔
268
}
269

270
static int32_t dmProcessCreateNodeReq(EDndNodeType ntype, SRpcMsg *pMsg) {
25,884✔
271
  int32_t code = 0;
25,884✔
272
  SDnode *pDnode = dmInstance();
25,884✔
273

274
  SMgmtWrapper *pWrapper = dmAcquireWrapper(pDnode, ntype);
25,884✔
275
  if (pWrapper != NULL) {
25,884✔
276
    dmReleaseWrapper(pWrapper);
×
277
    switch (ntype) {
×
278
      case MNODE:
×
279
        code = TSDB_CODE_MNODE_ALREADY_DEPLOYED;
×
280
        break;
×
281
      case QNODE:
×
282
        code = TSDB_CODE_QNODE_ALREADY_DEPLOYED;
×
283
        break;
×
284
      case SNODE:
×
285
        code = TSDB_CODE_SNODE_ALREADY_DEPLOYED;
×
286
        break;
×
287
      case BNODE:
×
288
        code = TSDB_CODE_BNODE_ALREADY_DEPLOYED;
×
289
        break;
×
290
      default:
×
291
        code = TSDB_CODE_APP_ERROR;
×
292
    }
293
    dError("failed to create node since %s", tstrerror(code));
×
294
    return code;
×
295
  }
296

297
  dInfo("start to process create-node-request");
25,884✔
298

299
  pWrapper = &pDnode->wrappers[ntype];
25,884✔
300

301
  if (taosMulMkDir(pWrapper->path) != 0) {
25,884✔
302
    dmReleaseWrapper(pWrapper);
×
303
    code = terrno;
×
304
    dError("failed to create dir:%s since %s", pWrapper->path, tstrerror(code));
×
305
    return code;
×
306
  }
307

308
  dInfo("path %s created", pWrapper->path);
25,884✔
309

310
  (void)taosThreadMutexLock(&pDnode->mutex);
25,884✔
311
  SMgmtInputOpt input = dmBuildMgmtInputOpt(pWrapper);
25,884✔
312

313
  dInfo("node:%s, start to create", pWrapper->name);
25,884✔
314
  code = (*pWrapper->func.createFp)(&input, pMsg);
25,884✔
315
  if (code != 0) {
25,884✔
316
    dError("node:%s, failed to create since %s", pWrapper->name, tstrerror(code));
×
317
  } else {
318
    dInfo("node:%s, has been created", pWrapper->name);
25,884✔
319
    code = dmOpenNode(pWrapper);
25,884✔
320
    if (code == 0) {
25,884✔
321
      code = dmStartNode(pWrapper);
25,884✔
322
    }
323
    pWrapper->deployed = true;
25,884✔
324
    pWrapper->required = true;
25,884✔
325
  }
326

327
  (void)taosThreadMutexUnlock(&pDnode->mutex);
25,884✔
328
  return code;
25,884✔
329
}
330

331

332
static int32_t dmProcessAlterNodeReq(EDndNodeType ntype, SRpcMsg *pMsg) {
177✔
333
  int32_t code = 0;
177✔
334
  if (SNODE != ntype) {
177✔
335
    dError("failed to process msgType %d since node type is NOT snode", pMsg->msgType);
×
336
    return TSDB_CODE_INVALID_MSG;
×
337
  }
338
  
339
  SDnode *pDnode = dmInstance();
177✔
340
  SMgmtWrapper *pWrapper = dmAcquireWrapper(pDnode, ntype);
177✔
341

342
  dInfo("start to process alter-node-request");
177✔
343

344
  pWrapper = &pDnode->wrappers[ntype];
177✔
345

346
  (void)taosThreadMutexLock(&pDnode->mutex);
177✔
347
  SMgmtInputOpt input = dmBuildMgmtInputOpt(pWrapper);
177✔
348

349
  dInfo("node:%s, start to update", pWrapper->name);
177✔
350
  code = (*pWrapper->func.createFp)(&input, pMsg);
177✔
351
  if (code != 0) {
177✔
352
    dError("node:%s, failed to update since %s", pWrapper->name, tstrerror(code));
×
353
  } else {
354
    dInfo("node:%s, has been updated", pWrapper->name);
177✔
355
  }
356

357
  (void)taosThreadMutexUnlock(&pDnode->mutex);
177✔
358

359
  dmReleaseWrapper(pWrapper);
177✔
360
  
361
  return code;
177✔
362
}
363

364

365
static int32_t dmProcessAlterNodeTypeReq(EDndNodeType ntype, SRpcMsg *pMsg) {
65,527✔
366
  int32_t code = 0;
65,527✔
367
  SDnode *pDnode = dmInstance();
65,527✔
368

369
  SMgmtWrapper *pWrapper = dmAcquireWrapper(pDnode, ntype);
65,527✔
370
  if (pWrapper == NULL) {
65,527✔
371
    dError("fail to process alter node type since node not exist");
×
372
    return TSDB_CODE_INVALID_MSG;
×
373
  }
374
  dmReleaseWrapper(pWrapper);
65,527✔
375

376
  dInfo("node:%s, start to process alter-node-type-request", pWrapper->name);
65,527✔
377

378
  pWrapper = &pDnode->wrappers[ntype];
65,527✔
379

380
  if (pWrapper->func.nodeRoleFp != NULL) {
65,527✔
381
    ESyncRole role = (*pWrapper->func.nodeRoleFp)(pWrapper->pMgmt);
65,527✔
382
    dInfo("node:%s, checking node role:%d", pWrapper->name, role);
65,527✔
383
    if (role == TAOS_SYNC_ROLE_VOTER) {
65,527✔
384
      dError("node:%s, failed to alter node type since node already is role:%d", pWrapper->name, role);
×
385
      code = TSDB_CODE_MNODE_ALREADY_IS_VOTER;
×
386
      return code;
×
387
    }
388
  }
389

390
  if (pWrapper->func.isCatchUpFp != NULL) {
65,527✔
391
    dInfo("node:%s, checking node catch up", pWrapper->name);
65,527✔
392
    if ((*pWrapper->func.isCatchUpFp)(pWrapper->pMgmt) != 1) {
65,527✔
393
      code = TSDB_CODE_MNODE_NOT_CATCH_UP;
59,940✔
394
      return code;
59,940✔
395
    }
396
  }
397

398
  dInfo("node:%s, catched up leader, continue to process alter-node-type-request", pWrapper->name);
5,587✔
399

400
  (void)taosThreadMutexLock(&pDnode->mutex);
5,587✔
401

402
  dInfo("node:%s, stopping node", pWrapper->name);
5,587✔
403
  dmStopNode(pWrapper);
5,587✔
404
  dInfo("node:%s, closing node", pWrapper->name);
5,587✔
405
  dmCloseNode(pWrapper);
5,587✔
406

407
  pWrapper = &pDnode->wrappers[ntype];
5,587✔
408
  if (taosMkDir(pWrapper->path) != 0) {
5,587✔
409
    (void)taosThreadMutexUnlock(&pDnode->mutex);
×
410
    code = terrno;
×
411
    dError("failed to create dir:%s since %s", pWrapper->path, tstrerror(code));
×
412
    return code;
×
413
  }
414

415
  SMgmtInputOpt input = dmBuildMgmtInputOpt(pWrapper);
5,587✔
416

417
  dInfo("node:%s, start to create", pWrapper->name);
5,587✔
418
  code = (*pWrapper->func.createFp)(&input, pMsg);
5,587✔
419
  if (code != 0) {
5,587✔
420
    dError("node:%s, failed to create since %s", pWrapper->name, tstrerror(code));
×
421
  } else {
422
    dInfo("node:%s, has been created", pWrapper->name);
5,587✔
423
    code = dmOpenNode(pWrapper);
5,587✔
424
    if (code == 0) {
5,587✔
425
      code = dmStartNode(pWrapper);
5,587✔
426
    }
427
    pWrapper->deployed = true;
5,587✔
428
    pWrapper->required = true;
5,587✔
429
  }
430

431
  (void)taosThreadMutexUnlock(&pDnode->mutex);
5,587✔
432
  return code;
5,587✔
433
}
434

435
static int32_t dmProcessDropNodeReq(EDndNodeType ntype, SRpcMsg *pMsg) {
19,559✔
436
  int32_t code = 0;
19,559✔
437
  SDnode *pDnode = dmInstance();
19,559✔
438

439
  SMgmtWrapper *pWrapper = dmAcquireWrapper(pDnode, ntype);
19,559✔
440
  if (pWrapper == NULL) {
19,559✔
441
    switch (ntype) {
×
442
      case MNODE:
×
443
        code = TSDB_CODE_MNODE_NOT_DEPLOYED;
×
444
        break;
×
445
      case QNODE:
×
446
        code = TSDB_CODE_QNODE_NOT_DEPLOYED;
×
447
        break;
×
448
      case SNODE:
×
449
        code = TSDB_CODE_SNODE_NOT_DEPLOYED;
×
450
        break;
×
451
      case BNODE:
×
452
        code = TSDB_CODE_BNODE_NOT_DEPLOYED;
×
453
        break;
×
454
      default:
×
455
        code = TSDB_CODE_APP_ERROR;
×
456
    }
457

458
    dError("failed to drop node since %s", tstrerror(code));
×
459
    return terrno = code;
×
460
  }
461

462
  (void)taosThreadMutexLock(&pDnode->mutex);
19,559✔
463
  SMgmtInputOpt input = dmBuildMgmtInputOpt(pWrapper);
19,559✔
464

465
  dInfo("node:%s, start to drop", pWrapper->name);
19,559✔
466
  code = (*pWrapper->func.dropFp)(&input, pMsg);
19,559✔
467
  if (code != 0) {
19,559✔
468
    dError("node:%s, failed to drop since %s", pWrapper->name, tstrerror(code));
×
469
  } else {
470
    dInfo("node:%s, has been dropped", pWrapper->name);
19,559✔
471
    pWrapper->required = false;
19,559✔
472
    pWrapper->deployed = false;
19,559✔
473
  }
474

475
  dmReleaseWrapper(pWrapper);
19,559✔
476

477
  if (code == 0) {
19,559✔
478
    dmStopNode(pWrapper);
19,559✔
479
    dmCloseNode(pWrapper);
19,559✔
480
    taosRemoveDir(pWrapper->path);
19,559✔
481
  }
482
  (void)taosThreadMutexUnlock(&pDnode->mutex);
19,559✔
483
  return code;
19,559✔
484
}
485

486
SMgmtInputOpt dmBuildMgmtInputOpt(SMgmtWrapper *pWrapper) {
2,846,073✔
487
  SMgmtInputOpt opt = {
14,226,477✔
488
      .path = pWrapper->path,
2,846,073✔
489
      .name = pWrapper->name,
2,846,073✔
490
      .pTfs = pWrapper->pDnode->pTfs,
2,846,073✔
491
      .pData = &pWrapper->pDnode->data,
2,846,073✔
492
      .processCreateNodeFp = dmProcessCreateNodeReq,
493
      .processAlterNodeFp = dmProcessAlterNodeReq,
494
      .processAlterNodeTypeFp = dmProcessAlterNodeTypeReq,
495
      .processDropNodeFp = dmProcessDropNodeReq,
496
      .sendMonitorReportFp = dmSendMonitorReport,
497
      .sendMetricsReportFp = dmSendMetricsReport,
498
      .monitorCleanExpiredSamplesFp = dmMonitorCleanExpiredSamples,
499
      .metricsCleanExpiredSamplesFp = dmMetricsCleanExpiredSamples,
500
      .sendAuditRecordFp = auditSendRecordsInBatch,
501
      .getVnodeLoadsFp = dmGetVnodeLoads,
502
      .getVnodeLoadsLiteFp = dmGetVnodeLoadsLite,
503
      .setVnodeSyncTimeoutFp = dmSetVnodeSyncTimeout,
504
      .getMnodeLoadsFp = dmGetMnodeLoads,
505
      .setMnodeSyncTimeoutFp = dmSetMnodeSyncTimeout,
506
      .getQnodeLoadsFp = dmGetQnodeLoads,
507
      .stopDnodeFp = dmStop,
508
  };
509

510
  opt.msgCb = dmGetMsgcb(pWrapper->pDnode);
2,846,073✔
511
  return opt;
2,846,073✔
512
}
513

514
void dmReportStartup(const char *pName, const char *pDesc) {
19,087,546✔
515
  SStartupInfo *pStartup = &(dmInstance()->startup);
19,087,546✔
516
  tstrncpy(pStartup->name, pName, TSDB_STEP_NAME_LEN);
19,087,546✔
517
  tstrncpy(pStartup->desc, pDesc, TSDB_STEP_DESC_LEN);
19,087,546✔
518
  dDebug("step:%s, %s", pStartup->name, pStartup->desc);
19,087,546✔
519
}
19,087,546✔
520

521
int64_t dmGetClusterId() { return globalDnode.data.clusterId; }
×
522

523
bool dmReadyForTest() { return dmInstance()->data.dnodeVer > 0; }
×
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