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

taosdata / TDengine / #4308

14 Jun 2025 02:06PM UTC coverage: 62.454% (-0.3%) from 62.777%
#4308

push

travis-ci

web-flow
fix: taosdump windows pthread_mutex_unlock crash(3.0) (#31357)

* fix: windows pthread_mutex_unlock crash

* enh: sync from main fix taosdump crash windows

* fix: restore .github action branch to main

153985 of 315105 branches covered (48.87%)

Branch coverage included in aggregate %.

238120 of 312727 relevant lines covered (76.14%)

6462519.65 hits per line

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

70.31
/source/util/src/tlog.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 "tlog.h"
18
#include "os.h"
19
#include "tconfig.h"
20
#include "tglobal.h"
21
#include "tjson.h"
22
#include "ttime.h"
23
#include "tutil.h"
24
#include "tcommon.h"
25

26
#define LOG_MAX_LINE_SIZE              (10024)
27
#define LOG_MAX_LINE_BUFFER_SIZE       (LOG_MAX_LINE_SIZE + 3)
28
#define LOG_MAX_STACK_LINE_SIZE        (512)
29
#define LOG_MAX_STACK_LINE_BUFFER_SIZE (LOG_MAX_STACK_LINE_SIZE + 3)
30
#define LOG_MAX_LINE_DUMP_SIZE         (1024 * 1024)
31
#define LOG_MAX_LINE_DUMP_BUFFER_SIZE  (LOG_MAX_LINE_DUMP_SIZE + 128)
32

33
#define LOG_FILE_DAY_LEN 64
34

35
#define LOG_DEFAULT_BUF_SIZE (20 * 1024 * 1024)  // 20MB
36
#define LOG_SLOW_BUF_SIZE    (10 * 1024 * 1024)  // 10MB
37

38
#define LOG_DEFAULT_INTERVAL 25
39
#define LOG_INTERVAL_STEP    5
40
#define LOG_MIN_INTERVAL     5
41
#define LOG_MAX_INTERVAL     25
42
#define LOG_MAX_WAIT_MSEC    1000
43

44
#define LOG_BUF_BUFFER(x) ((x)->buffer)
45
#define LOG_BUF_START(x)  ((x)->buffStart)
46
#define LOG_BUF_END(x)    ((x)->buffEnd)
47
#define LOG_BUF_SIZE(x)   ((x)->buffSize)
48
#define LOG_BUF_MUTEX(x)  ((x)->buffMutex)
49

50
#ifdef TD_ENTERPRISE
51
#define LOG_EDITION_FLG ("E")
52
#else
53
#define LOG_EDITION_FLG ("C")
54
#endif
55

56
typedef enum {
57
  LOG_OUTPUT_FILE = 0,    // default
58
  LOG_OUTPUT_STDOUT = 1,  // stdout set by -o option on the command line
59
  LOG_OUTPUT_STDERR = 2,  // stderr set by -o option on the command line
60
  LOG_OUTPUT_NULL = 4,    // /dev/null set by -o option on the command line
61
} ELogOutputType;
62

63
typedef struct {
64
  char         *buffer;
65
  int32_t       buffStart;
66
  int32_t       buffEnd;
67
  int32_t       buffSize;
68
  int32_t       minBuffSize;
69
  TdFilePtr     pFile;
70
  int32_t       stop;
71
  TdThread      asyncThread;
72
  TdThreadMutex buffMutex;
73
  int32_t       writeInterval;
74
  int32_t       lastDuration;
75
  int32_t       lock;
76
} SLogBuff;
77

78
typedef struct {
79
  int32_t       fileNum;
80
  int32_t       lines;
81
  int32_t       flag;
82
  int32_t       openInProgress;
83
  int64_t       lastKeepFileSec;
84
  int64_t       timestampToday;
85
  int8_t        outputType;  // ELogOutputType
86
  pid_t         pid;
87
  char          logName[PATH_MAX];
88
  char          slowLogName[PATH_MAX];
89
  SLogBuff     *logHandle;
90
  SLogBuff     *slowHandle;
91
  TdThreadMutex logMutex;
92
} SLogObj;
93

94
extern SConfig *tsCfg;
95
static int8_t   tsLogInited = 0;
96
static SLogObj  tsLogObj = {.fileNum = 1, .slowHandle = NULL};
97
static int64_t  tsAsyncLogLostLines = 0;
98
static int32_t  tsDaylightActive; /* Currently in daylight saving time. */
99
static SRWLatch tsLogRotateLatch = 0;
100

101
bool tsLogEmbedded = 0;
102
bool tsAsyncLog = true;
103
#ifdef ASSERT_NOT_CORE
104
bool tsAssert = false;
105
#else
106
bool tsAssert = true;
107
#endif
108
int32_t tsNumOfLogLines = 10000000;
109
int32_t tsLogKeepDays = 0;
110
char   *tsLogOutput = NULL;
111
LogFp   tsLogFp = NULL;
112
int64_t tsNumOfErrorLogs = 0;
113
int64_t tsNumOfInfoLogs = 0;
114
int64_t tsNumOfDebugLogs = 0;
115
int64_t tsNumOfTraceLogs = 0;
116
int64_t tsNumOfSlowLogs = 0;
117

118
// log
119
int32_t dDebugFlag = 131;
120
int32_t vDebugFlag = 131;
121
int32_t mDebugFlag = 131;
122
int32_t cDebugFlag = 131;
123
int32_t jniDebugFlag = 131;
124
int32_t tmrDebugFlag = 131;
125
int32_t uDebugFlag = 131;
126
int32_t rpcDebugFlag = 131;
127
int32_t qDebugFlag = 131;
128
int32_t stDebugFlag = 131;
129
int32_t wDebugFlag = 131;
130
int32_t azDebugFlag = 131;
131
int32_t sDebugFlag = 131;
132
int32_t tsdbDebugFlag = 131;
133
int32_t tdbDebugFlag = 131;
134
int32_t tqDebugFlag = 131;
135
int32_t fsDebugFlag = 131;
136
int32_t metaDebugFlag = 131;
137
int32_t udfDebugFlag = 131;
138
int32_t smaDebugFlag = 131;
139
int32_t idxDebugFlag = 131;
140
int32_t sndDebugFlag = 131;
141
int32_t simDebugFlag = 131;
142

143
int32_t tqClientDebugFlag = 131;
144

145
int64_t dbgEmptyW = 0;
146
int64_t dbgWN = 0;
147
int64_t dbgSmallWN = 0;
148
int64_t dbgBigWN = 0;
149
int64_t dbgWSize = 0;
150

151
static void     *taosAsyncOutputLog(void *param);
152
static int32_t   taosPushLogBuffer(SLogBuff *pLogBuf, const char *msg, int32_t msgLen);
153
static SLogBuff *taosLogBuffNew(int32_t bufSize);
154
static void      taosCloseLogByFd(TdFilePtr pFile);
155
static int32_t   taosInitNormalLog(const char *fn, int32_t maxFileNum);
156
static void      taosWriteLog(SLogBuff *pLogBuf);
157
static void      taosWriteSlowLog(SLogBuff *pLogBuf);
158

159
static int32_t taosStartLog() {
22,714✔
160
  TdThreadAttr threadAttr;
161
  (void)taosThreadAttrInit(&threadAttr);
22,714✔
162
#ifdef TD_COMPACT_OS
163
  (void)taosThreadAttrSetStackSize(&threadAttr, STACK_SIZE_SMALL);
164
#endif
165
  if (taosThreadCreate(&(tsLogObj.logHandle->asyncThread), &threadAttr, taosAsyncOutputLog, tsLogObj.logHandle) != 0) {
22,714!
166
    return terrno;
×
167
  }
168
  (void)taosThreadAttrDestroy(&threadAttr);
22,714✔
169
  return 0;
22,714✔
170
}
171

172
static int32_t getDay(char *buf, int32_t bufSize) {
22,696✔
173
  time_t  t;
174
  int32_t code = taosTime(&t);
22,696✔
175
  if (code != 0) {
22,696!
176
    return code;
×
177
  }
178
  struct tm tmInfo;
179
  if (taosLocalTime(&t, &tmInfo, buf, bufSize, NULL) != NULL) {
22,696!
180
    TAOS_UNUSED(taosStrfTime(buf, bufSize, "%Y-%m-%d", &tmInfo));
22,696✔
181
  }
182
  return 0;
22,696✔
183
}
184

185
static void getFullPathName(char *fullName, const char *logName) {
45,409✔
186
  if (strlen(tsLogDir) != 0) {
45,409!
187
    char lastC = tsLogDir[strlen(tsLogDir) - 1];
45,409✔
188
    if (lastC == '\\' || lastC == '/') {
45,409!
189
      snprintf(fullName, PATH_MAX,
16✔
190
               "%s"
191
               "%s",
192
               tsLogDir, logName);
193
    } else {
194
      snprintf(fullName, PATH_MAX, "%s" TD_DIRSEP "%s", tsLogDir, logName);
45,393✔
195
    }
196
  } else {
197
    snprintf(fullName, PATH_MAX, "%s", logName);
×
198
  }
199
}
45,409✔
200

201
int32_t taosInitSlowLog() {
22,695✔
202
  char logFileName[64] = {0};
22,695✔
203
#ifdef CUS_PROMPT
204
  (void)snprintf(logFileName, 64, "%sSlowLog", CUS_PROMPT);
22,695✔
205
#else
206
  (void)snprintf(logFileName, 64, "taosSlowLog");
207
#endif
208

209
  getFullPathName(tsLogObj.slowLogName, logFileName);
22,695✔
210

211
  char    name[PATH_MAX + TD_TIME_STR_LEN] = {0};
22,695✔
212
  char    day[TD_TIME_STR_LEN] = {0};
22,695✔
213
  int32_t code = getDay(day, sizeof(day));
22,695✔
214
  if (code != 0) {
22,695!
215
    (void)printf("failed to get day, reason:%s\n", tstrerror(code));
×
216
    return code;
×
217
  }
218
  (void)snprintf(name, PATH_MAX + TD_TIME_STR_LEN, "%s.%s", tsLogObj.slowLogName, day);
22,695✔
219

220
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
22,695✔
221
  tsLogObj.slowHandle = taosLogBuffNew(LOG_SLOW_BUF_SIZE);
22,695✔
222
  if (tsLogObj.slowHandle == NULL) return terrno;
22,695!
223

224
  TAOS_UNUSED(taosUmaskFile(0));
22,695✔
225
  tsLogObj.slowHandle->pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_READ | TD_FILE_WRITE | TD_FILE_APPEND);
22,695✔
226
  if (tsLogObj.slowHandle->pFile == NULL) {
22,695!
227
    (void)printf("\nfailed to open slow log file:%s, reason:%s\n", name, strerror(ERRNO));
×
228
    return terrno;
×
229
  }
230

231
  return 0;
22,695✔
232
}
233

234
int32_t taosInitLogOutput(const char **ppLogName) {
22,713✔
235
  const char *pLog = tsLogOutput;
22,713✔
236
  const char *pLogName = NULL;
22,713✔
237
  if (pLog) {
22,713✔
238
    if (!tIsValidFilePath(pLog, NULL)) {
31✔
239
      fprintf(stderr, "invalid log output destination:%s, contains illegal char\n", pLog);
4✔
240
      return TSDB_CODE_INVALID_CFG;
4✔
241
    }
242
    if (0 == strcasecmp(pLog, "stdout")) {
27✔
243
      tsLogObj.outputType = LOG_OUTPUT_STDOUT;
3✔
244
      if (ppLogName) *ppLogName = pLog;
3!
245
      return 0;
3✔
246
    }
247
    if (0 == strcasecmp(pLog, "stderr")) {
24✔
248
      tsLogObj.outputType = LOG_OUTPUT_STDERR;
3✔
249
      if (ppLogName) *ppLogName = pLog;
3!
250
      return 0;
3✔
251
    }
252
    if (0 == strcasecmp(pLog, "/dev/null")) {
21✔
253
      tsLogObj.outputType = LOG_OUTPUT_NULL;
1✔
254
      if (ppLogName) *ppLogName = pLog;
1!
255
      return 0;
1✔
256
    }
257
    int32_t len = strlen(pLog);
20✔
258
    if (len < 1) {
20!
259
      fprintf(stderr, "invalid log output destination:%s, should not be empty\n", pLog);
×
260
      return TSDB_CODE_INVALID_CFG;
×
261
    }
262
    const char *p = pLog + (len - 1);
20✔
263
    if (*p == '/' || *p == '\\') {
20✔
264
      return 0;
8✔
265
    }
266

267
    if ((p = strrchr(pLog, '/')) || (p = strrchr(pLog, '\\'))) {
12!
268
      pLogName = p + 1;
6✔
269
    } else {
270
      pLogName = pLog;
6✔
271
    }
272
    if (strcmp(pLogName, ".") == 0 || strcmp(pLogName, "..") == 0) {
12✔
273
      fprintf(stderr, "invalid log output destination:%s\n", pLog);
2✔
274
      return TSDB_CODE_INVALID_CFG;
2✔
275
    }
276

277
    if (!tIsValidFileName(pLogName, NULL)) {
10!
278
      fprintf(stderr, "invalid log output destination:%s, contains illegal char\n", pLog);
×
279
      return TSDB_CODE_INVALID_CFG;
×
280
    }
281
    if (ppLogName) *ppLogName = pLogName;
10!
282
  }
283
  return 0;
22,692✔
284
}
285

286
int32_t taosInitLog(const char *logName, int32_t maxFiles, bool tsc) {
22,800✔
287
  if (atomic_val_compare_exchange_8(&tsLogInited, 0, 1) != 0) return 0;
22,800✔
288
  int32_t code = osUpdate();
22,718✔
289
  if (code != 0) {
22,718!
290
    uError("failed to update os info, reason:%s", tstrerror(code));
×
291
  }
292

293
  if (tsLogObj.outputType == LOG_OUTPUT_STDOUT || tsLogObj.outputType == LOG_OUTPUT_STDERR ||
22,718✔
294
      tsLogObj.outputType == LOG_OUTPUT_NULL) {
22,714!
295
    return 0;
4✔
296
  }
297

298
  TAOS_CHECK_RETURN(taosInitNormalLog(logName, maxFiles));
22,714!
299
  if (tsc) {
22,714✔
300
    TAOS_CHECK_RETURN(taosInitSlowLog());
22,695!
301
  }
302
  TAOS_CHECK_RETURN(taosStartLog());
22,714!
303
  return 0;
22,714✔
304
}
305

306
void taosSetNoNewFile() { tsLogObj.openInProgress = 1; }
1✔
307

308
static void taosStopLog() {
22,709✔
309
  if (tsLogObj.logHandle) {
22,709✔
310
    tsLogObj.logHandle->stop = 1;
22,703✔
311
  }
312
  if (tsLogObj.slowHandle) {
22,709✔
313
    tsLogObj.slowHandle->stop = 1;
22,691✔
314
  }
315
}
22,709✔
316

317
void taosCloseLog() {
22,709✔
318
  taosStopLog();
22,709✔
319

320
  if (tsLogObj.logHandle != NULL && taosCheckPthreadValid(tsLogObj.logHandle->asyncThread)) {
22,709!
321
    (void)taosThreadJoin(tsLogObj.logHandle->asyncThread, NULL);
22,703✔
322
    taosThreadClear(&tsLogObj.logHandle->asyncThread);
22,703✔
323
  }
324

325
  if (tsLogObj.slowHandle != NULL) {
22,709✔
326
    (void)taosThreadMutexDestroy(&tsLogObj.slowHandle->buffMutex);
22,691✔
327
    (void)taosCloseFile(&tsLogObj.slowHandle->pFile);
22,691✔
328
    taosMemoryFreeClear(tsLogObj.slowHandle->buffer);
22,691!
329
    taosMemoryFreeClear(tsLogObj.slowHandle);
22,691!
330
  }
331

332
  if (tsLogObj.logHandle != NULL) {
22,709✔
333
    tsLogInited = 0;
22,703✔
334

335
    (void)taosThreadMutexDestroy(&tsLogObj.logHandle->buffMutex);
22,703✔
336
    (void)taosCloseFile(&tsLogObj.logHandle->pFile);
22,703✔
337
    taosMemoryFreeClear(tsLogObj.logHandle->buffer);
22,703!
338
    (void)taosThreadMutexDestroy(&tsLogObj.logMutex);
22,703✔
339
    taosMemoryFreeClear(tsLogObj.logHandle);
22,703!
340
    tsLogObj.logHandle = NULL;
22,703✔
341
  }
342
  taosMemoryFreeClear(tsLogOutput);
22,709!
343
}
22,709✔
344

345
static bool taosLockLogFile(TdFilePtr pFile) {
48,239✔
346
  if (pFile == NULL) return false;
48,239!
347

348
  if (tsLogObj.fileNum > 1) {
48,239✔
349
    int32_t ret = taosLockFile(pFile);
42,553✔
350
    if (ret == 0) {
42,553✔
351
      return true;
32,240✔
352
    }
353
  }
354

355
  return false;
15,999✔
356
}
357

358
static void taosUnLockLogFile(TdFilePtr pFile) {
15,259✔
359
  if (pFile == NULL) return;
15,259!
360

361
  if (tsLogObj.fileNum > 1) {
15,259✔
362
    int32_t code = taosUnLockFile(pFile);
15,258✔
363
    if (code != 0) {
15,258!
364
      TAOS_UNUSED(printf("failed to unlock log file:%p, reason:%s\n", pFile, tstrerror(code)));
×
365
    }
366
  }
367
}
368

369
static void taosReserveOldLog(char *oldName, char *keepName) {
5✔
370
  if (tsLogKeepDays == 0) {
5!
371
    keepName[0] = 0;
5✔
372
    return;
5✔
373
  }
374

375
  int32_t code = 0;
×
376
  int64_t fileSec = taosGetTimestampSec();
×
377
  if (tsLogObj.lastKeepFileSec < fileSec) {
×
378
    tsLogObj.lastKeepFileSec = fileSec;
×
379
  } else {
380
    fileSec = ++tsLogObj.lastKeepFileSec;
×
381
  }
382
  snprintf(keepName, PATH_MAX + 20, "%s.%" PRId64, tsLogObj.logName, fileSec);
×
383
  if ((code = taosRenameFile(oldName, keepName))) {
×
384
    keepName[0] = 0;
×
385
    uError("failed to rename file:%s to %s since %s", oldName, keepName, tstrerror(code));
×
386
  }
387
}
388

389
static void taosKeepOldLog(char *oldName) {
5✔
390
  if (oldName[0] != 0) {
5✔
391
    int32_t   code = 0, lino = 0;
4✔
392
    TdFilePtr oldFile = NULL;
4✔
393
    if ((oldFile = taosOpenFile(oldName, TD_FILE_READ))) {
4!
394
      TAOS_CHECK_GOTO(taosLockFile(oldFile), &lino, _exit2);
4✔
395
      char compressFileName[PATH_MAX + 20];
396
      snprintf(compressFileName, PATH_MAX + 20, "%s.gz", oldName);
3✔
397
      TAOS_CHECK_GOTO(taosCompressFile(oldName, compressFileName), &lino, _exit1);
3!
398
      TAOS_CHECK_GOTO(taosRemoveFile(oldName), &lino, _exit1);
3!
399
    _exit1:
3✔
400
      TAOS_UNUSED(taosUnLockFile(oldFile));
3✔
401
    _exit2:
4✔
402
      TAOS_UNUSED(taosCloseFile(&oldFile));
4✔
403
    } else {
404
      code = terrno;
×
405
    }
406
    if (code != 0 && tsLogEmbedded == 1) {  // print error messages only in embedded log mode
4!
407
      // avoid using uWarn or uError, as they may open a new log file and potentially cause a deadlock.
408
      fprintf(stderr, "WARN: failed at line %d to keep old log file:%s, reason:%s\n", lino, oldName, tstrerror(code));
1✔
409
    }
410
  }
411
}
5✔
412
typedef struct {
413
  TdFilePtr pOldFile;
414
  char      keepName[PATH_MAX + 20];
415
} OldFileKeeper;
416
static OldFileKeeper *taosOpenNewFile() {
5✔
417
  char keepName[PATH_MAX + 20];
418
  TAOS_UNUSED(snprintf(keepName, sizeof(keepName), "%s.%d", tsLogObj.logName, tsLogObj.flag));
5✔
419

420
  tsLogObj.flag ^= 1;
5✔
421
  tsLogObj.lines = 0;
5✔
422
  char name[PATH_MAX + 20];
423
  TAOS_UNUSED(snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag));
5✔
424

425
  TAOS_UNUSED(taosUmaskFile(0));
5✔
426

427
  TdFilePtr pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
5✔
428
  if (pFile == NULL) {
5!
429
    tsLogObj.flag ^= 1;
×
430
    tsLogObj.lines = tsNumOfLogLines - 1000;
×
431
    uError("open new log file %s fail! reason:%s, reuse lastlog", name, tstrerror(terrno));
×
432
    return NULL;
×
433
  }
434

435
  TAOS_UNUSED(taosLockLogFile(pFile));
5✔
436
  if (taosLSeekFile(pFile, 0, SEEK_SET) < 0) {
5!
437
    uWarn("failed to seek file:%s, reason:%s", name, tstrerror(terrno));
×
438
  }
439

440
  TdFilePtr pOldFile = tsLogObj.logHandle->pFile;
5✔
441
  tsLogObj.logHandle->pFile = pFile;
5✔
442
  tsLogObj.lines = 0;
5✔
443
  OldFileKeeper *oldFileKeeper = taosMemoryMalloc(sizeof(OldFileKeeper));
5!
444
  if (oldFileKeeper == NULL) {
5!
445
    uError("create old log keep info faild! mem is not enough.");
×
446
    return NULL;
×
447
  }
448
  oldFileKeeper->pOldFile = pOldFile;
5✔
449
  taosReserveOldLog(keepName, oldFileKeeper->keepName);
5✔
450

451
  uInfo("   new log file:%d is opened", tsLogObj.flag);
5!
452
  uInfo("==================================");
5!
453
  return oldFileKeeper;
5✔
454
}
455

456
static void *taosThreadToCloseOldFile(void *param) {
5✔
457
  if (!param) return NULL;
5!
458
  OldFileKeeper *oldFileKeeper = (OldFileKeeper *)param;
5✔
459
  taosSsleep(20);
5✔
460
  taosWLockLatch(&tsLogRotateLatch);
1✔
461
  taosCloseLogByFd(oldFileKeeper->pOldFile);
1✔
462
  taosKeepOldLog(oldFileKeeper->keepName);
1✔
463
  taosMemoryFree(oldFileKeeper);
1!
464
  if (tsLogKeepDays != 0) {
1!
465
    taosRemoveOldFiles(tsLogDir, abs(tsLogKeepDays));
×
466
  }
467
  taosWUnLockLatch(&tsLogRotateLatch);
1✔
468
  return NULL;
1✔
469
}
470

471
static int32_t taosOpenNewLogFile() {
5✔
472
  (void)taosThreadMutexLock(&tsLogObj.logMutex);
5✔
473

474
  if (tsLogObj.lines > tsNumOfLogLines && tsLogObj.openInProgress == 0) {
5!
475
    tsLogObj.openInProgress = 1;
5✔
476

477
    uInfo("open new log file ......");
5!
478
    TdThread     thread;
479
    TdThreadAttr attr;
480
    (void)taosThreadAttrInit(&attr);
5✔
481
    (void)taosThreadAttrSetDetachState(&attr, PTHREAD_CREATE_DETACHED);
5✔
482
#ifdef TD_COMPACT_OS
483
    (void)taosThreadAttrSetStackSize(&attr, STACK_SIZE_SMALL);
484
#endif
485
    OldFileKeeper *oldFileKeeper = taosOpenNewFile();
5✔
486
    if (!oldFileKeeper) {
5!
487
      tsLogObj.openInProgress = 0;
×
488
      TAOS_UNUSED(taosThreadMutexUnlock(&tsLogObj.logMutex));
×
489
      (void)taosThreadAttrDestroy(&attr);
×
490
      return terrno;
×
491
    }
492
    if (taosThreadCreate(&thread, &attr, taosThreadToCloseOldFile, oldFileKeeper) != 0) {
5!
493
      uError("failed to create thread to close old log file");
×
494
      taosMemoryFreeClear(oldFileKeeper);
×
495
    }
496
    (void)taosThreadAttrDestroy(&attr);
5✔
497
    tsLogObj.openInProgress = 0;
5✔
498
  }
499

500
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
5✔
501

502
  return 0;
5✔
503
}
504

505
void taosOpenNewSlowLogFile() {
2✔
506
  (void)taosThreadMutexLock(&tsLogObj.logMutex);
2✔
507
  int64_t delta = taosGetTimestampSec() - tsLogObj.timestampToday;
2✔
508
  if (delta >= 0 && delta < 86400) {
2!
509
    uInfo("timestampToday is already equal to today, no need to open new slow log file");
1!
510
    (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
1✔
511
    return;
1✔
512
  }
513

514
  for (int32_t i = 1; atomic_val_compare_exchange_32(&tsLogObj.slowHandle->lock, 0, 1) == 1; ++i) {
1!
515
    if (i % 1000 == 0) {
×
516
      TAOS_UNUSED(sched_yield());
×
517
    }
518
  }
519
  tsLogObj.slowHandle->lastDuration = LOG_MAX_WAIT_MSEC;  // force write
1✔
520
  taosWriteLog(tsLogObj.slowHandle);
1✔
521
  atomic_store_32(&tsLogObj.slowHandle->lock, 0);
1✔
522

523
  char    day[TD_TIME_STR_LEN] = {0};
1✔
524
  int32_t code = getDay(day, sizeof(day));
1✔
525
  if (code != 0) {
1!
526
    uError("failed to get day, reason:%s", tstrerror(code));
×
527
    (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
528
    return;
×
529
  }
530
  TdFilePtr pFile = NULL;
1✔
531
  char      name[PATH_MAX + TD_TIME_STR_LEN] = {0};
1✔
532
  (void)snprintf(name, PATH_MAX + TD_TIME_STR_LEN, "%s.%s", tsLogObj.slowLogName, day);
1✔
533
  pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
1✔
534
  if (pFile == NULL) {
1!
535
    uError("open new log file fail! reason:%s, reuse lastlog", strerror(ERRNO));
×
536
    (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
537
    return;
×
538
  }
539

540
  TdFilePtr pOldFile = tsLogObj.slowHandle->pFile;
1✔
541
  tsLogObj.slowHandle->pFile = pFile;
1✔
542
  (void)taosCloseFile(&pOldFile);
1✔
543
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
1✔
544
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
1✔
545
}
546

547
void taosResetLog() {
3✔
548
  // force create a new log file
549
  tsLogObj.lines = tsNumOfLogLines + 10;
3✔
550

551
  if (tsLogObj.logHandle) {
3!
552
    int32_t code = taosOpenNewLogFile();
3✔
553
    if (code != 0) {
3!
554
      uError("failed to open new log file, reason:%s", tstrerror(code));
×
555
    }
556
    uInfo("==================================");
3!
557
    uInfo("   reset log file ");
3!
558
  }
559
}
3✔
560

561
void taosLogObjSetToday(int64_t ts) { tsLogObj.timestampToday = ts; }
1✔
562

563
static bool taosCheckFileIsOpen(char *logFileName) {
54,544✔
564
  TdFilePtr pFile = taosOpenFile(logFileName, TD_FILE_WRITE);
54,544✔
565
  if (pFile == NULL) {
54,544✔
566
    if (lastErrorIsFileNotExist()) {
29,024!
567
      return false;
29,024✔
568
    } else {
569
      printf("\n%s:%d failed to open log file:%s, reason:%s\n", __func__, __LINE__, logFileName, strerror(ERRNO));
×
570
      return true;
×
571
    }
572
  }
573

574
  if (taosLockLogFile(pFile)) {
25,520✔
575
    taosUnLockLogFile(pFile);
15,258✔
576
    (void)taosCloseFile(&pFile);
15,258✔
577
    return false;
15,258✔
578
  } else {
579
    (void)taosCloseFile(&pFile);
10,262✔
580
    return true;
10,262✔
581
  }
582
}
583

584
static void decideLogFileName(const char *fn, int32_t maxFileNum) {
22,714✔
585
  tsLogObj.fileNum = maxFileNum;
22,714✔
586
  if (tsLogObj.fileNum > 1) {
22,714✔
587
    for (int32_t i = 0; i < tsLogObj.fileNum; i++) {
27,293✔
588
      char fileName[PATH_MAX + 10];
589

590
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.0", fn, i);
27,272✔
591
      bool file1open = taosCheckFileIsOpen(fileName);
27,272✔
592

593
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.1", fn, i);
27,272✔
594
      bool file2open = taosCheckFileIsOpen(fileName);
27,272✔
595

596
      if (!file1open && !file2open) {
27,272!
597
        (void)snprintf(tsLogObj.logName, PATH_MAX, "%s%d", fn, i);
17,010✔
598
        return;
17,010✔
599
      }
600
    }
601
  }
602

603
  if (strlen(fn) < PATH_MAX) {
5,704!
604
    tstrncpy(tsLogObj.logName, fn, PATH_MAX);
5,704✔
605
  }
606
}
607

608
static void decideLogFileNameFlag() {
22,714✔
609
  char    name[PATH_MAX] = "\0";
22,714✔
610
  int64_t logstat0_mtime = 0;
22,714✔
611
  int64_t logstat1_mtime = 0;
22,714✔
612
  bool    log0Exist = false;
22,714✔
613
  bool    log1Exist = false;
22,714✔
614

615
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;
22,714✔
616
  if (logNameLen < PATH_MAX) {
22,714!
617
    TAOS_UNUSED(snprintf(name, PATH_MAX, "%s%s", tsLogObj.logName, ".0"));
22,714✔
618
    log0Exist = taosStatFile(name, NULL, &logstat0_mtime, NULL) == 0;
22,714✔
619
    name[logNameLen - 1] = '1';
22,714✔
620
    log1Exist = taosStatFile(name, NULL, &logstat1_mtime, NULL) == 0;
22,714✔
621
  }
622

623
  // if none of the log files exist, open 0, if both exists, open the old one
624
  if (!log0Exist && !log1Exist) {
22,714!
625
    tsLogObj.flag = 0;
6,436✔
626
  } else if (!log1Exist) {
16,278✔
627
    tsLogObj.flag = 0;
16,270✔
628
  } else if (!log0Exist) {
8!
629
    tsLogObj.flag = 1;
×
630
  } else {
631
    tsLogObj.flag = (logstat0_mtime > logstat1_mtime) ? 0 : 1;
8✔
632
  }
633
}
22,714✔
634

635
static void processLogFileName(const char *logName, int32_t maxFileNum) {
22,714✔
636
  char fullName[PATH_MAX] = {0};
22,714✔
637
  getFullPathName(fullName, logName);
22,714✔
638
  decideLogFileName(fullName, maxFileNum);
22,714✔
639
  decideLogFileNameFlag();
22,714✔
640
}
22,714✔
641

642
static int32_t taosInitNormalLog(const char *logName, int32_t maxFileNum) {
22,714✔
643
  int32_t code = 0, lino = 0;
22,714✔
644
#ifdef WINDOWS_STASH
645
  /*
646
   * always set maxFileNum to 1
647
   * means client log filename is unique in windows
648
   */
649
  maxFileNum = 1;
650
#endif
651

652
  processLogFileName(logName, maxFileNum);
22,714✔
653

654
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;  // logName + ".0" or ".1"
22,714✔
655

656
  if (logNameLen < 0 || logNameLen >= PATH_MAX) {
22,714!
657
    uError("log name:%s is invalid since length:%d is out of range", logName, logNameLen);
×
658
    return TSDB_CODE_INVALID_CFG;
×
659
  }
660

661
  char name[PATH_MAX] = "\0";
22,714✔
662
  (void)snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag);
22,714✔
663
  (void)taosThreadMutexInit(&tsLogObj.logMutex, NULL);
22,714✔
664

665
  TAOS_UNUSED(taosUmaskFile(0));
22,714✔
666
  tsLogObj.logHandle = taosLogBuffNew(LOG_DEFAULT_BUF_SIZE);
22,714✔
667
  if (tsLogObj.logHandle == NULL) return terrno;
22,714!
668

669
  tsLogObj.logHandle->pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_READ | TD_FILE_WRITE);
22,714✔
670
  if (tsLogObj.logHandle->pFile == NULL) {
22,714!
671
    (void)printf("\n%s:%d failed to open log file:%s, reason:%s\n", __func__, __LINE__, name, strerror(ERRNO));
×
672
    return terrno;
×
673
  }
674
  TAOS_UNUSED(taosLockLogFile(tsLogObj.logHandle->pFile));
22,714✔
675

676
  // only an estimate for number of lines
677
  int64_t filesize = 0;
22,714✔
678
  TAOS_CHECK_EXIT(taosFStatFile(tsLogObj.logHandle->pFile, &filesize, NULL));
22,714!
679

680
  tsLogObj.lines = (int32_t)(filesize / 60);
22,714✔
681

682
  if (taosLSeekFile(tsLogObj.logHandle->pFile, 0, SEEK_END) < 0) {
22,714!
683
    TAOS_CHECK_EXIT(terrno);
×
684
  }
685

686
  (void)snprintf(name, sizeof(name),
22,714✔
687
                 "==================================================\n"
688
                 "                new log file\n"
689
                 "==================================================\n");
690
  if (taosWriteFile(tsLogObj.logHandle->pFile, name, (uint32_t)strlen(name)) <= 0) {
22,714!
691
    TAOS_CHECK_EXIT(terrno);
×
692
  }
693

694
_exit:
22,714✔
695
  if (code != 0) {
22,714!
696
    taosUnLockLogFile(tsLogObj.logHandle->pFile);
×
697
    TAOS_UNUSED(printf("failed to init normal log file:%s at line %d, reason:%s\n", name, lino, tstrerror(code)));
×
698
  }
699
  return code;
22,714✔
700
}
701

702
static void taosUpdateLogNums(ELogLevel level) {
660,583,224✔
703
  switch (level) {
660,583,224!
704
    case DEBUG_ERROR:
716,639✔
705
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfErrorLogs, 1));
716,639✔
706
      break;
716,658✔
707
    case DEBUG_INFO:
25,537,476✔
708
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfInfoLogs, 1));
25,537,476✔
709
      break;
25,557,749✔
710
    case DEBUG_DEBUG:
349,646,460✔
711
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfDebugLogs, 1));
349,646,460✔
712
      break;
349,765,213✔
713
    case DEBUG_DUMP:
284,719,198✔
714
    case DEBUG_TRACE:
715
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfTraceLogs, 1));
284,719,198✔
716
      break;
284,764,203✔
717
    default:
×
718
      break;
×
719
  }
720
}
660,767,274✔
721

722
static inline int32_t taosBuildLogHead(char *buffer, const char *flags) {
662,038,070✔
723
  struct tm      Tm, *ptm;
724
  struct timeval timeSecs;
725

726
  TAOS_UNUSED(taosGetTimeOfDay(&timeSecs));
662,038,070✔
727
  time_t curTime = timeSecs.tv_sec;
661,992,043✔
728
  ptm = taosLocalTime(&curTime, &Tm, NULL, 0, NULL);
661,992,043✔
729
  if (ptm == NULL) {
662,256,387!
730
    uError("%s failed to get local time, code:%d", __FUNCTION__, ERRNO);
×
731
    return 0;
×
732
  }
733
  return snprintf(buffer, LOG_MAX_STACK_LINE_BUFFER_SIZE, "%02d/%02d %02d:%02d:%02d.%06d %08" PRId64 " %s %s",
662,256,387✔
734
                  ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec,
662,246,114✔
735
                  taosGetSelfPthreadId(), LOG_EDITION_FLG, flags);
736
}
737

738
static inline void taosPrintLogImp(ELogLevel level, int32_t dflag, const char *buffer, int32_t len) {
661,119,207✔
739
  if ((dflag & DEBUG_FILE) && tsLogObj.logHandle && tsLogObj.logHandle->pFile != NULL && osLogSpaceSufficient()) {
661,119,207!
740
    taosUpdateLogNums(level);
660,602,209✔
741
    if (tsAsyncLog) {
660,779,804✔
742
      TAOS_UNUSED(taosPushLogBuffer(tsLogObj.logHandle, buffer, len));
5,293,141✔
743
    } else {
744
      TAOS_UNUSED(taosWriteFile(tsLogObj.logHandle->pFile, buffer, len));
655,486,663✔
745
    }
746

747
    if (tsNumOfLogLines > 0) {
660,863,508!
748
      TAOS_UNUSED(atomic_add_fetch_32(&tsLogObj.lines, 1));
660,867,087✔
749
      if ((tsLogObj.lines > tsNumOfLogLines) && (tsLogObj.openInProgress == 0)) {
660,881,332✔
750
        TAOS_UNUSED(taosOpenNewLogFile());
2✔
751
      }
752
    }
753
  }
754

755
  int fd = 0;
661,385,134✔
756
  if (tsLogObj.outputType == LOG_OUTPUT_FILE) {
661,385,134✔
757
#ifndef TAOSD_INTEGRATED    
758
    if (dflag & DEBUG_SCREEN) fd = 1;
661,383,956✔
759
#else
760
    if ((dflag & DEBUG_SCREEN) && tsLogEmbedded) fd = 1;
761
#endif
762
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDOUT) {
1,178✔
763
    fd = 1;
582✔
764
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDERR) {
596✔
765
    fd = 2;
576✔
766
  }
767

768
  if (fd) {
661,385,134✔
769
#pragma GCC diagnostic push
770
#pragma GCC diagnostic ignored "-Wunused-result"
771
#ifndef TD_ASTRA
772
    if (write(fd, buffer, (uint32_t)len) < 0) {
13,046,265✔
773
      TAOS_UNUSED(printf("failed to write log to screen, reason:%s\n", strerror(ERRNO)));
7,766✔
774
    }
775
#else
776
    TAOS_UNUSED(fprintf(fd == 1 ? stdout : stderr, "%s", buffer));
777
#endif
778
#pragma GCC diagnostic pop
779
  }
780
}
661,385,183✔
781

782
/*
783
  use taosPrintLogImpl_useStackBuffer to avoid stack overflow
784

785
*/
786
static int8_t taosPrintLogImplUseStackBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
661,201,700✔
787
                                             va_list args) {
788
  char    buffer[LOG_MAX_STACK_LINE_BUFFER_SIZE];
789
  int32_t len = taosBuildLogHead(buffer, flags);
661,201,700✔
790

791
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_STACK_LINE_BUFFER_SIZE - len - 1, format, args);
661,194,113✔
792
  if (writeLen > LOG_MAX_STACK_LINE_SIZE) {
661,194,113✔
793
    return 1;
896,722✔
794
  }
795

796
  buffer[writeLen++] = '\n';
660,297,391✔
797
  buffer[writeLen] = 0;
660,297,391✔
798

799
  taosPrintLogImp(level, dflag, buffer, writeLen);
660,297,391✔
800

801
  if (tsLogFp && level <= DEBUG_INFO) {
660,486,914✔
802
    buffer[writeLen - 1] = 0;
11,108,117✔
803
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
22,216,211✔
804
  }
805
  return 0;
660,488,593✔
806
}
807
static int8_t taosPrintLogImplUseHeapBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
896,697✔
808
                                            va_list args) {
809
  char *buffer = taosMemoryCalloc(1, LOG_MAX_LINE_BUFFER_SIZE + 1);
896,697!
810
  if (buffer == NULL) {
896,743!
811
    return 1;
×
812
  }
813
  int32_t len = taosBuildLogHead(buffer, flags);
896,743✔
814

815
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len - 1, format, args);
896,756✔
816

817
  if (writeLen > LOG_MAX_LINE_SIZE) writeLen = LOG_MAX_LINE_SIZE;
896,756✔
818
  buffer[writeLen++] = '\n';
896,756✔
819
  buffer[writeLen] = 0;
896,756✔
820

821
  taosPrintLogImp(level, dflag, buffer, writeLen);
896,756✔
822

823
  if (tsLogFp && level <= DEBUG_INFO) {
896,764✔
824
    buffer[writeLen - 1] = 0;
88,351✔
825
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
176,702✔
826
  }
827
  taosMemoryFree(buffer);
896,764!
828
  return 0;
896,764✔
829
}
830
void taosPrintLog(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
660,975,337✔
831
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
660,975,337!
832

833
  va_list argpointer, argpointer_copy;
834
  va_start(argpointer, format);
660,975,337✔
835
  va_copy(argpointer_copy, argpointer);
660,975,337✔
836

837
  if (taosPrintLogImplUseStackBuffer(flags, level, dflag, format, argpointer) == 0) {
660,975,337✔
838
  } else {
839
    TAOS_UNUSED(taosPrintLogImplUseHeapBuffer(flags, level, dflag, format, argpointer_copy));
896,709✔
840
  }
841
  va_end(argpointer_copy);
661,383,785✔
842
  va_end(argpointer);
661,383,785✔
843
}
844

845
void taosPrintLongString(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
2,831✔
846
  if (!osLogSpaceSufficient()) return;
2,831!
847
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
2,831!
848

849
  char *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
2,831!
850
  if (!buffer) return;
2,831!
851
  int32_t len = taosBuildLogHead(buffer, flags);
2,831✔
852

853
  va_list argpointer;
854
  va_start(argpointer, format);
2,831✔
855
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
2,831✔
856
  va_end(argpointer);
2,831✔
857

858
  len = len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 ? LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 : len;
2,831✔
859
  buffer[len++] = '\n';
2,831✔
860
  buffer[len] = 0;
2,831✔
861

862
  taosPrintLogImp(level, dflag, buffer, len);
2,831✔
863
  taosMemoryFree(buffer);
2,831!
864
}
865

866
void taosPrintSlowLog(const char *format, ...) {
349✔
867
  if (!osLogSpaceSufficient()) return;
349!
868

869
  int64_t delta = taosGetTimestampSec() - tsLogObj.timestampToday;
349✔
870
  if (delta >= 86400 || delta < 0) {
349!
871
    taosOpenNewSlowLogFile();
1✔
872
  }
873

874
  char   *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
349!
875
  int32_t len = taosBuildLogHead(buffer, "");
349✔
876

877
  va_list argpointer;
878
  va_start(argpointer, format);
349✔
879
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
349✔
880
  va_end(argpointer);
349✔
881

882
  if (len < 0 || len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2) {
349!
883
    len = LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2;
×
884
  }
885
  buffer[len++] = '\n';
349✔
886
  buffer[len] = 0;
349✔
887

888
  TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfSlowLogs, 1));
349✔
889

890
  if (tsAsyncLog) {
349!
891
    TAOS_UNUSED(taosPushLogBuffer(tsLogObj.slowHandle, buffer, len));
×
892
  } else {
893
    TAOS_UNUSED(taosWriteFile(tsLogObj.slowHandle->pFile, buffer, len));
349✔
894
  }
895

896
  taosMemoryFree(buffer);
349!
897
}
898

899
static void taosCloseLogByFd(TdFilePtr pFile) {
1✔
900
  if (pFile != NULL) {
1!
901
    taosUnLockLogFile(pFile);
1✔
902
    (void)taosCloseFile(&pFile);
1✔
903
  }
904
}
1✔
905

906
static SLogBuff *taosLogBuffNew(int32_t bufSize) {
45,409✔
907
  SLogBuff *pLogBuf = NULL;
45,409✔
908

909
  pLogBuf = taosMemoryCalloc(1, sizeof(SLogBuff));
45,409!
910
  if (pLogBuf == NULL) return NULL;
45,409!
911

912
  LOG_BUF_BUFFER(pLogBuf) = taosMemoryMalloc(bufSize);
45,409!
913
  if (LOG_BUF_BUFFER(pLogBuf) == NULL) goto _err;
45,409!
914

915
  LOG_BUF_START(pLogBuf) = LOG_BUF_END(pLogBuf) = 0;
45,409✔
916
  LOG_BUF_SIZE(pLogBuf) = bufSize;
45,409✔
917
  pLogBuf->minBuffSize = bufSize / 10;
45,409✔
918
  pLogBuf->stop = 0;
45,409✔
919
  pLogBuf->writeInterval = LOG_DEFAULT_INTERVAL;
45,409✔
920
  pLogBuf->lock = 0;
45,409✔
921
  if (taosThreadMutexInit(&LOG_BUF_MUTEX(pLogBuf), NULL) < 0) goto _err;
45,409!
922
  // tsem_init(&(pLogBuf->buffNotEmpty), 0, 0);
923

924
  return pLogBuf;
45,409✔
925

926
_err:
×
927
  taosMemoryFreeClear(LOG_BUF_BUFFER(pLogBuf));
×
928
  taosMemoryFreeClear(pLogBuf);
×
929
  return NULL;
×
930
}
931

932
static void taosCopyLogBuffer(SLogBuff *pLogBuf, int32_t start, int32_t end, const char *msg, int32_t msgLen) {
5,299,653✔
933
  if (start > end) {
5,299,653!
934
    memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
×
935
  } else {
936
    if (LOG_BUF_SIZE(pLogBuf) - end < msgLen) {
5,299,653!
937
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, LOG_BUF_SIZE(pLogBuf) - end);
×
938
      memcpy(LOG_BUF_BUFFER(pLogBuf), msg + LOG_BUF_SIZE(pLogBuf) - end, msgLen - LOG_BUF_SIZE(pLogBuf) + end);
×
939
    } else {
940
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
5,299,653✔
941
    }
942
  }
943
  LOG_BUF_END(pLogBuf) = (LOG_BUF_END(pLogBuf) + msgLen) % LOG_BUF_SIZE(pLogBuf);
5,299,653✔
944
}
5,299,653✔
945

946
static int32_t taosPushLogBuffer(SLogBuff *pLogBuf, const char *msg, int32_t msgLen) {
5,290,448✔
947
  int32_t        start = 0;
5,290,448✔
948
  int32_t        end = 0;
5,290,448✔
949
  int32_t        remainSize = 0;
5,290,448✔
950
  static int64_t lostLine = 0;
951
  char           tmpBuf[128];
952
  int32_t        tmpBufLen = 0;
5,290,448✔
953

954
  if (pLogBuf == NULL || pLogBuf->stop) return -1;
5,290,448!
955

956
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
5,289,960✔
957
  start = LOG_BUF_START(pLogBuf);
5,299,653✔
958
  end = LOG_BUF_END(pLogBuf);
5,299,653✔
959

960
  remainSize = (start > end) ? (start - end - 1) : (start + LOG_BUF_SIZE(pLogBuf) - end - 1);
5,299,653!
961

962
  if (lostLine > 0) {
5,299,653!
963
    snprintf(tmpBuf, tListLen(tmpBuf), "...Lost %" PRId64 " lines here...\n", lostLine);
×
964
    tmpBufLen = (int32_t)strlen(tmpBuf);
×
965
  }
966

967
  if (remainSize <= msgLen || ((lostLine > 0) && (remainSize <= (msgLen + tmpBufLen)))) {
5,299,653!
968
    lostLine++;
×
969
    tsAsyncLogLostLines++;
×
970
    (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
×
971
    return -1;
×
972
  }
973

974
  if (lostLine > 0) {
5,299,653!
975
    taosCopyLogBuffer(pLogBuf, start, end, tmpBuf, tmpBufLen);
×
976
    lostLine = 0;
×
977
  }
978

979
  taosCopyLogBuffer(pLogBuf, LOG_BUF_START(pLogBuf), LOG_BUF_END(pLogBuf), msg, msgLen);
5,299,653✔
980

981
  // int32_t w = atomic_sub_fetch_32(&waitLock, 1);
982
  /*
983
  if (w <= 0 || ((remainSize - msgLen - tmpBufLen) < (LOG_BUF_SIZE(pLogBuf) * 4 /5))) {
984
    tsem_post(&(pLogBuf->buffNotEmpty));
985
    dbgPostN++;
986
  } else {
987
    dbgNoPostN++;
988
  }
989
  */
990

991
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
5,299,653✔
992

993
  return 0;
5,297,024✔
994
}
995

996
static int32_t taosGetLogRemainSize(SLogBuff *pLogBuf, int32_t start, int32_t end) {
220,294✔
997
  int32_t rSize = end - start;
220,294✔
998

999
  return rSize >= 0 ? rSize : LOG_BUF_SIZE(pLogBuf) + rSize;
220,294!
1000
}
1001

1002
static void taosWriteSlowLog(SLogBuff *pLogBuf) {
12,961,724✔
1003
  int32_t lock = atomic_val_compare_exchange_32(&pLogBuf->lock, 0, 1);
12,961,724✔
1004
  if (lock == 1) return;
12,961,724!
1005
  taosWriteLog(pLogBuf);
12,961,724✔
1006
  atomic_store_32(&pLogBuf->lock, 0);
12,961,724✔
1007
}
1008
static void taosWriteLog(SLogBuff *pLogBuf) {
25,931,750✔
1009
  int32_t start = LOG_BUF_START(pLogBuf);
25,931,750✔
1010
  int32_t end = LOG_BUF_END(pLogBuf);
25,931,750✔
1011

1012
  if (start == end) {
25,931,750✔
1013
    dbgEmptyW++;
25,728,643✔
1014
    pLogBuf->writeInterval = LOG_MAX_INTERVAL;
25,728,643✔
1015
    return;
25,728,643✔
1016
  }
1017

1018
  int32_t pollSize = taosGetLogRemainSize(pLogBuf, start, end);
203,107✔
1019
  if (pollSize < pLogBuf->minBuffSize) {
203,107!
1020
    pLogBuf->lastDuration += pLogBuf->writeInterval;
203,107✔
1021
    if (pLogBuf->lastDuration < LOG_MAX_WAIT_MSEC) {
203,107✔
1022
      return;
185,920✔
1023
    }
1024
  }
1025

1026
  pLogBuf->lastDuration = 0;
17,187✔
1027

1028
  if (start < end) {
17,187!
1029
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, pollSize));
17,187✔
1030
  } else {
1031
    int32_t tsize = LOG_BUF_SIZE(pLogBuf) - start;
×
1032
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, tsize));
×
1033

1034
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf), end));
×
1035
  }
1036

1037
  dbgWN++;
17,187✔
1038
  dbgWSize += pollSize;
17,187✔
1039

1040
  if (pollSize < pLogBuf->minBuffSize) {
17,187!
1041
    dbgSmallWN++;
17,187✔
1042
    if (pLogBuf->writeInterval < LOG_MAX_INTERVAL) {
17,187!
1043
      pLogBuf->writeInterval += LOG_INTERVAL_STEP;
×
1044
    }
1045
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 3) {
×
1046
    dbgBigWN++;
×
1047
    pLogBuf->writeInterval = LOG_MIN_INTERVAL;
×
1048
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 4) {
×
1049
    if (pLogBuf->writeInterval > LOG_MIN_INTERVAL) {
×
1050
      pLogBuf->writeInterval -= LOG_INTERVAL_STEP;
×
1051
    }
1052
  }
1053

1054
  LOG_BUF_START(pLogBuf) = (LOG_BUF_START(pLogBuf) + pollSize) % LOG_BUF_SIZE(pLogBuf);
17,187✔
1055

1056
  start = LOG_BUF_START(pLogBuf);
17,187✔
1057
  end = LOG_BUF_END(pLogBuf);
17,187✔
1058

1059
  pollSize = taosGetLogRemainSize(pLogBuf, start, end);
17,187✔
1060
  if (pollSize < pLogBuf->minBuffSize) {
17,187!
1061
    return;
17,187✔
1062
  }
1063

1064
  pLogBuf->writeInterval = 0;
×
1065
}
1066

1067
#define LOG_ROTATE_INTERVAL 3600
1068
#if !defined(TD_ENTERPRISE) || defined(ASSERT_NOT_CORE) || defined(GRANTS_CFG)
1069
#define LOG_INACTIVE_TIME 7200
1070
#define LOG_ROTATE_BOOT   900
1071
#else
1072
#define LOG_INACTIVE_TIME 5
1073
#define LOG_ROTATE_BOOT   (LOG_INACTIVE_TIME + 1)
1074
#endif
1075

1076
static void *taosLogRotateFunc(void *param) {
7,339✔
1077
  setThreadName("logRotate");
7,339✔
1078
  int32_t code = 0;
7,339✔
1079
  taosWLockLatch(&tsLogRotateLatch);
7,339✔
1080
  // compress or remove the old log files
1081
  TdDirPtr pDir = taosOpenDir(tsLogDir);
7,339✔
1082
  if (!pDir) goto _exit;
7,339!
1083
  TdDirEntryPtr de = NULL;
7,339✔
1084
  while ((de = taosReadDir(pDir))) {
46,100✔
1085
    if (taosDirEntryIsDir(de)) {
38,761✔
1086
      continue;
38,757✔
1087
    }
1088
    char *fname = taosGetDirEntryName(de);
24,079✔
1089
    if (!fname) {
24,079!
1090
      continue;
×
1091
    }
1092

1093
    char *pSec = strrchr(fname, '.');
24,079✔
1094
    if (!pSec) {
24,079✔
1095
      continue;
2✔
1096
    }
1097
    char *pIter = pSec;
24,077✔
1098
    bool  isSec = true;
24,077✔
1099
    while (*(++pIter)) {
68,603✔
1100
      if (!isdigit(*pIter)) {
54,055✔
1101
        isSec = false;
9,529✔
1102
        break;
9,529✔
1103
      }
1104
    }
1105
    if (!isSec) {
24,077✔
1106
      continue;
9,529✔
1107
    }
1108

1109
    int64_t fileSec = 0;
14,548✔
1110
    if ((code = taosStr2int64(pSec + 1, &fileSec)) != 0) {
14,548!
1111
      uWarn("%s:%d failed to convert %s to int64 since %s", __func__, __LINE__, pSec + 1, tstrerror(code));
×
1112
      continue;
×
1113
    }
1114
    if (fileSec <= 100) {
14,548✔
1115
      continue;
14,544✔
1116
    }
1117

1118
    char fullName[PATH_MAX] = {0};
4✔
1119
    snprintf(fullName, sizeof(fullName), "%s%s%s", tsLogDir, TD_DIRSEP, fname);
4✔
1120

1121
    int64_t mtime = 0;
4✔
1122
    if ((code = taosStatFile(fullName, NULL, &mtime, NULL)) != 0) {
4!
1123
      uWarn("%s:%d failed to stat file %s since %s", __func__, __LINE__, fullName, tstrerror(code));
×
1124
      continue;
×
1125
    }
1126

1127
    int64_t inactiveSec = taosGetTimestampMs() / 1000 - mtime;
4✔
1128

1129
    if (inactiveSec < LOG_INACTIVE_TIME) {
4!
1130
      continue;
×
1131
    }
1132

1133
    int32_t days = inactiveSec / 86400 + 1;
4✔
1134
    if (tsLogKeepDays != 0 && days > abs(tsLogKeepDays)) {
4!
1135
      TAOS_UNUSED(taosRemoveFile(fullName));
×
1136
      uInfo("file:%s is removed, days:%d, keepDays:%d, sed:%" PRId64, fullName, days, tsLogKeepDays, fileSec);
×
1137
    } else {
1138
      taosKeepOldLog(fullName);  // compress
4✔
1139
    }
1140
  }
1141
  if ((code = taosCloseDir(&pDir)) != 0) {
7,339!
1142
    uWarn("%s:%d failed to close dir %s since %s\n", __func__, __LINE__, tsLogDir, tstrerror(code));
×
1143
  }
1144

1145
  if (tsLogKeepDays != 0) {
7,339✔
1146
    taosRemoveOldFiles(tsLogDir, abs(tsLogKeepDays));
10✔
1147
  }
1148
_exit:
7,329✔
1149
  taosWUnLockLatch(&tsLogRotateLatch);
7,339✔
1150
  return NULL;
7,339✔
1151
}
1152

1153
static void *taosAsyncOutputLog(void *param) {
22,714✔
1154
  SLogBuff *pLogBuf = (SLogBuff *)tsLogObj.logHandle;
22,714✔
1155
  SLogBuff *pSlowBuf = (SLogBuff *)tsLogObj.slowHandle;
22,714✔
1156

1157
  setThreadName("log");
22,714✔
1158
  int32_t count = 0;
22,714✔
1159
  int32_t updateCron = 0;
22,714✔
1160
  int32_t writeInterval = 0;
22,714✔
1161
  int64_t lastCheckSec = taosGetTimestampMs() / 1000 - (LOG_ROTATE_INTERVAL - LOG_ROTATE_BOOT);
22,714✔
1162

1163
  while (1) {
12,924,619✔
1164
    if (pSlowBuf) {
12,947,333✔
1165
      writeInterval = TMIN(pLogBuf->writeInterval, pSlowBuf->writeInterval);
12,939,037✔
1166
    } else {
1167
      writeInterval = pLogBuf->writeInterval;
8,296✔
1168
    }
1169
    count += writeInterval;
12,947,333✔
1170
    updateCron++;
12,947,333✔
1171
    taosMsleep(writeInterval);
12,947,333✔
1172
    if (count > 1000) {
12,947,322✔
1173
      TAOS_UNUSED(osUpdate());
309,305✔
1174
      count = 0;
309,305✔
1175
    }
1176

1177
    // Polling the buffer
1178
    taosWriteLog(pLogBuf);
12,947,322✔
1179
    if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
12,947,322✔
1180

1181
    if (pLogBuf->stop || (pSlowBuf && pSlowBuf->stop)) {
12,947,322!
1182
      pLogBuf->lastDuration = LOG_MAX_WAIT_MSEC;
22,703✔
1183
      taosWriteLog(pLogBuf);
22,703✔
1184
      if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
22,703✔
1185
      break;
22,703✔
1186
    }
1187

1188
    // process the log rotation every LOG_ROTATE_INTERVAL
1189
    int64_t curSec = taosGetTimestampMs() / 1000;
12,924,619✔
1190
    if (curSec >= lastCheckSec) {
12,924,619!
1191
      if ((curSec - lastCheckSec) >= LOG_ROTATE_INTERVAL) {
12,924,619✔
1192
        TdThread     thread;
1193
        TdThreadAttr attr;
1194
        (void)taosThreadAttrInit(&attr);
7,339✔
1195
        (void)taosThreadAttrSetDetachState(&attr, PTHREAD_CREATE_DETACHED);
7,339✔
1196
#ifdef TD_COMPACT_OS
1197
        (void)taosThreadAttrSetStackSize(&attr, STACK_SIZE_SMALL);
1198
#endif
1199
        if (taosThreadCreate(&thread, &attr, taosLogRotateFunc, tsLogObj.logHandle) == 0) {
7,339!
1200
          uInfo("process log rotation");
7,339!
1201
          lastCheckSec = curSec;
7,339✔
1202
        } else {
1203
          uWarn("failed to create thread to process log rotation");
×
1204
        }
1205
        (void)taosThreadAttrDestroy(&attr);
7,339✔
1206
      }
1207
    } else if (curSec < lastCheckSec) {
×
1208
      lastCheckSec = curSec;
×
1209
    }
1210
  }
1211

1212
  return NULL;
22,703✔
1213
}
1214

1215
bool taosAssertDebug(bool condition, const char *file, int32_t line, bool core, const char *format, ...) {
2✔
1216
  if (condition) return false;
2✔
1217

1218
  const char *flags = "UTL FATAL ";
1✔
1219
  ELogLevel   level = DEBUG_FATAL;
1✔
1220
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
1✔
1221
  char        buffer[LOG_MAX_LINE_BUFFER_SIZE];
1222
  int32_t     len = taosBuildLogHead(buffer, flags);
1✔
1223

1224
  va_list argpointer;
1225
  va_start(argpointer, format);
1✔
1226
  len = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len, format, argpointer);
1✔
1227
  va_end(argpointer);
1✔
1228
  buffer[len++] = '\n';
1✔
1229
  buffer[len] = 0;
1✔
1230
  taosPrintLogImp(1, 255, buffer, len);
1✔
1231

1232
  taosPrintLog(flags, level, dflag, "tAssert at file %s:%d exit:%d", file, line, tsAssert);
1✔
1233
#ifndef TD_ASTRA
1234
  taosPrintTrace(flags, level, dflag, -1);
17!
1235
#endif
1236
  if (tsAssert || core) {
1!
1237
    taosCloseLog();
×
1238
    taosMsleep(300);
×
1239

1240
#ifdef NDEBUG
1241
    abort();
1242
#else
1243
    assert(0);
×
1244
#endif
1245
  }
1246

1247
  return true;
1✔
1248
}
1249
#ifdef USE_REPORT
1250
void taosLogCrashInfo(char *nodeType, char *pMsg, int64_t msgLen, int signum, void *sigInfo) {
2✔
1251
  const char *flags = "UTL FATAL ";
2✔
1252
  ELogLevel   level = DEBUG_FATAL;
2✔
1253
  int32_t     dflag = 255;
2✔
1254
  char        filepath[PATH_MAX] = {0};
2✔
1255
  TdFilePtr   pFile = NULL;
2✔
1256

1257
  if (pMsg && msgLen > 0) {
2!
1258
    snprintf(filepath, sizeof(filepath), "%s%s.%sCrashLog", tsLogDir, TD_DIRSEP, nodeType);
1✔
1259

1260
    pFile = taosOpenFile(filepath, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
1✔
1261
    if (pFile == NULL) {
1!
1262
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1263
      goto _return;
×
1264
    }
1265

1266
    if (taosLockFile(pFile) < 0) {
1!
1267
      taosPrintLog(flags, level, dflag, "failed to lock file:%s since %s", filepath, terrstr());
×
1268
      goto _return;
×
1269
    }
1270

1271
    int64_t writeSize = taosWriteFile(pFile, &msgLen, sizeof(msgLen));
1✔
1272
    if (sizeof(msgLen) != writeSize) {
1!
1273
      TAOS_UNUSED(taosUnLockFile(pFile));
×
1274
      taosPrintLog(flags, level, dflag, "failed to write len to file:%s,%p wlen:%" PRId64 " tlen:%lu since %s",
×
1275
                   filepath, pFile, writeSize, sizeof(msgLen), terrstr());
1276
      goto _return;
×
1277
    }
1278

1279
    writeSize = taosWriteFile(pFile, pMsg, msgLen);
1✔
1280
    if (msgLen != writeSize) {
1!
1281
      TAOS_UNUSED(taosUnLockFile(pFile));
×
1282
      taosPrintLog(flags, level, dflag, "failed to write file:%s,%p wlen:%" PRId64 " tlen:%" PRId64 " since %s",
×
1283
                   filepath, pFile, writeSize, msgLen, terrstr());
1284
      goto _return;
×
1285
    }
1286

1287
    TAOS_UNUSED(taosUnLockFile(pFile));
1✔
1288
  }
1289

1290
_return:
1✔
1291

1292
  if (pFile) (void)taosCloseFile(&pFile);
2✔
1293

1294
  taosPrintLog(flags, level, dflag, "crash signal is %d", signum);
2✔
1295

1296
// print the stack trace
1297
#if 0
1298
#ifdef _TD_DARWIN_64
1299
  taosPrintTrace(flags, level, dflag, 4);
1300
#elif !defined(WINDOWS)
1301
  taosPrintLog(flags, level, dflag, "sender PID:%d cmdline:%s", ((siginfo_t *)sigInfo)->si_pid,
1302
               taosGetCmdlineByPID(((siginfo_t *)sigInfo)->si_pid));
1303
  taosPrintTrace(flags, level, dflag, 3);
1304
#else
1305
  taosPrintTrace(flags, level, dflag, 8);
1306
#endif
1307
#endif
1308
  taosMemoryFree(pMsg);
2!
1309
}
2✔
1310

1311
typedef enum {
1312
  CRASH_LOG_WRITER_UNKNOWN = 0,
1313
  CRASH_LOG_WRITER_INIT = 1,
1314
  CRASH_LOG_WRITER_WAIT,
1315
  CRASH_LOG_WRITER_RUNNING,
1316
  CRASH_LOG_WRITER_QUIT
1317
} CrashStatus;
1318
typedef struct crashBasicInfo {
1319
  int8_t  status;
1320
  int64_t clusterId;
1321
  int64_t startTime;
1322
  char   *nodeType;
1323
  int     signum;
1324
  void   *sigInfo;
1325
  tsem_t  sem;
1326
  int64_t reportThread;
1327
} crashBasicInfo;
1328

1329
crashBasicInfo gCrashBasicInfo = {0};
1330

1331
void setCrashWriterStatus(int8_t status) { atomic_store_8(&gCrashBasicInfo.status, status); }
2✔
1332
bool reportThreadSetQuit() {
×
1333
  CrashStatus status =
×
1334
      atomic_val_compare_exchange_8(&gCrashBasicInfo.status, CRASH_LOG_WRITER_INIT, CRASH_LOG_WRITER_QUIT);
×
1335
  if (status == CRASH_LOG_WRITER_INIT) {
×
1336
    return true;
×
1337
  } else {
1338
    return false;
×
1339
  }
1340
}
1341

1342
bool setReportThreadWait() {
1✔
1343
  CrashStatus status =
1✔
1344
      atomic_val_compare_exchange_8(&gCrashBasicInfo.status, CRASH_LOG_WRITER_INIT, CRASH_LOG_WRITER_WAIT);
1✔
1345
  if (status == CRASH_LOG_WRITER_INIT) {
1!
1346
    return true;
1✔
1347
  } else {
1348
    return false;
×
1349
  }
1350
}
1351
bool setReportThreadRunning() {
1✔
1352
  CrashStatus status =
1✔
1353
      atomic_val_compare_exchange_8(&gCrashBasicInfo.status, CRASH_LOG_WRITER_WAIT, CRASH_LOG_WRITER_RUNNING);
1✔
1354
  if (status == CRASH_LOG_WRITER_WAIT) {
1!
1355
    return true;
1✔
1356
  } else {
1357
    return false;
×
1358
  }
1359
}
1360
static void checkWriteCrashLogToFileInNewThead() {
1✔
1361
  if (setReportThreadRunning()) {
1!
1362
    char       *pMsg = NULL;
1✔
1363
    const char *flags = "UTL FATAL ";
1✔
1364
    ELogLevel   level = DEBUG_FATAL;
1✔
1365
    int32_t     dflag = 255;
1✔
1366
    int64_t     msgLen = -1;
1✔
1367

1368
    if (tsEnableCrashReport) {
1!
1369
      if (taosGenCrashJsonMsg(gCrashBasicInfo.signum, &pMsg, gCrashBasicInfo.clusterId, gCrashBasicInfo.startTime)) {
×
1370
        taosPrintLog(flags, level, dflag, "failed to generate crash json msg");
×
1371
      } else {
1372
        msgLen = strlen(pMsg);
×
1373
      }
1374
    }
1375
    taosLogCrashInfo(gCrashBasicInfo.nodeType, pMsg, msgLen, gCrashBasicInfo.signum, gCrashBasicInfo.sigInfo);
1✔
1376
    setCrashWriterStatus(CRASH_LOG_WRITER_INIT);
1✔
1377
    int32_t code = tsem_post(&gCrashBasicInfo.sem);
1✔
1378
    if (code != 0 ) {
1!
1379
      uError("failed to post sem for crashBasicInfo, code:%d", code);
×
1380
    }
1381
    TAOS_UNUSED(tsem_post(&gCrashBasicInfo.sem));
1✔
1382
  }
1383
}
1✔
1384

1385
void checkAndPrepareCrashInfo() {
1✔
1386
  return checkWriteCrashLogToFileInNewThead();
1✔
1387
}
1388

1389
int32_t initCrashLogWriter() {
1✔
1390
  int32_t code = tsem_init(&gCrashBasicInfo.sem, 0, 0);
1✔
1391
  if (code != 0) {
1!
1392
    uError("failed to init sem for crashLogWriter, code:%d", code);
×
1393
    return code;
×
1394
  }
1395
  gCrashBasicInfo.reportThread = taosGetSelfPthreadId();
1✔
1396
  setCrashWriterStatus(CRASH_LOG_WRITER_INIT);
1✔
1397
  return code;
1✔
1398
}
1399

1400
void writeCrashLogToFile(int signum, void *sigInfo, char *nodeType, int64_t clusterId, int64_t startTime) {
2✔
1401
  if (gCrashBasicInfo.reportThread == taosGetSelfPthreadId()) {
2✔
1402
    return;
1✔
1403
  }
1404
  if (setReportThreadWait()) {
1!
1405
    gCrashBasicInfo.clusterId = clusterId;
1✔
1406
    gCrashBasicInfo.startTime = startTime;
1✔
1407
    gCrashBasicInfo.nodeType = nodeType;
1✔
1408
    gCrashBasicInfo.signum = signum;
1✔
1409
    gCrashBasicInfo.sigInfo = sigInfo;
1✔
1410
    TAOS_UNUSED(tsem_wait(&gCrashBasicInfo.sem));
1✔
1411
  }
1412
}
1413

1414
void taosReadCrashInfo(char *filepath, char **pMsg, int64_t *pMsgLen, TdFilePtr *pFd) {
2✔
1415
  const char *flags = "UTL FATAL ";
2✔
1416
  ELogLevel   level = DEBUG_FATAL;
2✔
1417
  int32_t     dflag = 255;
2✔
1418
  TdFilePtr   pFile = NULL;
2✔
1419
  bool        truncateFile = false;
2✔
1420
  char       *buf = NULL;
2✔
1421

1422
  if (NULL == *pFd) {
2!
1423
    int64_t filesize = 0;
2✔
1424
    if (taosStatFile(filepath, &filesize, NULL, NULL) < 0) {
2!
1425
      if (TAOS_SYSTEM_ERROR(ENOENT) == terrno) {
×
1426
        return;
×
1427
      }
1428

1429
      taosPrintLog(flags, level, dflag, "failed to stat file:%s since %s", filepath, terrstr());
×
1430
      return;
×
1431
    }
1432

1433
    if (filesize <= 0) {
2!
1434
      return;
×
1435
    }
1436

1437
    pFile = taosOpenFile(filepath, TD_FILE_READ | TD_FILE_WRITE);
2✔
1438
    if (pFile == NULL) {
2!
1439
      if (ENOENT == ERRNO) {
×
1440
        return;
×
1441
      }
1442

1443
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1444
      return;
×
1445
    }
1446

1447
    TAOS_UNUSED(taosLockFile(pFile));
2✔
1448
  } else {
1449
    pFile = *pFd;
×
1450
  }
1451

1452
  int64_t msgLen = 0;
2✔
1453
  int64_t readSize = taosReadFile(pFile, &msgLen, sizeof(msgLen));
2✔
1454
  if (sizeof(msgLen) != readSize) {
2!
1455
    truncateFile = true;
×
1456
    if (readSize < 0) {
×
1457
      taosPrintLog(flags, level, dflag, "failed to read len from file:%s,%p wlen:%" PRId64 " tlen:%lu since %s",
×
1458
                   filepath, pFile, readSize, sizeof(msgLen), terrstr());
1459
    }
1460
    goto _return;
×
1461
  }
1462

1463
  buf = taosMemoryMalloc(msgLen);
2!
1464
  if (NULL == buf) {
2!
1465
    taosPrintLog(flags, level, dflag, "failed to malloc buf, size:%" PRId64, msgLen);
×
1466
    goto _return;
×
1467
  }
1468

1469
  readSize = taosReadFile(pFile, buf, msgLen);
2✔
1470
  if (msgLen != readSize) {
2✔
1471
    truncateFile = true;
1✔
1472
    taosPrintLog(flags, level, dflag, "failed to read file:%s,%p wlen:%" PRId64 " tlen:%" PRId64 " since %s", filepath,
1✔
1473
                 pFile, readSize, msgLen, terrstr());
1474
    goto _return;
1✔
1475
  }
1476

1477
  *pMsg = buf;
1✔
1478
  *pMsgLen = msgLen;
1✔
1479
  *pFd = pFile;
1✔
1480

1481
  return;
1✔
1482

1483
_return:
1✔
1484

1485
  if (truncateFile) {
1!
1486
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
1✔
1487
  }
1488
  TAOS_UNUSED(taosUnLockFile(pFile));
1✔
1489
  TAOS_UNUSED(taosCloseFile(&pFile));
1✔
1490
  taosMemoryFree(buf);
1!
1491

1492
  *pMsg = NULL;
1✔
1493
  *pMsgLen = 0;
1✔
1494
  *pFd = NULL;
1✔
1495
}
1496

1497
void taosReleaseCrashLogFile(TdFilePtr pFile, bool truncateFile) {
1✔
1498
  if (truncateFile) {
1!
1499
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
1✔
1500
  }
1501

1502
  TAOS_UNUSED(taosUnLockFile(pFile));
1✔
1503
  TAOS_UNUSED(taosCloseFile(&pFile));
1✔
1504
}
1✔
1505
#endif // USE_REPORT
1506

1507
#ifdef NDEBUG
1508
bool taosAssertRelease(bool condition) {
1509
  if (condition) return false;
1510

1511
  const char *flags = "UTL FATAL ";
1512
  ELogLevel   level = DEBUG_FATAL;
1513
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
1514

1515
  taosPrintLog(flags, level, dflag, "tAssert called in release mode, exit:%d", tsAssert);
1516
  taosPrintTrace(flags, level, dflag, 0);
1517

1518
  if (tsAssert) {
1519
    taosMsleep(300);
1520
    abort();
1521
  }
1522

1523
  return true;
1524
}
1525
#endif
1526

1527
#define NUM_BASE 100
1528
#define DIGIT_LENGTH 2
1529
#define MAX_DIGITS 24
1530

1531
char* u64toaFastLut(uint64_t val, char* buf) {
5✔
1532
  // Look-up table for 2-digit numbers
1533
  static const char* lut =
1534
      "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455"
1535
      "5657585960616263646566676869707172737475767778798081828384858687888990919293949596979899";
1536

1537
  char  temp[MAX_DIGITS];
1538
  char* p = temp + tListLen(temp);
5✔
1539

1540
  // Process the digits greater than or equal to 100
1541
  while (val >= NUM_BASE) {
11✔
1542
    // Get the last 2 digits from the look-up table and add to the buffer
1543
    p -= DIGIT_LENGTH;
6✔
1544
    strncpy(p, lut + (val % NUM_BASE) * DIGIT_LENGTH, DIGIT_LENGTH);
6✔
1545
    val /= NUM_BASE;
6✔
1546
  }
1547

1548
  // Process the remaining 1 or 2 digits
1549
  if (val >= 10) {
5✔
1550
    // If the number is 10 or more, get the 2 digits from the look-up table
1551
    p -= DIGIT_LENGTH;
2✔
1552
    strncpy(p, lut + val * DIGIT_LENGTH, DIGIT_LENGTH);
2✔
1553
  } else if (val > 0 || p == temp) {
3!
1554
    // If the number is less than 10, add the single digit to the buffer
1555
    p -= 1;
2✔
1556
    *p = val + '0';
2✔
1557
  }
1558

1559
  int64_t len = temp + tListLen(temp) - p;
5✔
1560
  if (len > 0) {
5✔
1561
    memcpy(buf, p, len);
4✔
1562
  } else {
1563
    buf[0] = '0';
1✔
1564
    len = 1;
1✔
1565
  }
1566
  buf[len] = '\0';
5✔
1567

1568
  return buf + len;
5✔
1569
}
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