Revert "New journal disk based indexing for agent memory reduction" (#14000)
Revert "New journal disk based indexing for agent memory reduction (#13885)" This reverts commit 224b051a2b2bab39a4b536e531ab9ca590bf31bb.
Costa Tsaousis committed
Nov 15, 2022 at 23:49 UTC
becd97a3660af34104c557ba6c2877f624143c2e
30 files changed
+651
-2320
collectors/plugins.d/pluginsd_parser.c
+2
-30
@@ -293,25 +293,9 @@ PARSER_RC pluginsd_chart_definition_end(char **words, size_t num_words, void *us
293
// rrdhost_hostname(host), rrdset_id(st),
294
// (unsigned long long)first_entry_child, (unsigned long long)last_entry_child);
295
296
- bool ok = true;
297
- if(!rrdset_flag_check(st, RRDSET_FLAG_RECEIVER_REPLICATION_IN_PROGRESS)) {
298
-
299
-#ifdef NETDATA_INTERNAL_CHECKS
300
- st->replay.start_streaming = false;
301
- st->replay.after = 0;
302
- st->replay.before = 0;
303
-#endif
304
-
305
- rrdset_flag_clear(st, RRDSET_FLAG_RECEIVER_REPLICATION_FINISHED);
306
- rrdset_flag_set(st, RRDSET_FLAG_RECEIVER_REPLICATION_IN_PROGRESS);
307
-
308
- ok = replicate_chart_request(send_to_plugin, user_object->parser, host, st, first_entry_child,
309
- last_entry_child, 0, 0);
310
- }
311
- else {
312
- internal_error(true, "RRDSET: not sending duplicate replication request for chart '%s'", rrdset_id(st));
313
- }
296
+ rrdset_flag_clear(st, RRDSET_FLAG_RECEIVER_REPLICATION_FINISHED);
297
298
+ bool ok = replicate_chart_request(send_to_plugin, user_object->parser, host, st, first_entry_child, last_entry_child, 0, 0);
299
return ok ? PARSER_RC_OK : PARSER_RC_ERROR;
300
}
301
@@ -891,11 +875,6 @@ PARSER_RC pluginsd_replay_rrdset_begin(char **words, size_t num_words, void *use
875
time_t start_time = strtol(start_time_str, NULL, 0);
876
time_t end_time = strtol(end_time_str, NULL, 0);
877
894
- internal_error(
895
- (!st->replay.start_streaming && (end_time < st->replay.after || start_time > st->replay.before)),
896
- "REPLAY: received a " PLUGINSD_KEYWORD_REPLAY_BEGIN " on chart '%s' ('%s') on host '%s', from %ld to %ld, which does not match our request (%ld to %ld).",
897
- rrdset_name(st), rrdset_id(st), rrdhost_hostname(st->rrdhost), start_time, end_time, st->replay.after, st->replay.before);
898
-
878
if(start_time && end_time) {
879
if (start_time > end_time) {
880
error("REPLAY: requested a " PLUGINSD_KEYWORD_REPLAY_BEGIN " on chart '%s' ('%s') on host '%s', but timings are invalid (%ld to %ld). Disabling it.",
@@ -1156,18 +1135,11 @@ PARSER_RC pluginsd_replay_end(char **words, size_t num_words, void *user)
1135
st->counter++;
1136
st->counter_done++;
1137
1159
-#ifdef NETDATA_INTERNAL_CHECKS
1160
- st->replay.start_streaming = false;
1161
- st->replay.after = 0;
1162
- st->replay.before = 0;
1163
-#endif
1164
-
1138
if (start_streaming) {
1139
if (st->update_every != update_every_child)
1140
rrdset_set_update_every(st, update_every_child);
1141
1142
rrdset_flag_set(st, RRDSET_FLAG_RECEIVER_REPLICATION_FINISHED);
1170
- rrdset_flag_clear(st, RRDSET_FLAG_RECEIVER_REPLICATION_IN_PROGRESS);
1143
rrdset_flag_clear(st, RRDSET_FLAG_SYNC_CLOCK);
1144
return PARSER_RC_OK;
1145
}
daemon/global_statistics.c
-3
@@ -865,7 +865,6 @@ static void dbengine_statistics_charts(void) {
865
866
{
867
static RRDSET *st_long_term_pages = NULL;
868
- static RRDDIM *rd_memory = NULL;
868
static RRDDIM *rd_total = NULL;
869
static RRDDIM *rd_insertions = NULL;
870
static RRDDIM *rd_deletions = NULL;
@@ -886,7 +885,6 @@ static void dbengine_statistics_charts(void) {
885
localhost->rrd_update_every,
886
RRDSET_TYPE_LINE);
887
889
- rd_memory = rrddim_add(st_long_term_pages, "journal v2 descriptors", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
888
rd_total = rrddim_add(st_long_term_pages, "total", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
889
rd_insertions = rrddim_add(st_long_term_pages, "insertions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
890
rd_deletions = rrddim_add(st_long_term_pages, "deletions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
@@ -895,7 +893,6 @@ static void dbengine_statistics_charts(void) {
893
} else
894
rrdset_next(st_long_term_pages);
895
898
- rrddim_set_by_pointer(st_long_term_pages, rd_memory, (collected_number)stats_array[37]);
896
rrddim_set_by_pointer(st_long_term_pages, rd_total, (collected_number)stats_array[2]);
897
rrddim_set_by_pointer(st_long_term_pages, rd_insertions, (collected_number)stats_array[5]);
898
rrddim_set_by_pointer(st_long_term_pages, rd_deletions, (collected_number)stats_array[6]);
daemon/main.c
-3
@@ -680,9 +680,6 @@ static void get_netdata_configured_variables() {
680
681
db_engine_use_malloc = config_get_boolean(CONFIG_SECTION_DB, "dbengine page cache with malloc", CONFIG_BOOLEAN_NO);
682
default_rrdeng_page_cache_mb = (int) config_get_number(CONFIG_SECTION_DB, "dbengine page cache size MB", default_rrdeng_page_cache_mb);
683
- db_engine_journal_indexing = config_get_boolean(CONFIG_SECTION_DB, "dbengine enable journal indexing", CONFIG_BOOLEAN_YES);
684
- db_engine_journal_check = config_get_boolean(CONFIG_SECTION_DB, "dbengine enable journal integrity check", CONFIG_BOOLEAN_NO);
685
-
683
if(default_rrdeng_page_cache_mb < RRDENG_MIN_PAGE_CACHE_SIZE_MB) {
684
error("Invalid page cache size %d given. Defaulting to %d.", default_rrdeng_page_cache_mb, RRDENG_MIN_PAGE_CACHE_SIZE_MB);
685
default_rrdeng_page_cache_mb = RRDENG_MIN_PAGE_CACHE_SIZE_MB;
database/engine/datafile.c
+7
-34
@@ -1,29 +1,9 @@
1
// SPDX-License-Identifier: GPL-3.0-or-later
2
#include "rrdengine.h"
3
4
-void df_extent_delete_all_unsafe(struct rrdengine_datafile *datafile)
5
-{
6
- struct extent_info *extent = datafile->extents.first, *next_extent;
7
-
8
- char path[RRDENG_PATH_MAX];
9
-
10
- generate_journalfilepath_v2(datafile, path, sizeof(path));
11
- internal_error(true, "Deleting extents of file %s", path);
12
- unsigned count = 0;
13
- while (extent) {
14
- next_extent = extent->next;
15
- freez(extent);
16
- count++;
17
- extent = next_extent;
18
- }
19
- datafile->extents.first = NULL;
20
- internal_error(true, "Deleted %u extents of file %s", count, path);
21
-}
22
-
4
void df_extent_insert(struct extent_info *extent)
5
{
6
struct rrdengine_datafile *datafile = extent->datafile;
26
- uv_rwlock_wrlock(&datafile->extent_rwlock);
7
8
if (likely(NULL != datafile->extents.last)) {
9
datafile->extents.last->next = extent;
@@ -32,14 +12,10 @@ void df_extent_insert(struct extent_info *extent)
12
datafile->extents.first = extent;
13
}
14
datafile->extents.last = extent;
35
-
36
- uv_rwlock_wrunlock(&datafile->extent_rwlock);
15
}
16
17
void datafile_list_insert(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile)
18
{
41
- uv_rwlock_wrlock(&ctx->datafiles.rwlock);
42
-
19
if (likely(NULL != ctx->datafiles.last)) {
20
ctx->datafiles.last->next = datafile;
21
}
@@ -47,13 +23,12 @@ void datafile_list_insert(struct rrdengine_instance *ctx, struct rrdengine_dataf
23
ctx->datafiles.first = datafile;
24
}
25
ctx->datafiles.last = datafile;
50
-
51
- uv_rwlock_wrunlock(&ctx->datafiles.rwlock);
26
}
27
54
-void datafile_list_delete_unsafe(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile)
28
+void datafile_list_delete(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile)
29
{
30
struct rrdengine_datafile *next;
31
+
32
next = datafile->next;
33
fatal_assert((NULL != next) && (ctx->datafiles.first == datafile) && (ctx->datafiles.last != datafile));
34
ctx->datafiles.first = next;
@@ -69,7 +44,6 @@ static void datafile_init(struct rrdengine_datafile *datafile, struct rrdengine_
44
datafile->file = (uv_file)0;
45
datafile->pos = 0;
46
datafile->extents.first = datafile->extents.last = NULL; /* will be populated by journalfile */
72
- fatal_assert(0 == uv_rwlock_init(&datafile->extent_rwlock));
47
datafile->journalfile = NULL;
48
datafile->next = NULL;
49
datafile->ctx = ctx;
@@ -123,7 +97,7 @@ int unlink_data_file(struct rrdengine_datafile *datafile)
97
return ret;
98
}
99
126
-int destroy_data_file_unsafe(struct rrdengine_datafile *datafile)
100
+int destroy_data_file(struct rrdengine_datafile *datafile)
101
{
102
struct rrdengine_instance *ctx = datafile->ctx;
103
uv_fs_t req;
@@ -202,7 +176,7 @@ int create_data_file(struct rrdengine_datafile *datafile)
176
uv_fs_req_cleanup(&req);
177
posix_memfree(superblock);
178
if (ret < 0) {
205
- destroy_data_file_unsafe(datafile);
179
+ destroy_data_file(datafile);
180
return ret;
181
}
182
@@ -330,8 +304,10 @@ static int scan_data_files(struct rrdengine_instance *ctx)
304
305
datafiles = callocz(MIN(ret, MAX_DATAFILES), sizeof(*datafiles));
306
for (matched_files = 0 ; UV_EOF != uv_fs_scandir_next(&req, &dent) && matched_files < MAX_DATAFILES ; ) {
307
+ info("Scanning file \"%s/%s\"", ctx->dbfiles_path, dent.name);
308
ret = sscanf(dent.name, DATAFILE_PREFIX RRDENG_FILE_NUMBER_SCAN_TMPL DATAFILE_EXTENSION, &tier, &no);
309
if (2 == ret) {
310
+ info("Matched file \"%s/%s\"", ctx->dbfiles_path, dent.name);
311
datafile = mallocz(sizeof(*datafile));
312
datafile_init(datafile, ctx, tier, no);
313
datafiles[matched_files++] = datafile;
@@ -361,7 +337,6 @@ static int scan_data_files(struct rrdengine_instance *ctx)
337
journalfile = mallocz(sizeof(*journalfile));
338
datafile->journalfile = journalfile;
339
journalfile_init(journalfile, datafile);
364
- journalfile->file_index = i;
340
ret = load_journal_file(ctx, journalfile, datafile);
341
if (0 != ret) {
342
if (!must_delete_pair) /* If datafile is still open close it */
@@ -371,7 +346,6 @@ static int scan_data_files(struct rrdengine_instance *ctx)
346
if (must_delete_pair) {
347
char path[RRDENG_PATH_MAX];
348
374
- // TODO: Also delete the version 2
349
error("Deleting invalid data and journal file pair.");
350
ret = unlink_journal_file(journalfile);
351
if (!ret) {
@@ -433,7 +407,7 @@ int create_new_datafile_pair(struct rrdengine_instance *ctx, unsigned tier, unsi
407
return 0;
408
409
error_after_journalfile:
436
- destroy_data_file_unsafe(datafile);
410
+ destroy_data_file(datafile);
411
freez(journalfile);
412
error_after_datafile:
413
freez(datafile);
@@ -447,7 +421,6 @@ int init_data_files(struct rrdengine_instance *ctx)
421
{
422
int ret;
423
450
- fatal_assert(0 == uv_rwlock_init(&ctx->datafiles.rwlock));
424
ret = scan_data_files(ctx);
425
if (ret < 0) {
426
error("Failed to scan path \"%s\".", ctx->dbfiles_path);
database/engine/datafile.h
+2
-12
@@ -13,13 +13,7 @@ struct rrdengine_instance;
13
#define DATAFILE_PREFIX "datafile-"
14
#define DATAFILE_EXTENSION ".ndf"
15
16
-#ifndef MAX_DATAFILE_SIZE
16
#define MAX_DATAFILE_SIZE (1073741824LU)
18
-#endif
19
-#if MIN_DATAFILE_SIZE > MAX_DATAFILE_SIZE
20
-#error MIN_DATAFILE_SIZE > MAX_DATAFILE_SIZE
21
-#endif
22
-
17
#define MIN_DATAFILE_SIZE (4194304LU)
18
#define MAX_DATAFILES (65536) /* Supports up to 64TiB for now */
19
#define TARGET_DATAFILES (20)
@@ -32,7 +26,6 @@ struct extent_info {
26
uint8_t number_of_pages;
27
struct rrdengine_datafile *datafile;
28
struct extent_info *next;
35
- uint32_t index; // This is the entent index for version 2
29
struct rrdeng_page_descr *pages[];
30
};
31
@@ -48,7 +41,6 @@ struct rrdengine_datafile {
41
unsigned fileno;
42
uv_file file;
43
uint64_t pos;
51
- uv_rwlock_t extent_rwlock;
44
struct rrdengine_instance *ctx;
45
struct rrdengine_df_extents extents;
46
struct rrdengine_journalfile *journalfile;
@@ -56,22 +48,20 @@ struct rrdengine_datafile {
48
};
49
50
struct rrdengine_datafile_list {
59
- uv_rwlock_t rwlock;
51
struct rrdengine_datafile *first; /* oldest */
52
struct rrdengine_datafile *last; /* newest */
53
};
54
55
void df_extent_insert(struct extent_info *extent);
56
void datafile_list_insert(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile);
66
-void datafile_list_delete_unsafe(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile);
57
+void datafile_list_delete(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile);
58
void generate_datafilepath(struct rrdengine_datafile *datafile, char *str, size_t maxlen);
59
int close_data_file(struct rrdengine_datafile *datafile);
60
int unlink_data_file(struct rrdengine_datafile *datafile);
70
-int destroy_data_file_unsafe(struct rrdengine_datafile *datafile);
61
+int destroy_data_file(struct rrdengine_datafile *datafile);
62
int create_data_file(struct rrdengine_datafile *datafile);
63
int create_new_datafile_pair(struct rrdengine_instance *ctx, unsigned tier, unsigned fileno);
64
int init_data_files(struct rrdengine_instance *ctx);
65
void finalize_data_files(struct rrdengine_instance *ctx);
75
-void df_extent_delete_all_unsafe(struct rrdengine_datafile *datafile);
66
67
#endif /* NETDATA_DATAFILE_H */
\ No newline at end of file
database/engine/journalfile.c
+34
-1092
@@ -1,25 +1,6 @@
1
// SPDX-License-Identifier: GPL-3.0-or-later
2
#include "rrdengine.h"
3
4
-void queue_journalfile_v2_migration(struct rrdengine_worker_config *wc)
5
-{
6
- struct rrdeng_work *work_request;
7
-
8
- if (unlikely(wc->running_journal_migration))
9
- return;
10
-
11
- work_request = mallocz(sizeof(*work_request));
12
- work_request->req.data = work_request;
13
- work_request->wc = wc;
14
- work_request->count = 0;
15
- work_request->rerun = false;
16
- wc->running_journal_migration = 1;
17
- if (unlikely(uv_queue_work(wc->loop, &work_request->req, start_journal_indexing, after_journal_indexing))) {
18
- freez(work_request);
19
- wc->running_journal_migration = 0;
20
- }
21
-}
22
-
4
static void flush_transaction_buffer_cb(uv_fs_t* req)
5
{
6
struct generic_io_descriptor *io_descr = req->data;
@@ -66,7 +47,6 @@ void wal_flush_transaction_buffer(struct rrdengine_worker_config* wc)
47
io_descr->bytes = size;
48
io_descr->pos = journalfile->pos;
49
io_descr->req.data = io_descr;
69
- io_descr->data = journalfile;
50
io_descr->completion = NULL;
51
52
io_descr->iov = uv_buf_init((void *)io_descr->buf, size);
@@ -113,12 +93,6 @@ void * wal_get_transaction_buffer(struct rrdengine_worker_config* wc, unsigned s
93
return ctx->commit_log.buf + buf_pos;
94
}
95
116
-void generate_journalfilepath_v2(struct rrdengine_datafile *datafile, char *str, size_t maxlen)
117
-{
118
- (void) snprintfz(str, maxlen, "%s/" WALFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL WALFILE_EXTENSION_V2,
119
- datafile->ctx->dbfiles_path, datafile->tier, datafile->fileno);
120
-}
121
-
96
void generate_journalfilepath(struct rrdengine_datafile *datafile, char *str, size_t maxlen)
97
{
98
(void) snprintfz(str, maxlen, "%s/" WALFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL WALFILE_EXTENSION,
@@ -130,49 +104,26 @@ void journalfile_init(struct rrdengine_journalfile *journalfile, struct rrdengin
104
journalfile->file = (uv_file)0;
105
journalfile->pos = 0;
106
journalfile->datafile = datafile;
133
- journalfile->journal_data = NULL;
134
- journalfile->journal_data_size = 0;
135
- journalfile->JudyL_array = (Pvoid_t) NULL;
136
- journalfile->data = NULL;
137
- journalfile->file_index = 0;
138
- journalfile->last_access = 0;
107
}
108
141
-static int close_uv_file(struct rrdengine_datafile *datafile, uv_file file)
109
+int close_journal_file(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
110
{
111
+ struct rrdengine_instance *ctx = datafile->ctx;
112
+ uv_fs_t req;
113
int ret;
114
char path[RRDENG_PATH_MAX];
115
146
- uv_fs_t req;
147
- ret = uv_fs_close(NULL, &req, file, NULL);
116
+ generate_journalfilepath(datafile, path, sizeof(path));
117
+
118
+ ret = uv_fs_close(NULL, &req, journalfile->file, NULL);
119
if (ret < 0) {
149
- generate_journalfilepath(datafile, path, sizeof(path));
120
error("uv_fs_close(%s): %s", path, uv_strerror(ret));
151
- ++datafile->ctx->stats.fs_errors;
121
+ ++ctx->stats.fs_errors;
122
rrd_stat_atomic_add(&global_fs_errors, 1);
123
}
124
uv_fs_req_cleanup(&req);
155
- return ret;
156
-}
157
-
158
-int close_journal_file(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
159
-{
160
- struct rrdengine_instance *ctx = datafile->ctx;
161
- char path[RRDENG_PATH_MAX];
162
-
163
- if (likely(journalfile->journal_data)) {
164
- if (munmap(journalfile->journal_data, journalfile->journal_data_size)) {
165
- generate_journalfilepath_v2(datafile, path, sizeof(path));
166
- error("Failed to unmap journal index file for %s", path);
167
- ++ctx->stats.fs_errors;
168
- rrd_stat_atomic_add(&global_fs_errors, 1);
169
- }
170
- journalfile->journal_data = NULL;
171
- journalfile->journal_data_size = 0;
172
- return 0;
173
- }
125
175
- return close_uv_file(datafile, journalfile->file);
126
+ return ret;
127
}
128
129
int unlink_journal_file(struct rrdengine_journalfile *journalfile)
@@ -198,16 +149,14 @@ int unlink_journal_file(struct rrdengine_journalfile *journalfile)
149
return ret;
150
}
151
201
-int destroy_journal_file_unsafe(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
152
+int destroy_journal_file(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
153
{
154
struct rrdengine_instance *ctx = datafile->ctx;
155
uv_fs_t req;
156
int ret;
157
char path[RRDENG_PATH_MAX];
207
- char path_v2[RRDENG_PATH_MAX];
158
159
generate_journalfilepath(datafile, path, sizeof(path));
210
- generate_journalfilepath_v2(datafile, path_v2, sizeof(path));
160
161
ret = uv_fs_ftruncate(NULL, &req, journalfile->file, 0, NULL);
162
if (ret < 0) {
@@ -217,12 +166,9 @@ int destroy_journal_file_unsafe(struct rrdengine_journalfile *journalfile, struc
166
}
167
uv_fs_req_cleanup(&req);
168
220
- (void) close_uv_file(datafile, journalfile->file);
221
-
222
- // This is the new journal v2 index file
223
- ret = uv_fs_unlink(NULL, &req, path_v2, NULL);
169
+ ret = uv_fs_close(NULL, &req, journalfile->file, NULL);
170
if (ret < 0) {
225
- error("uv_fs_fsunlink(%s): %s", path, uv_strerror(ret));
171
+ error("uv_fs_close(%s): %s", path, uv_strerror(ret));
172
++ctx->stats.fs_errors;
173
rrd_stat_atomic_add(&global_fs_errors, 1);
174
}
@@ -236,15 +182,8 @@ int destroy_journal_file_unsafe(struct rrdengine_journalfile *journalfile, struc
182
}
183
uv_fs_req_cleanup(&req);
184
239
- ++ctx->stats.journalfile_deletions;
185
++ctx->stats.journalfile_deletions;
186
242
- if (journalfile->journal_data) {
243
- if (munmap(journalfile->journal_data, journalfile->journal_data_size)) {
244
- error("Failed to unmap index file %s", path_v2);
245
- }
246
- }
247
-
187
return ret;
188
}
189
@@ -288,7 +227,7 @@ int create_journal_file(struct rrdengine_journalfile *journalfile, struct rrdeng
227
uv_fs_req_cleanup(&req);
228
posix_memfree(superblock);
229
if (ret < 0) {
291
- destroy_journal_file_unsafe(journalfile, datafile);
230
+ destroy_journal_file(journalfile, datafile);
231
return ret;
232
}
233
@@ -427,67 +366,36 @@ static void restore_extent_metadata(struct rrdengine_instance *ctx, struct rrden
366
uv_rwlock_wrlock(&pg_cache->metrics_index.lock);
367
PValue = JudyHSIns(&pg_cache->metrics_index.JudyHS_array, temp_id, sizeof(uuid_t), PJE0);
368
fatal_assert(NULL == *PValue); /* TODO: figure out concurrency model */
430
- *PValue = page_index = create_page_index(temp_id, ctx);
431
- page_index->prev = pg_cache->metrics_index.last_page_index;
432
- pg_cache->metrics_index.last_page_index = page_index;
369
+ *PValue = page_index = create_page_index(temp_id, ctx);
370
+ page_index->prev = pg_cache->metrics_index.last_page_index;
371
+ pg_cache->metrics_index.last_page_index = page_index;
372
uv_rwlock_wrunlock(&pg_cache->metrics_index.lock);
373
}
374
436
- // Lookup this descriptor
437
- Word_t p_time = start_time_ut / USEC_PER_SEC;
438
- uv_rwlock_rdlock(&page_index->lock);
439
- PValue = JudyLFirst(page_index->JudyL_array, &p_time, PJE0);
440
- descr = (NULL == PValue) ? NULL: *PValue;
441
- uv_rwlock_rdunlock(&page_index->lock);
442
-
443
- bool descr_found = false;
444
- if (unlikely(descr && descr->start_time_ut == start_time_ut)) {
445
- // We have this descriptor already
446
- descr_found = true;
447
-
448
-#ifdef NETDATA_INTERNAL_CHECKS
449
- char uuid_str[UUID_STR_LEN];
450
- uuid_unparse_lower(page_index->id, uuid_str);
451
- internal_error(true, "REMOVING UUID %s with %lu, %lu length=%u (fileno=%u), extent database offset = %lu, size = %u",
452
- uuid_str, start_time_ut, end_time_ut, jf_metric_data->descr[i].page_length, descr->extent->datafile->fileno,
453
- descr->extent->offset, descr->extent->size);
454
- internal_error(true, "APPLYING UUID %s with %lu, %lu length=%u (fileno=%u), extent database offset = %lu, size = %u",
455
- uuid_str, start_time_ut, end_time_ut, jf_metric_data->descr[i].page_length, extent->datafile->fileno,
456
- extent->offset, extent->size);
457
-#endif
458
- // Remove entry from previous extent
459
- unlink_descriptor_extent_unsafe(descr);
460
- internal_error(true, "REMOVING UUID %s with %lu OK", uuid_str, start_time_ut);
461
- }
462
- else {
463
- descr = pg_cache_create_descr();
464
- descr->id = &page_index->id;
465
- }
466
-
375
+ descr = pg_cache_create_descr();
376
descr->page_length = jf_metric_data->descr[i].page_length;
377
descr->start_time_ut = start_time_ut;
378
descr->end_time_ut = end_time_ut;
379
descr->update_every_s = (update_every_s > 0) ? (uint32_t)update_every_s : (page_index->latest_update_every_s);
471
-
380
+ descr->id = &page_index->id;
381
descr->extent = extent;
382
descr->type = page_type;
383
extent->pages[valid_pages++] = descr;
475
- if (likely(!descr_found))
476
- (void)pg_cache_insert(ctx, page_index, descr, true);
384
+ pg_cache_insert(ctx, page_index, descr);
385
478
- if (page_index->latest_time_ut == descr->end_time_ut)
386
+ if(page_index->latest_time_ut == descr->end_time_ut)
387
page_index->latest_update_every_s = descr->update_every_s;
388
389
if(descr->update_every_s == 0)
482
- fatal("DBENGINE: page descriptor update every is zero, end_time_ut = %llu, start_time_ut = %llu, entries = %zu",
390
+ fatal(
391
+ "DBENGINE: page descriptor update every is zero, end_time_ut = %llu, start_time_ut = %llu, entries = %zu",
392
(unsigned long long)end_time_ut, (unsigned long long)start_time_ut, entries);
393
}
394
395
extent->number_of_pages = valid_pages;
396
488
- if (likely(valid_pages)) {
397
+ if (likely(valid_pages))
398
df_extent_insert(extent);
490
- }
399
else {
400
freez(extent);
401
ctx->load_errors[LOAD_ERRORS_DROPPED_EXTENT].counter++;
@@ -536,13 +444,13 @@ static unsigned replay_transaction(struct rrdengine_instance *ctx, struct rrdeng
444
return size_bytes;
445
}
446
switch (jf_header->type) {
539
- case STORE_DATA:
540
- debug(D_RRDENGINE, "Replaying transaction %"PRIu64"", jf_header->id);
541
- restore_extent_metadata(ctx, journalfile, buf + sizeof(*jf_header), payload_length);
542
- break;
543
- default:
544
- error("Unknown transaction type. Skipping record.");
545
- break;
447
+ case STORE_DATA:
448
+ debug(D_RRDENGINE, "Replaying transaction %"PRIu64"", jf_header->id);
449
+ restore_extent_metadata(ctx, journalfile, buf + sizeof(*jf_header), payload_length);
450
+ break;
451
+ default:
452
+ error("Unknown transaction type. Skipping record.");
453
+ break;
454
}
455
456
return size_bytes;
@@ -610,905 +518,12 @@ static uint64_t iterate_transactions(struct rrdengine_instance *ctx, struct rrde
518
if (likely(journal_is_mmapped))
519
buf += size_bytes;
520
}
613
- skip_file:
521
+skip_file:
522
if (unlikely(!journal_is_mmapped))
523
posix_memfree(buf);
524
return max_id;
525
}
526
619
-bool unlink_descriptor_extent_unsafe(struct rrdeng_page_descr *descr)
620
-{
621
- if (unlikely(!descr || !descr->extent))
622
- return true;
623
-
624
- struct extent_info *extent = descr->extent;
625
- for (uint8_t index = 0; index < extent->number_of_pages; index++) {
626
- if (extent->pages[index] == descr) {
627
- extent->pages[index] = NULL;
628
- return true;
629
- }
630
- }
631
- return false;
632
-}
633
-
634
-// Checks that the extent list checksum is valid
635
-static int check_journal_v2_extent_list (void *data_start, size_t file_size)
636
-{
637
- UNUSED(file_size);
638
- uLong crc;
639
-
640
- struct journal_v2_header *j2_header = (void *) data_start;
641
- struct journal_v2_block_trailer *journal_v2_trailer;
642
-
643
- journal_v2_trailer = (struct journal_v2_block_trailer *) ((uint8_t *) data_start + j2_header->extent_trailer_offset);
644
- crc = crc32(0L, Z_NULL, 0);
645
- crc = crc32(crc, (uint8_t *) data_start + j2_header->extent_offset, j2_header->extent_count * sizeof(struct journal_extent_list));
646
- if (unlikely(crc32cmp(journal_v2_trailer->checksum, crc))) {
647
- error("Extent list CRC32 check: FAILED");
648
- return 1;
649
- }
650
-
651
- return 0;
652
-}
653
-
654
-// Checks that the metric list (UUIDs) checksum is valid
655
-static int check_journal_v2_metric_list(void *data_start, size_t file_size)
656
-{
657
- UNUSED(file_size);
658
- uLong crc;
659
-
660
- struct journal_v2_header *j2_header = (void *) data_start;
661
- struct journal_v2_block_trailer *journal_v2_trailer;
662
-
663
- journal_v2_trailer = (struct journal_v2_block_trailer *) ((uint8_t *) data_start + j2_header->metric_trailer_offset);
664
- crc = crc32(0L, Z_NULL, 0);
665
- crc = crc32(crc, (uint8_t *) data_start + j2_header->metric_offset, j2_header->metric_count * sizeof(struct journal_metric_list));
666
- if (unlikely(crc32cmp(journal_v2_trailer->checksum, crc))) {
667
- error("Metric list CRC32 check: FAILED");
668
- return 1;
669
- }
670
- return 0;
671
-}
672
-
673
-static int check_journal_v2_file(void *data_start, size_t file_size, uint32_t original_size)
674
-{
675
- int rc;
676
- uLong crc;
677
-
678
- struct journal_v2_header *j2_header = (void *) data_start;
679
- struct journal_v2_block_trailer *journal_v2_trailer;
680
-
681
- if (j2_header->magic == JOURVAL_V2_REBUILD_MAGIC)
682
- return 2;
683
-
684
- // Magic failure
685
- if (j2_header->magic != JOURVAL_V2_MAGIC)
686
- return 1;
687
-
688
- if (j2_header->total_file_size != file_size)
689
- return 1;
690
-
691
- if (original_size && j2_header->original_file_size != original_size)
692
- return 1;
693
-
694
- journal_v2_trailer = (struct journal_v2_block_trailer *) ((uint8_t *) data_start + file_size - sizeof(*journal_v2_trailer));
695
-
696
- crc = crc32(0L, Z_NULL, 0);
697
- crc = crc32(crc, (void *) j2_header, sizeof(*j2_header));
698
-
699
- rc = crc32cmp(journal_v2_trailer->checksum, crc);
700
- if (unlikely(rc)) {
701
- error("File CRC32 check: FAILED");
702
- return 1;
703
- }
704
-
705
- rc = check_journal_v2_extent_list(data_start, file_size);
706
- if (rc) return 1;
707
-
708
- rc = check_journal_v2_metric_list(data_start, file_size);
709
- if (rc) return 1;
710
-
711
- if (!db_engine_journal_check)
712
- return 0;
713
-
714
- // Verify complete UUID chain
715
-
716
- struct journal_metric_list *metric = (void *) (data_start + j2_header->metric_offset);
717
-
718
- unsigned verified = 0;
719
- unsigned entries;
720
- unsigned total_pages = 0;
721
-
722
- info("Checking %u metrics that exist in the journal", j2_header->metric_count);
723
- for (entries = 0; entries < j2_header->metric_count; entries++) {
724
-
725
- char uuid_str[UUID_STR_LEN];
726
- uuid_unparse_lower(metric->uuid, uuid_str);
727
- struct journal_page_header *metric_list_header = (void *) (data_start + metric->page_offset);
728
- struct journal_page_header local_metric_list_header = *metric_list_header;
729
-
730
- local_metric_list_header.crc = JOURVAL_V2_MAGIC;
731
-
732
- crc = crc32(0L, Z_NULL, 0);
733
- crc = crc32(crc, (void *) &local_metric_list_header, sizeof(local_metric_list_header));
734
- rc = crc32cmp(metric_list_header->checksum, crc);
735
-
736
- internal_error(true, "Index %u : %s entries %u at offset %u (%llu -- %llu) verified, HEADER CRC computed %lu, stored %u", entries, uuid_str, metric->entries, metric->page_offset,
737
- j2_header->start_time_ut + (usec_t) metric->delta_start * USEC_PER_SEC, j2_header->start_time_ut + (usec_t) metric->delta_end * USEC_PER_SEC,
738
- crc, metric_list_header->crc);
739
- if (!rc) {
740
- struct journal_v2_block_trailer *journal_trailer =
741
- (void *) data_start + metric->page_offset + sizeof(struct journal_page_header) + (metric_list_header->entries * sizeof(struct journal_page_list));
742
-
743
- crc = crc32(0L, Z_NULL, 0);
744
- crc = crc32(crc, (uint8_t *) metric_list_header + sizeof(struct journal_page_header), metric_list_header->entries * sizeof(struct journal_page_list));
745
- rc = crc32cmp(journal_trailer->checksum, crc);
746
- internal_error(rc, "Index %u : %s entries %u at offset %u verified, DATA CRC computed %lu, stored %u", entries, uuid_str, metric->entries, metric->page_offset,
747
- crc, metric_list_header->crc);
748
- if (!rc) {
749
- total_pages += metric_list_header->entries;
750
- verified++;
751
- }
752
- }
753
-
754
- metric++;
755
- if (((uint8_t *) metric - (uint8_t *) data_start) > (uint32_t) file_size) {
756
- info("Verification failed EOF reached -- total entries %u, verified %u", entries, verified);
757
- return 1;
758
- }
759
- }
760
-
761
- if (entries != verified) {
762
- info("Verification failed -- total entries %u, verified %u", entries, verified);
763
- return 1;
764
- }
765
- info("Verification succeeded -- total entries %u, verified %u (%u total pages)", entries, verified, total_pages);
766
-
767
- return 0;
768
-}
769
-
770
-int load_journal_file_v2(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
771
-{
772
- struct page_cache *pg_cache = &ctx->pg_cache;
773
- struct pg_cache_page_index *page_index;
774
- int ret, fd;
775
- uint64_t file_size;
776
- char path[RRDENG_PATH_MAX];
777
- struct stat statbuf;
778
- uint32_t original_file_size = 0;
779
-
780
- generate_journalfilepath(datafile, path, sizeof(path));
781
- ret = stat(path, &statbuf);
782
- if (!ret)
783
- original_file_size = (uint32_t)statbuf.st_size;
784
-
785
- generate_journalfilepath_v2(datafile, path, sizeof(path));
786
-
787
- fd = open(path, O_RDONLY);
788
- if (fd < 0) {
789
- if (errno == ENOENT)
790
- return 1;
791
- ++ctx->stats.fs_errors;
792
- rrd_stat_atomic_add(&global_fs_errors, 1);
793
- error("Failed to open %s", path);
794
- return 1;
795
- }
796
-
797
- ret = fstat(fd, &statbuf);
798
- if (ret) {
799
- error("Failed to get file information for %s", path);
800
- close(fd);
801
- return 1;
802
- }
803
-
804
- file_size = (size_t)statbuf.st_size;
805
-
806
- if (file_size < sizeof(struct journal_v2_header)) {
807
- error_report("Invalid file %s. Not the expected size", path);
808
- close(fd);
809
- return 1;
810
- }
811
-
812
- usec_t start_loading = now_realtime_usec();
813
- uint8_t *data_start = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fd, 0);
814
- if (data_start == MAP_FAILED) {
815
- close(fd);
816
- return 1;
817
- }
818
- close(fd);
819
-
820
- info("Checking integrity of %s", path);
821
- int rc = check_journal_v2_file(data_start, file_size, original_file_size);
822
- if (rc) {
823
- if (rc == 2)
824
- error_report("File %s needs to be rebuilt", path);
825
- else
826
- error_report("File %s is invalid", path);
827
- if (unlikely(munmap(data_start, file_size)))
828
- error("Failed to unmap %s", path);
829
- return 1;
830
- }
831
-
832
- struct journal_v2_header *j2_header = (void *) data_start;
833
-
834
- size_t entries = j2_header->metric_count;
835
-
836
- if (!entries) {
837
- if (unlikely(munmap(data_start, file_size)))
838
- error("Failed to unmap %s", path);
839
- return 1;
840
- }
841
-
842
- rc = madvise(data_start, file_size, MADV_DONTFORK);
843
- if (rc)
844
- error("MADV_DONTFORK: setting failed");
845
-
846
- rc = madvise(data_start, file_size, MADV_DONTDUMP);
847
- if (rc)
848
- error("MADV_DONTDUMP: setting failed");
849
-
850
- struct journal_metric_list *metric = (struct journal_metric_list *) (data_start + j2_header->metric_offset);
851
-
852
- uv_rwlock_wrlock(&pg_cache->metrics_index.lock);
853
-
854
- // Initialize the journal file to be able to access the data
855
- journalfile->journal_data = data_start;
856
- journalfile->journal_data_size = file_size;
857
-
858
- usec_t header_start_time = j2_header->start_time_ut;
859
- for (size_t i=0; i < entries; i++) {
860
- Pvoid_t *PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, metric->uuid, sizeof(uuid_t));
861
- if (likely(NULL != PValue)) {
862
- page_index = *PValue;
863
- }
864
- else {
865
- PValue = JudyHSIns(&pg_cache->metrics_index.JudyHS_array, metric->uuid, sizeof(uuid_t), PJE0);
866
- fatal_assert(NULL == *PValue);
867
- *PValue = page_index = create_page_index(&metric->uuid, ctx);
868
- page_index->oldest_time_ut = LLONG_MAX;
869
- page_index->latest_time_ut = 0;
870
- page_index->prev = pg_cache->metrics_index.last_page_index;
871
- pg_cache->metrics_index.last_page_index = page_index;
872
- }
873
-
874
- usec_t metric_start_ut = header_start_time + (usec_t ) metric->delta_start * USEC_PER_SEC;
875
- usec_t metric_end_ut = header_start_time + (usec_t ) metric->delta_end * USEC_PER_SEC;
876
-
877
- if (page_index->oldest_time_ut > metric_start_ut)
878
- page_index->oldest_time_ut = metric_start_ut;
879
-
880
- if (page_index->latest_time_ut < metric_end_ut)
881
- page_index->latest_time_ut = metric_end_ut;
882
-
883
- ++page_index->page_count;
884
- ++pg_cache->page_descriptors;
885
- metric++;
886
- }
887
-
888
- uv_rwlock_wrunlock(&pg_cache->metrics_index.lock);
889
-
890
- info("Journal file \"%s\" loaded (size:%"PRIu64") with %lu metrics in %d ms",
891
- path, file_size, entries,
892
- (int) ((now_realtime_usec() - start_loading) / USEC_PER_MS));
893
- return 0;
894
-}
895
-
896
-
897
-struct metric_info_s {
898
- uuid_t *id;
899
- struct pg_cache_page_index *page_index;
900
- uint32_t entries;
901
- time_t min_index_time_s;
902
- time_t max_index_time_s;
903
- usec_t min_time_ut;
904
- usec_t max_time_ut;
905
- uint32_t page_list_header;
906
- Pvoid_t JudyL_array;
907
-};
908
-
909
-struct journal_metric_list_to_sort {
910
- struct metric_info_s *metric_info;
911
-};
912
-
913
-static int journal_metric_compare (const void *item1, const void *item2)
914
-{
915
- const struct metric_info_s *metric1 = ((struct journal_metric_list_to_sort *) item1)->metric_info;
916
- const struct metric_info_s *metric2 = ((struct journal_metric_list_to_sort *) item2)->metric_info;
917
-
918
- return uuid_compare(*(metric1->id), *(metric2->id));
919
-}
920
-
921
-
922
-// Write list of extents for the journalfile
923
-void *journal_v2_write_extent_list(struct rrdengine_journalfile *journalfile, void *data)
924
-{
925
- struct extent_info *extent = journalfile->datafile->extents.first;
926
- struct journal_extent_list *j2_extent = (void *) data;
927
- while (extent) {
928
- j2_extent->datafile_offset = extent->offset;
929
- j2_extent->datafile_size = extent->size;
930
- j2_extent->pages = extent->number_of_pages;
931
- j2_extent->file_index = journalfile->file_index;
932
- j2_extent++;
933
- extent = extent->next;
934
- };
935
- return j2_extent;
936
-}
937
-
938
-static int verify_journal_space(struct journal_v2_header *j2_header, void *data, uint32_t bytes)
939
-{
940
- if ((unsigned long)(((uint8_t *) data - (uint8_t *) j2_header->data) + bytes) > (j2_header->total_file_size - sizeof(struct journal_v2_block_trailer)))
941
- return 1;
942
-
943
- return 0;
944
-}
945
-
946
-void *journal_v2_write_metric_page(struct journal_v2_header *j2_header, void *data, struct metric_info_s *metric_info, uint32_t pages_offset)
947
-{
948
- struct journal_metric_list *metric = (void *) data;
949
-
950
- if (verify_journal_space(j2_header, data, sizeof(*metric)))
951
- return NULL;
952
-
953
- uuid_copy(metric->uuid, *metric_info->id);
954
- metric->entries = metric_info->entries;
955
- metric->page_offset = pages_offset;
956
- metric->delta_start = (metric_info->min_time_ut - j2_header->start_time_ut) / USEC_PER_SEC;
957
- metric->delta_end = (metric_info->max_time_ut - j2_header->start_time_ut) / USEC_PER_SEC;
958
-
959
- return ++metric;
960
-}
961
-
962
-void *journal_v2_write_data_page_header(struct journal_v2_header *j2_header __maybe_unused, void *data, struct metric_info_s *metric_info, uint32_t uuid_offset)
963
-{
964
- struct journal_page_header *data_page_header = (void *) data;
965
- uLong crc;
966
-
967
- uuid_copy(data_page_header->uuid, *metric_info->id);
968
- data_page_header->entries = metric_info->entries;
969
- data_page_header->uuid_offset = uuid_offset; // data header OFFSET poings to METRIC in the directory
970
- data_page_header->crc = JOURVAL_V2_MAGIC;
971
- crc = crc32(0L, Z_NULL, 0);
972
- crc = crc32(crc, (void *) data_page_header, sizeof(*data_page_header));
973
- crc32set(data_page_header->checksum, crc);
974
- return ++data_page_header;
975
-}
976
-
977
-void *journal_v2_write_data_page_trailer(struct journal_v2_header *j2_header __maybe_unused, void *data, void *page_header)
978
-{
979
- struct journal_page_header *data_page_header = (void *) page_header;
980
- struct journal_v2_block_trailer *journal_trailer = (void *) data;
981
- uLong crc;
982
-
983
- crc = crc32(0L, Z_NULL, 0);
984
- crc = crc32(crc, (uint8_t *) page_header + sizeof(struct journal_page_header), data_page_header->entries * sizeof(struct journal_page_list));
985
- crc32set(journal_trailer->checksum, crc);
986
- return ++journal_trailer;
987
-}
988
-
989
-void *journal_v2_write_data_page(struct journal_v2_header *j2_header, void *data, struct rrdeng_page_descr *descr)
990
-{
991
- if (unlikely(!descr))
992
- return data;
993
-
994
- struct journal_page_list *data_page = data;
995
-
996
- // verify that we can write number of bytes
997
- if (verify_journal_space(j2_header, data, sizeof(*data_page)))
998
- return NULL;
999
-
1000
- fatal_assert(descr->extent != NULL);
1001
-
1002
- uint32_t extent_index = unlikely(NULL == descr->extent) ? UINT32_MAX : descr->extent->index;
1003
-
1004
- data_page->delta_start_s = (descr->start_time_ut - j2_header->start_time_ut) / USEC_PER_SEC;
1005
- data_page->delta_end_s = (descr->end_time_ut - j2_header->start_time_ut) / USEC_PER_SEC;
1006
- data_page->extent_index = extent_index;
1007
- data_page->update_every_s = (uint16_t) descr->update_every_s;
1008
- data_page->page_length = descr->page_length;
1009
- data_page->type = descr->type;
1010
-
1011
- // Rebuild on start to resolve unknown entry
1012
- if (unlikely(UINT32_MAX == extent_index))
1013
- j2_header->magic = JOURVAL_V2_REBUILD_MAGIC;
1014
-
1015
- return ++data_page;
1016
-}
1017
-
1018
-// For a page_index write all descr @ time entries
1019
-// Must be recorded in metric_info->entries
1020
-void *journal_v2_write_descriptors(struct journal_v2_header *j2_header, void *data, struct metric_info_s *metric_info, struct rrdengine_journalfile *journalfile)
1021
-{
1022
- struct rrdeng_page_descr *descr;
1023
- Pvoid_t *PValue;
1024
-
1025
- struct journal_page_list *data_page = (void *)data;
1026
- struct page_cache *pg_cache = &journalfile->datafile->ctx->pg_cache;
1027
- struct pg_cache_page_index *page_index;
1028
-
1029
- uv_rwlock_rdlock(&pg_cache->metrics_index.lock);
1030
- PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, metric_info->id, sizeof(uuid_t));
1031
- page_index = (NULL == PValue) ? NULL : *PValue;
1032
- uv_rwlock_rdunlock(&pg_cache->metrics_index.lock);
1033
-
1034
- if (page_index == NULL)
1035
- return data_page;
1036
-
1037
- // We need to write all descriptors with index metric_info->min_index_time_s, metric_info->max_index_time_s
1038
- // that belong to this journal file
1039
-
1040
- Word_t index_time = metric_info->min_index_time_s;
1041
- unsigned entries = 0;
1042
-
1043
- uv_rwlock_rdlock(&page_index->lock);
1044
-
1045
- Pvoid_t JudyL_array = metric_info->JudyL_array ? metric_info->JudyL_array : page_index->JudyL_array;
1046
-
1047
- // Need page_index lock if running live
1048
- for (PValue = JudyLFirst(JudyL_array, &index_time, PJE0),
1049
- descr = unlikely(NULL == PValue) ? NULL : *PValue;
1050
- descr != NULL;
1051
- PValue = JudyLNext(JudyL_array, &index_time, PJE0),
1052
- descr = unlikely(NULL == PValue) ? NULL : *PValue) {
1053
-
1054
- if (unlikely((time_t) index_time > metric_info->max_index_time_s) || entries == metric_info->entries)
1055
- break;
1056
-
1057
- // Write one descriptor and return the next data page location
1058
- data_page = journal_v2_write_data_page(j2_header, (void *)data_page, descr);
1059
-
1060
- entries++;
1061
- if (unlikely(!data_page))
1062
- break;
1063
- }
1064
-
1065
- uv_rwlock_rdunlock(&page_index->lock);
1066
- return data_page;
1067
-}
1068
-
1069
-static void journal_v2_remove_active_descriptors(struct rrdengine_journalfile *journalfile, struct metric_info_s *metric_info, bool startup)
1070
-{
1071
- if (true == startup) {
1072
- // This is during startup, so we are the only ones accessing the structures
1073
- // thats why we can safely remote the entire page_index->JudyL_array
1074
- struct rrdeng_page_descr *descr;
1075
- Word_t index_time;
1076
- Pvoid_t *PValue;
1077
- struct pg_cache_page_index *page_index;
1078
-
1079
- page_index = metric_info->page_index;
1080
-
1081
- for (index_time = 0, PValue = JudyLFirst(page_index->JudyL_array, &index_time, PJE0),
1082
- descr = unlikely(NULL == PValue) ? NULL : *PValue; descr != NULL;
1083
- PValue = JudyLNext(page_index->JudyL_array, &index_time, PJE0),
1084
- descr = unlikely(NULL == PValue) ? NULL : *PValue) {
1085
-
1086
- rrdeng_page_descr_freez(descr);
1087
- }
1088
- (void)JudyLFreeArray(&page_index->JudyL_array, PJE0);
1089
- }
1090
- else {
1091
- // This is during runtime
1092
- struct rrdeng_page_descr *descr;
1093
- Pvoid_t *PValue;
1094
- struct pg_cache_page_index *page_index = metric_info->page_index;
1095
- struct page_cache *pg_cache = &page_index->ctx->pg_cache;
1096
- struct rrdengine_instance *ctx = page_index->ctx;
1097
-
1098
- Word_t index_time = metric_info->min_index_time_s;
1099
- uint32_t metric_info_offset = metric_info->page_list_header;
1100
-
1101
- struct journal_page_header *page_list_header = (struct journal_page_header *) ((uint8_t *) journalfile->journal_data + metric_info_offset);
1102
- struct journal_v2_header *journal_header = (struct journal_v2_header *) journalfile->journal_data;
1103
- // Sanity check that we refer to the same UUID
1104
- fatal_assert(uuid_compare(page_list_header->uuid, *metric_info->id) == 0);
1105
-
1106
- struct journal_page_list *page_list = (struct journal_page_list *)((uint8_t *) page_list_header + sizeof(*page_list_header));
1107
- struct journal_extent_list *extent_list = (void *)((uint8_t *)journal_header + journal_header->extent_offset);
1108
-
1109
- uint32_t index = 0;
1110
- uint32_t entries = page_list_header->entries;
1111
-
1112
- uv_rwlock_rdlock(&page_index->lock);
1113
-
1114
- bool mark_journalfile_for_expiration_check = false;
1115
- for (PValue = JudyLFirst(metric_info->JudyL_array, &index_time, PJE0),
1116
- descr = unlikely(NULL == PValue) ? NULL : *PValue;
1117
- descr != NULL;
1118
- PValue = JudyLNext(metric_info->JudyL_array, &index_time, PJE0),
1119
- descr = unlikely(NULL == PValue) ? NULL : *PValue) {
1120
-
1121
- if (unlikely((time_t) index_time > metric_info->max_index_time_s) || index == entries)
1122
- break;
1123
-
1124
- if (descr->extent_entry || (!descr->extent_entry && descr->extent && descr->extent->datafile->journalfile != journalfile))
1125
- continue;
1126
-
1127
- struct journal_page_list *page_entry = &page_list[index++];
1128
-
1129
- if (likely(page_entry->extent_index != UINT32_MAX)) {
1130
-
1131
- fatal_assert(descr->extent->offset == extent_list[page_entry->extent_index].datafile_offset);
1132
- fatal_assert(descr->extent->size == extent_list[page_entry->extent_index].datafile_size);
1133
-
1134
- rrdeng_page_descr_mutex_lock(ctx, descr);
1135
- while (!pg_cache_try_get_unsafe(descr, 1)) {
1136
- pg_cache_wait_event_unsafe(descr);
1137
- }
1138
-
1139
- descr->extent_entry = &extent_list[page_entry->extent_index];
1140
- descr->extent = NULL;
1141
- descr->file = journalfile->datafile->file;
1142
- ++pg_cache->active_descriptors;
1143
- pg_cache_put_unsafe(descr);
1144
- rrdeng_try_deallocate_pg_cache_descr(ctx, descr);
1145
- rrdeng_page_descr_mutex_unlock(ctx, descr);
1146
- mark_journalfile_for_expiration_check = true;
1147
- }
1148
- }
1149
-
1150
- if (mark_journalfile_for_expiration_check) {
1151
- uint32_t page_offset = (uint8_t *)page_list_header - (uint8_t *)journalfile->journal_data;
1152
- mark_journalfile_descriptor(pg_cache, journalfile, page_offset, 1);
1153
- }
1154
-
1155
- uv_rwlock_rdunlock(&page_index->lock);
1156
- }
1157
-}
1158
-
1159
-bool descriptor_is_corrupted(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr)
1160
-{
1161
- struct page_cache *pg_cache = &ctx->pg_cache;
1162
- struct pg_cache_page_index *page_index = get_page_index(pg_cache, descr->id);
1163
-
1164
- if (unlikely(!page_index))
1165
- return true;
1166
-
1167
- time_t index_time_s = (time_t) (descr->start_time_ut / USEC_PER_SEC);
1168
- struct rrdeng_page_descr *idx_descr = get_descriptor(page_index, index_time_s);
1169
-
1170
- bool is_corrupted = (idx_descr != descr);
1171
-
1172
-#ifdef NETDATA_INTERNAL_CHECKS
1173
- char uuid_str[UUID_STR_LEN];
1174
- uuid_unparse_lower(page_index->id, uuid_str);
1175
- internal_error(is_corrupted, "Descriptor corrupted (Extent %p Judy %p) @ %ld", descr, idx_descr, index_time_s);
1176
-#endif
1177
-
1178
- return is_corrupted;
1179
-}
1180
-
1181
-static bool journalfile_ready_to_index(struct rrdengine_datafile *datafile)
1182
-{
1183
- struct extent_info *extent = datafile->extents.first;
1184
- while (extent) {
1185
- uint8_t extent_pages = extent->number_of_pages;
1186
- for (uint8_t index = 0; index < extent_pages; index++) {
1187
- struct rrdeng_page_descr *descr = extent->pages[index];
1188
- if (unlikely(!descr))
1189
- continue;
1190
- if (unlikely(!descr->extent))
1191
- return false;
1192
- }
1193
- extent = extent->next;
1194
- }
1195
- return true;
1196
-}
1197
-
1198
-// Migrate the journalfile pointed by datafile
1199
-// activate : make the new file active immediately
1200
-// journafile data will be set and descriptors (if deleted) will be repopulated as needed
1201
-// startup : if the migration is done during agent startup
1202
-// this will allow us to optimize certain things
1203
-void migrate_journal_file_v2(struct rrdengine_datafile *datafile, bool activate, bool startup)
1204
-{
1205
- char path[RRDENG_PATH_MAX];
1206
- size_t number_of_extents = 0; // Number of extents
1207
- size_t number_of_metrics = 0; // Number of unique metrics (UUIDS)
1208
- size_t number_of_pages = 0; // Total number of descriptors @ time
1209
- Pvoid_t *PValue;
1210
- Pvoid_t metrics_JudyL_array = NULL;
1211
- Pvoid_t metrics_JudyHS_array = NULL;
1212
- struct rrdengine_instance *ctx = datafile->ctx;
1213
- struct rrdengine_journalfile *journalfile = datafile->journalfile;
1214
- usec_t min_time_ut = LLONG_MAX;
1215
- usec_t max_time_ut = 0;
1216
- struct metric_info_s *metric_info;
1217
-
1218
- // Do nothing if we already have a mmaped file
1219
- if (unlikely(journalfile->journal_data))
1220
- return;
1221
-
1222
- generate_journalfilepath_v2(datafile, path, sizeof(path));
1223
- info("Indexing file %s", path);
1224
-
1225
-#ifdef NETDATA_INTERNAL_CHECKS
1226
- usec_t start_loading = now_realtime_usec();
1227
-#endif
1228
-
1229
- if (false == startup)
1230
- uv_rwlock_rdlock(&ctx->datafiles.rwlock);
1231
-
1232
- struct extent_info *extent = datafile->extents.first;
1233
- while (extent) {
1234
- uint8_t extent_pages = extent->number_of_pages;
1235
- for (uint8_t index = 0; index < extent_pages; index++) {
1236
- struct rrdeng_page_descr *descr = extent->pages[index];
1237
-
1238
- if (unlikely(!descr))
1239
- continue;
1240
-
1241
- if (false == startup) {
1242
- if (unlikely(descriptor_is_corrupted(ctx, descr))) {
1243
- extent->pages[index] = NULL;
1244
- continue;
1245
- }
1246
- }
1247
-
1248
- PValue = JudyHSGet(metrics_JudyHS_array, descr->id, sizeof(uuid_t));
1249
- if (likely(NULL != PValue)) {
1250
- metric_info = *PValue;
1251
- }
1252
- else {
1253
- PValue = JudyHSIns(&metrics_JudyHS_array, descr->id, sizeof(uuid_t), PJE0);
1254
- *PValue = metric_info = mallocz(sizeof(*metric_info));
1255
-
1256
- metric_info->entries =0;
1257
- metric_info->min_time_ut = LLONG_MAX;
1258
- metric_info->max_time_ut = 0;
1259
- metric_info->min_index_time_s = LLONG_MAX;
1260
- metric_info->max_index_time_s = 0;
1261
- metric_info->id = descr->id;
1262
- metric_info->page_index = NULL;
1263
- metric_info->page_list_header = 0;
1264
- metric_info->JudyL_array = (Pvoid_t) NULL;
1265
-
1266
- PValue = JudyLIns(&metrics_JudyL_array,number_of_metrics, PJE0);
1267
- *PValue = metric_info;
1268
- number_of_metrics++;
1269
- }
1270
- time_t current_index_time_s = (time_t) (descr->start_time_ut / USEC_PER_SEC);
1271
-
1272
- if (metric_info->min_time_ut > descr->start_time_ut) {
1273
- metric_info->min_time_ut = descr->start_time_ut;
1274
- metric_info->min_index_time_s = current_index_time_s;
1275
- }
1276
-
1277
- metric_info->max_index_time_s= MAX(metric_info->max_index_time_s, current_index_time_s);
1278
- metric_info->max_time_ut = MAX(metric_info->max_time_ut , descr->end_time_ut);
1279
-
1280
- if (false == startup) {
1281
- PValue = JudyLIns(&metric_info->JudyL_array, current_index_time_s, PJE0);
1282
- fatal_assert(NULL != PValue && NULL == *PValue);
1283
- *PValue = descr;
1284
- }
1285
-
1286
- metric_info->entries++;
1287
- number_of_pages++;
1288
-
1289
- // Maintain the min max times to add to the journal header
1290
- min_time_ut = MIN(min_time_ut, descr->start_time_ut);
1291
- max_time_ut = MAX(max_time_ut, descr->end_time_ut);
1292
- }
1293
- extent->index = number_of_extents++;
1294
- extent = extent->next;
1295
- }
1296
- info("File %s has %lu extents", path, number_of_extents);
1297
-
1298
- if (false == startup)
1299
- uv_rwlock_rdunlock(&ctx->datafiles.rwlock);
1300
-
1301
- internal_error(true, "Scan and extbuild metric %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1302
-
1303
- // Calculate total jourval file size
1304
- size_t total_file_size = 0;
1305
- total_file_size += (sizeof(struct journal_v2_header) + JOURNAL_V2_HEADER_PADDING_SZ);
1306
-
1307
- // Extents will start here
1308
- uint32_t extent_offset = total_file_size;
1309
- total_file_size += (number_of_extents * sizeof(struct journal_extent_list));
1310
-
1311
- uint32_t extent_offset_trailer = total_file_size;
1312
- total_file_size += sizeof(struct journal_v2_block_trailer);
1313
-
1314
- // UUID list will start here
1315
- uint32_t metrics_offset = total_file_size;
1316
- total_file_size += (number_of_metrics * sizeof(struct journal_metric_list));
1317
-
1318
- // UUID list trailer
1319
- uint32_t metric_offset_trailer = total_file_size;
1320
- total_file_size += sizeof(struct journal_v2_block_trailer);
1321
-
1322
- // descr @ time will start here
1323
- uint32_t pages_offset = total_file_size;
1324
- total_file_size += (number_of_pages * (sizeof(struct journal_page_list) + sizeof(struct journal_page_header) + sizeof(struct journal_v2_block_trailer)));
1325
-
1326
- // File trailer
1327
- uint32_t trailer_offset = total_file_size;
1328
- total_file_size += sizeof(struct journal_v2_block_trailer);
1329
-
1330
- uint8_t *data_start = netdata_mmap(path, total_file_size, MAP_SHARED, 0, false);
1331
- uint8_t *data = data_start;
1332
-
1333
- memset(data_start, 0, extent_offset);
1334
-
1335
- // Write header
1336
- struct journal_v2_header j2_header;
1337
- memset(&j2_header, 0, sizeof(j2_header));
1338
-
1339
- j2_header.magic = JOURVAL_V2_MAGIC;
1340
- j2_header.start_time_ut = min_time_ut;
1341
- j2_header.end_time_ut = max_time_ut;
1342
- j2_header.extent_count = number_of_extents;
1343
- j2_header.extent_offset = extent_offset;
1344
- j2_header.metric_count = number_of_metrics;
1345
- j2_header.metric_offset = metrics_offset;
1346
- j2_header.page_count = number_of_pages;
1347
- j2_header.page_offset = pages_offset;
1348
- j2_header.extent_trailer_offset = extent_offset_trailer;
1349
- j2_header.metric_trailer_offset = metric_offset_trailer;
1350
- j2_header.total_file_size = total_file_size;
1351
- j2_header.original_file_size = (uint32_t) journalfile->pos;
1352
- j2_header.data = data_start; // Used during migration
1353
-
1354
- struct journal_v2_block_trailer *journal_v2_trailer;
1355
-
1356
- // Write all the extents we have
1357
- data = journal_v2_write_extent_list(journalfile, data_start + extent_offset);
1358
- internal_error(true, "Write extent list so far %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1359
-
1360
- fatal_assert(data == data_start + extent_offset_trailer);
1361
-
1362
- // Calculate CRC for extents
1363
- journal_v2_trailer = (struct journal_v2_block_trailer *) (data_start + extent_offset_trailer);
1364
- uLong crc;
1365
- crc = crc32(0L, Z_NULL, 0);
1366
- crc = crc32(crc, (uint8_t *) data_start + extent_offset, number_of_extents * sizeof(struct journal_extent_list));
1367
- crc32set(journal_v2_trailer->checksum, crc);
1368
-
1369
- internal_error(true, "CALCULATE CRC FOR EXTENT %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1370
- // Skip the trailer, point to the metrics off
1371
- data += sizeof(struct journal_v2_block_trailer);
1372
-
1373
- // Sanity check -- we must be at the metrics_offset
1374
- fatal_assert(data == data_start + metrics_offset);
1375
-
1376
- // Allocate array to sort UUIDs and keep them sorted in the journal because we want to do binary search when we do lookups
1377
- struct journal_metric_list_to_sort *uuid_list = mallocz(number_of_metrics * sizeof(struct journal_metric_list_to_sort));
1378
-
1379
- Word_t Index;
1380
- struct page_cache *pg_cache = &ctx->pg_cache;
1381
- struct pg_cache_page_index *page_index;
1382
- for (Index = 0, PValue = JudyLFirst(metrics_JudyL_array, &Index, PJE0),
1383
- metric_info = unlikely(NULL == PValue) ? NULL : *PValue;
1384
- metric_info != NULL;
1385
- PValue = JudyLNext(metrics_JudyL_array, &Index, PJE0),
1386
- metric_info = unlikely(NULL == PValue) ? NULL : *PValue) {
1387
-
1388
- fatal_assert(Index < number_of_metrics);
1389
- uuid_list[Index].metric_info = metric_info;
1390
-
1391
- if (false == startup)
1392
- uv_rwlock_rdlock(&pg_cache->metrics_index.lock);
1393
-
1394
- PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, metric_info->id, sizeof(uuid_t));
1395
- page_index = (NULL == PValue) ? NULL : *PValue;
1396
-
1397
- if (false == startup)
1398
- uv_rwlock_rdunlock(&pg_cache->metrics_index.lock);
1399
-
1400
- fatal_assert(NULL != page_index);
1401
-
1402
- metric_info->page_index = page_index;
1403
-
1404
- }
1405
- // Cleanup judy arrays we no longer need
1406
- JudyLFreeArray(&metrics_JudyL_array, PJE0);
1407
- JudyHSFreeArray(&metrics_JudyHS_array, PJE0);
1408
-
1409
- qsort(&uuid_list[0], number_of_metrics, sizeof(struct journal_metric_list_to_sort), journal_metric_compare);
1410
- internal_error(true, "Traverse and qsort UUID %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1411
- // Write sorted UUID LIST
1412
- // The loop will write a single UUID entry then
1413
- // Write all entries (descr @ time) for that UUID at the proper location (header, number of entries, trailer)
1414
- // Move on to write the next UUID
1415
- // Write trailer after the UUID list
1416
- for (Index = 0; Index < number_of_metrics; Index++) {
1417
- metric_info = uuid_list[Index].metric_info;
1418
-
1419
- // Calculate current UUID offset from start of file. We will store this in the data page header
1420
- uint32_t uuid_offset = data - data_start;
1421
-
1422
- // Write the UUID we are processing
1423
- data = (void *) journal_v2_write_metric_page(&j2_header, data, metric_info, pages_offset);
1424
- if (unlikely(!data))
1425
- break;
1426
-
1427
- // Next we will write
1428
- // Header
1429
- // Detailed entries (descr @ time)
1430
- // Trailer (checksum)
1431
-
1432
- // Keep the page_list_header, to be used for migration when where agent is running
1433
- metric_info->page_list_header = pages_offset;
1434
- // Write page header
1435
- void *metric_page = journal_v2_write_data_page_header(&j2_header, data_start + pages_offset, metric_info, uuid_offset);
1436
-
1437
- // Start writing descr @ time
1438
- void *page_trailer = journal_v2_write_descriptors(&j2_header, metric_page, metric_info, journalfile);
1439
- if (unlikely(!page_trailer))
1440
- break;
1441
-
1442
- // Trailer (checksum)
1443
- uint8_t *next_page_address = journal_v2_write_data_page_trailer(&j2_header, page_trailer, data_start + pages_offset);
1444
-
1445
- // Calculate start of the pages start for next descriptor
1446
- pages_offset += (metric_info->entries * (sizeof(struct journal_page_list)) + sizeof(struct journal_page_header) + sizeof(struct journal_v2_block_trailer));
1447
- // Verify we are at the right location
1448
- fatal_assert(pages_offset == (next_page_address - data_start));
1449
- }
1450
- // Data should be at the UUID trailer offset
1451
- fatal_assert(data == data_start + metric_offset_trailer);
1452
-
1453
- internal_error(true, "WRITE METRICS AND PAGES %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1454
-
1455
- // Calculate CRC for metrics
1456
- journal_v2_trailer = (struct journal_v2_block_trailer *) (data_start + metric_offset_trailer);
1457
- crc = crc32(0L, Z_NULL, 0);
1458
- crc = crc32(crc, (uint8_t *) data_start + metrics_offset, number_of_metrics * sizeof(struct journal_metric_list));
1459
- crc32set(journal_v2_trailer->checksum, crc);
1460
- internal_error(true, "CALCULATE CRC FOR UUIDs %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1461
-
1462
- // Prepare to write checksum for the file
1463
- j2_header.data = NULL;
1464
- journal_v2_trailer = (struct journal_v2_block_trailer *) (data_start + trailer_offset);
1465
- crc = crc32(0L, Z_NULL, 0);
1466
- crc = crc32(crc, (void *) &j2_header, sizeof(j2_header));
1467
- crc32set(journal_v2_trailer->checksum, crc);
1468
-
1469
- // Write header to the file
1470
- memcpy(data_start, &j2_header, sizeof(j2_header));
1471
-
1472
- internal_error(true, "FILE COMPLETED --------> %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1473
-
1474
- info("Migrated journal file %s, File size %lu", path, total_file_size);
1475
-
1476
- if (activate) {
1477
- journalfile->journal_data = data_start;
1478
- journalfile->journal_data_size = total_file_size;
1479
-
1480
- // HERE we need to remove old descriptors and activate the new ones
1481
- {
1482
- for (Index = 0; Index < number_of_metrics; Index++) {
1483
- journal_v2_remove_active_descriptors(journalfile, uuid_list[Index].metric_info, startup);
1484
-
1485
- if (false == startup)
1486
- JudyLFreeArray(&uuid_list[Index].metric_info->JudyL_array, PJE0);
1487
-
1488
- freez(uuid_list[Index].metric_info);
1489
- }
1490
- internal_error(true, "ACTIVATING NEW INDEX JNL %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1491
-
1492
- if (false == startup) {
1493
- uv_rwlock_wrlock(&journalfile->datafile->extent_rwlock);
1494
- df_extent_delete_all_unsafe(journalfile->datafile);
1495
- uv_rwlock_wrunlock(&journalfile->datafile->extent_rwlock);
1496
- }
1497
- else
1498
- df_extent_delete_all_unsafe(journalfile->datafile);
1499
- }
1500
-
1501
- ctx->disk_space += total_file_size;
1502
- }
1503
- else {
1504
- // If we failed and didnt process the entire list, free the rest
1505
- for (Index = 0; Index < number_of_metrics; Index++)
1506
- freez(uuid_list[Index].metric_info);
1507
- netdata_munmap(data_start, total_file_size);
1508
- }
1509
- freez(uuid_list);
1510
-}
1511
-
527
int load_journal_file(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile,
528
struct rrdengine_datafile *datafile)
529
{
@@ -1517,24 +532,15 @@ int load_journal_file(struct rrdengine_instance *ctx, struct rrdengine_journalfi
532
int ret, fd, error;
533
uint64_t file_size, max_id;
534
char path[RRDENG_PATH_MAX];
1520
- int should_try_migration = 0;
1521
-
1522
- // Do not try to load the latest file (always rebuild and live migrate)
1523
- if (datafile->fileno != ctx->last_fileno && db_engine_journal_indexing) {
1524
- if (!(should_try_migration = load_journal_file_v2(ctx, journalfile, datafile))) {
1525
- return 0;
1526
- }
1527
- }
535
536
generate_journalfilepath(datafile, path, sizeof(path));
1530
-
1531
- // If it is not the last file, open read only
1532
- fd = open_file_direct_io(path, datafile->fileno == ctx->last_fileno ? O_RDWR : O_RDONLY, &file);
537
+ fd = open_file_direct_io(path, O_RDWR, &file);
538
if (fd < 0) {
539
++ctx->stats.fs_errors;
540
rrd_stat_atomic_add(&global_fs_errors, 1);
541
return fd;
542
}
543
+ info("Loading journal file \"%s\".", path);
544
545
ret = check_file_properties(file, &file_size, sizeof(struct rrdeng_df_sb));
546
if (ret)
@@ -1542,17 +548,14 @@ int load_journal_file(struct rrdengine_instance *ctx, struct rrdengine_journalfi
548
file_size = ALIGN_BYTES_FLOOR(file_size);
549
550
ret = check_journal_file_superblock(file);
1545
- if (ret) {
1546
- info("Invalid journal file \"%s\" ; superblock check failed.", path);
551
+ if (ret)
552
goto error;
1548
- }
553
ctx->stats.io_read_bytes += sizeof(struct rrdeng_jf_sb);
554
++ctx->stats.io_read_requests;
555
556
journalfile->file = file;
557
journalfile->pos = file_size;
1554
-
1555
- journalfile->data = netdata_mmap(path, file_size, MAP_SHARED, 0, !(datafile->fileno == ctx->last_fileno));
558
+ journalfile->data = netdata_mmap(path, file_size, MAP_SHARED, 0);
559
info("Loading journal file \"%s\" using %s.", path, journalfile->data?"MMAP":"uv_fs_read");
560
561
max_id = iterate_transactions(ctx, journalfile);
@@ -1562,16 +565,6 @@ int load_journal_file(struct rrdengine_instance *ctx, struct rrdengine_journalfi
565
info("Journal file \"%s\" loaded (size:%"PRIu64").", path, file_size);
566
if (likely(journalfile->data))
567
netdata_munmap(journalfile->data, file_size);
1565
-
1566
- // Don't Index the last file
1567
- if (ctx->last_fileno == journalfile->datafile->fileno || !db_engine_journal_indexing)
1568
- return 0;
1569
-
1570
- if (should_try_migration == 1)
1571
- migrate_journal_file_v2(datafile, true, true);
1572
- else
1573
- error_report("File %s cannot be migrated to the new journal format. Index will be allocated in memory", path);
1574
-
568
return 0;
569
570
error:
@@ -1586,57 +579,6 @@ int load_journal_file(struct rrdengine_instance *ctx, struct rrdengine_journalfi
579
return error;
580
}
581
1589
-void after_journal_indexing(uv_work_t *req, int status)
1590
-{
1591
- struct rrdeng_work *work_request = req->data;
1592
- struct rrdengine_worker_config *wc = work_request->wc;
1593
-
1594
- if (likely(status != UV_ECANCELED)) {
1595
- errno = 0;
1596
- if (likely(work_request->count))
1597
- internal_error(true, "Journal indexing done; %u files processed", work_request->count);
1598
- }
1599
- wc->running_journal_migration = 0;
1600
- wc->run_indexing= work_request->rerun;
1601
- freez(work_request);
1602
-}
1603
-
1604
-#define MAX_RETRIES_TO_START_INDEX (100)
1605
-void start_journal_indexing(uv_work_t *req)
1606
-{
1607
- struct rrdeng_work *work_request = req->data;
1608
- struct rrdengine_worker_config *wc = work_request->wc;
1609
- struct rrdengine_instance *ctx = wc->ctx;
1610
-
1611
- unsigned count = 0;
1612
- while ((wc->now_deleting_files || wc->now_deleting_descriptors) && count++ < MAX_RETRIES_TO_START_INDEX)
1613
- sleep_usec(100 * USEC_PER_MS);
1614
-
1615
- if (count == MAX_RETRIES_TO_START_INDEX)
1616
- return;
1617
-
1618
- struct rrdengine_datafile *datafile = ctx->datafiles.first;
1619
-
1620
- while (datafile && datafile->fileno != ctx->last_fileno) {
1621
- if (unlikely(!datafile->journalfile->journal_data)) {
1622
- bool ready_to_index = journalfile_ready_to_index(datafile);
1623
- if (ready_to_index) {
1624
- info("Journal file %u is ready to be indexed", datafile->fileno);
1625
- migrate_journal_file_v2(datafile, true, false);
1626
- ++work_request->count;
1627
- }
1628
- else {
1629
- info("Journal file %u is not ready to be indexed", datafile->fileno);
1630
- work_request->rerun = true;
1631
- sleep_usec(100 * USEC_PER_MS);
1632
- }
1633
- }
1634
- datafile = datafile->next;
1635
- if (unlikely(NO_QUIESCE != ctx->quiesce))
1636
- break;
1637
- }
1638
-}
1639
-
582
void init_commit_log(struct rrdengine_instance *ctx)
583
{
584
ctx->commit_log.buf = NULL;
database/engine/journalfile.h
+2
-86
@@ -13,98 +13,16 @@ struct rrdengine_journalfile;
13
14
#define WALFILE_PREFIX "journalfile-"
15
#define WALFILE_EXTENSION ".njf"
16
-#define WALFILE_EXTENSION_V2 ".njfv2"
16
18
-#define is_descr_journal_v2(descr) ((descr)->extent_entry != NULL)
17
18
/* only one event loop is supported for now */
19
struct rrdengine_journalfile {
20
uv_file file;
21
uint64_t pos;
22
void *data;
25
- uint16_t file_index; // File index
26
- void *journal_data; // MMAPed file of journal v2
27
- uint32_t journal_data_size; // Total file size mapped
28
- Pvoid_t JudyL_array; // Used to track active v2 descriptors
29
- time_t last_access; // Last access for v2 descriptors to decide cleanup
23
struct rrdengine_datafile *datafile;
24
};
25
33
-
34
-// Journal v2 structures
35
-
36
-#define JOURVAL_V2_MAGIC (0x01221019)
37
-#define JOURVAL_V2_REBUILD_MAGIC (0x00221019)
38
-
39
-struct journal_v2_block_trailer {
40
- union {
41
- uint8_t checksum[CHECKSUM_SZ]; /* CRC32 */
42
- uint32_t crc;
43
- };
44
-};
45
-
46
-// Journal V2
47
-// 28 bytes
48
-struct journal_page_header {
49
- union {
50
- uint8_t checksum[4]; // CRC check
51
- uint32_t crc;
52
- };
53
- uint32_t uuid_offset; // Points back to the UUID list which should point here (UUIDs should much)
54
- uint32_t entries; // Entries
55
- uuid_t uuid; // Which UUID this is
56
-};
57
-
58
-// 20 bytes
59
-struct journal_page_list {
60
- uint32_t delta_start_s; // relative to the start time of journal
61
- uint32_t delta_end_s; // relative to delta_start
62
- uint32_t extent_index; // Index to the extent (extent list) (bytes from BASE)
63
- uint16_t update_every_s;
64
- uint16_t page_length;
65
- uint8_t type;
66
-};
67
-
68
-// UUID_LIST
69
-// 32 bytes
70
-struct journal_metric_list {
71
- uuid_t uuid;
72
- uint32_t entries; // Number of entries
73
- uint32_t page_offset; // OFFSET that contains entries * struct( journal_page_list )
74
- uint32_t delta_start; // Min time of metric
75
- uint32_t delta_end; // Max time of metric (to be used to populate page_index)
76
-};
77
-
78
-// 16 bytes
79
-struct journal_extent_list {
80
- uint64_t datafile_offset; // Datafile offset to find the extent
81
- uint32_t datafile_size; // Size of the extent
82
- uint16_t file_index; // which file index is this datafile[index]
83
- uint8_t pages; // number of pages (not all are necesssarily valid)
84
-};
85
-
86
-// 72 bytes
87
-struct journal_v2_header {
88
- uint32_t magic;
89
- usec_t start_time_ut; // Min start time of journal
90
- usec_t end_time_ut; // Maximum end time of journal
91
- uint32_t extent_count; // Count of extents
92
- uint32_t extent_offset;
93
- uint32_t metric_count; // Count of metrics (unique UUIDS)
94
- uint32_t metric_offset;
95
- uint32_t page_count; // Total count of pages (descriptors @ time)
96
- uint32_t page_offset;
97
- uint32_t extent_trailer_offset; // CRC for entent list
98
- uint32_t metric_trailer_offset; // CRC for metric list
99
- uint32_t original_file_size; // This is the original journal file
100
- uint32_t total_file_size; // This is the total file size
101
- void *data; // Used when building the index
102
-};
103
-
104
-#define JOURNAL_V2_HEADER_PADDING_SZ (RRDENG_BLOCK_SIZE - (sizeof(struct journal_v2_header)))
105
-
106
-
107
-
26
/* only one event loop is supported for now */
27
struct transaction_commit_log {
28
uint64_t transaction_id;
@@ -116,18 +34,16 @@ struct transaction_commit_log {
34
};
35
36
void generate_journalfilepath(struct rrdengine_datafile *datafile, char *str, size_t maxlen);
119
-void generate_journalfilepath_v2(struct rrdengine_datafile *datafile, char *str, size_t maxlen);
37
void journalfile_init(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile);
38
void *wal_get_transaction_buffer(struct rrdengine_worker_config* wc, unsigned size);
39
void wal_flush_transaction_buffer(struct rrdengine_worker_config* wc);
40
int close_journal_file(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile);
41
int unlink_journal_file(struct rrdengine_journalfile *journalfile);
125
-int destroy_journal_file_unsafe(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile);
42
+int destroy_journal_file(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile);
43
int create_journal_file(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile);
44
int load_journal_file(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile,
45
struct rrdengine_datafile *datafile);
46
void init_commit_log(struct rrdengine_instance *ctx);
130
-bool unlink_descriptor_extent_unsafe(struct rrdeng_page_descr *descr);
131
-void queue_journalfile_v2_migration(struct rrdengine_worker_config *wc);
47
+
48
49
#endif /* NETDATA_JOURNALFILE_H */
\ No newline at end of file
database/engine/pagecache.c
+167
-402
@@ -134,9 +134,6 @@ struct rrdeng_page_descr *pg_cache_create_descr(void)
134
descr->pg_cache_descr_state = 0;
135
descr->pg_cache_descr = NULL;
136
descr->update_every_s = 0;
137
- descr->extent_entry = NULL;
138
- descr->type = 0;
139
- descr->file = -1;
137
138
return descr;
139
}
@@ -161,41 +158,13 @@ void pg_cache_wake_up_waiters(struct rrdengine_instance *ctx, struct rrdeng_page
158
* The lock will be released and re-acquired. The descriptor is not guaranteed
159
* to exist after this function returns.
160
*/
164
-#ifdef NETDATA_INTERNAL_CHECKS
165
-void pg_cache_wait_event_unsafe_with_trace(struct rrdeng_page_descr *descr, const char *function, size_t line)
166
-#else
161
void pg_cache_wait_event_unsafe(struct rrdeng_page_descr *descr)
168
-#endif
162
{
163
struct page_cache_descr *pg_cache_descr = descr->pg_cache_descr;
164
172
-#ifdef NETDATA_INTERNAL_CHECKS
173
- if(pg_cache_descr->owner.tid != gettid())
174
- fatal("DBENGINE: pg_cache_descr is not locked by me in %s(). It is locked by thread %u, I am %u",
175
- __FUNCTION__, (unsigned)pg_cache_descr->owner.tid, (unsigned)gettid());
176
-
177
- struct pg_cache_waiter w = {
178
- .line = line,
179
- .function = function,
180
- .tid = gettid(),
181
- .next = NULL,
182
- .prev = NULL,
183
- };
184
-
185
- DOUBLE_LINKED_LIST_PREPEND_UNSAFE(pg_cache_descr->wait_list, &w, prev, next);
186
-#endif
187
-
165
++pg_cache_descr->waiters;
166
uv_cond_wait(&pg_cache_descr->cond, &pg_cache_descr->mutex);
167
--pg_cache_descr->waiters;
191
-
192
-#ifdef NETDATA_INTERNAL_CHECKS
193
- DOUBLE_LINKED_LIST_REMOVE_UNSAFE(pg_cache_descr->wait_list, &w, prev, next);
194
-
195
- pg_cache_descr->owner.function = function;
196
- pg_cache_descr->owner.line = line;
197
- pg_cache_descr->owner.tid = gettid();
198
-#endif
168
}
169
170
/*
@@ -204,43 +173,15 @@ void pg_cache_wait_event_unsafe(struct rrdeng_page_descr *descr)
173
* to exist after this function returns.
174
* Returns UV_ETIMEDOUT if timeout_sec seconds pass.
175
*/
207
-#ifdef NETDATA_INTERNAL_CHECKS
208
-int pg_cache_timedwait_event_unsafe_with_trace(struct rrdeng_page_descr *descr, uint64_t timeout_sec, const char *function, size_t line)
209
-#else
176
int pg_cache_timedwait_event_unsafe(struct rrdeng_page_descr *descr, uint64_t timeout_sec)
211
-#endif
177
{
178
int ret;
179
struct page_cache_descr *pg_cache_descr = descr->pg_cache_descr;
180
216
-#ifdef NETDATA_INTERNAL_CHECKS
217
- if(pg_cache_descr->owner.tid != gettid())
218
- fatal("DBENGINE: pg_cache_descr is not locked by me in %s(). It is locked by thread %u, I am %u",
219
- __FUNCTION__, (unsigned)pg_cache_descr->owner.tid, (unsigned)gettid());
220
-
221
- struct pg_cache_waiter w = {
222
- .line = line,
223
- .function = function,
224
- .tid = gettid(),
225
- .next = NULL,
226
- .prev = NULL,
227
- };
228
-
229
- DOUBLE_LINKED_LIST_PREPEND_UNSAFE(pg_cache_descr->wait_list, &w, prev, next);
230
-#endif
231
-
181
++pg_cache_descr->waiters;
182
ret = uv_cond_timedwait(&pg_cache_descr->cond, &pg_cache_descr->mutex, timeout_sec * NSEC_PER_SEC);
183
--pg_cache_descr->waiters;
184
236
-#ifdef NETDATA_INTERNAL_CHECKS
237
- DOUBLE_LINKED_LIST_REMOVE_UNSAFE(pg_cache_descr->wait_list, &w, prev, next);
238
-
239
- pg_cache_descr->owner.function = function;
240
- pg_cache_descr->owner.line = line;
241
- pg_cache_descr->owner.tid = gettid();
242
-#endif
243
-
185
return ret;
186
}
187
@@ -354,11 +295,6 @@ unsigned long pg_cache_soft_limit(struct rrdengine_instance *ctx)
295
return ctx->cache_pages_low_watermark + (unsigned long)ctx->metric_API_max_producers;
296
}
297
357
-unsigned long pg_cache_warn_limit(struct rrdengine_instance *ctx)
358
-{
359
- return ctx->cache_pages_warn_watermark + (unsigned long)ctx->metric_API_max_producers;
360
-}
361
-
298
/*
299
* This function returns the maximum number of dirty pages that are committed to be written to disk allowed in the page
300
* cache.
@@ -386,10 +322,9 @@ static void pg_cache_reserve_pages(struct rrdengine_instance *ctx, unsigned numb
322
if (pg_cache->populated_pages + number >= pg_cache_hard_limit(ctx) + 1)
323
debug(D_RRDENGINE, "==Page cache full. Reserving %u pages.==",
324
number);
389
-
325
while (pg_cache->populated_pages + number >= pg_cache_hard_limit(ctx) + 1) {
326
392
- if (!(pg_cache_try_evict_one_page_unsafe(ctx))) {
327
+ if (!pg_cache_try_evict_one_page_unsafe(ctx)) {
328
/* failed to evict */
329
struct completion compl;
330
struct rrdeng_cmd cmd;
@@ -455,6 +390,7 @@ static int pg_cache_try_reserve_pages(struct rrdengine_instance *ctx, unsigned n
390
ret = 1; /* success */
391
}
392
uv_rwlock_wrunlock(&pg_cache->pg_cache_rwlock);
393
+
394
return ret;
395
}
396
@@ -477,8 +413,8 @@ static void pg_cache_evict_unsafe(struct rrdengine_instance *ctx, struct rrdeng_
413
* If it fails it sets in_flight_descr to the oldest descriptor that has write-back in progress,
414
* or it sets it to NULL if no write-back is in progress.
415
*
480
-* Returns 1 on success and 0 on failure.
481
-*/
416
+ * Returns 1 on success and 0 on failure.
417
+ */
418
static int pg_cache_try_evict_one_page_unsafe(struct rrdengine_instance *ctx)
419
{
420
struct page_cache *pg_cache = &ctx->pg_cache;
@@ -522,16 +458,10 @@ static int pg_cache_try_evict_one_page_unsafe(struct rrdengine_instance *ctx)
458
* @param is_exclusive_holder must be non-zero if the caller holds an exclusive page reference.
459
* @param metric_id is set to the metric the page belongs to, if it's safe to delete the metric and metric_id is not
460
* NULL. Otherwise, metric_id is not set.
525
- * @spin True to keep trying to release the page, false to try once
461
* @return 1 if it's safe to delete the metric, 0 otherwise.
462
*/
528
-uint8_t pg_cache_punch_hole(
529
- struct rrdengine_instance *ctx,
530
- struct rrdeng_page_descr *descr,
531
- uint8_t remove_dirty,
532
- uint8_t is_exclusive_holder,
533
- uuid_t(*metric_id),
534
- bool update_page_duration)
463
+uint8_t pg_cache_punch_hole(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr, uint8_t remove_dirty,
464
+ uint8_t is_exclusive_holder, uuid_t *metric_id)
465
{
466
struct page_cache *pg_cache = &ctx->pg_cache;
467
struct page_cache_descr *pg_cache_descr = NULL;
@@ -555,8 +485,7 @@ uint8_t pg_cache_punch_hole(
485
}
486
goto destroy;
487
}
558
- if (update_page_duration)
559
- --page_index->page_count;
488
+ --page_index->page_count;
489
if (!page_index->writers && !page_index->page_count) {
490
can_delete_metric = 1;
491
if (metric_id) {
@@ -568,11 +497,7 @@ uint8_t pg_cache_punch_hole(
497
498
uv_rwlock_wrlock(&pg_cache->pg_cache_rwlock);
499
++ctx->stats.pg_cache_deletions;
571
- if (update_page_duration)
572
- --pg_cache->page_descriptors;
573
-
574
- if (is_descr_journal_v2(descr))
575
- --pg_cache->active_descriptors;
500
+ --pg_cache->page_descriptors;
501
uv_rwlock_wrunlock(&pg_cache->pg_cache_rwlock);
502
503
rrdeng_page_descr_mutex_lock(ctx, descr);
@@ -587,7 +512,7 @@ uint8_t pg_cache_punch_hole(
512
}
513
}
514
if (remove_dirty) {
590
- pg_cache_descr->flags &= ~(RRD_PAGE_DIRTY | RRD_PAGE_INVALID);
515
+ pg_cache_descr->flags &= ~RRD_PAGE_DIRTY;
516
} else {
517
/* even a locked page could be dirty */
518
while (unlikely(pg_cache_descr->flags & RRD_PAGE_DIRTY)) {
@@ -615,8 +540,7 @@ uint8_t pg_cache_punch_hole(
540
}
541
destroy:
542
rrdeng_page_descr_freez(descr);
618
- if (update_page_duration)
619
- pg_cache_update_metric_times(page_index);
543
+ pg_cache_update_metric_times(page_index);
544
545
return can_delete_metric;
546
}
@@ -632,272 +556,33 @@ static inline int is_page_in_time_range(struct rrdeng_page_descr *descr, usec_t
556
(pg_start >= start_time && pg_start <= end_time);
557
}
558
635
-static uint32_t find_matching_page(struct journal_page_header *page_list_header, uint32_t delta_start_time_s)
636
-{
637
- uint32_t left = 0;
638
- uint32_t right = page_list_header->entries;
639
-
640
- while (left < right) {
641
- struct journal_page_list *page_list = (struct journal_page_list *) ((uint8_t *) page_list_header + sizeof(*page_list_header));
642
- struct journal_page_list *page_entry;
643
-
644
- uint32_t middle_delta_start_s;
645
- uint32_t middle_delta_end_s;
646
-
647
- uint32_t middle = (left + right) >> 1;
648
-
649
- page_entry = &page_list[middle];
650
- middle_delta_start_s = page_entry->delta_start_s;
651
- middle_delta_end_s = page_entry->delta_end_s;
652
-
653
- if (delta_start_time_s >= middle_delta_start_s && delta_start_time_s <= middle_delta_end_s)
654
- return middle;
655
-
656
- if (delta_start_time_s < middle_delta_end_s)
657
- right = middle;
658
- else if(delta_start_time_s > middle_delta_end_s)
659
- left = middle + 1;
660
- else
661
- return middle;
662
- }
663
- return right;
664
-}
665
-
666
-bool descr_exists_unsafe( struct pg_cache_page_index *page_index, time_t start_time_s)
667
-{
668
- return (NULL != JudyLGet(page_index->JudyL_array, start_time_s, PJE0));
669
-}
670
-
671
-void mark_journalfile_descriptor( struct page_cache *pg_cache, struct rrdengine_journalfile *journalfile, uint32_t page_offset, uint32_t Index)
672
-{
673
- Pvoid_t *PValue;
674
-
675
- uv_rwlock_wrlock(&pg_cache->v2_lock);
676
- PValue = JudyLIns(&journalfile->JudyL_array, (Word_t)page_offset, PJE0);
677
- *(uint32_t *)PValue = (Index + 1);
678
- journalfile->last_access = now_realtime_sec();
679
- uv_rwlock_wrunlock(&pg_cache->v2_lock);
680
-}
681
-
682
-static void update_journal_access_time(struct rrdengine_journalfile *journalfile, struct pg_cache_page_index *page_index, struct rrdeng_page_descr *descr)
683
-{
684
- if (journalfile) {
685
- journalfile->last_access = now_realtime_sec();
686
- return;
687
- }
688
-
689
- if (unlikely(!page_index || !descr))
690
- return;
691
-
692
- if (!is_descr_journal_v2(descr))
693
- return;
694
-
695
- struct rrdengine_instance *ctx = page_index->ctx;
696
-
697
- uv_rwlock_rdlock(&ctx->datafiles.rwlock);
698
- struct rrdengine_datafile *datafile = ctx->datafiles.first;
699
- while (datafile) {
700
- journalfile = datafile->journalfile;
701
- if (!journalfile->journal_data) {
702
- datafile = datafile->next;
703
- continue;
704
- }
705
- if (datafile->file == descr->file) {
706
- journalfile->last_access = now_realtime_sec();
707
- break;
708
- }
709
- datafile = datafile->next;
710
- }
711
- uv_rwlock_rdunlock(&ctx->datafiles.rwlock);
712
-}
713
-
714
-// Note: We have read lock on page index
715
-// We release and escalate to write lock
716
-// Return to read lock when done
717
-static struct rrdeng_page_descr *add_pages_from_timerange(
718
- struct journal_page_header *page_list_header,
719
- uint32_t delta_start_time_s,
720
- uint32_t delta_end_time_s,
721
- usec_t journal_start_time_ut,
722
- struct pg_cache_page_index *page_index,
723
- struct journal_extent_list *extent_list,
724
- struct rrdengine_datafile *datafile,
725
- uint32_t cache_pages)
726
-{
727
-
728
- struct rrdengine_instance *ctx = page_index->ctx;
729
- struct page_cache *pg_cache = &ctx->pg_cache;
730
- time_t journal_start_time_s = (time_t)(journal_start_time_ut / USEC_PER_SEC);
731
- struct journal_page_list *page_list = (struct journal_page_list *)((uint8_t *) page_list_header + sizeof(*page_list_header));
732
-
733
- uint32_t pos = find_matching_page(page_list_header, delta_start_time_s);
734
-
735
- // This is the page offset that we will store to check for v2 descriptors later on
736
- uint32_t page_offset = (uint8_t *) page_list_header - (uint8_t *) datafile->journalfile->journal_data;
737
- uint32_t entries = page_list_header->entries;
738
- uint32_t pages_to_cache = MIN(pos + cache_pages, entries);
739
-
740
- struct rrdeng_page_descr *descr = NULL;
741
-
742
- bool journal_updated = false;
743
- bool rw_lock_acquired = false;
744
-
745
- // We will cache pages_to_cache pages or until our end time is out of range
746
- for (uint32_t x = pos; x < pages_to_cache; x++) {
747
-
748
- struct journal_page_list *page_entry = &page_list[x];
749
-
750
- if (page_entry->extent_index == UINT32_MAX)
751
- continue;
752
-
753
- if (delta_end_time_s < page_entry->delta_start_s)
754
- break;
755
-
756
- time_t index_time_s = (time_t) (journal_start_time_s + page_entry->delta_start_s);
757
-
758
- if (!descr_exists_unsafe(page_index, index_time_s)) {
759
- struct rrdeng_page_descr *new_descr = pg_cache_create_descr();
760
- new_descr->page_length = page_entry->page_length;
761
- new_descr->start_time_ut = index_time_s * USEC_PER_SEC;
762
- new_descr->end_time_ut = (journal_start_time_s + page_entry->delta_end_s) * USEC_PER_SEC;
763
- new_descr->id = &page_index->id;
764
- new_descr->extent = NULL;
765
- new_descr->extent_entry = &extent_list[page_entry->extent_index];
766
- new_descr->type = page_entry->type;
767
- new_descr->update_every_s = page_entry->update_every_s;
768
- new_descr->file = datafile->file;
769
-
770
- if (false == rw_lock_acquired) {
771
- uv_rwlock_rdunlock(&page_index->lock);
772
- uv_rwlock_wrlock(&page_index->lock);
773
- rw_lock_acquired = true;
774
- }
775
-
776
- struct rrdeng_page_descr *added_descr = pg_cache_insert(ctx, page_index, new_descr, false);
777
- if (unlikely(added_descr != new_descr))
778
- rrdeng_page_descr_freez(new_descr);
779
-
780
- if (!descr) {
781
- descr = added_descr;
782
- // Mark the area to check
783
- mark_journalfile_descriptor(pg_cache, datafile->journalfile, page_offset, x);
784
- journal_updated = true;
785
- }
786
- }
787
- }
788
-
789
- if (!journal_updated)
790
- update_journal_access_time(datafile->journalfile, NULL, NULL);
791
-
792
- // Check if we have switched to rw lock for the page index and switch back
793
- if (rw_lock_acquired) {
794
- uv_rwlock_wrunlock(&page_index->lock);
795
- uv_rwlock_rdlock(&page_index->lock);
796
- }
797
- return descr;
798
-};
799
-
800
-static int journal_metric_uuid_compare(const void *key, const void *metric)
801
-{
802
- return uuid_compare(*(uuid_t *) key, ((struct journal_metric_list *) metric)->uuid);
803
-}
804
-
805
-//
806
-// Steps
807
-// 1. Find which journal has the start time within its range
808
-// 2. Find the UUID in that journal
809
-// 3. Find the array of times for that UUID (convert from the journal header to the offset needed)
810
-// Note: We have page_index lock
811
-// cache pages is the maximum pages to fetch (create metadata for)
812
-// This will be limited by the end_time or if we run out of pages in the matching journal
813
-// pages that could be precached but exist in another journal will not be precached
814
-static struct rrdeng_page_descr *populate_page_index(
815
- struct pg_cache_page_index *page_index,
816
- usec_t start_time_ut,
817
- usec_t end_time_ut,
818
- uint32_t cache_pages)
559
+static inline int is_point_in_time_in_page(struct rrdeng_page_descr *descr, usec_t point_in_time)
560
{
820
- struct rrdengine_instance *ctx = page_index->ctx;
821
-
822
- uv_rwlock_rdlock(&ctx->datafiles.rwlock);
823
-
824
- struct rrdengine_datafile *datafile = ctx->datafiles.first;
825
- while (datafile) {
826
- struct journal_v2_header *journal_header = (struct journal_v2_header *) datafile->journalfile->journal_data;
827
- if (!journal_header) {
828
- datafile = datafile->next;
829
- continue;
830
- }
831
- if (start_time_ut >= journal_header->start_time_ut && start_time_ut <= journal_header->end_time_ut) {
832
-
833
- struct journal_metric_list *uuid_list = (struct journal_metric_list *)((uint8_t *) journal_header + journal_header->metric_offset);
834
-
835
- struct journal_metric_list *uuid_entry = bsearch(
836
- &page_index->id,
837
- uuid_list,
838
- (size_t)journal_header->metric_count,
839
- sizeof(struct journal_metric_list),
840
- journal_metric_uuid_compare);
841
-
842
- uint32_t delta_start_time = (start_time_ut - journal_header->start_time_ut) / USEC_PER_SEC;
843
- uint32_t delta_end_time = (end_time_ut - journal_header->start_time_ut) / USEC_PER_SEC;
844
-
845
- if (uuid_entry && ((delta_start_time >= uuid_entry->delta_start && delta_start_time <= uuid_entry->delta_end))) {
846
-
847
- struct journal_page_header *page_list_header = (struct journal_page_header *) ((uint8_t *) journal_header + uuid_entry->page_offset);
848
- struct rrdeng_page_descr *descr = add_pages_from_timerange(
849
- page_list_header,
850
- delta_start_time,
851
- delta_end_time,
852
- journal_header->start_time_ut,
853
- page_index,
854
- (void *)((uint8_t *)journal_header + journal_header->extent_offset),
855
- datafile,
856
- cache_pages);
857
-
858
- uv_rwlock_rdunlock(&ctx->datafiles.rwlock);
859
- return descr;
860
- }
861
- }
862
- datafile = datafile->next;
863
- }
864
-
865
- uv_rwlock_rdunlock(&ctx->datafiles.rwlock);
866
- return NULL;
561
+ return (point_in_time >= descr->start_time_ut && point_in_time <= descr->end_time_ut);
562
}
563
564
/* The caller must hold the page index lock */
870
-static inline struct rrdeng_page_descr *find_first_page_in_time_range(
871
- struct pg_cache_page_index *page_index,
872
- usec_t start_time_ut,
873
- usec_t end_time_ut,
874
- uint32_t cache_pages)
565
+static inline struct rrdeng_page_descr *
566
+ find_first_page_in_time_range(struct pg_cache_page_index *page_index, usec_t start_time, usec_t end_time)
567
{
876
- struct rrdeng_page_descr *descr= NULL;
877
-
568
+ struct rrdeng_page_descr *descr = NULL;
569
Pvoid_t *PValue;
570
Word_t Index;
571
881
- Index = (Word_t) (start_time_ut / USEC_PER_SEC);
572
+ Index = (Word_t)(start_time / USEC_PER_SEC);
573
PValue = JudyLLast(page_index->JudyL_array, &Index, PJE0);
574
if (likely(NULL != PValue)) {
575
descr = *PValue;
885
- if (is_page_in_time_range(descr, start_time_ut, end_time_ut)) {
886
- update_journal_access_time(NULL, page_index, descr);
576
+ if (is_page_in_time_range(descr, start_time, end_time)) {
577
return descr;
578
}
579
}
580
891
- descr = populate_page_index(page_index, start_time_ut, end_time_ut, cache_pages);
892
- if (descr)
893
- return descr;
894
-
895
- Index = (Word_t) (start_time_ut / USEC_PER_SEC);
581
+ Index = (Word_t)(start_time / USEC_PER_SEC);
582
PValue = JudyLFirst(page_index->JudyL_array, &Index, PJE0);
583
if (likely(NULL != PValue)) {
584
descr = *PValue;
899
- if (is_page_in_time_range(descr, start_time_ut, end_time_ut)) {
900
- update_journal_access_time(NULL, page_index, descr);
585
+ if (is_page_in_time_range(descr, start_time, end_time)) {
586
return descr;
587
}
588
}
@@ -953,13 +638,9 @@ void pg_cache_update_metric_times(struct pg_cache_page_index *page_index)
638
page_index->latest_time_ut = latest_time;
639
}
640
956
-
641
/* If index is NULL lookup by UUID (descr->id) */
958
-struct rrdeng_page_descr *pg_cache_insert(
959
- struct rrdengine_instance *ctx,
960
- struct pg_cache_page_index *index,
961
- struct rrdeng_page_descr *descr,
962
- bool lock_and_count)
642
+void pg_cache_insert(struct rrdengine_instance *ctx, struct pg_cache_page_index *index,
643
+ struct rrdeng_page_descr *descr)
644
{
645
struct page_cache *pg_cache = &ctx->pg_cache;
646
Pvoid_t *PValue;
@@ -988,34 +669,44 @@ struct rrdeng_page_descr *pg_cache_insert(
669
page_index = index;
670
}
671
991
- if (lock_and_count)
992
- uv_rwlock_wrlock(&page_index->lock);
993
-
672
+ uv_rwlock_wrlock(&page_index->lock);
673
PValue = JudyLIns(&page_index->JudyL_array, (Word_t)(descr->start_time_ut / USEC_PER_SEC), PJE0);
995
- fatal_assert(NULL != PValue);
996
-
997
- if (unlikely(*PValue) && !lock_and_count)
998
- return *PValue;
999
-
674
*PValue = descr;
1001
- if (lock_and_count)
1002
- ++page_index->page_count;
1003
-
675
+ ++page_index->page_count;
676
pg_cache_add_new_metric_time(page_index, descr);
1005
-
1006
- if (lock_and_count)
1007
- uv_rwlock_wrunlock(&page_index->lock);
677
+ uv_rwlock_wrunlock(&page_index->lock);
678
679
uv_rwlock_wrlock(&pg_cache->pg_cache_rwlock);
1010
- if (lock_and_count) {
1011
- ++ctx->stats.pg_cache_insertions;
1012
- ++pg_cache->page_descriptors;
1013
- }
1014
- if (is_descr_journal_v2(descr))
1015
- ++pg_cache->active_descriptors;
680
+ ++ctx->stats.pg_cache_insertions;
681
+ ++pg_cache->page_descriptors;
682
uv_rwlock_wrunlock(&pg_cache->pg_cache_rwlock);
683
+}
684
1018
- return descr;
685
+usec_t pg_cache_oldest_time_in_range(struct rrdengine_instance *ctx, uuid_t *id, usec_t start_time_ut, usec_t end_time_ut)
686
+{
687
+ struct page_cache *pg_cache = &ctx->pg_cache;
688
+ struct rrdeng_page_descr *descr = NULL;
689
+ Pvoid_t *PValue;
690
+ struct pg_cache_page_index *page_index = NULL;
691
+
692
+ uv_rwlock_rdlock(&pg_cache->metrics_index.lock);
693
+ PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, id, sizeof(uuid_t));
694
+ if (likely(NULL != PValue)) {
695
+ page_index = *PValue;
696
+ }
697
+ uv_rwlock_rdunlock(&pg_cache->metrics_index.lock);
698
+ if (NULL == PValue) {
699
+ return INVALID_TIME;
700
+ }
701
+
702
+ uv_rwlock_rdlock(&page_index->lock);
703
+ descr = find_first_page_in_time_range(page_index, start_time_ut, end_time_ut);
704
+ if (NULL == descr) {
705
+ uv_rwlock_rdunlock(&page_index->lock);
706
+ return INVALID_TIME;
707
+ }
708
+ uv_rwlock_rdunlock(&page_index->lock);
709
+ return descr->start_time_ut;
710
}
711
712
/**
@@ -1067,11 +758,8 @@ void pg_cache_get_filtered_info_prev(struct rrdengine_instance *ctx, struct pg_c
758
* 2. It did not succeed to get a reference.
759
* 3. It did not succeed to reserve a spot in the page cache.
760
*/
1070
-struct rrdeng_page_descr *pg_cache_lookup_unpopulated_and_lock(
1071
- struct rrdengine_instance *ctx,
1072
- uuid_t(*id),
1073
- usec_t start_time_ut,
1074
- struct pg_alignment *alignment)
761
+struct rrdeng_page_descr *pg_cache_lookup_unpopulated_and_lock(struct rrdengine_instance *ctx, uuid_t *id,
762
+ usec_t start_time_ut)
763
{
764
struct page_cache *pg_cache = &ctx->pg_cache;
765
struct rrdeng_page_descr *descr = NULL;
@@ -1088,11 +776,6 @@ struct rrdeng_page_descr *pg_cache_lookup_unpopulated_and_lock(
776
}
777
uv_rwlock_rdunlock(&pg_cache->metrics_index.lock);
778
1091
- if (page_index && page_index->alignment && alignment && page_index->alignment != alignment) {
1092
- if (pg_cache->populated_pages >= pg_cache_warn_limit(ctx))
1093
- return NULL;
1094
- }
1095
-
779
if ((NULL == PValue) || !pg_cache_try_reserve_pages(ctx, 1)) {
780
/* Failed to find page or failed to reserve a spot in the cache */
781
return NULL;
@@ -1172,7 +855,7 @@ unsigned pg_cache_preload(struct rrdengine_instance *ctx, uuid_t *id, usec_t sta
855
}
856
857
uv_rwlock_rdlock(&page_index->lock);
1175
- descr = find_first_page_in_time_range(page_index, start_time_ut, end_time_ut, PAGE_CACHE_MAX_PRELOAD_PAGES);
858
+ descr = find_first_page_in_time_range(page_index, start_time_ut, end_time_ut);
859
if (NULL == descr) {
860
uv_rwlock_rdunlock(&page_index->lock);
861
debug(D_RRDENGINE, "%s: No page was found to attempt preload.", __func__);
@@ -1186,18 +869,12 @@ unsigned pg_cache_preload(struct rrdengine_instance *ctx, uuid_t *id, usec_t sta
869
*page_info_arrayp = mallocz(page_info_array_max_size);
870
}
871
1189
- struct rrdeng_page_descr *last_descr = NULL;
872
for (count = 0, preload_count = 0 ;
873
descr != NULL && is_page_in_time_range(descr, start_time_ut, end_time_ut) ;
874
PValue = JudyLNext(page_index->JudyL_array, &Index, PJE0),
875
descr = unlikely(NULL == PValue) ? NULL : *PValue) {
876
/* Iterate all pages in range */
877
1196
- if (last_descr == descr)
1197
- break;
1198
-
1199
- last_descr = descr;
1200
-
878
if (unlikely(0 == descr->page_length))
879
continue;
880
if (page_info_arrayp) {
@@ -1230,6 +907,7 @@ unsigned pg_cache_preload(struct rrdengine_instance *ctx, uuid_t *id, usec_t sta
907
}
908
}
909
rrdeng_page_descr_mutex_unlock(ctx, descr);
910
+
911
}
912
uv_rwlock_rdunlock(&page_index->lock);
913
@@ -1255,8 +933,7 @@ unsigned pg_cache_preload(struct rrdengine_instance *ctx, uuid_t *id, usec_t sta
933
if (NULL == next) {
934
continue;
935
}
1258
- if ((descr->extent && descr->extent == next->extent) ||
1259
- ((descr->extent_entry && descr->extent_entry == next->extent_entry))) {
936
+ if (descr->extent == next->extent) {
937
/* same extent, consolidate */
938
if (!pg_cache_try_reserve_pages(ctx, 1)) {
939
failed_to_reserve = 1;
@@ -1292,13 +969,13 @@ unsigned pg_cache_preload(struct rrdengine_instance *ctx, uuid_t *id, usec_t sta
969
}
970
971
/*
1295
- * Searches for the first page between start_time and end_time and gets a reference.
1296
- * start_time and end_time are inclusive.
972
+ * Searches for a page and gets a reference.
973
+ * When point_in_time is INVALID_TIME get any page.
974
* If index is NULL lookup by UUID (id).
975
*/
976
struct rrdeng_page_descr *
1300
-pg_cache_lookup_next(struct rrdengine_instance *ctx, struct pg_cache_page_index *index, uuid_t *id,
1301
- usec_t start_time_ut, usec_t end_time_ut)
977
+ pg_cache_lookup(struct rrdengine_instance *ctx, struct pg_cache_page_index *index, uuid_t *id,
978
+ usec_t point_in_time_ut)
979
{
980
struct page_cache *pg_cache = &ctx->pg_cache;
981
struct rrdeng_page_descr *descr = NULL;
@@ -1306,6 +983,7 @@ pg_cache_lookup_next(struct rrdengine_instance *ctx, struct pg_cache_page_index
983
unsigned long flags;
984
Pvoid_t *PValue;
985
struct pg_cache_page_index *page_index = NULL;
986
+ Word_t Index;
987
uint8_t page_not_in_cache;
988
989
if (unlikely(NULL == index)) {
@@ -1325,13 +1003,17 @@ pg_cache_lookup_next(struct rrdengine_instance *ctx, struct pg_cache_page_index
1003
1004
page_not_in_cache = 0;
1005
uv_rwlock_rdlock(&page_index->lock);
1328
- int retry_count = 0;
1006
while (1) {
1330
- descr = find_first_page_in_time_range(page_index, start_time_ut, end_time_ut, PAGE_CACHE_MAX_PRELOAD_PAGES);
1331
- if (NULL == descr || 0 == descr->page_length || retry_count == default_rrdeng_page_fetch_retries) {
1007
+ Index = (Word_t)(point_in_time_ut / USEC_PER_SEC);
1008
+ PValue = JudyLLast(page_index->JudyL_array, &Index, PJE0);
1009
+ if (likely(NULL != PValue)) {
1010
+ descr = *PValue;
1011
+ }
1012
+ if (NULL == PValue ||
1013
+ 0 == descr->page_length ||
1014
+ (INVALID_TIME != point_in_time_ut &&
1015
+ !is_point_in_time_in_page(descr, point_in_time_ut))) {
1016
/* non-empty page not found */
1333
- if (retry_count == default_rrdeng_page_fetch_retries)
1334
- error_report("Page cache timeout while waiting for page %p : returning FAIL", descr);
1017
uv_rwlock_rdunlock(&page_index->lock);
1018
1019
pg_cache_release_pages(ctx, 1);
@@ -1340,22 +1022,108 @@ pg_cache_lookup_next(struct rrdengine_instance *ctx, struct pg_cache_page_index
1022
rrdeng_page_descr_mutex_lock(ctx, descr);
1023
pg_cache_descr = descr->pg_cache_descr;
1024
flags = pg_cache_descr->flags;
1343
-
1344
- if ((flags & RRD_PAGE_INVALID)) {
1345
- bool can_drop_page = pg_cache_try_get_unsafe(descr, 1);
1025
+ if ((flags & RRD_PAGE_POPULATED) && pg_cache_try_get_unsafe(descr, 0)) {
1026
+ /* success */
1027
rrdeng_page_descr_mutex_unlock(ctx, descr);
1028
+ debug(D_RRDENGINE, "%s: Page was found in memory.", __func__);
1029
+ break;
1030
+ }
1031
+ if (!(flags & RRD_PAGE_POPULATED) && pg_cache_try_get_unsafe(descr, 1)) {
1032
+ struct rrdeng_cmd cmd;
1033
1034
uv_rwlock_rdunlock(&page_index->lock);
1349
- pg_cache_release_pages(ctx, 1);
1035
1351
- if (likely(can_drop_page)) {
1352
- info("Dropping invalid page descr=%lu - pg_cache=%lu - Ref=%u", descr->pg_cache_descr_state,
1353
- descr->pg_cache_descr->flags, descr->pg_cache_descr->refcnt);
1354
- pg_cache_punch_hole(ctx, descr, 0, 1, NULL, false);
1036
+ cmd.opcode = RRDENG_READ_PAGE;
1037
+ cmd.read_page.page_cache_descr = descr;
1038
+ rrdeng_enq_cmd(&ctx->worker_config, &cmd);
1039
+
1040
+ debug(D_RRDENGINE, "%s: Waiting for page to be asynchronously read from disk:", __func__);
1041
+ if(unlikely(debug_flags & D_RRDENGINE))
1042
+ print_page_cache_descr(descr, "", true);
1043
+ while (!(pg_cache_descr->flags & RRD_PAGE_POPULATED)) {
1044
+ pg_cache_wait_event_unsafe(descr);
1045
}
1046
+ /* success */
1047
+ /* Downgrade exclusive reference to allow other readers */
1048
+ pg_cache_descr->flags &= ~RRD_PAGE_LOCKED;
1049
+ pg_cache_wake_up_waiters_unsafe(descr);
1050
+ rrdeng_page_descr_mutex_unlock(ctx, descr);
1051
+ rrd_stat_atomic_add(&ctx->stats.pg_cache_misses, 1);
1052
+ return descr;
1053
+ }
1054
+ uv_rwlock_rdunlock(&page_index->lock);
1055
+ debug(D_RRDENGINE, "%s: Waiting for page to be unlocked:", __func__);
1056
+ if(unlikely(debug_flags & D_RRDENGINE))
1057
+ print_page_cache_descr(descr, "", true);
1058
+ if (!(flags & RRD_PAGE_POPULATED))
1059
+ page_not_in_cache = 1;
1060
+ pg_cache_wait_event_unsafe(descr);
1061
+ rrdeng_page_descr_mutex_unlock(ctx, descr);
1062
+
1063
+ /* reset scan to find again */
1064
+ uv_rwlock_rdlock(&page_index->lock);
1065
+ }
1066
+ uv_rwlock_rdunlock(&page_index->lock);
1067
+
1068
+ if (!(flags & RRD_PAGE_DIRTY))
1069
+ pg_cache_replaceQ_set_hot(ctx, descr);
1070
+ pg_cache_release_pages(ctx, 1);
1071
+ if (page_not_in_cache)
1072
+ rrd_stat_atomic_add(&ctx->stats.pg_cache_misses, 1);
1073
+ else
1074
+ rrd_stat_atomic_add(&ctx->stats.pg_cache_hits, 1);
1075
+ return descr;
1076
+}
1077
+
1078
+/*
1079
+ * Searches for the first page between start_time and end_time and gets a reference.
1080
+ * start_time and end_time are inclusive.
1081
+ * If index is NULL lookup by UUID (id).
1082
+ */
1083
+struct rrdeng_page_descr *
1084
+pg_cache_lookup_next(struct rrdengine_instance *ctx, struct pg_cache_page_index *index, uuid_t *id,
1085
+ usec_t start_time_ut, usec_t end_time_ut)
1086
+{
1087
+ struct page_cache *pg_cache = &ctx->pg_cache;
1088
+ struct rrdeng_page_descr *descr = NULL;
1089
+ struct page_cache_descr *pg_cache_descr = NULL;
1090
+ unsigned long flags;
1091
+ Pvoid_t *PValue;
1092
+ struct pg_cache_page_index *page_index = NULL;
1093
+ uint8_t page_not_in_cache;
1094
+
1095
+ if (unlikely(NULL == index)) {
1096
+ uv_rwlock_rdlock(&pg_cache->metrics_index.lock);
1097
+ PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, id, sizeof(uuid_t));
1098
+ if (likely(NULL != PValue)) {
1099
+ page_index = *PValue;
1100
+ }
1101
+ uv_rwlock_rdunlock(&pg_cache->metrics_index.lock);
1102
+ if (NULL == PValue) {
1103
return NULL;
1104
}
1105
+ } else {
1106
+ page_index = index;
1107
+ }
1108
+ pg_cache_reserve_pages(ctx, 1);
1109
1110
+ page_not_in_cache = 0;
1111
+ uv_rwlock_rdlock(&page_index->lock);
1112
+ int retry_count = 0;
1113
+ while (1) {
1114
+ descr = find_first_page_in_time_range(page_index, start_time_ut, end_time_ut);
1115
+ if (NULL == descr || 0 == descr->page_length || retry_count == default_rrdeng_page_fetch_retries) {
1116
+ /* non-empty page not found */
1117
+ if (retry_count == default_rrdeng_page_fetch_retries)
1118
+ error_report("Page cache timeout while waiting for page %p : returning FAIL", descr);
1119
+ uv_rwlock_rdunlock(&page_index->lock);
1120
+
1121
+ pg_cache_release_pages(ctx, 1);
1122
+ return NULL;
1123
+ }
1124
+ rrdeng_page_descr_mutex_lock(ctx, descr);
1125
+ pg_cache_descr = descr->pg_cache_descr;
1126
+ flags = pg_cache_descr->flags;
1127
if ((flags & RRD_PAGE_POPULATED) && pg_cache_try_get_unsafe(descr, 0)) {
1128
/* success */
1129
rrdeng_page_descr_mutex_unlock(ctx, descr);
@@ -1397,6 +1165,7 @@ pg_cache_lookup_next(struct rrdengine_instance *ctx, struct pg_cache_page_index
1165
++retry_count;
1166
}
1167
rrdeng_page_descr_mutex_unlock(ctx, descr);
1168
+
1169
/* reset scan to find again */
1170
uv_rwlock_rdlock(&page_index->lock);
1171
}
@@ -1417,9 +1186,9 @@ struct pg_cache_page_index *create_page_index(uuid_t *id, struct rrdengine_insta
1186
struct pg_cache_page_index *page_index;
1187
1188
page_index = mallocz(sizeof(*page_index));
1420
- fatal_assert(0 == uv_rwlock_init(&page_index->lock));
1189
page_index->JudyL_array = (Pvoid_t) NULL;
1190
uuid_copy(page_index->id, *id);
1191
+ fatal_assert(0 == uv_rwlock_init(&page_index->lock));
1192
page_index->oldest_time_ut = INVALID_TIME;
1193
page_index->latest_time_ut = INVALID_TIME;
1194
page_index->prev = NULL;
@@ -1466,15 +1235,12 @@ void init_page_cache(struct rrdengine_instance *ctx)
1235
struct page_cache *pg_cache = &ctx->pg_cache;
1236
1237
pg_cache->page_descriptors = 0;
1469
- pg_cache->active_descriptors = 0;
1238
pg_cache->populated_pages = 0;
1239
fatal_assert(0 == uv_rwlock_init(&pg_cache->pg_cache_rwlock));
1240
1241
init_metrics_index(ctx);
1242
init_replaceQ(ctx);
1243
init_committed_page_index(ctx);
1476
-
1477
- fatal_assert(0 == uv_rwlock_init(&pg_cache->v2_lock));
1244
}
1245
1246
void free_page_cache(struct rrdengine_instance *ctx)
@@ -1538,4 +1304,3 @@ void free_page_cache(struct rrdengine_instance *ctx)
1304
fatal_assert(NULL == pg_cache->metrics_index.JudyHS_array);
1305
info("Freed %lu bytes of memory from page cache.", pages_dirty_index_bytes + pages_index_bytes + metrics_index_bytes);
1306
}
1541
-
database/engine/pagecache.h
+12
-51
@@ -20,18 +20,6 @@ struct rrdeng_page_descr;
20
#define RRD_PAGE_READ_PENDING (1LU << 2)
21
#define RRD_PAGE_WRITE_PENDING (1LU << 3)
22
#define RRD_PAGE_POPULATED (1LU << 4)
23
-#define RRD_PAGE_INVALID (1LU << 5)
24
-
25
-#ifdef NETDATA_INTERNAL_CHECKS
26
-struct pg_cache_waiter {
27
- const char *function;
28
- size_t line;
29
- pid_t tid;
30
-
31
- struct pg_cache_waiter *next;
32
- struct pg_cache_waiter *prev;
33
-};
34
-#endif
23
24
struct page_cache_descr {
25
struct rrdeng_page_descr *descr; /* parent descriptor */
@@ -41,12 +29,6 @@ struct page_cache_descr {
29
struct page_cache_descr *next; /* LRU */
30
31
unsigned refcnt;
44
-
45
-#ifdef NETDATA_INTERNAL_CHECKS
46
- struct pg_cache_waiter *wait_list;
47
- struct pg_cache_waiter owner;
48
-#endif
49
-
32
uv_mutex_t mutex; /* always take it after the page cache lock or after the commit lock */
33
uv_cond_t cond;
34
unsigned waiters;
@@ -67,7 +49,6 @@ struct page_cache_descr {
49
* -----------------------------+------------+------------+-----------|
50
* number of descriptor users | DESTROY | LOCKED | ALLOCATED |
51
*/
70
-
52
struct rrdeng_page_descr {
53
uuid_t *id; /* never changes */
54
struct extent_info *extent;
@@ -84,8 +65,6 @@ struct rrdeng_page_descr {
65
uint32_t update_every_s:24;
66
uint8_t type;
67
uint32_t page_length;
87
- uv_file file; // This is the datafile this descriptor belongs
88
- void *extent_entry;
68
};
69
70
#define PAGE_INFO_SCRATCH_SZ (8)
@@ -100,7 +79,7 @@ struct rrdeng_page_info {
79
/* returns 1 for success, 0 for failure */
80
typedef int pg_cache_page_info_filter_t(struct rrdeng_page_descr *);
81
103
-#define PAGE_CACHE_MAX_PRELOAD_PAGES (64)
82
+#define PAGE_CACHE_MAX_PRELOAD_PAGES (256)
83
84
struct pg_alignment {
85
uint32_t page_length;
@@ -175,30 +154,18 @@ struct pg_cache_replaceQ {
154
155
struct page_cache { /* TODO: add statistics */
156
uv_rwlock_t pg_cache_rwlock; /* page cache lock */
178
- uv_rwlock_t v2_lock;
157
158
struct pg_cache_metrics_index metrics_index;
159
struct pg_cache_committed_page_index committed_page_index;
160
struct pg_cache_replaceQ replaceQ;
161
162
unsigned page_descriptors;
185
- unsigned active_descriptors;
163
unsigned populated_pages;
164
};
165
166
void pg_cache_wake_up_waiters_unsafe(struct rrdeng_page_descr *descr);
167
void pg_cache_wake_up_waiters(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr);
191
-
192
-#ifdef NETDATA_INTERNAL_CHECKS
193
-#define pg_cache_wait_event_unsafe(descr) pg_cache_wait_event_unsafe_with_trace(descr, __FUNCTION__, __LINE__)
194
-void pg_cache_wait_event_unsafe_with_trace(struct rrdeng_page_descr *descr, const char *function, size_t line);
195
-#define pg_cache_timedwait_event_unsafe(descr, timeout_sec) pg_cache_timedwait_event_unsafe_with_trace(descr, timeout_sec, __FUNCTION__, __LINE__)
196
-int pg_cache_timedwait_event_unsafe_with_trace(struct rrdeng_page_descr *descr, uint64_t timeout_sec, const char *function, size_t line);
197
-#else
168
void pg_cache_wait_event_unsafe(struct rrdeng_page_descr *descr);
199
-int pg_cache_timedwait_event_unsafe(struct rrdeng_page_descr *descr, uint64_t timeout_sec);
200
-#endif
201
-
169
unsigned long pg_cache_wait_event(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr);
170
void pg_cache_replaceQ_insert(struct rrdengine_instance *ctx,
171
struct rrdeng_page_descr *descr);
@@ -210,27 +177,23 @@ struct rrdeng_page_descr *pg_cache_create_descr(void);
177
int pg_cache_try_get_unsafe(struct rrdeng_page_descr *descr, int exclusive_access);
178
void pg_cache_put_unsafe(struct rrdeng_page_descr *descr);
179
void pg_cache_put(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr);
213
-struct rrdeng_page_descr *pg_cache_insert(
214
- struct rrdengine_instance *ctx,
215
- struct pg_cache_page_index *index,
216
- struct rrdeng_page_descr *descr,
217
- bool lock_and_count);
218
-
219
-uint8_t pg_cache_punch_hole(
220
- struct rrdengine_instance *ctx,
221
- struct rrdeng_page_descr *descr,
222
- uint8_t remove_dirty,
223
- uint8_t is_exclusive_holder,
224
- uuid_t(*metric_id),
225
- bool update_page_duration);
226
-
180
+void pg_cache_insert(struct rrdengine_instance *ctx, struct pg_cache_page_index *index,
181
+ struct rrdeng_page_descr *descr);
182
+uint8_t pg_cache_punch_hole(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr,
183
+ uint8_t remove_dirty, uint8_t is_exclusive_holder, uuid_t *metric_id);
184
+usec_t pg_cache_oldest_time_in_range(struct rrdengine_instance *ctx, uuid_t *id,
185
+ usec_t start_time_ut, usec_t end_time_ut);
186
void pg_cache_get_filtered_info_prev(struct rrdengine_instance *ctx, struct pg_cache_page_index *page_index,
187
usec_t point_in_time_ut, pg_cache_page_info_filter_t *filter,
188
struct rrdeng_page_info *page_info);
230
-struct rrdeng_page_descr *pg_cache_lookup_unpopulated_and_lock(struct rrdengine_instance *ctx, uuid_t(*id), usec_t start_time_ut, struct pg_alignment *alignment);
189
+struct rrdeng_page_descr *pg_cache_lookup_unpopulated_and_lock(struct rrdengine_instance *ctx, uuid_t *id,
190
+ usec_t start_time_ut);
191
unsigned
192
pg_cache_preload(struct rrdengine_instance *ctx, uuid_t *id, usec_t start_time_ut, usec_t end_time_ut,
193
struct rrdeng_page_info **page_info_arrayp, struct pg_cache_page_index **ret_page_indexp);
194
+struct rrdeng_page_descr *
195
+ pg_cache_lookup(struct rrdengine_instance *ctx, struct pg_cache_page_index *index, uuid_t *id,
196
+ usec_t point_in_time_ut);
197
struct rrdeng_page_descr *
198
pg_cache_lookup_next(struct rrdengine_instance *ctx, struct pg_cache_page_index *index, uuid_t *id,
199
usec_t start_time_ut, usec_t end_time_ut);
@@ -241,7 +204,6 @@ void pg_cache_add_new_metric_time(struct pg_cache_page_index *page_index, struct
204
void pg_cache_update_metric_times(struct pg_cache_page_index *page_index);
205
unsigned long pg_cache_hard_limit(struct rrdengine_instance *ctx);
206
unsigned long pg_cache_soft_limit(struct rrdengine_instance *ctx);
244
-unsigned long pg_cache_warn_limit(struct rrdengine_instance *ctx);
207
unsigned long pg_cache_committed_hard_limit(struct rrdengine_instance *ctx);
208
209
void rrdeng_page_descr_aral_go_singlethreaded(void);
@@ -251,7 +213,6 @@ void rrdeng_page_descr_use_mmap(void);
213
bool rrdeng_page_descr_is_mmap(void);
214
struct rrdeng_page_descr *rrdeng_page_descr_mallocz(void);
215
void rrdeng_page_descr_freez(struct rrdeng_page_descr *descr);
254
-void mark_journalfile_descriptor( struct page_cache *pg_cache, struct rrdengine_journalfile *journalfile, uint32_t page_offset, uint32_t Index);
216
217
static inline void
218
pg_cache_atomic_get_pg_info(struct rrdeng_page_descr *descr, usec_t *end_time_ut_p, uint32_t *page_lengthp)
database/engine/rrdengine.c
+257
-313
@@ -20,7 +20,7 @@ void *dbengine_page_alloc() {
20
if (unlikely(db_engine_use_malloc))
21
page = mallocz(RRDENG_BLOCK_SIZE);
22
else {
23
- page = netdata_mmap(NULL, RRDENG_BLOCK_SIZE, MAP_PRIVATE, enable_ksm, false);
23
+ page = netdata_mmap(NULL, RRDENG_BLOCK_SIZE, MAP_PRIVATE, enable_ksm);
24
if(!page) fatal("Cannot allocate dbengine page cache page, with mmap()");
25
}
26
return page;
@@ -60,6 +60,181 @@ static void sanity_check(void)
60
BUILD_BUG_ON(sizeof(((struct rrdeng_page_info *)0)->scratch) < 2 * sizeof(uint32_t));
61
}
62
63
+/* always inserts into tail */
64
+static inline void xt_cache_replaceQ_insert(struct rrdengine_worker_config* wc,
65
+ struct extent_cache_element *xt_cache_elem)
66
+{
67
+ struct extent_cache *xt_cache = &wc->xt_cache;
68
+
69
+ xt_cache_elem->prev = NULL;
70
+ xt_cache_elem->next = NULL;
71
+
72
+ if (likely(NULL != xt_cache->replaceQ_tail)) {
73
+ xt_cache_elem->prev = xt_cache->replaceQ_tail;
74
+ xt_cache->replaceQ_tail->next = xt_cache_elem;
75
+ }
76
+ if (unlikely(NULL == xt_cache->replaceQ_head)) {
77
+ xt_cache->replaceQ_head = xt_cache_elem;
78
+ }
79
+ xt_cache->replaceQ_tail = xt_cache_elem;
80
+}
81
+
82
+static inline void xt_cache_replaceQ_delete(struct rrdengine_worker_config* wc,
83
+ struct extent_cache_element *xt_cache_elem)
84
+{
85
+ struct extent_cache *xt_cache = &wc->xt_cache;
86
+ struct extent_cache_element *prev, *next;
87
+
88
+ prev = xt_cache_elem->prev;
89
+ next = xt_cache_elem->next;
90
+
91
+ if (likely(NULL != prev)) {
92
+ prev->next = next;
93
+ }
94
+ if (likely(NULL != next)) {
95
+ next->prev = prev;
96
+ }
97
+ if (unlikely(xt_cache_elem == xt_cache->replaceQ_head)) {
98
+ xt_cache->replaceQ_head = next;
99
+ }
100
+ if (unlikely(xt_cache_elem == xt_cache->replaceQ_tail)) {
101
+ xt_cache->replaceQ_tail = prev;
102
+ }
103
+ xt_cache_elem->prev = xt_cache_elem->next = NULL;
104
+}
105
+
106
+static inline void xt_cache_replaceQ_set_hot(struct rrdengine_worker_config* wc,
107
+ struct extent_cache_element *xt_cache_elem)
108
+{
109
+ xt_cache_replaceQ_delete(wc, xt_cache_elem);
110
+ xt_cache_replaceQ_insert(wc, xt_cache_elem);
111
+}
112
+
113
+/* Returns the index of the cached extent if it was successfully inserted in the extent cache, otherwise -1 */
114
+static int try_insert_into_xt_cache(struct rrdengine_worker_config* wc, struct extent_info *extent)
115
+{
116
+ struct extent_cache *xt_cache = &wc->xt_cache;
117
+ struct extent_cache_element *xt_cache_elem;
118
+ unsigned idx;
119
+ int ret;
120
+
121
+ ret = find_first_zero(xt_cache->allocation_bitmap);
122
+ if (-1 == ret || ret >= MAX_CACHED_EXTENTS) {
123
+ for (xt_cache_elem = xt_cache->replaceQ_head ; NULL != xt_cache_elem ; xt_cache_elem = xt_cache_elem->next) {
124
+ idx = xt_cache_elem - xt_cache->extent_array;
125
+ if (!check_bit(xt_cache->inflight_bitmap, idx)) {
126
+ xt_cache_replaceQ_delete(wc, xt_cache_elem);
127
+ break;
128
+ }
129
+ }
130
+ if (NULL == xt_cache_elem)
131
+ return -1;
132
+ } else {
133
+ idx = (unsigned)ret;
134
+ xt_cache_elem = &xt_cache->extent_array[idx];
135
+ }
136
+ xt_cache_elem->extent = extent;
137
+ xt_cache_elem->fileno = extent->datafile->fileno;
138
+ xt_cache_elem->inflight_io_descr = NULL;
139
+ xt_cache_replaceQ_insert(wc, xt_cache_elem);
140
+ modify_bit(&xt_cache->allocation_bitmap, idx, 1);
141
+
142
+ return (int)idx;
143
+}
144
+
145
+/**
146
+ * Returns 0 if the cached extent was found in the extent cache, 1 otherwise.
147
+ * Sets *idx to point to the position of the extent inside the cache.
148
+ **/
149
+static uint8_t lookup_in_xt_cache(struct rrdengine_worker_config* wc, struct extent_info *extent, unsigned *idx)
150
+{
151
+ struct extent_cache *xt_cache = &wc->xt_cache;
152
+ struct extent_cache_element *xt_cache_elem;
153
+ unsigned i;
154
+
155
+ for (i = 0 ; i < MAX_CACHED_EXTENTS ; ++i) {
156
+ xt_cache_elem = &xt_cache->extent_array[i];
157
+ if (check_bit(xt_cache->allocation_bitmap, i) && xt_cache_elem->extent == extent &&
158
+ xt_cache_elem->fileno == extent->datafile->fileno) {
159
+ *idx = i;
160
+ return 0;
161
+ }
162
+ }
163
+ return 1;
164
+}
165
+
166
+#if 0 /* disabled code */
167
+static void delete_from_xt_cache(struct rrdengine_worker_config* wc, unsigned idx)
168
+{
169
+ struct extent_cache *xt_cache = &wc->xt_cache;
170
+ struct extent_cache_element *xt_cache_elem;
171
+
172
+ xt_cache_elem = &xt_cache->extent_array[idx];
173
+ xt_cache_replaceQ_delete(wc, xt_cache_elem);
174
+ xt_cache_elem->extent = NULL;
175
+ modify_bit(&wc->xt_cache.allocation_bitmap, idx, 0); /* invalidate it */
176
+ modify_bit(&wc->xt_cache.inflight_bitmap, idx, 0); /* not in-flight anymore */
177
+}
178
+#endif
179
+
180
+void enqueue_inflight_read_to_xt_cache(struct rrdengine_worker_config* wc, unsigned idx,
181
+ struct extent_io_descriptor *xt_io_descr)
182
+{
183
+ struct extent_cache *xt_cache = &wc->xt_cache;
184
+ struct extent_cache_element *xt_cache_elem;
185
+ struct extent_io_descriptor *old_next;
186
+
187
+ xt_cache_elem = &xt_cache->extent_array[idx];
188
+ old_next = xt_cache_elem->inflight_io_descr->next;
189
+ xt_cache_elem->inflight_io_descr->next = xt_io_descr;
190
+ xt_io_descr->next = old_next;
191
+}
192
+
193
+void read_cached_extent_cb(struct rrdengine_worker_config* wc, unsigned idx, struct extent_io_descriptor *xt_io_descr)
194
+{
195
+ unsigned i, j, page_offset;
196
+ struct rrdengine_instance *ctx = wc->ctx;
197
+ struct rrdeng_page_descr *descr;
198
+ struct page_cache_descr *pg_cache_descr;
199
+ void *page;
200
+ struct extent_info *extent = xt_io_descr->descr_array[0]->extent;
201
+
202
+ for (i = 0 ; i < xt_io_descr->descr_count; ++i) {
203
+ page = dbengine_page_alloc();
204
+ descr = xt_io_descr->descr_array[i];
205
+ for (j = 0, page_offset = 0 ; j < extent->number_of_pages ; ++j) {
206
+ /* care, we don't hold the descriptor mutex */
207
+ if (!uuid_compare(*extent->pages[j]->id, *descr->id) &&
208
+ extent->pages[j]->page_length == descr->page_length &&
209
+ extent->pages[j]->start_time_ut == descr->start_time_ut &&
210
+ extent->pages[j]->end_time_ut == descr->end_time_ut) {
211
+ break;
212
+ }
213
+ page_offset += extent->pages[j]->page_length;
214
+
215
+ }
216
+ /* care, we don't hold the descriptor mutex */
217
+ (void) memcpy(page, wc->xt_cache.extent_array[idx].pages + page_offset, descr->page_length);
218
+
219
+ rrdeng_page_descr_mutex_lock(ctx, descr);
220
+ pg_cache_descr = descr->pg_cache_descr;
221
+ pg_cache_descr->page = page;
222
+ pg_cache_descr->flags |= RRD_PAGE_POPULATED;
223
+ pg_cache_descr->flags &= ~RRD_PAGE_READ_PENDING;
224
+ rrdeng_page_descr_mutex_unlock(ctx, descr);
225
+ pg_cache_replaceQ_insert(ctx, descr);
226
+ if (xt_io_descr->release_descr) {
227
+ pg_cache_put(ctx, descr);
228
+ } else {
229
+ debug(D_RRDENGINE, "%s: Waking up waiters.", __func__);
230
+ pg_cache_wake_up_waiters(ctx, descr);
231
+ }
232
+ }
233
+ if (xt_io_descr->completion)
234
+ completion_mark_complete(xt_io_descr->completion);
235
+ freez(xt_io_descr);
236
+}
237
+
238
static void fill_page_with_nulls(void *page, uint32_t page_length, uint8_t type) {
239
switch(type) {
240
case PAGE_METRICS: {
@@ -97,30 +272,11 @@ static void fill_page_with_nulls(void *page, uint32_t page_length, uint8_t type)
272
}
273
}
274
100
-unsigned int getdatafile_fileno(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr)
101
-{
102
- if (descr->extent)
103
- return descr->extent->datafile->fileno;
104
-
105
- uv_rwlock_rdlock(&ctx->datafiles.rwlock);
106
- struct rrdengine_datafile *datafile = ctx->datafiles.first;
107
- while (datafile) {
108
- struct rrdengine_journalfile *journalfile = datafile->journalfile;
109
- if (journalfile->journal_data && datafile->file == descr->file)
110
- break;
111
- datafile = datafile->next;
112
- }
113
- uv_rwlock_rdunlock(&ctx->datafiles.rwlock);
114
-
115
- return datafile ? datafile->fileno : 0;
116
-}
117
-
275
static void do_extent_processing (struct rrdengine_worker_config *wc, struct extent_io_descriptor *xt_io_descr, bool read_failed)
276
{
277
struct rrdengine_instance *ctx = wc->ctx;
121
- struct rrdeng_page_descr *descr = NULL;
278
+ struct rrdeng_page_descr *descr;
279
struct page_cache_descr *pg_cache_descr;
123
- struct page_cache *pg_cache = &ctx->pg_cache;
280
int ret;
281
unsigned i, j, count;
282
void *page, *uncompressed_buf = NULL;
@@ -138,29 +294,33 @@ static void do_extent_processing (struct rrdengine_worker_config *wc, struct ext
294
trailer = xt_io_descr->buf + xt_io_descr->bytes - sizeof(*trailer);
295
296
if (unlikely(read_failed)) {
297
+ struct rrdengine_datafile *datafile = xt_io_descr->descr_array[0]->extent->datafile;
298
+
299
++ctx->stats.io_errors;
300
rrd_stat_atomic_add(&global_io_errors, 1);
301
have_read_error = 1;
144
- error("%s: uv_fs_read - extent at offset %"PRIu64"(%u) in datafile %u.", __func__, xt_io_descr->pos,
145
- xt_io_descr->bytes, getdatafile_fileno(ctx, xt_io_descr->descr_array[0]));
302
+ error("%s: uv_fs_read - extent at offset %"PRIu64"(%u) in datafile %u-%u.", __func__, xt_io_descr->pos,
303
+ xt_io_descr->bytes, datafile->tier, datafile->fileno);
304
goto after_crc_check;
305
}
306
crc = crc32(0L, Z_NULL, 0);
307
crc = crc32(crc, xt_io_descr->buf, xt_io_descr->bytes - sizeof(*trailer));
308
ret = crc32cmp(trailer->checksum, crc);
309
#ifdef NETDATA_INTERNAL_CHECKS
152
- if(xt_io_descr->descr_array[0]->extent) {
310
+ {
311
struct rrdengine_datafile *datafile = xt_io_descr->descr_array[0]->extent->datafile;
312
debug(D_RRDENGINE, "%s: Extent at offset %"PRIu64"(%u) was read from datafile %u-%u. CRC32 check: %s", __func__,
313
xt_io_descr->pos, xt_io_descr->bytes, datafile->tier, datafile->fileno, ret ? "FAILED" : "SUCCEEDED");
314
}
315
#endif
316
if (unlikely(ret)) {
317
+ struct rrdengine_datafile *datafile = xt_io_descr->descr_array[0]->extent->datafile;
318
+
319
++ctx->stats.io_errors;
320
rrd_stat_atomic_add(&global_io_errors, 1);
321
have_read_error = 1;
162
- error("%s: Extent at offset %"PRIu64"(%u) was read from datafile %u. CRC32 check: FAILED", __func__,
163
- xt_io_descr->pos, xt_io_descr->bytes, getdatafile_fileno(ctx, xt_io_descr->descr_array[0]));
322
+ error("%s: Extent at offset %"PRIu64"(%u) was read from datafile %u-%u. CRC32 check: FAILED", __func__,
323
+ xt_io_descr->pos, xt_io_descr->bytes, datafile->tier, datafile->fileno);
324
}
325
326
after_crc_check:
@@ -177,13 +337,33 @@ after_crc_check:
337
debug(D_RRDENGINE, "LZ4 decompressed %u bytes to %d bytes.", payload_length, ret);
338
/* care, we don't hold the descriptor mutex */
339
}
180
-
181
- uv_rwlock_rdlock(&pg_cache->metrics_index.lock);
182
- Pvoid_t *PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, xt_io_descr->descr_array[0]->id, sizeof(uuid_t));
183
- struct pg_cache_page_index *page_index = likely( NULL != PValue) ? *PValue : NULL;
184
- uv_rwlock_rdunlock(&pg_cache->metrics_index.lock);
185
-
186
- struct pg_alignment *alignment = likely(NULL != page_index) ? page_index->alignment : NULL;
340
+ {
341
+ uint8_t xt_is_cached = 0;
342
+ unsigned xt_idx;
343
+ struct extent_info *extent = xt_io_descr->descr_array[0]->extent;
344
+
345
+ xt_is_cached = !lookup_in_xt_cache(wc, extent, &xt_idx);
346
+ if (xt_is_cached && check_bit(wc->xt_cache.inflight_bitmap, xt_idx)) {
347
+ struct extent_cache *xt_cache = &wc->xt_cache;
348
+ struct extent_cache_element *xt_cache_elem = &xt_cache->extent_array[xt_idx];
349
+ struct extent_io_descriptor *curr, *next;
350
+
351
+ if (have_read_error) {
352
+ memset(xt_cache_elem->pages, 0, sizeof(xt_cache_elem->pages));
353
+ } else if (RRD_NO_COMPRESSION == header->compression_algorithm) {
354
+ (void)memcpy(xt_cache_elem->pages, xt_io_descr->buf + payload_offset, payload_length);
355
+ } else {
356
+ (void)memcpy(xt_cache_elem->pages, uncompressed_buf, uncompressed_payload_length);
357
+ }
358
+ /* complete all connected in-flight read requests */
359
+ for (curr = xt_cache_elem->inflight_io_descr->next ; curr ; curr = next) {
360
+ next = curr->next;
361
+ read_cached_extent_cb(wc, xt_idx, curr);
362
+ }
363
+ xt_cache_elem->inflight_io_descr = NULL;
364
+ modify_bit(&xt_cache->inflight_bitmap, xt_idx, 0); /* not in-flight anymore */
365
+ }
366
+ }
367
368
for (i = 0, page_offset = 0; i < count; page_offset += header->descr[i++].page_length) {
369
uint8_t is_prefetched_page;
@@ -198,13 +378,13 @@ after_crc_check:
378
header->descr[i].start_time_ut == descrj->start_time_ut &&
379
header->descr[i].end_time_ut == descrj->end_time_ut) {
380
descr = descrj;
201
- bitmap256_set_bit(&xt_io_descr->descr_array_wakeup, j, 0);
381
break;
382
}
383
}
384
is_prefetched_page = 0;
385
if (!descr) { /* This extent page has not been requested. Try populating it for locality (best effort). */
207
- descr = pg_cache_lookup_unpopulated_and_lock(ctx, (uuid_t *)header->descr[i].uuid, header->descr[i].start_time_ut, alignment);
386
+ descr = pg_cache_lookup_unpopulated_and_lock(ctx, (uuid_t *)header->descr[i].uuid,
387
+ header->descr[i].start_time_ut);
388
if (!descr)
389
continue; /* Failed to reserve a suitable page */
390
is_prefetched_page = 1;
@@ -233,18 +413,6 @@ after_crc_check:
413
pg_cache_wake_up_waiters(ctx, descr);
414
}
415
}
236
- for (j = 0 ; j < xt_io_descr->descr_count; ++j) {
237
- descr = xt_io_descr->descr_array[j];
238
- if (unlikely(bitmap256_get_bit(&xt_io_descr->descr_array_wakeup, j))) {
239
- rrdeng_page_descr_mutex_lock(ctx, descr);
240
- if (!(descr->pg_cache_descr->flags & RRD_PAGE_POPULATED)) {
241
- descr->pg_cache_descr->flags &= ~RRD_PAGE_READ_PENDING;
242
- descr->pg_cache_descr->flags |= RRD_PAGE_INVALID;
243
- }
244
- rrdeng_page_descr_mutex_unlock(ctx, descr);
245
- pg_cache_wake_up_waiters(ctx, descr);
246
- }
247
- }
416
if (!have_read_error && RRD_NO_COMPRESSION != header->compression_algorithm) {
417
freez(uncompressed_buf);
418
}
@@ -324,21 +492,12 @@ static void do_read_extent(struct rrdengine_worker_config* wc,
492
struct extent_io_descriptor *xt_io_descr;
493
struct rrdengine_datafile *datafile;
494
struct extent_info *extent = descr[0]->extent;
327
- uv_file file_to_use;
495
+ uint8_t xt_is_cached = 0, xt_is_inflight = 0;
496
+ unsigned xt_idx;
497
329
- struct journal_extent_list *extent_entry = (struct journal_extent_list *) descr[0]->extent_entry;
330
-
331
- if (likely(extent_entry)) {
332
- file_to_use = descr[0]->file;
333
- pos = extent_entry->datafile_offset;
334
- size_bytes = extent_entry->datafile_size;
335
- }
336
- else {
337
- datafile = extent->datafile;
338
- file_to_use = datafile->file;
339
- pos = extent->offset;
340
- size_bytes = extent->size;
341
- }
498
+ datafile = extent->datafile;
499
+ pos = extent->offset;
500
+ size_bytes = extent->size;
501
502
xt_io_descr = callocz(1, sizeof(*xt_io_descr));
503
for (i = 0 ; i < count; ++i) {
@@ -347,10 +506,9 @@ static void do_read_extent(struct rrdengine_worker_config* wc,
506
pg_cache_descr->flags |= RRD_PAGE_READ_PENDING;
507
rrdeng_page_descr_mutex_unlock(ctx, descr[i]);
508
xt_io_descr->descr_array[i] = descr[i];
350
- bitmap256_set_bit(&xt_io_descr->descr_array_wakeup, i, 1);
509
}
510
xt_io_descr->descr_count = count;
353
- xt_io_descr->file = file_to_use;
511
+ xt_io_descr->file = datafile->file;
512
xt_io_descr->bytes = size_bytes;
513
xt_io_descr->pos = pos;
514
xt_io_descr->req_worker.data = xt_io_descr;
@@ -358,6 +516,24 @@ static void do_read_extent(struct rrdengine_worker_config* wc,
516
xt_io_descr->release_descr = release_descr;
517
xt_io_descr->buf = NULL;
518
519
+ xt_is_cached = !lookup_in_xt_cache(wc, extent, &xt_idx);
520
+ if (xt_is_cached) {
521
+ xt_cache_replaceQ_set_hot(wc, &wc->xt_cache.extent_array[xt_idx]);
522
+ xt_is_inflight = check_bit(wc->xt_cache.inflight_bitmap, xt_idx);
523
+ if (xt_is_inflight) {
524
+ enqueue_inflight_read_to_xt_cache(wc, xt_idx, xt_io_descr);
525
+ return;
526
+ }
527
+ return read_cached_extent_cb(wc, xt_idx, xt_io_descr);
528
+ } else {
529
+ ret = try_insert_into_xt_cache(wc, extent);
530
+ if (-1 != ret) {
531
+ xt_idx = (unsigned)ret;
532
+ modify_bit(&wc->xt_cache.inflight_bitmap, xt_idx, 1);
533
+ wc->xt_cache.extent_array[xt_idx].inflight_io_descr = xt_io_descr;
534
+ }
535
+ }
536
+
537
ret = uv_queue_work(wc->loop, &xt_io_descr->req_worker, do_mmap_read_extent, read_mmap_extent_cb);
538
fatal_assert(-1 != ret);
539
@@ -471,7 +647,7 @@ static void invalidate_oldest_committed(void *arg)
647
648
goto out;
649
}
474
- pg_cache_punch_hole(ctx, descr, 1, 1, NULL, true);
650
+ pg_cache_punch_hole(ctx, descr, 1, 1, NULL);
651
652
uv_rwlock_wrlock(&pg_cache->committed_page_index.lock);
653
nr_committed_pages = --pg_cache->committed_page_index.nr_committed_pages;
@@ -522,152 +698,6 @@ void rrdeng_invalidate_oldest_committed(struct rrdengine_worker_config* wc)
698
}
699
}
700
525
-struct pg_cache_page_index *get_page_index(struct page_cache *pg_cache, uuid_t *uuid)
526
-{
527
- uv_rwlock_rdlock(&pg_cache->metrics_index.lock);
528
- Pvoid_t *PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, uuid, sizeof(uuid_t));
529
- struct pg_cache_page_index *page_index = (NULL == PValue) ? NULL : *PValue;
530
- uv_rwlock_rdunlock(&pg_cache->metrics_index.lock);
531
- return page_index;
532
-}
533
-
534
-struct rrdeng_page_descr *get_descriptor(struct pg_cache_page_index *page_index, time_t start_time_s)
535
-{
536
- uv_rwlock_rdlock(&page_index->lock);
537
- Pvoid_t *PValue = JudyLGet(page_index->JudyL_array, start_time_s, PJE0);
538
- struct rrdeng_page_descr *descr = unlikely(NULL == PValue) ? NULL : *PValue;
539
- uv_rwlock_rdunlock(&page_index->lock);
540
- return descr;
541
-};
542
-
543
-static bool try_to_remove_v2_descriptor( struct rrdengine_instance *ctx, struct pg_cache_page_index *page_index, time_t start_time_s, bool expired)
544
-{
545
- struct rrdeng_page_descr *descr = get_descriptor(page_index, start_time_s);
546
- if (unlikely(!descr))
547
- return true;
548
-
549
- rrdeng_page_descr_mutex_lock(ctx, descr);
550
- unsigned flags = descr->pg_cache_descr->flags & RRD_PAGE_POPULATED;
551
- if ((!flags || expired) && pg_cache_try_get_unsafe(descr, 1)) {
552
- rrdeng_page_descr_mutex_unlock(ctx, descr);
553
- pg_cache_punch_hole(ctx, descr, 0, 1, NULL, false);
554
- return true;
555
- }
556
- rrdeng_page_descr_mutex_unlock(ctx, descr);
557
-
558
- return false;
559
-}
560
-
561
-#ifndef DESCRIPTOR_EXPIRATION_TIME
562
-#define DESCRIPTOR_EXPIRATION_TIME (365 * 86400)
563
-#endif
564
-
565
-static void check_journal_file(struct rrdengine_journalfile *journalfile, size_t count)
566
-{
567
- struct rrdengine_instance *ctx = journalfile->datafile->ctx;
568
- struct page_cache *pg_cache = &ctx->pg_cache;
569
-
570
- Pvoid_t *PValue;
571
- Word_t page_address;
572
- uint32_t Index;
573
-
574
- struct journal_v2_header *journal_header = (struct journal_v2_header *) journalfile->journal_data;
575
- time_t journal_start_time_s = (time_t) (journal_header->start_time_ut / USEC_PER_SEC);
576
-
577
- uv_rwlock_rdlock(&pg_cache->v2_lock);
578
-
579
- bool expired = ((now_realtime_sec() - journalfile->last_access) > DESCRIPTOR_EXPIRATION_TIME);
580
-
581
- unsigned count_evicted = 0;
582
- for (page_address = 0,
583
- PValue = JudyLFirst(journalfile->JudyL_array, &page_address, PJE0),
584
- Index = unlikely(NULL == PValue) ? 0 : *(uint32_t *) PValue;
585
- Index ;
586
- PValue = JudyLNext(journalfile->JudyL_array, &page_address, PJE0),
587
- Index = unlikely(NULL == PValue) ? 0 : *(uint32_t *) PValue) {
588
-
589
- uv_rwlock_rdunlock(&pg_cache->v2_lock);
590
-
591
- // Assume we will evict everything
592
- bool all_evicted = true;
593
- // Get the page index will be working on
594
- struct journal_page_header *page_list_header = journalfile->journal_data + page_address;
595
- struct pg_cache_page_index *page_index = get_page_index(pg_cache, &page_list_header->uuid);
596
-
597
- if (likely(page_index)) {
598
- struct journal_page_list *page_list = (struct journal_page_list *) ((void *) page_list_header + sizeof(*page_list_header));
599
- uint32_t entries = page_list_header->entries;
600
-
601
- // First try to target the marked entry; Note marked entry is recorded +1
602
- struct journal_page_list *page_entry = &page_list[Index - 1];
603
- time_t index_time_s = journal_start_time_s + page_entry->delta_start_s;
604
- all_evicted = try_to_remove_v2_descriptor(ctx, page_index, index_time_s, expired);
605
-
606
- // Try to scan range ; all need to return evicted
607
- for (uint32_t x = 0; all_evicted && x < entries; x++) {
608
- index_time_s = journal_start_time_s + (&page_list[x])->delta_start_s;
609
- all_evicted = all_evicted && try_to_remove_v2_descriptor(ctx, page_index, index_time_s, expired);
610
- }
611
- }
612
-
613
- if (all_evicted) {
614
- uv_rwlock_wrlock(&pg_cache->v2_lock);
615
- (void) JudyLDel(&journalfile->JudyL_array, page_address, PJE0);
616
- uv_rwlock_wrunlock(&pg_cache->v2_lock);
617
- ++count_evicted;
618
- }
619
-
620
- uv_rwlock_rdlock(&pg_cache->v2_lock);
621
- if (count_evicted > count / 10)
622
- break;
623
- }
624
-
625
- uv_rwlock_rdunlock(&pg_cache->v2_lock);
626
-}
627
-
628
-void after_delete_descriptors(struct rrdengine_worker_config* wc)
629
-{
630
- int error = uv_thread_join(wc->now_deleting_descriptors);
631
- if (error)
632
- error("uv_thread_join(): %s", uv_strerror(error));
633
- freez(wc->now_deleting_descriptors);
634
- wc->now_deleting_descriptors = NULL;
635
- wc->cleanup_deleting_descriptors = 0;
636
- /* interrupt event loop */
637
- uv_stop(wc->loop);
638
-}
639
-
640
-void delete_descriptors(void *arg)
641
-{
642
- struct rrdengine_instance *ctx = arg;
643
- struct page_cache *pg_cache = &ctx->pg_cache;
644
- struct rrdengine_worker_config *wc = &ctx->worker_config;
645
-
646
- uv_rwlock_rdlock(&ctx->datafiles.rwlock);
647
- struct rrdengine_datafile *datafile = ctx->datafiles.first;
648
- struct rrdengine_journalfile *journalfile;
649
- while (datafile) {
650
- journalfile = datafile->journalfile;
651
- if (!journalfile->journal_data) {
652
- datafile = datafile->next;
653
- continue;
654
- }
655
-
656
- uv_rwlock_rdlock(&pg_cache->v2_lock);
657
- Word_t count = JudyLCount(journalfile->JudyL_array, 0, -1, PJE0);
658
- uv_rwlock_rdunlock(&pg_cache->v2_lock);
659
-
660
- if (unlikely(count))
661
- check_journal_file(journalfile, count);
662
-
663
- datafile = datafile->next;
664
- }
665
-
666
- uv_rwlock_rdunlock(&ctx->datafiles.rwlock);
667
- wc->cleanup_deleting_descriptors = 1;
668
- fatal_assert(0 == uv_async_send(&wc->async));
669
-}
670
-
701
void flush_pages_cb(uv_fs_t* req)
702
{
703
struct rrdengine_worker_config* wc = req->loop->data;
@@ -764,43 +794,15 @@ static int do_flush_pages(struct rrdengine_worker_config* wc, int force, struct
794
795
rrdeng_page_descr_mutex_lock(ctx, descr);
796
pg_cache_descr = descr->pg_cache_descr;
767
- bool invalid_page = ((pg_cache_descr->flags & RRD_PAGE_INVALID) == RRD_PAGE_INVALID);
768
- if (likely(false == invalid_page)) {
769
- if (!(pg_cache_descr->flags & RRD_PAGE_WRITE_PENDING)) {
770
- page_write_pending = 1;
771
- /* care, no reference being held */
772
- pg_cache_descr->flags |= RRD_PAGE_WRITE_PENDING;
773
- uncompressed_payload_length += descr->page_length;
774
- descr_commit_idx_array[count] = Index;
775
- eligible_pages[count++] = descr;
776
- }
777
- rrdeng_page_descr_mutex_unlock(ctx, descr);
778
- } else {
779
-#ifdef NETDATA_INTERNAL_CHECKS
780
- {
781
- char uuid_str[UUID_STR_LEN];
782
- uuid_unparse_lower(*descr->id, uuid_str);
783
- internal_error(true, "SKIPPING page %p marked as invalid for %s with %llu, %llu length=%u",
784
- descr, uuid_str, descr->start_time_ut, descr->end_time_ut, descr->page_length);
785
-
786
- struct pg_cache_page_index *page_index = get_page_index(pg_cache, descr->id);
787
- struct rrdeng_page_descr *in_cache_descr = get_descriptor(page_index,(time_t) (descr->start_time_ut / USEC_PER_SEC ));
788
-
789
- if (likely(in_cache_descr))
790
- internal_error(true, "MEMORY page %p found %s with %llu, %llu length=%u",
791
- in_cache_descr, uuid_str, in_cache_descr->start_time_ut / USEC_PER_SEC, in_cache_descr->end_time_ut / USEC_PER_SEC, in_cache_descr->page_length);
792
- else
793
- internal_error(true, "MEMORY page not found for %s", uuid_str);
794
- }
795
-#endif
796
- if (pg_cache_try_get_unsafe(descr, 1)) {
797
- rrdeng_page_descr_mutex_unlock(ctx, descr);
798
- pg_cache_punch_hole(ctx, descr, 0, 1, NULL, false);
799
- }
800
- else
801
- rrdeng_page_descr_mutex_unlock(ctx, descr);
797
+ if (!(pg_cache_descr->flags & RRD_PAGE_WRITE_PENDING)) {
798
page_write_pending = 1;
799
+ /* care, no reference being held */
800
+ pg_cache_descr->flags |= RRD_PAGE_WRITE_PENDING;
801
+ uncompressed_payload_length += descr->page_length;
802
+ descr_commit_idx_array[count] = Index;
803
+ eligible_pages[count++] = descr;
804
}
805
+ rrdeng_page_descr_mutex_unlock(ctx, descr);
806
807
if (page_write_pending) {
808
ret = JudyLDel(&pg_cache->committed_page_index.JudyL_array, Index, PJE0);
@@ -927,25 +929,21 @@ static void after_delete_old_data(struct rrdengine_worker_config* wc)
929
int ret, error;
930
char path[RRDENG_PATH_MAX];
931
930
- uv_rwlock_wrlock(&ctx->datafiles.rwlock);
931
-
932
datafile = ctx->datafiles.first;
933
journalfile = datafile->journalfile;
934
datafile_bytes = datafile->pos;
935
journalfile_bytes = journalfile->pos;
936
- deleted_bytes = journalfile->journal_data_size;
936
+ deleted_bytes = 0;
937
938
- info("Deleting data and journal files");
939
- datafile_list_delete_unsafe(ctx, datafile);
940
- ret = destroy_journal_file_unsafe(journalfile, datafile);
938
+ info("Deleting data and journal file pair.");
939
+ datafile_list_delete(ctx, datafile);
940
+ ret = destroy_journal_file(journalfile, datafile);
941
if (!ret) {
942
generate_journalfilepath(datafile, path, sizeof(path));
943
info("Deleted journal file \"%s\".", path);
944
- generate_journalfilepath_v2(datafile, path, sizeof(path));
945
- info("Deleted journal file \"%s\".", path);
944
deleted_bytes += journalfile_bytes;
945
}
948
- ret = destroy_data_file_unsafe(datafile);
946
+ ret = destroy_data_file(datafile);
947
if (!ret) {
948
generate_datafilepath(datafile, path, sizeof(path));
949
info("Deleted data file \"%s\".", path);
@@ -966,9 +964,6 @@ static void after_delete_old_data(struct rrdengine_worker_config* wc)
964
wc->now_deleting_files = NULL;
965
966
wc->cleanup_thread_deleting_files = 0;
969
-
970
- uv_rwlock_wrunlock(&ctx->datafiles.rwlock);
971
-
967
rrdcontext_db_rotation();
968
969
/* interrupt event loop */
@@ -987,18 +982,13 @@ static void delete_old_data(void *arg)
982
uuid_t metric_id;
983
984
/* Safe to use since it will be deleted after we are done */
990
-
985
datafile = ctx->datafiles.first;
986
993
- uv_rwlock_wrlock(&datafile->extent_rwlock);
987
for (extent = datafile->extents.first ; extent != NULL ; extent = next) {
988
count = extent->number_of_pages;
989
for (i = 0 ; i < count ; ++i) {
990
descr = extent->pages[i];
998
- if (unlikely(!descr))
999
- continue;
1000
-
1001
- can_delete_metric = pg_cache_punch_hole(ctx, descr, 0, 0, &metric_id, true);
991
+ can_delete_metric = pg_cache_punch_hole(ctx, descr, 0, 0, &metric_id);
992
if (unlikely(can_delete_metric)) {
993
/*
994
* If the metric is empty, has no active writers and if the metadata log has been initialized then
@@ -1010,31 +1000,19 @@ static void delete_old_data(void *arg)
1000
next = extent->next;
1001
freez(extent);
1002
}
1013
- uv_rwlock_wrunlock(&datafile->extent_rwlock);
1014
-
1003
wc->cleanup_thread_deleting_files = 1;
1004
/* wake up event loop */
1005
fatal_assert(0 == uv_async_send(&wc->async));
1006
}
1007
1020
-#define DESCRIPTOR_INITIAL_CLEANUP (60)
1021
-#ifndef DESCRIPTOR_INTERVAL_CLEANUP
1022
-#define DESCRIPTOR_INTERVAL_CLEANUP (1)
1023
-#endif
1024
-
1008
void rrdeng_test_quota(struct rrdengine_worker_config* wc)
1009
{
1027
- static time_t next_descriptor_cleanup = 0;
1010
struct rrdengine_instance *ctx = wc->ctx;
1011
struct rrdengine_datafile *datafile;
1012
unsigned current_size, target_size;
1013
uint8_t out_of_space, only_one_datafile;
1014
int ret, error;
1015
1034
- if (0 == next_descriptor_cleanup) {
1035
- next_descriptor_cleanup = now_realtime_sec() + DESCRIPTOR_INITIAL_CLEANUP;
1036
- }
1037
-
1016
out_of_space = 0;
1017
/* Do not allow the pinned pages to exceed the disk space quota to avoid deadlocks */
1018
if (unlikely(ctx->disk_space > MAX(ctx->max_disk_space, 2 * ctx->metric_API_max_producers * RRDENG_BLOCK_SIZE))) {
@@ -1046,33 +1024,14 @@ void rrdeng_test_quota(struct rrdengine_worker_config* wc)
1024
target_size = MIN(target_size, MAX_DATAFILE_SIZE);
1025
target_size = MAX(target_size, MIN_DATAFILE_SIZE);
1026
only_one_datafile = (datafile == ctx->datafiles.first) ? 1 : 0;
1049
-
1050
- if (unlikely(current_size >= target_size || (out_of_space && only_one_datafile)) && !wc->now_deleting_descriptors) {
1027
+ if (unlikely(current_size >= target_size || (out_of_space && only_one_datafile))) {
1028
/* Finalize data and journal file and create a new pair */
1052
- struct rrdengine_journalfile *journalfile = unlikely(NULL == ctx->datafiles.last) ? NULL : ctx->datafiles.last->journalfile;
1029
wal_flush_transaction_buffer(wc);
1030
ret = create_new_datafile_pair(ctx, 1, ctx->last_fileno + 1);
1031
if (likely(!ret)) {
1032
++ctx->last_fileno;
1057
- if (likely(journalfile && db_engine_journal_indexing))
1058
- wc->run_indexing = true;
1033
}
1034
}
1061
-
1062
- if (db_engine_journal_indexing && !wc->now_deleting_files && !wc->now_deleting_descriptors && !wc->running_journal_migration && !out_of_space &&
1063
- NO_QUIESCE == ctx->quiesce && next_descriptor_cleanup < now_realtime_sec()) {
1064
- next_descriptor_cleanup = now_realtime_sec() + DESCRIPTOR_INTERVAL_CLEANUP;
1065
-
1066
- wc->now_deleting_descriptors = mallocz(sizeof(*wc->now_deleting_descriptors));
1067
- wc->cleanup_deleting_descriptors = 0;
1068
- error = uv_thread_create(wc->now_deleting_descriptors, delete_descriptors, ctx);
1069
- if (error) {
1070
- error("uv_thread_create(): %s", uv_strerror(error));
1071
- freez(wc->now_deleting_descriptors);
1072
- wc->now_deleting_descriptors = NULL;
1073
- }
1074
- }
1075
-
1035
if (unlikely(out_of_space && NO_QUIESCE == ctx->quiesce)) {
1036
/* delete old data */
1037
if (wc->now_deleting_files) {
@@ -1101,7 +1060,7 @@ void rrdeng_test_quota(struct rrdengine_worker_config* wc)
1060
1061
static inline int rrdeng_threads_alive(struct rrdengine_worker_config* wc)
1062
{
1104
- if (wc->now_invalidating_dirty_pages || wc->now_deleting_files || wc->now_deleting_descriptors) {
1063
+ if (wc->now_invalidating_dirty_pages || wc->now_deleting_files) {
1064
return 1;
1065
}
1066
return 0;
@@ -1117,10 +1076,6 @@ static void rrdeng_cleanup_finished_threads(struct rrdengine_worker_config* wc)
1076
if (unlikely(wc->cleanup_thread_deleting_files)) {
1077
after_delete_old_data(wc);
1078
}
1120
-
1121
- if (unlikely(wc->cleanup_deleting_descriptors))
1122
- after_delete_descriptors(wc);
1123
-
1079
if (unlikely(SET_QUIESCE == ctx->quiesce && !rrdeng_threads_alive(wc))) {
1080
ctx->quiesce = QUIESCED;
1081
completion_mark_complete(&ctx->rrdengine_completion);
@@ -1289,9 +1244,8 @@ void timer_cb(uv_timer_t* handle)
1244
uv_stop(handle->loop);
1245
uv_update_time(handle->loop);
1246
rrdeng_test_quota(wc);
1292
-
1247
debug(D_RRDENGINE, "%s: timeout reached.", __func__);
1294
- if (likely(!wc->now_deleting_files && !wc->now_invalidating_dirty_pages && !wc->now_deleting_descriptors && !wc->running_journal_migration)) {
1248
+ if (likely(!wc->now_deleting_files && !wc->now_invalidating_dirty_pages)) {
1249
/* There is free space so we can write to disk and we are not actively deleting dirty buffers */
1250
struct page_cache *pg_cache = &ctx->pg_cache;
1251
unsigned long total_bytes, bytes_written, nr_committed_pages, bytes_to_write = 0, producers, low_watermark,
@@ -1323,12 +1277,6 @@ void timer_cb(uv_timer_t* handle)
1277
}
1278
}
1279
}
1326
-
1327
- if (true == wc->run_indexing) {
1328
- wc->run_indexing = false;
1329
- queue_journalfile_v2_migration(wc);
1330
- }
1331
-
1280
load_configuration_dynamic();
1281
#ifdef NETDATA_INTERNAL_CHECKS
1282
{
@@ -1336,6 +1284,7 @@ void timer_cb(uv_timer_t* handle)
1284
debug(D_RRDENGINE, "%s", get_rrdeng_statistics(wc->ctx, buf, sizeof(buf)));
1285
}
1286
#endif
1287
+
1288
worker_is_idle();
1289
}
1290
@@ -1384,14 +1333,9 @@ void rrdeng_worker(void* arg)
1333
wc->now_deleting_files = NULL;
1334
wc->cleanup_thread_deleting_files = 0;
1335
1387
- wc->now_deleting_descriptors = NULL;
1388
- wc->cleanup_deleting_descriptors = 0;
1389
- wc->running_journal_migration = 0;
1390
-
1336
wc->now_invalidating_dirty_pages = NULL;
1337
wc->cleanup_thread_invalidating_dirty_pages = 0;
1338
wc->inflight_dirty_pages = 0;
1394
- wc->run_indexing = false;
1339
1340
/* dirty page flushing timer */
1341
ret = uv_timer_init(loop, &timer_req);
database/engine/rrdengine.h
+12
-33
@@ -92,22 +92,12 @@ struct rrdeng_cmd {
92
union {
93
struct rrdeng_read_page read_page;
94
struct rrdeng_read_extent read_extent;
95
- struct rrdengine_journalfile *journalfile;
95
struct completion *completion;
96
};
97
};
98
99
#define RRDENG_CMD_Q_MAX_SIZE (2048)
100
102
-struct rrdeng_work {
103
- uv_work_t req;
104
- struct rrdengine_worker_config *wc;
105
- void *data;
106
- uint32_t count;
107
- bool rerun;
108
- struct completion *completion;
109
-};
110
-
101
struct rrdeng_cmdqueue {
102
unsigned head, tail;
103
struct rrdeng_cmd cmd_array[RRDENG_CMD_Q_MAX_SIZE];
@@ -127,7 +117,6 @@ struct extent_io_descriptor {
117
unsigned descr_count;
118
int release_descr;
119
struct rrdeng_page_descr *descr_array[MAX_PAGES_PER_EXTENT];
130
- BITMAP256 descr_array_wakeup;
120
Word_t descr_commit_idx_array[MAX_PAGES_PER_EXTENT];
121
struct extent_io_descriptor *next; /* multiple requests to be served by the same cached extent */
122
};
@@ -136,7 +125,6 @@ struct generic_io_descriptor {
125
uv_fs_t req;
126
uv_buf_t iov;
127
void *buf;
139
- void *data;
128
uint64_t pos;
129
unsigned bytes;
130
struct completion *completion;
@@ -145,8 +133,8 @@ struct generic_io_descriptor {
133
struct extent_cache_element {
134
struct extent_info *extent; /* The ABA problem is avoided with the help of fileno below */
135
unsigned fileno;
148
- struct extent_cache_element *prev; /* LRU */
149
- struct extent_cache_element *next; /* LRU */
136
+ struct extent_cache_element *prev; /* LRU */
137
+ struct extent_cache_element *next; /* LRU */
138
struct extent_io_descriptor *inflight_io_descr; /* I/O descriptor for in-flight extent */
139
uint8_t pages[MAX_PAGES_PER_EXTENT * RRDENG_BLOCK_SIZE];
140
};
@@ -157,7 +145,7 @@ struct extent_cache_element {
145
struct extent_cache {
146
struct extent_cache_element extent_array[MAX_CACHED_EXTENTS];
147
unsigned allocation_bitmap; /* 1 if the corresponding position in the extent_array is allocated */
160
- unsigned inflight_bitmap; /* 1 if the corresponding position in the extent_array is waiting for I/O */
148
+ unsigned inflight_bitmap; /* 1 if the corresponding position in the extent_array is waiting for I/O */
149
150
struct extent_cache_element *replaceQ_head; /* LRU */
151
struct extent_cache_element *replaceQ_tail; /* MRU */
@@ -167,23 +155,18 @@ struct rrdengine_worker_config {
155
struct rrdengine_instance *ctx;
156
157
uv_thread_t thread;
170
- uv_loop_t *loop;
158
+ uv_loop_t* loop;
159
uv_async_t async;
160
161
/* file deletion thread */
162
uv_thread_t *now_deleting_files;
175
- uv_thread_t *now_deleting_descriptors;
163
unsigned long cleanup_thread_deleting_files; /* set to 0 when now_deleting_files is still running */
177
- unsigned long cleanup_deleting_descriptors; /* set to 0 when now_deleting_descriptors is still running */
178
-
179
- unsigned long running_journal_migration;
164
165
/* dirty page deletion thread */
166
uv_thread_t *now_invalidating_dirty_pages;
167
/* set to 0 when now_invalidating_dirty_pages is still running */
168
unsigned long cleanup_thread_invalidating_dirty_pages;
169
unsigned inflight_dirty_pages;
186
- bool run_indexing;
170
171
/* FIFO command queue */
172
uv_mutex_t cmd_mutex;
@@ -242,9 +225,9 @@ extern rrdeng_stats_t rrdeng_reserved_file_descriptors;
225
extern rrdeng_stats_t global_pg_cache_over_half_dirty_events;
226
extern rrdeng_stats_t global_flushing_pressure_page_deletions; /* number of deleted pages */
227
245
-#define NO_QUIESCE (0) /* initial state when all operations function normally */
228
+#define NO_QUIESCE (0) /* initial state when all operations function normally */
229
#define SET_QUIESCE (1) /* set it before shutting down the instance, quiesce long running operations */
247
-#define QUIESCED (2) /* is set after all threads have finished running */
230
+#define QUIESCED (2) /* is set after all threads have finished running */
231
232
typedef enum {
233
LOAD_ERRORS_PAGE_FLIPPED_TIME = 0,
@@ -272,10 +255,9 @@ struct rrdengine_instance {
255
unsigned last_fileno; /* newest index of datafile and journalfile */
256
unsigned long max_cache_pages;
257
unsigned long cache_pages_low_watermark;
275
- unsigned long cache_pages_warn_watermark;
258
unsigned long metric_API_max_producers;
259
278
- uint8_t quiesce; /* set to SET_QUIESCE before shutdown of the engine */
260
+ uint8_t quiesce; /* set to SET_QUIESCE before shutdown of the engine */
261
uint8_t page_type; /* Default page type for this context */
262
263
struct rrdengine_statistics stats;
@@ -291,12 +273,9 @@ void dbengine_page_free(void *page);
273
274
int init_rrd_files(struct rrdengine_instance *ctx);
275
void finalize_rrd_files(struct rrdengine_instance *ctx);
294
-void rrdeng_test_quota(struct rrdengine_worker_config *wc);
295
-void rrdeng_worker(void *arg);
296
-void rrdeng_enq_cmd(struct rrdengine_worker_config *wc, struct rrdeng_cmd *cmd);
297
-struct rrdeng_cmd rrdeng_deq_cmd(struct rrdengine_worker_config *wc);
298
-void after_journal_indexing(uv_work_t *req, int status);
299
-void start_journal_indexing(uv_work_t *req);
300
-struct pg_cache_page_index *get_page_index(struct page_cache *pg_cache, uuid_t *uuid);
301
-struct rrdeng_page_descr *get_descriptor(struct pg_cache_page_index *page_index, time_t start_time_s);
276
+void rrdeng_test_quota(struct rrdengine_worker_config* wc);
277
+void rrdeng_worker(void* arg);
278
+void rrdeng_enq_cmd(struct rrdengine_worker_config* wc, struct rrdeng_cmd *cmd);
279
+struct rrdeng_cmd rrdeng_deq_cmd(struct rrdengine_worker_config* wc);
280
+
281
#endif /* NETDATA_RRDENGINE_H */
database/engine/rrdengineapi.c
+69
-18
@@ -31,8 +31,6 @@ int db_engine_use_malloc = 0;
31
int default_rrdeng_page_fetch_timeout = 3;
32
int default_rrdeng_page_fetch_retries = 3;
33
int default_rrdeng_page_cache_mb = 32;
34
-int db_engine_journal_indexing = 1;
35
-int db_engine_journal_check = 0;
34
int default_rrdeng_disk_quota_mb = 256;
35
int default_multidb_disk_quota_mb = 256;
36
/* Default behaviour is to unblock data collection if the page cache is full of dirty pages by dropping metrics */
@@ -287,7 +285,7 @@ void rrdeng_store_metric_flush_current_page(STORAGE_COLLECT_HANDLE *collection_h
285
if (page_is_empty) {
286
print_page_cache_descr(descr, "Page has empty metrics only, deleting", true);
287
pg_cache_put(ctx, descr);
290
- pg_cache_punch_hole(ctx, descr, 1, 0, NULL, true);
288
+ pg_cache_punch_hole(ctx, descr, 1, 0, NULL);
289
} else
290
rrdeng_commit_page(ctx, descr, handle->page_correlation_id);
291
} else {
@@ -422,7 +420,7 @@ static void rrdeng_store_metric_next_internal(STORAGE_COLLECT_HANDLE *collection
420
}
421
}
422
425
- (void )pg_cache_insert(ctx, page_index, descr, true);
423
+ pg_cache_insert(ctx, page_index, descr);
424
} else {
425
pg_cache_add_new_metric_time(page_index, descr);
426
}
@@ -463,9 +461,18 @@ void rrdeng_store_metric_next(STORAGE_COLLECT_HANDLE *collection_handle,
461
462
if(unlikely(points_gap != 1)) {
463
if (unlikely(points_gap <= 0)) {
466
- error_limit_static_global_var(erl, 1, 0);
467
- error_limit(&erl, "DBENGINE: ignoring past collected point at %llu, which is in the past of the current page end time %llu",
468
- point_in_time_ut, last_point_in_time_ut);
464
+ time_t now = now_realtime_sec();
465
+ static __thread size_t counter = 0;
466
+ static __thread time_t last_time_logged = 0;
467
+ counter++;
468
+
469
+ if(now - last_time_logged > 600) {
470
+ error("DBENGINE: collected point is in the past (repeated %zu times in the last %zu secs). Ignoring these data collection points.",
471
+ counter, (size_t)(last_time_logged?(now - last_time_logged):0));
472
+
473
+ last_time_logged = now;
474
+ counter = 0;
475
+ }
476
return;
477
}
478
@@ -493,7 +500,7 @@ void rrdeng_store_metric_next(STORAGE_COLLECT_HANDLE *collection_handle,
500
// print_page_cache_descr(descr, buffer, false);
501
502
// loop to fill the gap
496
- usec_t step_ut = update_every_ut;
503
+ usec_t step_ut = page_index->latest_update_every_s * USEC_PER_SEC;
504
usec_t last_point_filled_ut = last_point_in_time_ut + step_ut;
505
506
while (last_point_filled_ut < point_in_time_ut) {
@@ -506,12 +513,6 @@ void rrdeng_store_metric_next(STORAGE_COLLECT_HANDLE *collection_handle,
513
}
514
}
515
}
509
- else if(unlikely(point_in_time_ut <= page_index->latest_time_ut && page_index->latest_time_ut != INVALID_TIME)) {
510
- error_limit_static_global_var(erl, 1, 0);
511
- error_limit(&erl, "DBENGINE: ignoring past collected point at %llu, while is in the past of latest value in the database %llu",
512
- point_in_time_ut, page_index->latest_time_ut);
513
- return;
514
- }
516
517
rrdeng_store_metric_next_internal(collection_handle, point_in_time_ut, n, min_value, max_value, count, anomaly_count, flags);
518
}
@@ -550,6 +551,16 @@ void rrdeng_store_metric_change_collection_frequency(STORAGE_COLLECT_HANDLE *col
551
// ----------------------------------------------------------------------------
552
// query ops
553
554
+//static inline uint32_t *pginfo_to_dt(struct rrdeng_page_info *page_info)
555
+//{
556
+// return (uint32_t *)&page_info->scratch[0];
557
+//}
558
+//
559
+//static inline uint32_t *pginfo_to_points(struct rrdeng_page_info *page_info)
560
+//{
561
+// return (uint32_t *)&page_info->scratch[sizeof(uint32_t)];
562
+//}
563
+//
564
/*
565
* Gets a handle for loading metrics from the database.
566
* The handle must be released with rrdeng_load_metric_final().
@@ -613,7 +624,6 @@ static int rrdeng_load_page_next(struct storage_engine_query_handle *rrdimm_hand
624
usec_t wanted_start_time_ut = handle->wanted_start_time_s * USEC_PER_SEC;
625
descr = pg_cache_lookup_next(ctx, handle->page_index, &handle->page_index->id,
626
wanted_start_time_ut, rrdimm_handle->end_time_s * USEC_PER_SEC);
616
-
627
if (NULL == descr)
628
return 1;
629
@@ -920,6 +930,44 @@ void rrdeng_commit_page(struct rrdengine_instance *ctx, struct rrdeng_page_descr
930
pg_cache_put(ctx, descr);
931
}
932
933
+/* Gets a reference for the page */
934
+void *rrdeng_get_latest_page(struct rrdengine_instance *ctx, uuid_t *id, void **handle)
935
+{
936
+ struct rrdeng_page_descr *descr;
937
+ struct page_cache_descr *pg_cache_descr;
938
+
939
+ debug(D_RRDENGINE, "Reading existing page:");
940
+ descr = pg_cache_lookup(ctx, NULL, id, INVALID_TIME);
941
+ if (NULL == descr) {
942
+ *handle = NULL;
943
+
944
+ return NULL;
945
+ }
946
+ *handle = descr;
947
+ pg_cache_descr = descr->pg_cache_descr;
948
+
949
+ return pg_cache_descr->page;
950
+}
951
+
952
+/* Gets a reference for the page */
953
+void *rrdeng_get_page(struct rrdengine_instance *ctx, uuid_t *id, usec_t point_in_time_ut, void **handle)
954
+{
955
+ struct rrdeng_page_descr *descr;
956
+ struct page_cache_descr *pg_cache_descr;
957
+
958
+ debug(D_RRDENGINE, "Reading existing page:");
959
+ descr = pg_cache_lookup(ctx, NULL, id, point_in_time_ut);
960
+ if (NULL == descr) {
961
+ *handle = NULL;
962
+
963
+ return NULL;
964
+ }
965
+ *handle = descr;
966
+ pg_cache_descr = descr->pg_cache_descr;
967
+
968
+ return pg_cache_descr->page;
969
+}
970
+
971
/*
972
* Gathers Database Engine statistics.
973
* Careful when modifying this function.
@@ -970,8 +1018,7 @@ void rrdeng_get_37_statistics(struct rrdengine_instance *ctx, unsigned long long
1018
array[34] = (uint64_t)global_pg_cache_over_half_dirty_events;
1019
array[35] = (uint64_t)ctx->stats.flushing_pressure_page_deletions;
1020
array[36] = (uint64_t)global_flushing_pressure_page_deletions;
973
- array[37] = (uint64_t)pg_cache->active_descriptors;
974
- fatal_assert(RRDENG_NR_STATS == 38);
1021
+ fatal_assert(RRDENG_NR_STATS == 37);
1022
}
1023
1024
/* Releases reference to page */
@@ -1020,7 +1067,6 @@ int rrdeng_init(RRDHOST *host, struct rrdengine_instance **ctxp, char *dbfiles_p
1067
ctx->max_cache_pages = page_cache_mb * (1048576LU / RRDENG_BLOCK_SIZE);
1068
/* try to keep 5% of the page cache free */
1069
ctx->cache_pages_low_watermark = (ctx->max_cache_pages * 95LLU) / 100;
1023
- ctx->cache_pages_warn_watermark = (ctx->max_cache_pages * 90LLU) / 100;
1070
if (disk_space_mb < RRDENG_MIN_DISK_SPACE_MB)
1071
disk_space_mb = RRDENG_MIN_DISK_SPACE_MB;
1072
ctx->max_disk_space = disk_space_mb * 1048576LLU;
@@ -1054,6 +1100,11 @@ int rrdeng_init(RRDHOST *host, struct rrdengine_instance **ctxp, char *dbfiles_p
1100
if (ctx->worker_config.error) {
1101
goto error_after_rrdeng_worker;
1102
}
1103
+// error = metalog_init(ctx);
1104
+// if (error) {
1105
+// error("Failed to initialize metadata log file event loop.");
1106
+// goto error_after_rrdeng_worker;
1107
+// }
1108
1109
return 0;
1110
database/engine/rrdengineapi.h
+1
-3
@@ -8,7 +8,7 @@
8
#define RRDENG_MIN_PAGE_CACHE_SIZE_MB (8)
9
#define RRDENG_MIN_DISK_SPACE_MB (64)
10
11
-#define RRDENG_NR_STATS (38)
11
+#define RRDENG_NR_STATS (37)
12
13
#define RRDENG_FD_BUDGET_PER_INSTANCE (50)
14
@@ -16,8 +16,6 @@ extern int db_engine_use_malloc;
16
extern int default_rrdeng_page_fetch_timeout;
17
extern int default_rrdeng_page_fetch_retries;
18
extern int default_rrdeng_page_cache_mb;
19
-extern int db_engine_journal_indexing;
20
-extern int db_engine_journal_check;
19
extern int default_rrdeng_disk_quota_mb;
20
extern int default_multidb_disk_quota_mb;
21
extern uint8_t rrdeng_drop_metrics_under_page_cache_pressure;
database/engine/rrdenglocking.c
+2
-22
@@ -12,10 +12,6 @@ struct page_cache_descr *rrdeng_create_pg_cache_descr(struct rrdengine_instance
12
pg_cache_descr->prev = pg_cache_descr->next = NULL;
13
pg_cache_descr->refcnt = 0;
14
pg_cache_descr->waiters = 0;
15
-#ifdef NETDATA_INTERNAL_CHECKS
16
- pg_cache_descr->wait_list = NULL;
17
- pg_cache_descr->owner.function = NULL;
18
-#endif
15
fatal_assert(0 == uv_cond_init(&pg_cache_descr->cond));
16
fatal_assert(0 == uv_mutex_init(&pg_cache_descr->mutex));
17
@@ -31,11 +27,7 @@ void rrdeng_destroy_pg_cache_descr(struct rrdengine_instance *ctx, struct page_c
27
}
28
29
/* also allocates page cache descriptor if missing */
34
-#ifdef NETDATA_INTERNAL_CHECKS
35
-void rrdeng_page_descr_mutex_lock_with_trace(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr, const char *function, size_t line)
36
-#else
30
void rrdeng_page_descr_mutex_lock(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr)
38
-#endif
31
{
32
unsigned long old_state, old_users, new_state, ret_state;
33
struct page_cache_descr *pg_cache_descr = NULL;
@@ -98,27 +90,15 @@ void rrdeng_page_descr_mutex_lock(struct rrdengine_instance *ctx, struct rrdeng_
90
}
91
pg_cache_descr = descr->pg_cache_descr;
92
uv_mutex_lock(&pg_cache_descr->mutex);
101
-
102
-#ifdef NETDATA_INTERNAL_CHECKS
103
- pg_cache_descr->owner.function = function;
104
- pg_cache_descr->owner.line = line;
105
- pg_cache_descr->owner.tid = gettid();
106
-#endif
93
}
94
95
void rrdeng_page_descr_mutex_unlock(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr)
96
{
97
unsigned long old_state, new_state, ret_state, old_users;
112
- struct page_cache_descr *pg_cache_descr = descr->pg_cache_descr, *delete_pg_cache_descr = NULL;
98
+ struct page_cache_descr *pg_cache_descr, *delete_pg_cache_descr = NULL;
99
uint8_t we_locked;
100
115
-#ifdef NETDATA_INTERNAL_CHECKS
116
- pg_cache_descr->owner.function = "UNLOCKED";
117
- pg_cache_descr->owner.line = 0;
118
- pg_cache_descr->owner.tid = 0;
119
-#endif
120
-
121
- uv_mutex_unlock(&pg_cache_descr->mutex);
101
+ uv_mutex_unlock(&descr->pg_cache_descr->mutex);
102
103
we_locked = 0;
104
while (1) { /* spin */
database/engine/rrdenglocking.h
-7
@@ -10,14 +10,7 @@ struct page_cache_descr;
10
11
struct page_cache_descr *rrdeng_create_pg_cache_descr(struct rrdengine_instance *ctx);
12
void rrdeng_destroy_pg_cache_descr(struct rrdengine_instance *ctx, struct page_cache_descr *pg_cache_descr);
13
-
14
-#ifdef NETDATA_INTERNAL_CHECKS
15
-#define rrdeng_page_descr_mutex_lock(ctx, descr) rrdeng_page_descr_mutex_lock_with_trace(ctx, descr, __FUNCTION__, __LINE__)
16
-void rrdeng_page_descr_mutex_lock_with_trace(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr, const char *function, size_t line);
17
-#else
13
void rrdeng_page_descr_mutex_lock(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr);
19
-#endif
20
-
14
void rrdeng_page_descr_mutex_unlock(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr);
15
void rrdeng_try_deallocate_pg_cache_descr(struct rrdengine_instance *ctx, struct rrdeng_page_descr *descr);
16
database/rrd.h
+2
-12
@@ -533,9 +533,8 @@ typedef enum rrdset_flags {
533
534
RRDSET_FLAG_SENDER_REPLICATION_FINISHED = (1 << 22), // the sending side has completed replication
535
RRDSET_FLAG_RECEIVER_REPLICATION_FINISHED = (1 << 23), // the receiving side has completed replication
536
- RRDSET_FLAG_RECEIVER_REPLICATION_IN_PROGRESS = (1 << 24), // the receiving side has replication in progress
536
538
- RRDSET_FLAG_UPSTREAM_SEND_VARIABLES = (1 << 25), // a custom variable has been updated and needs to be exposed to parent
537
+ RRDSET_FLAG_UPSTREAM_SEND_VARIABLES = (1 << 24), // a custom variable has been updated and needs to be exposed to parent
538
} RRDSET_FLAGS;
539
540
#define rrdset_flag_check(st, flag) (__atomic_load_n(&((st)->flags), __ATOMIC_SEQ_CST) & (flag))
@@ -659,14 +658,6 @@ struct rrdset {
658
netdata_rwlock_t rwlock; // protection for RRDCALC *base
659
RRDCALC *base; // double linked list of RRDCALC related to this RRDSET
660
} alerts;
662
-
663
-#ifdef NETDATA_INTERNAL_CHECKS
664
- struct {
665
- bool start_streaming;
666
- time_t after;
667
- time_t before;
668
- } replay;
669
-#endif
661
};
662
663
#define rrdset_plugin_name(st) string2str((st)->plugin_name)
@@ -766,8 +757,6 @@ typedef enum {
757
// Configuration options
758
RRDHOST_OPTION_DELETE_OBSOLETE_CHARTS = (1 << 3), // delete files of obsolete charts
759
RRDHOST_OPTION_DELETE_ORPHAN_HOST = (1 << 4), // delete the entire host when orphan
769
-
770
- RRDHOST_OPTION_REPLICATION = (1 << 5), // when set, we support replication for this host
760
} RRDHOST_OPTIONS;
761
762
#define rrdhost_option_check(host, flag) ((host)->options & (flag))
@@ -948,6 +937,7 @@ struct rrdhost {
937
struct rrdpush_destinations *destination; // the current destination from the above list
938
SIMPLE_PATTERN *rrdpush_send_charts_matching; // pattern to match the charts to be sent
939
940
+ bool rrdpush_enable_replication; // enable replication
941
time_t rrdpush_seconds_to_replicate; // max time we want to replicate from the child
942
time_t rrdpush_replication_step; // seconds per replication step
943
database/rrddim.c
+3
-3
@@ -64,7 +64,7 @@ static void rrddim_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, v
64
size_t entries = st->entries;
65
if(!entries) entries = 5;
66
67
- rd->db = netdata_mmap(NULL, entries * sizeof(storage_number), MAP_PRIVATE, 1, false);
67
+ rd->db = netdata_mmap(NULL, entries * sizeof(storage_number), MAP_PRIVATE, 1);
68
if(!rd->db) {
69
info("Failed to use memory mode ram for chart '%s', dimension '%s', falling back to alloc", rrdset_name(st), rrddim_name(rd));
70
ctr->memory_mode = RRD_MEMORY_MODE_ALLOC;
@@ -666,8 +666,8 @@ bool rrddim_memory_load_or_create_map_save(RRDSET *st, RRDDIM *rd, RRD_MEMORY_MO
666
rrdset_strncpyz_name(filename, rrddim_id(rd), FILENAME_MAX);
667
snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
668
669
- rd_on_file = (struct rrddim_map_save_v019 *)netdata_mmap(
670
- fullfilename, size, ((memory_mode == RRD_MEMORY_MODE_MAP) ? MAP_SHARED : MAP_PRIVATE), 1, false);
669
+ rd_on_file = (struct rrddim_map_save_v019 *)netdata_mmap(fullfilename, size,
670
+ ((memory_mode == RRD_MEMORY_MODE_MAP) ? MAP_SHARED : MAP_PRIVATE), 1);
671
672
if(unlikely(!rd_on_file)) return false;
673
database/rrdhost.c
+3
-10
@@ -290,11 +290,7 @@ int is_legacy = 1;
290
host, rrdpush_enabled, rrdpush_destination, rrdpush_api_key, rrdpush_send_charts_matching);
291
}
292
293
- if(rrdpush_enable_replication)
294
- rrdhost_option_set(host, RRDHOST_OPTION_REPLICATION);
295
- else
296
- rrdhost_option_clear(host, RRDHOST_OPTION_REPLICATION);
297
-
293
+ host->rrdpush_enable_replication = rrdpush_enable_replication;
294
host->rrdpush_seconds_to_replicate = rrdpush_seconds_to_replicate;
295
host->rrdpush_replication_step = rrdpush_replication_step;
296
@@ -620,14 +616,11 @@ void rrdhost_update(RRDHOST *host
616
rrdcalctemplate_index_init(host);
617
rrdcalc_rrdhost_index_init(host);
618
623
- if(rrdpush_enable_replication)
624
- rrdhost_option_set(host, RRDHOST_OPTION_REPLICATION);
625
- else
626
- rrdhost_option_clear(host, RRDHOST_OPTION_REPLICATION);
627
-
619
+ host->rrdpush_enable_replication = rrdpush_enable_replication;
620
host->rrdpush_seconds_to_replicate = rrdpush_seconds_to_replicate;
621
host->rrdpush_replication_step = rrdpush_replication_step;
622
623
+
624
rrd_hosts_available++;
625
ml_new_host(host);
626
rrdhost_load_rrdcontext_data(host);
database/rrdset.c
+3
-1
@@ -2012,7 +2012,9 @@ bool rrdset_memory_load_or_create_map_save(RRDSET *st, RRD_MEMORY_MODE memory_mo
2012
2013
unsigned long size = sizeof(struct rrdset_map_save_v019);
2014
struct rrdset_map_save_v019 *st_on_file = (struct rrdset_map_save_v019 *)netdata_mmap(
2015
- fullfilename, size, ((memory_mode == RRD_MEMORY_MODE_MAP) ? MAP_SHARED : MAP_PRIVATE), 0, false);
2015
+ fullfilename, size,
2016
+ ((memory_mode == RRD_MEMORY_MODE_MAP) ? MAP_SHARED : MAP_PRIVATE),
2017
+ 0);
2018
2019
if(!st_on_file) return false;
2020
libnetdata/arrayalloc/arrayalloc.c
+2
-2
@@ -206,7 +206,7 @@ static void arrayalloc_add_page(ARAL *ar) {
206
char filename[FILENAME_MAX + 1];
207
snprintfz(filename, FILENAME_MAX, "%s/array_alloc.mmap/%s.%zu", *ar->cache_dir, ar->filename, ar->internal.file_number);
208
page->filename = strdupz(filename);
209
- page->data = netdata_mmap(page->filename, page->size, MAP_SHARED, 0, false);
209
+ page->data = netdata_mmap(page->filename, page->size, MAP_SHARED, 0);
210
if (unlikely(!page->data))
211
fatal("Cannot allocate arrayalloc buffer of size %zu on filename '%s'", page->size, page->filename);
212
}
@@ -344,7 +344,7 @@ void arrayalloc_freez(ARAL *ar, void *ptr) {
344
#endif
345
}
346
347
-#ifdef NETDATA_ARRAYALLOC_INTERNAL_CHECKS
347
+#ifdef NETDATA_INTERNAL_CHECKS
348
{
349
// find the page ptr belongs
350
ARAL_PAGE *page2 = find_page_with_allocation_internal_check(ar, ptr);
libnetdata/dictionary/dictionary.c
+2
-7
@@ -2171,13 +2171,11 @@ int dictionary_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(const D
2171
// ----------------------------------------------------------------------------
2172
// sorted walkthrough
2173
2174
-typedef int (*qsort_compar)(const void *item1, const void *item2);
2175
-
2174
static int dictionary_sort_compar(const void *item1, const void *item2) {
2175
return strcmp(item_get_name((*(DICTIONARY_ITEM **)item1)), item_get_name((*(DICTIONARY_ITEM **)item2)));
2176
}
2177
2180
-int dictionary_sorted_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(const DICTIONARY_ITEM *item, void *entry, void *data), void *data, dictionary_sorted_compar compar) {
2178
+int dictionary_sorted_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(const DICTIONARY_ITEM *item, void *entry, void *data), void *data) {
2179
if(unlikely(!dict || !callback)) return 0;
2180
2181
if(unlikely(is_dictionary_destroyed(dict))) {
@@ -2202,10 +2200,7 @@ int dictionary_sorted_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(
2200
if(unlikely(i != entries))
2201
entries = i;
2202
2205
- if(compar)
2206
- qsort(array, entries, sizeof(DICTIONARY_ITEM *), (qsort_compar)compar);
2207
- else
2208
- qsort(array, entries, sizeof(DICTIONARY_ITEM *), dictionary_sort_compar);
2203
+ qsort(array, entries, sizeof(DICTIONARY_ITEM *), dictionary_sort_compar);
2204
2205
bool callit = true;
2206
int ret = 0, r;
libnetdata/dictionary/dictionary.h
+3
-5
@@ -230,11 +230,9 @@ size_t dictionary_acquired_item_references(DICT_ITEM_CONST DICTIONARY_ITEM *item
230
#define dictionary_walkthrough_write(dict, callback, data) dictionary_walkthrough_rw(dict, 'w', callback, data)
231
int dictionary_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(const DICTIONARY_ITEM *item, void *value, void *data), void *data);
232
233
-typedef int (*dictionary_sorted_compar)(const DICTIONARY_ITEM **item1, const DICTIONARY_ITEM **item2);
234
-
235
-#define dictionary_sorted_walkthrough_read(dict, callback, data) dictionary_sorted_walkthrough_rw(dict, 'r', callback, data, NULL)
236
-#define dictionary_sorted_walkthrough_write(dict, callback, data) dictionary_sorted_walkthrough_rw(dict, 'w', callback, data, NULL)
237
-int dictionary_sorted_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(const DICTIONARY_ITEM *item, void *entry, void *data), void *data, dictionary_sorted_compar compar);
233
+#define dictionary_sorted_walkthrough_read(dict, callback, data) dictionary_sorted_walkthrough_rw(dict, 'r', callback, data)
234
+#define dictionary_sorted_walkthrough_write(dict, callback, data) dictionary_sorted_walkthrough_rw(dict, 'w', callback, data)
235
+int dictionary_sorted_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(const DICTIONARY_ITEM *item, void *entry, void *data), void *data);
236
237
// ----------------------------------------------------------------------------
238
// Traverse with foreach
libnetdata/libnetdata.c
+2
-3
@@ -1232,8 +1232,7 @@ static inline int madvise_mergeable(void *mem, size_t len) {
1232
#endif
1233
}
1234
1235
-void *netdata_mmap(const char *filename, size_t size, int flags, int ksm, bool read_only)
1236
-{
1235
+void *netdata_mmap(const char *filename, size_t size, int flags, int ksm) {
1236
// info("netdata_mmap('%s', %zu", filename, size);
1237
1238
// MAP_SHARED is used in memory mode map
@@ -1272,7 +1271,7 @@ void *netdata_mmap(const char *filename, size_t size, int flags, int ksm, bool r
1271
fd_for_mmap = -1;
1272
}
1273
1275
- mem = mmap(NULL, size, read_only ? PROT_READ : PROT_READ | PROT_WRITE, flags, fd_for_mmap, 0);
1274
+ mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd_for_mmap, 0);
1275
if (mem != MAP_FAILED) {
1276
1277
#ifdef NETDATA_TRACE_ALLOCATIONS
libnetdata/libnetdata.h
+1
-1
@@ -335,7 +335,7 @@ void posix_memfree(void *ptr);
335
void json_escape_string(char *dst, const char *src, size_t size);
336
void json_fix_string(char *s);
337
338
-void *netdata_mmap(const char *filename, size_t size, int flags, int ksm, bool read_only);
338
+void *netdata_mmap(const char *filename, size_t size, int flags, int ksm);
339
int netdata_munmap(void *ptr, size_t size);
340
int memory_file_save(const char *filename, void *mem, size_t size);
341
streaming/compression.c
-1
@@ -5,7 +5,6 @@
5
6
#define STREAM_COMPRESSION_MSG "STREAM_COMPRESSION"
7
8
-// signature MUST end with a newline
8
#define SIGNATURE ((uint32_t)('z' | 0x80) | (0x80 << 8) | (0x80 << 16) | ('\n' << 24))
9
#define SIGNATURE_MASK ((uint32_t)0xff | (0x80 << 8) | (0x80 << 16) | (0xff << 24))
10
#define SIGNATURE_SIZE 4
streaming/receiver.c
+3
-22
@@ -240,11 +240,8 @@ static int receiver_read(struct receiver_state *r, FILE *fp) {
240
return 0;
241
}
242
243
- // for compressed streams, the compression signature header ends with a new line
244
- // so, here we read a single line from the stream.
245
-
243
int ret = 0;
247
- if (read_stream(r, fp, r->read_buffer + r->read_len, sizeof(r->read_buffer) - r->read_len, &ret)) {
244
+ if (read_stream(r, fp, r->read_buffer + r->read_len, sizeof(r->read_buffer) - r->read_len - 1, &ret)) {
245
internal_error(true, "read_stream() failed (1).");
246
return 1;
247
}
@@ -287,7 +284,7 @@ static int receiver_read(struct receiver_state *r, FILE *fp) {
284
}
285
286
// Fill read buffer with decompressed data
290
- r->read_len += (int)r->decompressor->get(r->decompressor, r->read_buffer + r->read_len, sizeof(r->read_buffer) - r->read_len);
287
+ r->read_len = r->decompressor->get(r->decompressor, r->read_buffer, sizeof(r->read_buffer));
288
return 0;
289
}
290
@@ -727,16 +724,9 @@ static int rrdpush_receive(struct receiver_state *rpt)
724
725
rrdhost_set_is_parent_label(++localhost->senders_count);
726
730
- if(stream_has_capability(rpt->host->receiver, STREAM_CAP_REPLICATION)) {
731
- RRDSET *st;
732
- rrdset_foreach_read(st, rpt->host) {
733
- rrdset_flag_clear(st, RRDSET_FLAG_RECEIVER_REPLICATION_IN_PROGRESS | RRDSET_FLAG_RECEIVER_REPLICATION_FINISHED);
734
- }
735
- rrdset_foreach_done(st);
736
- }
737
-
727
rrdcontext_host_child_connected(rpt->host);
728
729
+
730
rrdhost_flag_clear(rpt->host, RRDHOST_FLAG_RRDPUSH_RECEIVER_DISCONNECTED);
731
732
size_t count = streaming_parser(rpt, &cd, fp_in, fp_out,
@@ -756,15 +746,6 @@ static int rrdpush_receive(struct receiver_state *rpt)
746
error("STREAM %s [receive from [%s]:%s]: disconnected (completed %zu updates).",
747
rpt->hostname, rpt->client_ip, rpt->client_port, count);
748
759
- if(stream_has_capability(rpt->host->receiver, STREAM_CAP_REPLICATION)) {
760
- RRDSET *st;
761
- rrdset_foreach_read(st, rpt->host) {
762
- rrdset_flag_clear(st, RRDSET_FLAG_RECEIVER_REPLICATION_IN_PROGRESS);
763
- rrdset_flag_set(st, RRDSET_FLAG_RECEIVER_REPLICATION_FINISHED);
764
- }
765
- rrdset_foreach_done(st);
766
- }
767
-
749
rrdcontext_host_child_disconnected(rpt->host);
750
751
#ifdef ENABLE_ACLK
streaming/replication.c
+2
-14
@@ -42,7 +42,7 @@ static time_t replicate_chart_timeframe(BUFFER *wb, RRDSET *st, time_t after, ti
42
rrddim_foreach_done(rd);
43
}
44
45
- time_t now = after + 1, actual_after = 0, actual_before = 0;
45
+ time_t now = after, actual_after = 0, actual_before = 0;
46
while(now <= before) {
47
time_t min_start_time = 0, min_end_time = 0;
48
for (size_t i = 0; i < dimensions && data[i].rd; i++) {
@@ -252,18 +252,6 @@ static bool send_replay_chart_cmd(send_command callback, void *callback_data, RR
252
}
253
#endif
254
255
-#ifdef NETDATA_INTERNAL_CHECKS
256
- internal_error(
257
- st->replay.after != 0 || st->replay.before != 0,
258
- "REPLAY: host '%s', chart '%s': sending replication request, while there is another inflight",
259
- rrdhost_hostname(st->rrdhost), rrdset_id(st)
260
- );
261
-
262
- st->replay.start_streaming = start_streaming;
263
- st->replay.after = after;
264
- st->replay.before = before;
265
-#endif
266
-
255
debug(D_REPLICATION, PLUGINSD_KEYWORD_REPLAY_CHART " \"%s\" \"%s\" %llu %llu\n",
256
rrdset_id(st), start_streaming ? "true" : "false", (unsigned long long)after, (unsigned long long)before);
257
@@ -289,7 +277,7 @@ bool replicate_chart_request(send_command callback, void *callback_data, RRDHOST
277
278
// if replication is disabled, send an empty replication request
279
// asking no data
292
- if (unlikely(!rrdhost_option_check(host, RRDHOST_OPTION_REPLICATION))) {
280
+ if (!host->rrdpush_enable_replication) {
281
internal_error(true,
282
"REPLAY: host '%s', chart '%s': sending empty replication request because replication is disabled",
283
rrdhost_hostname(host), rrdset_id(st));
streaming/rrdpush.h
-2
@@ -170,8 +170,6 @@ struct sender_state {
170
#endif
171
172
DICTIONARY *replication_requests;
173
- time_t replication_first_time;
174
- time_t replication_min_time;
173
};
174
175
struct receiver_state {
streaming/sender.c
+57
-127
@@ -21,14 +21,9 @@
21
#define WORKER_SENDER_JOB_BUFFER_RATIO 15
22
#define WORKER_SENDER_JOB_BYTES_RECEIVED 16
23
#define WORKER_SENDER_JOB_BYTES_SENT 17
24
-#define WORKER_SENDER_JOB_REPLAY_REQUEST 18
25
-#define WORKER_SENDER_JOB_REPLAY_RESPONSE 19
26
-#define WORKER_SENDER_JOB_REPLAY_QUEUE_SIZE 20
27
-#define WORKER_SENDER_JOB_REPLAY_COMPLETION 21
28
-#define WORKER_SENDER_JOB_FUNCTION 22
29
-
30
-#if WORKER_UTILIZATION_MAX_JOB_TYPES < 23
31
-#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 23
24
+
25
+#if WORKER_UTILIZATION_MAX_JOB_TYPES < 18
26
+#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 18
27
#endif
28
29
extern struct config stream_config;
@@ -86,8 +81,6 @@ static inline void deactivate_compression(struct sender_state *s) {
81
}
82
#endif
83
89
-#define SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE 3
90
-
84
// Collector thread finishing a transmission
85
void sender_commit(struct sender_state *s, BUFFER *wb) {
86
@@ -107,15 +100,15 @@ void sender_commit(struct sender_state *s, BUFFER *wb) {
100
101
netdata_mutex_lock(&s->mutex);
102
110
- if(unlikely(s->host->sender->buffer->max_size < (src_len + 1) * SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE)) {
111
- info("STREAM %s [send to %s]: max buffer size of %zu is too small for a data message of size %zu. Increasing the max buffer size to %d times the max data message size.",
112
- rrdhost_hostname(s->host), s->connected_to, s->host->sender->buffer->max_size, buffer_strlen(wb) + 1, SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE);
103
+ if(unlikely(s->host->sender->buffer->max_size < (buffer_strlen(wb) + 1) * 2)) {
104
+ error("STREAM %s [send to %s]: max buffer size of %zu is too small for data of size %zu. Increasing the max buffer size to twice the max data size.",
105
+ rrdhost_hostname(s->host), s->connected_to, s->host->sender->buffer->max_size, buffer_strlen(wb) + 1);
106
114
- s->host->sender->buffer->max_size = (src_len + 1) * SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE;
107
+ s->host->sender->buffer->max_size = (buffer_strlen(wb) + 1) * 2;
108
}
109
110
#ifdef ENABLE_COMPRESSION
118
- if (stream_has_capability(s, STREAM_CAP_COMPRESSION) && s->compressor) {
111
+ if (s->flags & SENDER_FLAG_COMPRESSION && s->compressor) {
112
while(src_len) {
113
size_t size_to_compress = src_len;
114
@@ -475,7 +468,7 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
468
469
#ifdef ENABLE_COMPRESSION
470
// If we don't want compression, remove it from our capabilities
478
- if(!(s->flags & SENDER_FLAG_COMPRESSION))
471
+ if(!(s->flags & SENDER_FLAG_COMPRESSION) && stream_has_capability(s, STREAM_CAP_COMPRESSION))
472
s->capabilities &= ~STREAM_CAP_COMPRESSION;
473
#endif // ENABLE_COMPRESSION
474
@@ -671,12 +664,20 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
664
return false;
665
666
#ifdef ENABLE_COMPRESSION
674
- if(stream_has_capability(s, STREAM_CAP_COMPRESSION)) {
675
- if(!s->compressor)
676
- s->compressor = create_compressor();
677
- else
667
+ // if the stream does not have compression capability,
668
+ // shut it down for us too.
669
+ // FIXME - this means that if there are multiple parents and one of them does not support compression
670
+ // we are going to shut it down for all of them eventually...
671
+ if(!stream_has_capability(s, STREAM_CAP_COMPRESSION))
672
+ s->flags &= ~SENDER_FLAG_COMPRESSION;
673
+
674
+ if(s->flags & SENDER_FLAG_COMPRESSION) {
675
+ if(s->compressor)
676
s->compressor->reset(s->compressor);
677
}
678
+ else
679
+ info("STREAM %s [send to %s]: compression is disabled on this connection.", rrdhost_hostname(host), s->connected_to);
680
+
681
#endif //ENABLE_COMPRESSION
682
683
log_sender_capabilities(s);
@@ -880,8 +881,6 @@ void execute_commands(struct sender_state *s) {
881
const char *keyword = get_word(words, num_words, 0);
882
883
if(keyword && strcmp(keyword, PLUGINSD_KEYWORD_FUNCTION) == 0) {
883
- worker_is_busy(WORKER_SENDER_JOB_FUNCTION);
884
-
884
char *transaction = get_word(words, num_words, 1);
885
char *timeout_s = get_word(words, num_words, 2);
886
char *function = get_word(words, num_words, 3);
@@ -910,10 +909,7 @@ void execute_commands(struct sender_state *s) {
909
stream_execute_function_callback(wb, code, tmp);
910
}
911
}
913
- }
914
- else if (keyword && strcmp(keyword, PLUGINSD_KEYWORD_REPLAY_CHART) == 0) {
915
- worker_is_busy(WORKER_SENDER_JOB_REPLAY_REQUEST);
916
-
912
+ } else if (keyword && strcmp(keyword, PLUGINSD_KEYWORD_REPLAY_CHART) == 0) {
913
const char *chart_id = get_word(words, num_words, 1);
914
const char *start_streaming = get_word(words, num_words, 2);
915
const char *after = get_word(words, num_words, 3);
@@ -936,8 +932,7 @@ void execute_commands(struct sender_state *s) {
932
};
933
dictionary_set(s->replication_requests, chart_id, &tmp, sizeof(struct replication_request));
934
}
939
- }
940
- else {
935
+ } else {
936
error("STREAM %s [send to %s] received unknown command over connection: %s", rrdhost_hostname(s->host), s->connected_to, words[0]?words[0]:"(unset)");
937
}
938
@@ -1050,12 +1045,10 @@ static bool replication_request_conflict_callback(const DICTIONARY_ITEM *item, v
1045
struct replication_request *rr = old_value;
1046
struct replication_request *rr_new = new_value;
1047
1053
- internal_error(
1054
- true,
1055
- "STREAM %s [send to %s]: duplicate replication command received for chart '%s' (existing from %llu to %llu [%s], new from %llu to %llu [%s])",
1056
- rrdhost_hostname(s->host), s->connected_to, dictionary_acquired_item_name(item),
1057
- (unsigned long long)rr->after, (unsigned long long)rr->before, rr->start_streaming?"true":"false",
1058
- (unsigned long long)rr_new->after, (unsigned long long)rr_new->before, rr_new->start_streaming?"true":"false");
1048
+ error("STREAM %s [send to %s]: duplicate replication command received for chart '%s' (existing from %llu to %llu [%s], new from %llu to %llu [%s])",
1049
+ rrdhost_hostname(s->host), s->connected_to, dictionary_acquired_item_name(item),
1050
+ (unsigned long long)rr->after, (unsigned long long)rr->before, rr->start_streaming?"true":"false",
1051
+ (unsigned long long)rr_new->after, (unsigned long long)rr_new->before, rr_new->start_streaming?"true":"false");
1052
1053
bool updated = false;
1054
@@ -1099,8 +1092,6 @@ void sender_init(RRDHOST *host)
1092
host->sender->flags |= SENDER_FLAG_COMPRESSION;
1093
host->sender->compressor = create_compressor();
1094
}
1102
- else
1103
- host->sender->flags &= ~SENDER_FLAG_COMPRESSION;
1095
#endif
1096
1097
netdata_mutex_init(&host->sender->mutex);
@@ -1119,98 +1110,45 @@ static size_t sender_buffer_used_percent(struct sender_state *s) {
1110
return (s->host->sender->buffer->max_size - available) * 100 / s->host->sender->buffer->max_size;
1111
}
1112
1122
-int replication_request_compar(const DICTIONARY_ITEM **item1, const DICTIONARY_ITEM **item2) {
1123
- struct replication_request *rr1 = dictionary_acquired_item_value(*item1);
1124
- struct replication_request *rr2 = dictionary_acquired_item_value(*item2);
1125
-
1126
- time_t after1 = rr1->after;
1127
- time_t after2 = rr2->after;
1128
-
1129
- if(after1 < after2)
1130
- return -1;
1131
- if(after1 > after2)
1132
- return 1;
1133
-
1134
- return 0;
1135
-}
1136
-
1137
-int process_one_replication_request(const DICTIONARY_ITEM *item, void *value, void *data) {
1138
- struct sender_state *s = data;
1139
-
1140
- size_t used_percent = sender_buffer_used_percent(s);
1141
- if(used_percent >= 50) return -1; // signal the traversal to stop
1142
-
1143
- worker_is_busy(WORKER_SENDER_JOB_REPLAY_RESPONSE);
1144
-
1145
- struct replication_request *rr = value;
1146
- const char *name = dictionary_acquired_item_name(item);
1147
-
1148
- // delete it from the dictionary
1149
- // the current item is referenced - it will not go away until the next iteration of the dfe loop
1150
- dictionary_del(s->replication_requests, name);
1151
-
1152
- // find the chart
1153
- RRDSET *st = rrdset_find(s->host, name);
1154
- if(unlikely(!st)) {
1155
- internal_error(true,
1156
- "STREAM %s [send to %s]: cannot find chart '%s' to satisfy pending replication command."
1157
- , rrdhost_hostname(s->host), s->connected_to, name);
1158
- return 0;
1159
- }
1160
-
1161
- if(rr->after < s->replication_first_time || !s->replication_first_time)
1162
- s->replication_first_time = rr->after;
1163
-
1164
- if(rr->before < s->replication_min_time || !s->replication_min_time)
1165
- s->replication_min_time = rr->before;
1166
-
1167
- netdata_thread_disable_cancelability();
1168
-
1169
- // send the replication data
1170
- bool start_streaming = replicate_chart_response(st->rrdhost, st,
1171
- rr->start_streaming, rr->after, rr->before);
1172
-
1173
- netdata_thread_enable_cancelability();
1174
-
1175
- // enable normal streaming if we have to
1176
- if (start_streaming) {
1177
- debug(D_REPLICATION, "Enabling metric streaming for chart %s.%s",
1178
- rrdhost_hostname(s->host), rrdset_id(st));
1179
-
1180
- rrdset_flag_set(st, RRDSET_FLAG_SENDER_REPLICATION_FINISHED);
1181
- }
1182
-
1183
- return 1;
1184
-}
1185
-
1113
static void process_replication_requests(struct sender_state *s) {
1187
- size_t entries = dictionary_entries(s->replication_requests);
1114
+ if(dictionary_entries(s->replication_requests) == 0)
1115
+ return;
1116
1189
- worker_set_metric(WORKER_SENDER_JOB_REPLAY_QUEUE_SIZE, (NETDATA_DOUBLE)entries);
1117
+ struct replication_request *rr;
1118
+ dfe_start_write(s->replication_requests, rr) {
1119
+ size_t used_percent = sender_buffer_used_percent(s);
1120
+ if(used_percent > 50) break;
1121
+
1122
+ // delete it from the dictionary
1123
+ // the current item is referenced - it will not go away until the next iteration of the dfe loop
1124
+ dictionary_del(s->replication_requests, rr_dfe.name);
1125
+
1126
+ // find the chart
1127
+ RRDSET *st = rrdset_find(s->host, rr_dfe.name);
1128
+ if(unlikely(!st)) {
1129
+ internal_error(true,
1130
+ "STREAM %s [send to %s]: cannot find chart '%s' to satisfy pending replication command."
1131
+ , rrdhost_hostname(s->host), s->connected_to, rr_dfe.name);
1132
+ continue;
1133
+ }
1134
1191
- if(!entries) {
1192
- worker_set_metric(WORKER_SENDER_JOB_REPLAY_COMPLETION, 100.0);
1193
- return;
1194
- }
1135
+ netdata_thread_disable_cancelability();
1136
1196
- s->replication_min_time = 0;
1137
+ // send the replication data
1138
+ bool start_streaming = replicate_chart_response(st->rrdhost, st,
1139
+ rr->start_streaming, rr->after, rr->before);
1140
1198
- int count = dictionary_sorted_walkthrough_rw(s->replication_requests, DICTIONARY_LOCK_WRITE,
1199
- process_one_replication_request, s,
1200
- replication_request_compar);
1141
+ netdata_thread_enable_cancelability();
1142
1202
- if(count != 0 && s->replication_min_time && s->replication_first_time) {
1203
- time_t now = now_realtime_sec();
1204
- if(now > s->replication_first_time && now >= s->replication_min_time) {
1205
- time_t completed = s->replication_min_time - s->replication_first_time;
1206
- time_t all_duration = now - s->replication_first_time;
1143
+ // enable normal streaming if we have to
1144
+ if (start_streaming) {
1145
+ debug(D_REPLICATION, "Enabling metric streaming for chart %s.%s",
1146
+ rrdhost_hostname(s->host), rrdset_id(st));
1147
1208
- NETDATA_DOUBLE percent = (NETDATA_DOUBLE) completed * 100.0 / (NETDATA_DOUBLE) all_duration;
1209
- worker_set_metric(WORKER_SENDER_JOB_REPLAY_COMPLETION, percent);
1148
+ rrdset_flag_set(st, RRDSET_FLAG_SENDER_REPLICATION_FINISHED);
1149
}
1150
}
1212
-
1213
- worker_is_idle();
1151
+ dfe_done(rr);
1152
}
1153
1154
void *rrdpush_sender_thread(void *ptr) {
@@ -1233,17 +1171,9 @@ void *rrdpush_sender_thread(void *ptr) {
1171
worker_register_job_name(WORKER_SENDER_JOB_DISCONNECT_NO_COMPRESSION, "disconnect no compression");
1172
worker_register_job_name(WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE, "disconnect bad handshake");
1173
1236
- worker_register_job_name(WORKER_SENDER_JOB_REPLAY_REQUEST, "replay request");
1237
- worker_register_job_name(WORKER_SENDER_JOB_REPLAY_RESPONSE, "replay response");
1238
- worker_register_job_name(WORKER_SENDER_JOB_FUNCTION, "function");
1239
-
1174
worker_register_job_custom_metric(WORKER_SENDER_JOB_BUFFER_RATIO, "used buffer ratio", "%", WORKER_METRIC_ABSOLUTE);
1175
worker_register_job_custom_metric(WORKER_SENDER_JOB_BYTES_RECEIVED, "bytes received", "bytes/s", WORKER_METRIC_INCREMENTAL);
1176
worker_register_job_custom_metric(WORKER_SENDER_JOB_BYTES_SENT, "bytes sent", "bytes/s", WORKER_METRIC_INCREMENTAL);
1243
- worker_register_job_custom_metric(WORKER_SENDER_JOB_REPLAY_COMPLETION, "replication completion", "%", WORKER_METRIC_ABSOLUTE);
1244
- worker_register_job_custom_metric(WORKER_SENDER_JOB_REPLAY_QUEUE_SIZE, "replications pending", "commands", WORKER_METRIC_ABSOLUTE);
1245
-
1246
- worker_set_metric(WORKER_SENDER_JOB_REPLAY_COMPLETION, 100.0);
1177
1178
struct sender_state *s = ptr;
1179
s->tid = gettid();
web/api/web_api_v1.c
+1
-1
@@ -1226,7 +1226,7 @@ inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
1226
#ifdef ENABLE_COMPRESSION
1227
if(host->sender){
1228
buffer_strcat(wb, "\t\"stream-compression\": ");
1229
- buffer_strcat(wb, stream_has_capability(host->sender, STREAM_CAP_COMPRESSION) ? "true" : "false");
1229
+ buffer_strcat(wb, (host->sender->flags & SENDER_FLAG_COMPRESSION) ? "true" : "false");
1230
buffer_strcat(wb, ",\n");
1231
}else{
1232
buffer_strcat(wb, "\t\"stream-compression\": null,\n");