added worker last job id to status file (#19992)
* added worker last job id to status file * added worker last job id to sentry * send sentry breadcrumb on all events * fix potential crash in pluginsd_acquire_dimension() * verify uuids loaded from sql are valid * add fatal conditions for missing journalfile, datafile, and datafile->ctx * make sure we check for datafile->ctx on all uses of it * add magic numbers to datafiles to find the race condition
Costa Tsaousis committed
Mar 29, 2025 at 15:16 UTC
bf6753d86b1bf15fd30af51327affc0554e6c624
12 files changed
+128
-74
src/daemon/daemon-status-file.c
+19
@@ -110,6 +110,7 @@ static uint64_t daemon_status_file_hash(DAEMON_STATUS_FILE *ds, const char *msg,
110
ND_PROFILE profile;
111
EXIT_REASON exit_reason;
112
RRD_DB_MODE db_mode;
113
+ uint32_t worker_job_id;
114
uint8_t db_tiers;
115
bool kubernetes;
116
bool sentry_available;
@@ -143,6 +144,7 @@ static uint64_t daemon_status_file_hash(DAEMON_STATUS_FILE *ds, const char *msg,
144
to_hash.sentry_fatal = ds->fatal.sentry,
145
to_hash.host_id = ds->host_id,
146
to_hash.machine_id = ds->machine_id,
147
+ to_hash.worker_job_id = ds->fatal.worker_job_id,
148
149
strncpyz(to_hash.version, ds->version, sizeof(to_hash.version) - 1);
150
strncpyz(to_hash.filename, ds->fatal.filename, sizeof(to_hash.filename) - 1);
@@ -304,6 +306,9 @@ static void daemon_status_file_to_json(BUFFER *wb, DAEMON_STATUS_FILE *ds) {
306
print_uint64_hex(buf, ds->fatal.fault_address);
307
buffer_json_member_add_string(wb, "fault_address", buf);
308
}
309
+
310
+ if(ds->v >= 23)
311
+ buffer_json_member_add_uint64(wb, "worker_job_id", ds->fatal.worker_job_id);
312
}
313
buffer_json_object_close(wb);
314
@@ -354,6 +359,7 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
359
bool required_v20 = version >= 20 ? strict : false;
360
bool required_v21 = version >= 21 ? strict : false;
361
bool required_v22 = version >= 22 ? strict : false;
362
+ bool required_v23 = version >= 23 ? strict : false;
363
364
// Parse timestamp
365
JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "@timestamp", datetime, error, required_v1);
@@ -498,6 +504,9 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
504
JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "fault_address", buf, error, required_v18);
505
ds->fatal.fault_address = str2ull_encoded(buf);
506
}
507
+
508
+ if(version >= 23)
509
+ JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "worker_job_id", SIGNAL_CODE_2id_h, ds->fatal.worker_job_id, error, required_v23);
510
});
511
512
// Parse the last posted object
@@ -1474,6 +1483,9 @@ void daemon_status_file_register_fatal(const char *filename, const char *functio
1483
if(stack_trace && *stack_trace && stack_trace_is_empty(&session_status))
1484
strncpyz(session_status.fatal.stack_trace, stack_trace, sizeof(session_status.fatal.stack_trace) - 1);
1485
1486
+ if(!session_status.fatal.worker_job_id)
1487
+ session_status.fatal.worker_job_id = workers_get_last_job_id();
1488
+
1489
if(line)
1490
session_status.fatal.line = line;
1491
@@ -1541,6 +1553,9 @@ bool daemon_status_file_deadly_signal_received(EXIT_REASON reason, SIGNAL_CODE c
1553
if(!session_status.fatal.thread_id)
1554
session_status.fatal.thread_id = gettid_cached();
1555
1556
+ if(!session_status.fatal.worker_job_id)
1557
+ session_status.fatal.worker_job_id = workers_get_last_job_id();
1558
+
1559
copy_and_clean_thread_name_if_empty(&session_status, nd_thread_tag_async_safe());
1560
1561
dsf_release(session_status);
@@ -1749,3 +1764,7 @@ ND_UUID daemon_status_file_get_host_id(void) {
1764
else
1765
return last_session_status.host_id;
1766
}
1767
+
1768
+size_t daemon_status_file_get_fatal_worker_job_id(void) {
1769
+ return session_status.fatal.worker_job_id;
1770
+}
src/daemon/daemon-status-file.h
+4
-2
@@ -8,7 +8,7 @@
8
#include "database/rrd-database-mode.h"
9
#include "claim/cloud-status.h"
10
11
-#define STATUS_FILE_VERSION 22
11
+#define STATUS_FILE_VERSION 23
12
13
typedef enum {
14
DAEMON_STATUS_NONE,
@@ -93,11 +93,12 @@ typedef struct daemon_status_file {
93
char function[128];
94
char errno_str[64];
95
char message[512];
96
- char stack_trace[2048];
96
+ char stack_trace[4096];
97
char thread[ND_THREAD_TAG_MAX + 1];
98
pid_t thread_id;
99
SIGNAL_CODE signal_code;
100
uintptr_t fault_address;
101
+ uint32_t worker_job_id;
102
bool sentry; // true when the error was also reported to sentry
103
} fatal;
104
@@ -155,5 +156,6 @@ DAEMON_STATUS daemon_status_file_get_status(void);
156
size_t daemon_status_file_get_restarts(void);
157
ssize_t daemon_status_file_get_reliability(void);
158
ND_UUID daemon_status_file_get_host_id(void);
159
+size_t daemon_status_file_get_fatal_worker_job_id(void);
160
161
#endif //NETDATA_DAEMON_STATUS_FILE_H
src/daemon/sentry-native/sentry-native.c
+30
-44
@@ -5,10 +5,13 @@
5
6
#include "sentry.h"
7
8
+static void nd_sentry_add_deadly_signal_as_breadcrumb(void);
9
+
10
static char sentry_path[FILENAME_MAX] = "";
9
-static char g_sentry_event_message[512] = {0};
11
11
-bool nd_sentry_crash_report_enabled = true;
12
+static bool sentry_initialized = false;
13
+static bool breadcrumb_added = false;
14
+static bool nd_sentry_crash_report_enabled = true;
15
16
const char *nd_sentry_path(void) {
17
return sentry_path;
@@ -86,14 +89,7 @@ static sentry_value_t nd_sentry_on_hook(sentry_value_t event) {
89
return sentry_value_new_null();
90
}
91
89
- nd_sentry_set_tag_status();
90
- nd_sentry_set_tag_uptime();
91
- nd_sentry_set_tag("thread", daemon_status_file_get_fatal_thread());
92
- nd_sentry_set_tag_uint64("thread_id", daemon_status_file_get_fatal_thread_id());
93
-
94
- // set the title of the event
95
- if(g_sentry_event_message[0])
96
- sentry_value_set_by_key(event, "message", sentry_value_new_string(g_sentry_event_message));
92
+ nd_sentry_add_deadly_signal_as_breadcrumb();
93
94
return event;
95
}
@@ -116,7 +112,7 @@ static sentry_value_t nd_sentry_before_send(
112
// sentry initialization
113
114
void nd_sentry_init(void) {
119
- if (!analytics_check_enabled())
115
+ if (!analytics_check_enabled() || sentry_initialized)
116
return;
117
118
// path where sentry should save stuff
@@ -186,10 +182,12 @@ void nd_sentry_init(void) {
182
nd_sentry_set_tag_uint64("restarts", daemon_status_file_get_restarts());
183
nd_sentry_set_tag_int64("reliability", daemon_status_file_get_reliability());
184
nd_sentry_set_tag("stack_traces", daemon_status_file_get_stack_trace_backend());
185
+
186
+ sentry_initialized = true;
187
}
188
189
void nd_sentry_fini(void) {
192
- if (!analytics_check_enabled())
190
+ if(!sentry_initialized)
191
return;
192
193
sentry_close();
@@ -231,17 +229,20 @@ static void nd_sentry_add_key_value_uint64(sentry_value_t data, const char *key,
229
sentry_value_set_by_key(data, key, sentry_value_new_string(buf));
230
}
231
234
-void nd_sentry_add_fatal_message_as_breadcrumb(void) {
235
- if (!analytics_check_enabled())
232
+void nd_sentry_add_breadcrumb(const char *category, const char *message) {
233
+ if(!sentry_initialized || breadcrumb_added)
234
return;
235
236
+ nd_sentry_set_tag_status();
237
+ nd_sentry_set_tag_uptime();
238
+
239
+ nd_sentry_set_tag("thread", daemon_status_file_get_fatal_thread());
240
+ nd_sentry_set_tag_uint64("thread_id", daemon_status_file_get_fatal_thread_id());
241
+ nd_sentry_set_tag_uint64("worker_job_id", daemon_status_file_get_fatal_worker_job_id());
242
+
243
const char *function = daemon_status_file_get_fatal_function();
244
if(!function || !*function)
240
- function = "unknown";
241
- else
242
- strncpyz(g_sentry_event_message, function, sizeof(g_sentry_event_message) - 1);
243
-
244
- nd_sentry_set_tag_uptime();
245
+ function = category;
246
247
// Set the transaction name to the function where the error occurred
248
// this should be low cardinality
@@ -250,7 +251,7 @@ void nd_sentry_add_fatal_message_as_breadcrumb(void) {
251
// Set the fingerprint to the function where the error occurred
252
sentry_set_fingerprint("{{ default }}", function, NULL);
253
253
- sentry_value_t crumb = sentry_value_new_breadcrumb("fatal", "fatal() event details");
254
+ sentry_value_t crumb = sentry_value_new_breadcrumb("fatal", message);
255
256
sentry_value_t data = sentry_value_new_object();
257
nd_sentry_add_key_value_charp(data, "message", daemon_status_file_get_fatal_message());
@@ -262,35 +263,20 @@ void nd_sentry_add_fatal_message_as_breadcrumb(void) {
263
nd_sentry_add_key_value_charp(data, "errno", daemon_status_file_get_fatal_errno());
264
nd_sentry_add_key_value_charp(data, "stack_trace", daemon_status_file_get_fatal_stack_trace());
265
nd_sentry_add_key_value_charp(data, "status", DAEMON_STATUS_2str(daemon_status_file_get_status()));
266
+ nd_sentry_add_key_value_uint64(data, "worker_job_id", daemon_status_file_get_fatal_worker_job_id());
267
268
sentry_value_set_by_key(crumb, "data", data);
269
sentry_add_breadcrumb(crumb);
270
}
271
270
-void nd_sentry_add_shutdown_timeout_as_breadcrumb(void) {
271
- if (!analytics_check_enabled())
272
- return;
273
-
274
- const char *function = "shutdown_timeout";
275
- strncpyz(g_sentry_event_message, function, sizeof(g_sentry_event_message) - 1);
276
-
277
- nd_sentry_set_tag_uptime();
278
-
279
- // Set the transaction name to the function where the error occurred
280
- // this should be low cardinality
281
- sentry_set_transaction(function);
282
-
283
- // Set the fingerprint to the function where the error occurred
284
- sentry_set_fingerprint("{{ default }}", function, NULL);
285
-
286
- sentry_value_t crumb = sentry_value_new_breadcrumb("fatal", "shutdown_timeout() event details");
272
+void nd_sentry_add_fatal_message_as_breadcrumb(void) {
273
+ nd_sentry_add_breadcrumb("fatal", "fatal message event details");
274
+}
275
288
- sentry_value_t data = sentry_value_new_object();
289
- nd_sentry_add_key_value_charp(data, "function", function);
290
- nd_sentry_add_key_value_charp(data, "thread", nd_thread_tag());
291
- nd_sentry_add_key_value_uint64(data, "thread_id", gettid_cached());
292
- nd_sentry_add_key_value_charp(data, "status", DAEMON_STATUS_2str(daemon_status_file_get_status()));
276
+static void nd_sentry_add_deadly_signal_as_breadcrumb(void) {
277
+ nd_sentry_add_breadcrumb("deadly_signal", "deadly signal event details");
278
+}
279
294
- sentry_value_set_by_key(crumb, "data", data);
295
- sentry_add_breadcrumb(crumb);
280
+void nd_sentry_add_shutdown_timeout_as_breadcrumb(void) {
281
+ nd_sentry_add_breadcrumb("shutdown_timeout", "shutdown timeout event details");
282
}
src/database/engine/datafile.c
+15
-11
@@ -28,6 +28,7 @@ static struct rrdengine_datafile *datafile_alloc_and_init(struct rrdengine_insta
28
datafile->fileno = fileno;
29
fatal_assert(0 == uv_rwlock_init(&datafile->extent_rwlock));
30
datafile->ctx = ctx;
31
+ datafile->magic1 = datafile->magic2 = DATAFILE_MAGIC;
32
33
datafile->users.available = true;
34
@@ -94,8 +95,8 @@ bool datafile_acquire_for_deletion(struct rrdengine_datafile *df, bool is_shutdo
95
// count the number of pages referencing this in the open cache
96
spinlock_unlock(&df->users.spinlock);
97
usec_t time_to_scan_ut = now_monotonic_usec();
97
- size_t clean_pages_in_open_cache = pgc_count_clean_pages_having_data_ptr(open_cache, (Word_t)df->ctx, df);
98
- size_t hot_pages_in_open_cache = pgc_count_hot_pages_having_data_ptr(open_cache, (Word_t)df->ctx, df);
98
+ size_t clean_pages_in_open_cache = pgc_count_clean_pages_having_data_ptr(open_cache, (Word_t)datafile_ctx(df), df);
99
+ size_t hot_pages_in_open_cache = pgc_count_hot_pages_having_data_ptr(open_cache, (Word_t)datafile_ctx(df), df);
100
time_to_scan_ut = now_monotonic_usec() - time_to_scan_ut;
101
spinlock_lock(&df->users.spinlock);
102
@@ -115,7 +116,7 @@ bool datafile_acquire_for_deletion(struct rrdengine_datafile *df, bool is_shutdo
116
"%zu clean and %zu hot open cache pages "
117
"- will be deleted shortly "
118
"(scanned open cache in %"PRIu64" usecs)",
118
- df->fileno, df->ctx->config.tier,
119
+ df->fileno, datafile_ctx(df)->config.tier,
120
df->users.lockers,
121
df->users.lockers_by_reason[DATAFILE_ACQUIRE_OPEN_CACHE],
122
df->users.lockers_by_reason[DATAFILE_ACQUIRE_PAGE_DETAILS],
@@ -132,7 +133,7 @@ bool datafile_acquire_for_deletion(struct rrdengine_datafile *df, bool is_shutdo
133
"%zu clean and %zu hot open cache pages "
134
"- will be deleted now "
135
"(scanned open cache in %"PRIu64" usecs)",
135
- df->fileno, df->ctx->config.tier,
136
+ df->fileno, datafile_ctx(df)->config.tier,
137
df->users.lockers,
138
df->users.lockers_by_reason[DATAFILE_ACQUIRE_OPEN_CACHE],
139
df->users.lockers_by_reason[DATAFILE_ACQUIRE_PAGE_DETAILS],
@@ -146,7 +147,7 @@ bool datafile_acquire_for_deletion(struct rrdengine_datafile *df, bool is_shutdo
147
"has %u lockers (oc:%u, pd:%u), "
148
"%zu clean and %zu hot open cache pages "
149
"(scanned open cache in %"PRIu64" usecs)",
149
- df->fileno, df->ctx->config.tier,
150
+ df->fileno, datafile_ctx(df)->config.tier,
151
df->users.lockers,
152
df->users.lockers_by_reason[DATAFILE_ACQUIRE_OPEN_CACHE],
153
df->users.lockers_by_reason[DATAFILE_ACQUIRE_PAGE_DETAILS],
@@ -163,12 +164,12 @@ bool datafile_acquire_for_deletion(struct rrdengine_datafile *df, bool is_shutdo
164
void generate_datafilepath(struct rrdengine_datafile *datafile, char *str, size_t maxlen)
165
{
166
(void) snprintfz(str, maxlen - 1, "%s/" DATAFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL DATAFILE_EXTENSION,
166
- datafile->ctx->config.dbfiles_path, datafile->tier, datafile->fileno);
167
+ datafile_ctx(datafile)->config.dbfiles_path, datafile->tier, datafile->fileno);
168
}
169
170
int close_data_file(struct rrdengine_datafile *datafile)
171
{
171
- struct rrdengine_instance *ctx = datafile->ctx;
172
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
173
uv_fs_t req;
174
int ret;
175
char path[RRDENG_PATH_MAX];
@@ -187,7 +188,7 @@ int close_data_file(struct rrdengine_datafile *datafile)
188
189
int unlink_data_file(struct rrdengine_datafile *datafile)
190
{
190
- struct rrdengine_instance *ctx = datafile->ctx;
191
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
192
uv_fs_t req;
193
int ret;
194
char path[RRDENG_PATH_MAX];
@@ -208,7 +209,7 @@ int unlink_data_file(struct rrdengine_datafile *datafile)
209
210
int destroy_data_file_unsafe(struct rrdengine_datafile *datafile)
211
{
211
- struct rrdengine_instance *ctx = datafile->ctx;
212
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
213
uv_fs_t req;
214
int ret;
215
char path[RRDENG_PATH_MAX];
@@ -243,7 +244,7 @@ int destroy_data_file_unsafe(struct rrdengine_datafile *datafile)
244
245
int create_data_file(struct rrdengine_datafile *datafile)
246
{
246
- struct rrdengine_instance *ctx = datafile->ctx;
247
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
248
uv_fs_t req;
249
uv_file file;
250
int ret, fd;
@@ -321,7 +322,7 @@ static int check_data_file_superblock(uv_file file)
322
323
static int load_data_file(struct rrdengine_datafile *datafile)
324
{
324
- struct rrdengine_instance *ctx = datafile->ctx;
325
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
326
uv_fs_t req;
327
uv_file file;
328
int ret, fd, error;
@@ -601,6 +602,9 @@ void finalize_data_files(struct rrdengine_instance *ctx)
602
spinlock_unlock(&datafile->writers.spinlock);
603
uv_rwlock_wrunlock(&ctx->datafiles.rwlock);
604
605
+ memset(journalfile, 0, sizeof(*journalfile));
606
+ memset(datafile, 0, sizeof(*datafile));
607
+
608
freez(journalfile);
609
freez(datafile);
610
src/database/engine/datafile.h
+17
@@ -44,8 +44,12 @@ typedef struct {
44
struct extent_page_details_list *base;
45
} EPDL_EXTENT;
46
47
+#define DATAFILE_MAGIC 0xDA7AF11E
48
+
49
/* only one event loop is supported for now */
50
struct rrdengine_datafile {
51
+ uint32_t magic1;
52
+
53
unsigned tier;
54
unsigned fileno;
55
uv_file file;
@@ -79,6 +83,8 @@ struct rrdengine_datafile {
83
RW_SPINLOCK spinlock;
84
Pvoid_t epdl_per_extent;
85
} extent_epdl;
86
+
87
+ uint32_t magic2;
88
};
89
90
bool datafile_acquire(struct rrdengine_datafile *df, DATAFILE_ACQUIRE_REASONS reason);
@@ -97,4 +103,15 @@ int create_new_datafile_pair(struct rrdengine_instance *ctx, bool having_lock);
103
int init_data_files(struct rrdengine_instance *ctx);
104
void finalize_data_files(struct rrdengine_instance *ctx);
105
106
+NEVERNULL ALWAYS_INLINE
107
+static struct rrdengine_instance *datafile_ctx(struct rrdengine_datafile *datafile) {
108
+ if(unlikely(!datafile->ctx))
109
+ fatal("DBENGINE: datafile %u of tier %u has no ctx", datafile->fileno, datafile->tier);
110
+
111
+ if(unlikely(datafile->magic1 != DATAFILE_MAGIC || datafile->magic2 != DATAFILE_MAGIC))
112
+ fatal("DBENGINE: datafile %u of tier %u has invalid magic", datafile->fileno, datafile->tier);
113
+
114
+ return datafile->ctx;
115
+}
116
+
117
#endif /* NETDATA_DATAFILE_H */
\ No newline at end of file
src/database/engine/journalfile.c
+26
-14
@@ -61,13 +61,13 @@ void journalfile_v1_extent_write(struct rrdengine_instance *ctx, struct rrdengin
61
void journalfile_v2_generate_path(struct rrdengine_datafile *datafile, char *str, size_t maxlen)
62
{
63
(void) snprintfz(str, maxlen, "%s/" WALFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL WALFILE_EXTENSION_V2,
64
- datafile->ctx->config.dbfiles_path, datafile->tier, datafile->fileno);
64
+ datafile_ctx(datafile)->config.dbfiles_path, datafile->tier, datafile->fileno);
65
}
66
67
void journalfile_v1_generate_path(struct rrdengine_datafile *datafile, char *str, size_t maxlen)
68
{
69
(void) snprintfz(str, maxlen - 1, "%s/" WALFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL WALFILE_EXTENSION,
70
- datafile->ctx->config.dbfiles_path, datafile->tier, datafile->fileno);
70
+ datafile_ctx(datafile)->config.dbfiles_path, datafile->tier, datafile->fileno);
71
}
72
73
// ----------------------------------------------------------------------------
@@ -155,15 +155,20 @@ ALWAYS_INLINE struct rrdengine_datafile *njfv2idx_find_and_acquire_j2_header(NJF
155
}
156
157
static void njfv2idx_add(struct rrdengine_datafile *datafile) {
158
+ if(unlikely(!datafile))
159
+ fatal("DBENGINE: NJFV2IDX trying to index a journal file with no datafile");
160
+
161
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
162
+
163
internal_fatal(datafile->journalfile->v2.last_time_s <= 0, "DBENGINE: NJFV2IDX trying to index a journal file with invalid first_time_s");
164
160
- rw_spinlock_write_lock(&datafile->ctx->njfv2idx.spinlock);
165
+ rw_spinlock_write_lock(&ctx->njfv2idx.spinlock);
166
datafile->journalfile->njfv2idx.indexed_as = datafile->journalfile->v2.last_time_s;
167
168
do {
169
internal_fatal(datafile->journalfile->njfv2idx.indexed_as <= 0, "DBENGINE: NJFV2IDX journalfile is already indexed");
170
166
- Pvoid_t *PValue = JudyLIns(&datafile->ctx->njfv2idx.JudyL, datafile->journalfile->njfv2idx.indexed_as, PJE0);
171
+ Pvoid_t *PValue = JudyLIns(&ctx->njfv2idx.JudyL, datafile->journalfile->njfv2idx.indexed_as, PJE0);
172
if (!PValue || PValue == PJERR)
173
fatal("DBENGINE: NJFV2IDX corrupted judy array");
174
@@ -177,21 +182,22 @@ static void njfv2idx_add(struct rrdengine_datafile *datafile) {
182
}
183
} while(1);
184
180
- rw_spinlock_write_unlock(&datafile->ctx->njfv2idx.spinlock);
185
+ rw_spinlock_write_unlock(&ctx->njfv2idx.spinlock);
186
}
187
188
static void njfv2idx_remove(struct rrdengine_datafile *datafile) {
189
internal_fatal(!datafile->journalfile->njfv2idx.indexed_as, "DBENGINE: NJFV2IDX journalfile to remove is not indexed");
190
186
- rw_spinlock_write_lock(&datafile->ctx->njfv2idx.spinlock);
191
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
192
+ rw_spinlock_write_lock(&ctx->njfv2idx.spinlock);
193
188
- int rc = JudyLDel(&datafile->ctx->njfv2idx.JudyL, datafile->journalfile->njfv2idx.indexed_as, PJE0);
194
+ int rc = JudyLDel(&ctx->njfv2idx.JudyL, datafile->journalfile->njfv2idx.indexed_as, PJE0);
195
(void)rc;
196
internal_fatal(!rc, "DBENGINE: NJFV2IDX cannot remove entry");
197
198
datafile->journalfile->njfv2idx.indexed_as = 0;
199
194
- rw_spinlock_write_unlock(&datafile->ctx->njfv2idx.spinlock);
200
+ rw_spinlock_write_unlock(&ctx->njfv2idx.spinlock);
201
}
202
203
// ----------------------------------------------------------------------------
@@ -214,7 +220,7 @@ static struct journal_v2_header *journalfile_v2_mounted_data_get(struct rrdengin
220
journalfile->v2.flags &= ~(JOURNALFILE_FLAG_IS_AVAILABLE | JOURNALFILE_FLAG_IS_MOUNTED);
221
spinlock_unlock(&journalfile->v2.spinlock);
222
217
- ctx_fs_error(journalfile->datafile->ctx);
223
+ ctx_fs_error(datafile_ctx(journalfile->datafile));
224
}
225
else {
226
__atomic_add_fetch(&rrdeng_cache_efficiency_stats.journal_v2_mapped, 1, __ATOMIC_RELAXED);
@@ -276,7 +282,7 @@ static bool journalfile_v2_mounted_data_unmount(struct rrdengine_journalfile *jo
282
journalfile_v2_generate_path(journalfile->datafile, path, sizeof(path));
283
netdata_log_error("DBENGINE: failed to unmap index file '%s'", path);
284
internal_fatal(true, "DBENGINE: failed to unmap file '%s'", path);
279
- ctx_fs_error(journalfile->datafile->ctx);
285
+ ctx_fs_error(datafile_ctx(journalfile->datafile));
286
}
287
else {
288
__atomic_add_fetch(&rrdeng_cache_efficiency_stats.journal_v2_unmapped, 1, __ATOMIC_RELAXED);
@@ -406,6 +412,12 @@ size_t journalfile_v2_data_size_get(struct rrdengine_journalfile *journalfile) {
412
}
413
414
void journalfile_v2_data_set(struct rrdengine_journalfile *journalfile, int fd, void *journal_data, uint32_t journal_data_size) {
415
+ if(unlikely(!journalfile))
416
+ fatal("DBENGINE: JOURNALFILE: trying to set journal data without a journalfile");
417
+
418
+ if(unlikely(!journalfile->datafile))
419
+ fatal("DBENGINE: JOURNALFILE: trying to set journal data without a datafile");
420
+
421
spinlock_lock(&journalfile->mmap.spinlock);
422
spinlock_lock(&journalfile->v2.spinlock);
423
@@ -488,7 +500,7 @@ static int close_uv_file(struct rrdengine_datafile *datafile, uv_file file)
500
if (ret < 0) {
501
journalfile_v1_generate_path(datafile, path, sizeof(path));
502
netdata_log_error("DBENGINE: uv_fs_close(%s): %s", path, uv_strerror(ret));
491
- ctx_fs_error(datafile->ctx);
503
+ ctx_fs_error(datafile_ctx(datafile));
504
}
505
uv_fs_req_cleanup(&req);
506
return ret;
@@ -507,7 +519,7 @@ int journalfile_close(struct rrdengine_journalfile *journalfile, struct rrdengin
519
int journalfile_unlink(struct rrdengine_journalfile *journalfile)
520
{
521
struct rrdengine_datafile *datafile = journalfile->datafile;
510
- struct rrdengine_instance *ctx = datafile->ctx;
522
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
523
uv_fs_t req;
524
int ret;
525
char path[RRDENG_PATH_MAX];
@@ -528,7 +540,7 @@ int journalfile_unlink(struct rrdengine_journalfile *journalfile)
540
541
int journalfile_destroy_unsafe(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
542
{
531
- struct rrdengine_instance *ctx = datafile->ctx;
543
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
544
uv_fs_t req;
545
int ret;
546
char path[RRDENG_PATH_MAX];
@@ -572,7 +584,7 @@ int journalfile_destroy_unsafe(struct rrdengine_journalfile *journalfile, struct
584
585
int journalfile_create(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
586
{
575
- struct rrdengine_instance *ctx = datafile->ctx;
587
+ struct rrdengine_instance *ctx = datafile_ctx(datafile);
588
uv_fs_t req;
589
uv_file file;
590
int ret, fd;
src/database/engine/rrdengine.c
+3
@@ -1293,6 +1293,9 @@ void datafile_delete(struct rrdengine_instance *ctx, struct rrdengine_datafile *
1293
rw_spinlock_write_unlock(&datafile->extent_epdl.spinlock);
1294
}
1295
1296
+ memset(journal_file, 0, sizeof(*journal_file));
1297
+ memset(datafile, 0, sizeof(*datafile));
1298
+
1299
freez(journal_file);
1300
freez(datafile);
1301
src/database/engine/rrdengineapi.c
+2
-2
@@ -1337,7 +1337,7 @@ static void populate_v2_statistics(struct rrdengine_datafile *datafile, RRDENG_S
1337
1338
time_t update_every_s;
1339
1340
- size_t points = descr->page_length / CTX_POINT_SIZE_BYTES(datafile->ctx);
1340
+ size_t points = descr->page_length / CTX_POINT_SIZE_BYTES(datafile_ctx(datafile));
1341
1342
time_t start_time_s = journal_start_time_s + descr->delta_start_s;
1343
time_t end_time_s = journal_start_time_s + descr->delta_end_s;
@@ -1345,7 +1345,7 @@ static void populate_v2_statistics(struct rrdengine_datafile *datafile, RRDENG_S
1345
if(likely(points > 1))
1346
update_every_s = (time_t) ((end_time_s - start_time_s) / (points - 1));
1347
else {
1348
- update_every_s = (time_t) (nd_profile.update_every * get_tier_grouping(datafile->ctx->config.tier));
1348
+ update_every_s = (time_t) (nd_profile.update_every * get_tier_grouping(datafile_ctx(datafile)->config.tier));
1349
stats->single_point_pages++;
1350
}
1351
src/database/sqlite/sqlite_metadata.c
+2
@@ -2088,6 +2088,8 @@ size_t populate_metrics_from_database(void *mrg, void (*populate_cb)(void *mrg,
2088
usec_t started_ut = now_monotonic_usec();
2089
while (sqlite3_step(res) == SQLITE_ROW) {
2090
nd_uuid_t *uuid = (nd_uuid_t *)sqlite3_column_blob(res, 0);
2091
+ if (!uuid || sqlite3_column_bytes(res, 0) != sizeof(nd_uuid_t))
2092
+ continue;
2093
2094
for (size_t tier = 0; tier < nd_profile.storage_tiers ; tier++) {
2095
if (unlikely(!multidb_ctx[tier]))
src/libnetdata/worker_utilization/worker_utilization.c
+7
@@ -95,6 +95,11 @@ static struct workers_globals {
95
};
96
97
static __thread struct worker *worker = NULL; // the current thread worker
98
+static __thread size_t last_job_id = 0;
99
+
100
+size_t workers_get_last_job_id() {
101
+ return last_job_id;
102
+}
103
104
static ALWAYS_INLINE usec_t worker_now_monotonic_usec(void) {
105
#ifdef NETDATA_WITHOUT_WORKERS_LATENCY
@@ -256,6 +261,8 @@ static void worker_is_busy_do(size_t job_id) {
261
}
262
263
ALWAYS_INLINE void worker_is_busy(size_t job_id) {
264
+ last_job_id = job_id;
265
+
266
if(likely(!worker || job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES))
267
return;
268
src/libnetdata/worker_utilization/worker_utilization.h
+2
@@ -43,6 +43,8 @@ void worker_register_job_name(size_t job_id, const char *name);
43
void worker_register_job_custom_metric(size_t job_id, const char *name, const char *units, WORKER_METRIC_TYPE type);
44
void worker_unregister(void);
45
46
+size_t workers_get_last_job_id();
47
+
48
void worker_is_idle(void);
49
void worker_is_busy(size_t job_id);
50
void worker_set_metric(size_t job_id, NETDATA_DOUBLE value);
src/plugins.d/pluginsd_internals.h
+1
-1
@@ -219,7 +219,7 @@ static ALWAYS_INLINE RRDDIM *pluginsd_acquire_dimension(RRDHOST *host, RRDSET *s
219
if(likely(rd)) {
220
const char *id = prd->id;
221
222
- if(strcmp(id, dimension) == 0) {
222
+ if(id && *id && strcmp(id, dimension) == 0) {
223
// we found it cached
224
return rd;
225
}