52
mrg_metric_release(main_mrg, metric);
53
}
54
55
-static void flush_transaction_buffer_cb(uv_fs_t* req)
55
+static void wal_flush_transaction_buffer_cb(uv_fs_t* req)
56
{
57
worker_is_busy(RRDENG_FLUSH_TRANSACTION_BUFFER_CB);
58
99
100
io_descr->iov = uv_buf_init((void *)io_descr->buf, wal->buf_size);
101
ret = uv_fs_write(loop, &io_descr->req, journalfile->file, &io_descr->iov, 1,
102
- journalfile->pos, flush_transaction_buffer_cb);
102
+ journalfile->pos, wal_flush_transaction_buffer_cb);
103
fatal_assert(-1 != ret);
104
journalfile->pos += wal->buf_size;
105
ctx->disk_space += wal->buf_size;
107
++ctx->stats.io_write_requests;
108
}
109
110
-void generate_journalfilepath_v2(struct rrdengine_datafile *datafile, char *str, size_t maxlen)
110
+void journalfile_v2_generate_path(struct rrdengine_datafile *datafile, char *str, size_t maxlen)
111
{
112
(void) snprintfz(str, maxlen, "%s/" WALFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL WALFILE_EXTENSION_V2,
113
datafile->ctx->dbfiles_path, datafile->tier, datafile->fileno);
114
}
115
116
-void generate_journalfilepath(struct rrdengine_datafile *datafile, char *str, size_t maxlen)
116
+void journalfile_generate_path(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,
119
datafile->ctx->dbfiles_path, datafile->tier, datafile->fileno);
120
}
121
122
-void journalfile_init(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
122
+static struct journal_v2_header *journalfile_v2_mounted_data_get(struct rrdengine_journalfile *journalfile, size_t *data_size) {
123
+ struct journal_v2_header *j2_header = NULL;
124
+
125
+ netdata_spinlock_lock(&journalfile->mmap.spinlock);
126
+
127
+ if(!journalfile->mmap.data) {
128
+ journalfile->mmap.data = mmap(NULL, journalfile->mmap.size, PROT_READ, MAP_SHARED, journalfile->mmap.fd, 0);
129
+ if (journalfile->mmap.data == MAP_FAILED) {
130
+ internal_fatal(true, "DBENGINE: failed to re-mmap() journal file v2");
131
+ close(journalfile->mmap.fd);
132
+ journalfile->mmap.fd = -1;
133
+ journalfile->mmap.data = NULL;
134
+ journalfile->mmap.size = 0;
135
+
136
+ netdata_spinlock_lock(&journalfile->v2.spinlock);
137
+ journalfile->v2.flags &= ~(JOURNALFILE_FLAG_IS_AVAILABLE | JOURNALFILE_FLAG_IS_MOUNTED);
138
+ netdata_spinlock_unlock(&journalfile->v2.spinlock);
139
+
140
+ ++journalfile->datafile->ctx->stats.fs_errors;
141
+ rrd_stat_atomic_add(&global_fs_errors, 1);
142
+ }
143
+ else {
144
+ __atomic_add_fetch(&rrdeng_cache_efficiency_stats.journal_v2_mapped, 1, __ATOMIC_RELAXED);
145
+
146
+ madvise_dontfork(journalfile->mmap.data, journalfile->mmap.size);
147
+ madvise_dontdump(journalfile->mmap.data, journalfile->mmap.size);
148
+ madvise_random(journalfile->mmap.data, journalfile->mmap.size);
149
+ madvise_dontneed(journalfile->mmap.data, journalfile->mmap.size);
150
+
151
+ netdata_spinlock_lock(&journalfile->v2.spinlock);
152
+ journalfile->v2.flags |= JOURNALFILE_FLAG_IS_AVAILABLE | JOURNALFILE_FLAG_IS_MOUNTED;
153
+ netdata_spinlock_unlock(&journalfile->v2.spinlock);
154
+ }
155
+ }
156
+
157
+ if(journalfile->mmap.data) {
158
+ j2_header = journalfile->mmap.data;
159
+
160
+ if (data_size)
161
+ *data_size = journalfile->mmap.size;
162
+ }
163
+
164
+ netdata_spinlock_unlock(&journalfile->mmap.spinlock);
165
+
166
+ return j2_header;
167
+}
168
+
169
+static bool journalfile_v2_mounted_data_unmount(struct rrdengine_journalfile *journalfile, bool have_locks) {
170
+ bool unmounted = false;
171
+
172
+ if(!have_locks) {
173
+ netdata_spinlock_lock(&journalfile->mmap.spinlock);
174
+ netdata_spinlock_lock(&journalfile->v2.spinlock);
175
+ }
176
+
177
+ if(!journalfile->v2.refcount && journalfile->mmap.data) {
178
+ if (munmap(journalfile->mmap.data, journalfile->mmap.size)) {
179
+ char path[RRDENG_PATH_MAX];
180
+ journalfile_v2_generate_path(journalfile->datafile, path, sizeof(path));
181
+ error("DBENGINE: failed to unmap index file '%s'", path);
182
+ internal_fatal(true, "DBENGINE: failed to unmap file '%s'", path);
183
+ ++journalfile->datafile->ctx->stats.fs_errors;
184
+ rrd_stat_atomic_add(&global_fs_errors, 1);
185
+ }
186
+ else {
187
+ __atomic_add_fetch(&rrdeng_cache_efficiency_stats.journal_v2_unmapped, 1, __ATOMIC_RELAXED);
188
+ journalfile->mmap.data = NULL;
189
+ journalfile->v2.flags &= ~JOURNALFILE_FLAG_IS_MOUNTED;
190
+ }
191
+
192
+ unmounted = true;
193
+ }
194
+
195
+ if(!have_locks) {
196
+ netdata_spinlock_unlock(&journalfile->v2.spinlock);
197
+ netdata_spinlock_unlock(&journalfile->mmap.spinlock);
198
+ }
199
+
200
+ return unmounted;
201
+}
202
+
203
+struct journal_v2_header *journalfile_v2_data_acquire(struct rrdengine_journalfile *journalfile, size_t *data_size, time_t wanted_first_time_s, time_t wanted_last_time_s) {
204
+ netdata_spinlock_lock(&journalfile->v2.spinlock);
205
+
206
+ bool has_data = (journalfile->v2.flags & JOURNALFILE_FLAG_IS_AVAILABLE);
207
+ bool is_mounted = (journalfile->v2.flags & JOURNALFILE_FLAG_IS_MOUNTED);
208
+ bool do_we_need_it = false;
209
+ bool unmount = false;
210
+
211
+ if(has_data) {
212
+ if (!wanted_first_time_s || !wanted_last_time_s ||
213
+ is_page_in_time_range(journalfile->v2.first_time_s, journalfile->v2.last_time_s,
214
+ wanted_first_time_s, wanted_last_time_s) == PAGE_IS_IN_RANGE) {
215
+
216
+ journalfile->v2.refcount++;
217
+
218
+ do_we_need_it = true;
219
+ journalfile->v2.not_needed_counter = 0;
220
+
221
+ if (!wanted_first_time_s && !wanted_last_time_s && !is_mounted)
222
+ journalfile->v2.flags |= JOURNALFILE_FLAG_MOUNTED_FOR_RETENTION;
223
+ else
224
+ journalfile->v2.flags &= ~JOURNALFILE_FLAG_MOUNTED_FOR_RETENTION;
225
+
226
+ }
227
+ else if (is_mounted) {
228
+ // this journal has data, but it does not match our query
229
+
230
+ if (!journalfile->v2.refcount) {
231
+ // this journal has no references
232
+
233
+ if (!journalfile->v2.not_needed_counter)
234
+ journalfile->v2.not_needed_since_s = now_monotonic_sec();
235
+
236
+ if ((++journalfile->v2.not_needed_counter) % 100 == 0) {
237
+ // at least 100 times it has been evaluated since last use
238
+
239
+ if (now_monotonic_sec() - journalfile->v2.not_needed_since_s >= 120)
240
+ // 2 minutes have passed since last use
241
+ unmount = true;
242
+ }
243
+ }
244
+ }
245
+ }
246
+ netdata_spinlock_unlock(&journalfile->v2.spinlock);
247
+
248
+ if(do_we_need_it)
249
+ return journalfile_v2_mounted_data_get(journalfile, data_size);
250
+
251
+ else if(unmount)
252
+ journalfile_v2_mounted_data_unmount(journalfile, false);
253
+
254
+ return NULL;
255
+}
256
+
257
+void journalfile_v2_data_release(struct rrdengine_journalfile *journalfile) {
258
+ netdata_spinlock_lock(&journalfile->v2.spinlock);
259
+
260
+ internal_fatal(!journalfile->mmap.data, "trying to release a journalfile without data");
261
+ internal_fatal(journalfile->v2.refcount < 1, "trying to release a non-acquired journalfile");
262
+
263
+ bool unmount = false;
264
+
265
+ journalfile->v2.refcount--;
266
+
267
+ if(journalfile->v2.refcount == 0) {
268
+ journalfile->v2.not_needed_counter = 0;
269
+
270
+ if(journalfile->v2.flags & JOURNALFILE_FLAG_MOUNTED_FOR_RETENTION)
271
+ unmount = true;
272
+ }
273
+ netdata_spinlock_unlock(&journalfile->v2.spinlock);
274
+
275
+ if(unmount)
276
+ journalfile_v2_mounted_data_unmount(journalfile, false);
277
+}
278
+
279
+bool journalfile_v2_data_available(struct rrdengine_journalfile *journalfile) {
280
+
281
+ netdata_spinlock_lock(&journalfile->v2.spinlock);
282
+ bool has_data = (journalfile->v2.flags & JOURNALFILE_FLAG_IS_AVAILABLE);
283
+ netdata_spinlock_unlock(&journalfile->v2.spinlock);
284
+
285
+ return has_data;
286
+}
287
+
288
+size_t journalfile_v2_data_size_get(struct rrdengine_journalfile *journalfile) {
289
+
290
+ netdata_spinlock_lock(&journalfile->mmap.spinlock);
291
+ size_t data_size = journalfile->mmap.size;
292
+ netdata_spinlock_unlock(&journalfile->mmap.spinlock);
293
+
294
+ return data_size;
295
+}
296
+
297
+void journalfile_v2_data_set(struct rrdengine_journalfile *journalfile, int fd, void *journal_data, uint32_t journal_data_size) {
298
+ netdata_spinlock_lock(&journalfile->mmap.spinlock);
299
+ netdata_spinlock_lock(&journalfile->v2.spinlock);
300
+
301
+ internal_fatal(journalfile->mmap.fd != -1, "DBENGINE JOURNALFILE: trying to re-set journal fd");
302
+ internal_fatal(journalfile->mmap.data, "DBENGINE JOURNALFILE: trying to re-set journal_data");
303
+ internal_fatal(journalfile->v2.refcount, "DBENGINE JOURNALFILE: trying to re-set journal_data of referenced journalfile");
304
+
305
+ journalfile->mmap.fd = fd;
306
+ journalfile->mmap.data = journal_data;
307
+ journalfile->mmap.size = journal_data_size;
308
+ journalfile->v2.not_needed_since_s = now_monotonic_sec();
309
+ journalfile->v2.flags |= JOURNALFILE_FLAG_IS_AVAILABLE | JOURNALFILE_FLAG_IS_MOUNTED;
310
+
311
+ struct journal_v2_header *j2_header = journalfile->mmap.data;
312
+ journalfile->v2.first_time_s = (time_t)(j2_header->start_time_ut / USEC_PER_SEC);
313
+ journalfile->v2.last_time_s = (time_t)(j2_header->end_time_ut / USEC_PER_SEC);
314
+
315
+ journalfile_v2_mounted_data_unmount(journalfile, true);
316
+
317
+ netdata_spinlock_unlock(&journalfile->v2.spinlock);
318
+ netdata_spinlock_unlock(&journalfile->mmap.spinlock);
319
+}
320
+
321
+static void journalfile_v2_data_unmap_permanently(struct rrdengine_journalfile *journalfile) {
322
+ bool has_references = false;
323
+
324
+ do {
325
+ if (has_references)
326
+ sleep_usec(10 * USEC_PER_MS);
327
+
328
+ netdata_spinlock_lock(&journalfile->mmap.spinlock);
329
+ netdata_spinlock_lock(&journalfile->v2.spinlock);
330
+
331
+ if(journalfile_v2_mounted_data_unmount(journalfile, true)) {
332
+ close(journalfile->mmap.fd);
333
+ journalfile->mmap.fd = -1;
334
+ journalfile->mmap.data = NULL;
335
+ journalfile->mmap.size = 0;
336
+ journalfile->v2.first_time_s = 0;
337
+ journalfile->v2.last_time_s = 0;
338
+ journalfile->v2.flags = 0;
339
+ }
340
+ else {
341
+ has_references = true;
342
+ internal_error(true, "DBENGINE JOURNALFILE: waiting for journalfile to be available to unmap...");
343
+ }
344
+
345
+ netdata_spinlock_unlock(&journalfile->v2.spinlock);
346
+ netdata_spinlock_unlock(&journalfile->mmap.spinlock);
347
+
348
+ } while(has_references);
349
+}
350
+
351
+struct rrdengine_journalfile *journalfile_alloc_and_init(struct rrdengine_datafile *datafile)
352
{
124
- journalfile->file = (uv_file)0;
125
- journalfile->pos = 0;
353
+ struct rrdengine_journalfile *journalfile = callocz(1, sizeof(struct rrdengine_journalfile));
354
journalfile->datafile = datafile;
127
- SET_JOURNAL_DATA(journalfile, 0);
128
- SET_JOURNAL_DATA_SIZE(journalfile, 0);
129
- journalfile->data = NULL;
355
+ netdata_spinlock_init(&journalfile->mmap.spinlock);
356
+ netdata_spinlock_init(&journalfile->v2.spinlock);
357
+ journalfile->mmap.fd = -1;
358
+ datafile->journalfile = journalfile;
359
+ return journalfile;
360
}
361
362
static int close_uv_file(struct rrdengine_datafile *datafile, uv_file file)
367
uv_fs_t req;
368
ret = uv_fs_close(NULL, &req, file, NULL);
369
if (ret < 0) {
140
- generate_journalfilepath(datafile, path, sizeof(path));
370
+ journalfile_generate_path(datafile, path, sizeof(path));
371
error("DBENGINE: uv_fs_close(%s): %s", path, uv_strerror(ret));
372
++datafile->ctx->stats.fs_errors;
373
rrd_stat_atomic_add(&global_fs_errors, 1);
376
return ret;
377
}
378
149
-int close_journal_file(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
379
+int journalfile_close(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
380
{
151
- struct rrdengine_instance *ctx = datafile->ctx;
152
- char path[RRDENG_PATH_MAX];
153
-
154
- void *journal_data = GET_JOURNAL_DATA(journalfile);
155
- size_t journal_data_size = GET_JOURNAL_DATA_SIZE(journalfile);
156
-
157
- if (likely(journal_data)) {
158
- if (munmap(journal_data, journal_data_size)) {
159
- generate_journalfilepath_v2(datafile, path, sizeof(path));
160
- error("DBENGINE: failed to unmap journal index file for %s", path);
161
- ++ctx->stats.fs_errors;
162
- rrd_stat_atomic_add(&global_fs_errors, 1);
163
- }
164
- SET_JOURNAL_DATA(journalfile, 0);
165
- SET_JOURNAL_DATA_SIZE(journalfile, 0);
381
+ if(journalfile_v2_data_available(journalfile)) {
382
+ journalfile_v2_data_unmap_permanently(journalfile);
383
return 0;
384
}
385
386
return close_uv_file(datafile, journalfile->file);
387
}
388
172
-int unlink_journal_file(struct rrdengine_journalfile *journalfile)
389
+int journalfile_unlink(struct rrdengine_journalfile *journalfile)
390
{
391
struct rrdengine_datafile *datafile = journalfile->datafile;
392
struct rrdengine_instance *ctx = datafile->ctx;
394
int ret;
395
char path[RRDENG_PATH_MAX];
396
180
- generate_journalfilepath(datafile, path, sizeof(path));
397
+ journalfile_generate_path(datafile, path, sizeof(path));
398
399
ret = uv_fs_unlink(NULL, &req, path, NULL);
400
if (ret < 0) {
409
return ret;
410
}
411
195
-int destroy_journal_file_unsafe(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
412
+int journalfile_destroy_unsafe(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
413
{
414
struct rrdengine_instance *ctx = datafile->ctx;
415
uv_fs_t req;
417
char path[RRDENG_PATH_MAX];
418
char path_v2[RRDENG_PATH_MAX];
419
203
- generate_journalfilepath(datafile, path, sizeof(path));
204
- generate_journalfilepath_v2(datafile, path_v2, sizeof(path));
420
+ journalfile_generate_path(datafile, path, sizeof(path));
421
+ journalfile_v2_generate_path(datafile, path_v2, sizeof(path));
422
423
if (journalfile->file) {
424
ret = uv_fs_ftruncate(NULL, &req, journalfile->file, 0, NULL);
451
++ctx->stats.journalfile_deletions;
452
++ctx->stats.journalfile_deletions;
453
237
- void *journal_data = GET_JOURNAL_DATA(journalfile);
238
- size_t journal_data_size = GET_JOURNAL_DATA_SIZE(journalfile);
239
-
240
- if (journal_data) {
241
- if (munmap(journal_data, journal_data_size)) {
242
- error("DBENGINE: failed to unmap index file %s", path_v2);
243
- }
244
- }
454
+ if(journalfile_v2_data_available(journalfile))
455
+ journalfile_v2_data_unmap_permanently(journalfile);
456
457
return ret;
458
}
459
249
-int create_journal_file(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
460
+int journalfile_create(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
461
{
462
struct rrdengine_instance *ctx = datafile->ctx;
463
uv_fs_t req;
467
uv_buf_t iov;
468
char path[RRDENG_PATH_MAX];
469
259
- generate_journalfilepath(datafile, path, sizeof(path));
470
+ journalfile_generate_path(datafile, path, sizeof(path));
471
fd = open_file_direct_io(path, O_CREAT | O_RDWR | O_TRUNC, &file);
472
if (fd < 0) {
473
++ctx->stats.fs_errors;
497
uv_fs_req_cleanup(&req);
498
posix_memfree(superblock);
499
if (ret < 0) {
289
- destroy_journal_file_unsafe(journalfile, datafile);
500
+ journalfile_destroy_unsafe(journalfile, datafile);
501
return ret;
502
}
503
508
return 0;
509
}
510
300
-static int check_journal_file_superblock(uv_file file)
511
+static int journalfile_check_superblock(uv_file file)
512
{
513
int ret;
514
struct rrdeng_jf_sb *superblock;
542
return ret;
543
}
544
334
-static void restore_extent_metadata(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile, void *buf, unsigned max_size)
545
+static void journalfile_restore_extent_metadata(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile, void *buf, unsigned max_size)
546
{
547
static BITMAP256 page_error_map;
548
unsigned i, count, payload_length, descr_size;
618
* Sets id to the current transaction id or to 0 if unknown.
619
* Returns size of transaction record or 0 for unknown size.
620
*/
410
-static unsigned replay_transaction(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile,
411
- void *buf, uint64_t *id, unsigned max_size)
621
+static unsigned journalfile_replay_transaction(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile,
622
+ void *buf, uint64_t *id, unsigned max_size)
623
{
624
unsigned payload_length, size_bytes;
625
int ret;
657
switch (jf_header->type) {
658
case STORE_DATA:
659
debug(D_RRDENGINE, "Replaying transaction %"PRIu64"", jf_header->id);
449
- restore_extent_metadata(ctx, journalfile, buf + sizeof(*jf_header), payload_length);
660
+ journalfile_restore_extent_metadata(ctx, journalfile, buf + sizeof(*jf_header), payload_length);
661
break;
662
default:
663
error("DBENGINE: unknown transaction type, skipping record.");
674
* Page cache must already be initialized.
675
* Returns the maximum transaction id it discovered.
676
*/
466
-static uint64_t iterate_transactions(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile)
677
+static uint64_t journalfile_iterate_transactions(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile)
678
{
679
uv_file file;
680
uint64_t file_size;//, data_file_size;
718
unsigned max_size;
719
720
max_size = pos + size_bytes - pos_i;
510
- ret = replay_transaction(ctx, journalfile, buf + pos_i, &id, max_size);
721
+ ret = journalfile_replay_transaction(ctx, journalfile, buf + pos_i, &id, max_size);
722
if (!ret) /* TODO: support transactions bigger than 4K */
723
/* unknown transaction size, move on to the next block */
724
pos_i = ALIGN_BYTES_FLOOR(pos_i + RRDENG_BLOCK_SIZE);
736
}
737
738
// Checks that the extent list checksum is valid
528
-static int check_journal_v2_extent_list (void *data_start, size_t file_size)
739
+static int journalfile_check_v2_extent_list (void *data_start, size_t file_size)
740
{
741
UNUSED(file_size);
742
uLong crc;
756
}
757
758
// Checks that the metric list (UUIDs) checksum is valid
548
-static int check_journal_v2_metric_list(void *data_start, size_t file_size)
759
+static int journalfile_check_v2_metric_list(void *data_start, size_t file_size)
760
{
761
UNUSED(file_size);
762
uLong crc;
781
// 2 Force rebuild
782
// 3 skip
783
573
-static int check_journal_v2_file(void *data_start, size_t file_size, uint32_t original_size)
784
+static int journalfile_v2_validate(void *data_start, size_t file_size, uint32_t original_size)
785
{
786
int rc;
787
uLong crc;
816
return 1;
817
}
818
608
- rc = check_journal_v2_extent_list(data_start, file_size);
819
+ rc = journalfile_check_v2_extent_list(data_start, file_size);
820
if (rc) return 1;
821
611
- rc = check_journal_v2_metric_list(data_start, file_size);
822
+ rc = journalfile_check_v2_metric_list(data_start, file_size);
823
if (rc) return 1;
824
825
if (!db_engine_journal_check)
878
return 0;
879
}
880
670
-int load_journal_file_v2(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
881
+int journalfile_v2_load(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
882
{
883
int ret, fd;
884
uint64_t file_size;
886
struct stat statbuf;
887
uint32_t original_file_size = 0;
888
678
- generate_journalfilepath(datafile, path, sizeof(path));
889
+ journalfile_generate_path(datafile, path, sizeof(path));
890
ret = stat(path, &statbuf);
891
if (!ret)
892
original_file_size = (uint32_t)statbuf.st_size;
893
683
- generate_journalfilepath_v2(datafile, path, sizeof(path));
894
+ journalfile_v2_generate_path(datafile, path, sizeof(path));
895
896
fd = open(path, O_RDONLY);
897
if (fd < 0) {
924
close(fd);
925
return 1;
926
}
716
- close(fd);
927
928
info("DBENGINE: checking integrity of '%s'", path);
719
- int rc = check_journal_v2_file(data_start, file_size, original_file_size);
929
+ int rc = journalfile_v2_validate(data_start, file_size, original_file_size);
930
if (unlikely(rc)) {
931
if (rc == 2)
932
error_report("File %s needs to be rebuilt", path);
938
if (unlikely(munmap(data_start, file_size)))
939
error("DBENGINE: failed to unmap '%s'", path);
940
941
+ close(fd);
942
return rc;
943
}
944
949
if (unlikely(munmap(data_start, file_size)))
950
error("DBENGINE: failed to unmap '%s'", path);
951
952
+ close(fd);
953
return 1;
954
}
955
958
959
struct journal_metric_list *metric = (struct journal_metric_list *) (data_start + j2_header->metric_offset);
960
749
- // Initialize the journal file to be able to access the data
750
- SET_JOURNAL_DATA(journalfile, data_start);
751
- SET_JOURNAL_DATA_SIZE(journalfile, file_size);
752
-
961
time_t header_start_time_s = (time_t) (j2_header->start_time_ut / USEC_PER_SEC);
962
963
time_t now_s = now_realtime_sec();
979
info("DBENGINE: journal file '%s' loaded (size:%"PRIu64") with %u metrics in %d ms", path, file_size, entries,
980
(int) ((now_realtime_usec() - start_loading) / USEC_PER_MS));
981
982
+ // Initialize the journal file to be able to access the data
983
+ journalfile_v2_data_set(journalfile, fd, data_start, file_size);
984
+
985
// File is OK load it
986
return 0;
987
}
990
struct jv2_metrics_info *metric_info;
991
};
992
782
-static int journal_metric_compare (const void *item1, const void *item2)
993
+static int journalfile_metric_compare (const void *item1, const void *item2)
994
{
995
const struct jv2_metrics_info *metric1 = ((struct journal_metric_list_to_sort *) item1)->metric_info;
996
const struct jv2_metrics_info *metric2 = ((struct journal_metric_list_to_sort *) item2)->metric_info;
1000
1001
1002
// Write list of extents for the journalfile
792
-void *journal_v2_write_extent_list(Pvoid_t JudyL_extents_pos, void *data)
1003
+void *journalfile_v2_write_extent_list(Pvoid_t JudyL_extents_pos, void *data)
1004
{
1005
Pvoid_t *PValue;
1006
struct journal_extent_list *j2_extent_base = (void *) data;
1021
return j2_extent_base + count;
1022
}
1023
813
-static int verify_journal_space(struct journal_v2_header *j2_header, void *data, uint32_t bytes)
1024
+static int journalfile_verify_space(struct journal_v2_header *j2_header, void *data, uint32_t bytes)
1025
{
1026
if ((unsigned long)(((uint8_t *) data - (uint8_t *) j2_header->data) + bytes) > (j2_header->total_file_size - sizeof(struct journal_v2_block_trailer)))
1027
return 1;
1029
return 0;
1030
}
1031
821
-void *journal_v2_write_metric_page(struct journal_v2_header *j2_header, void *data, struct jv2_metrics_info *metric_info, uint32_t pages_offset)
1032
+void *journalfile_v2_write_metric_page(struct journal_v2_header *j2_header, void *data, struct jv2_metrics_info *metric_info, uint32_t pages_offset)
1033
{
1034
struct journal_metric_list *metric = (void *) data;
1035
825
- if (verify_journal_space(j2_header, data, sizeof(*metric)))
1036
+ if (journalfile_verify_space(j2_header, data, sizeof(*metric)))
1037
return NULL;
1038
1039
uuid_copy(metric->uuid, *metric_info->uuid);
1045
return ++metric;
1046
}
1047
837
-void *journal_v2_write_data_page_header(struct journal_v2_header *j2_header __maybe_unused, void *data, struct jv2_metrics_info *metric_info, uint32_t uuid_offset)
1048
+void *journalfile_v2_write_data_page_header(struct journal_v2_header *j2_header __maybe_unused, void *data, struct jv2_metrics_info *metric_info, uint32_t uuid_offset)
1049
{
1050
struct journal_page_header *data_page_header = (void *) data;
1051
uLong crc;
1060
return ++data_page_header;
1061
}
1062
852
-void *journal_v2_write_data_page_trailer(struct journal_v2_header *j2_header __maybe_unused, void *data, void *page_header)
1063
+void *journalfile_v2_write_data_page_trailer(struct journal_v2_header *j2_header __maybe_unused, void *data, void *page_header)
1064
{
1065
struct journal_page_header *data_page_header = (void *) page_header;
1066
struct journal_v2_block_trailer *journal_trailer = (void *) data;
1072
return ++journal_trailer;
1073
}
1074
864
-void *journal_v2_write_data_page(struct journal_v2_header *j2_header, void *data, struct jv2_page_info *page_info)
1075
+void *journalfile_v2_write_data_page(struct journal_v2_header *j2_header, void *data, struct jv2_page_info *page_info)
1076
{
1077
struct journal_page_list *data_page = data;
1078
868
- if (verify_journal_space(j2_header, data, sizeof(*data_page)))
1079
+ if (journalfile_verify_space(j2_header, data, sizeof(*data_page)))
1080
return NULL;
1081
1082
struct extent_io_data *ei = page_info->custom_data;
1093
}
1094
1095
// Must be recorded in metric_info->entries
885
-void *journal_v2_write_descriptors(struct journal_v2_header *j2_header, void *data, struct jv2_metrics_info *metric_info)
1096
+void *journalfile_v2_write_descriptors(struct journal_v2_header *j2_header, void *data, struct jv2_metrics_info *metric_info)
1097
{
1098
Pvoid_t *PValue;
1099
1108
while ((PValue = JudyLFirstThenNext(JudyL_array, &index_time, &first))) {
1109
page_info = *PValue;
1110
// Write one descriptor and return the next data page location
900
- data_page = journal_v2_write_data_page(j2_header, (void *)data_page, page_info);
1111
+ data_page = journalfile_v2_write_data_page(j2_header, (void *) data_page, page_info);
1112
if (NULL == data_page)
1113
break;
1114
}
1121
// startup : if the migration is done during agent startup
1122
// this will allow us to optimize certain things
1123
913
-void do_migrate_to_v2_callback(Word_t section, unsigned datafile_fileno __maybe_unused, uint8_t type __maybe_unused,
914
- Pvoid_t JudyL_metrics, Pvoid_t JudyL_extents_pos,
915
- size_t number_of_extents, size_t number_of_metrics, size_t number_of_pages, void *user_data)
1124
+void journalfile_migrate_to_v2_callback(Word_t section, unsigned datafile_fileno __maybe_unused, uint8_t type __maybe_unused,
1125
+ Pvoid_t JudyL_metrics, Pvoid_t JudyL_extents_pos,
1126
+ size_t number_of_extents, size_t number_of_metrics, size_t number_of_pages, void *user_data)
1127
{
1128
char path[RRDENG_PATH_MAX];
1129
Pvoid_t *PValue;
1134
time_t max_time_s = 0;
1135
struct jv2_metrics_info *metric_info;
1136
926
- generate_journalfilepath_v2(datafile, path, sizeof(path));
1137
+ journalfile_v2_generate_path(datafile, path, sizeof(path));
1138
1139
info("DBENGINE: indexing file '%s': extents %zu, metrics %zu, pages %zu",
1140
path,
1172
uint32_t trailer_offset = total_file_size;
1173
total_file_size += sizeof(struct journal_v2_block_trailer);
1174
964
- uint8_t *data_start = netdata_mmap(path, total_file_size, MAP_SHARED, 0, false);
1175
+ int fd_v2;
1176
+ uint8_t *data_start = netdata_mmap(path, total_file_size, MAP_SHARED, 0, false, &fd_v2);
1177
uint8_t *data = data_start;
1178
1179
memset(data_start, 0, extent_offset);
1199
1200
struct journal_v2_block_trailer *journal_v2_trailer;
1201
990
- data = journal_v2_write_extent_list(JudyL_extents_pos, data_start + extent_offset);
1202
+ data = journalfile_v2_write_extent_list(JudyL_extents_pos, data_start + extent_offset);
1203
internal_error(true, "DBENGINE: write extent list so far %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1204
1205
fatal_assert(data == data_start + extent_offset_trailer);
1237
j2_header.start_time_ut = min_time_s * USEC_PER_SEC;
1238
j2_header.end_time_ut = max_time_s * USEC_PER_SEC;
1239
1028
- qsort(&uuid_list[0], number_of_metrics, sizeof(struct journal_metric_list_to_sort), journal_metric_compare);
1240
+ qsort(&uuid_list[0], number_of_metrics, sizeof(struct journal_metric_list_to_sort), journalfile_metric_compare);
1241
internal_error(true, "DBENGINE: traverse and qsort UUID %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1242
1243
uint32_t resize_file_to = total_file_size;
1249
uint32_t uuid_offset = data - data_start;
1250
1251
// Write the UUID we are processing
1040
- data = (void *) journal_v2_write_metric_page(&j2_header, data, metric_info, pages_offset);
1252
+ data = (void *) journalfile_v2_write_metric_page(&j2_header, data, metric_info, pages_offset);
1253
if (unlikely(!data))
1254
break;
1255
1261
// Keep the page_list_header, to be used for migration when where agent is running
1262
metric_info->page_list_header = pages_offset;
1263
// Write page header
1052
- void *metric_page = journal_v2_write_data_page_header(&j2_header, data_start + pages_offset, metric_info, uuid_offset);
1264
+ void *metric_page = journalfile_v2_write_data_page_header(&j2_header, data_start + pages_offset, metric_info,
1265
+ uuid_offset);
1266
1267
// Start writing descr @ time
1055
- void *page_trailer = journal_v2_write_descriptors(&j2_header, metric_page, metric_info);
1268
+ void *page_trailer = journalfile_v2_write_descriptors(&j2_header, metric_page, metric_info);
1269
if (unlikely(!page_trailer))
1270
break;
1271
1272
// Trailer (checksum)
1060
- uint8_t *next_page_address = journal_v2_write_data_page_trailer(&j2_header, page_trailer, data_start + pages_offset);
1273
+ uint8_t *next_page_address = journalfile_v2_write_data_page_trailer(&j2_header, page_trailer,
1274
+ data_start + pages_offset);
1275
1276
// Calculate start of the pages start for next descriptor
1277
pages_offset += (metric_info->number_of_pages * (sizeof(struct journal_page_list)) + sizeof(struct journal_page_header) + sizeof(struct journal_v2_block_trailer));
1308
1309
info("DBENGINE: migrated journal file '%s', file size %zu", path, total_file_size);
1310
1097
- SET_JOURNAL_DATA(journalfile, data_start);
1098
- SET_JOURNAL_DATA_SIZE(journalfile, total_file_size);
1311
+ // msync(data_start, total_file_size, MS_SYNC);
1312
+ journalfile_v2_data_set(journalfile, fd_v2, data_start, total_file_size);
1313
1314
internal_error(true, "DBENGINE: ACTIVATING NEW INDEX JNL %llu", (now_realtime_usec() - start_loading) / USEC_PER_MS);
1315
ctx->disk_space += total_file_size;
1341
ctx->disk_space += sizeof(struct journal_v2_header);
1342
}
1343
1130
-int load_journal_file(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile,
1131
- struct rrdengine_datafile *datafile)
1344
+int journalfile_load(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile,
1345
+ struct rrdengine_datafile *datafile)
1346
{
1347
uv_fs_t req;
1348
uv_file file;
1352
1353
// Do not try to load the latest file (always rebuild and live migrate)
1354
if (datafile->fileno != ctx->last_fileno) {
1141
- if (!load_journal_file_v2(ctx, journalfile, datafile))
1355
+ if (!journalfile_v2_load(ctx, journalfile, datafile)) {
1356
+// unmap_journal_file(journalfile);
1357
return 0;
1358
+ }
1359
}
1360
1145
- generate_journalfilepath(datafile, path, sizeof(path));
1361
+ journalfile_generate_path(datafile, path, sizeof(path));
1362
1363
// If it is not the last file, open read only
1364
fd = open_file_direct_io(path, O_RDWR, &file);
1373
goto error;
1374
file_size = ALIGN_BYTES_FLOOR(file_size);
1375
1160
- ret = check_journal_file_superblock(file);
1376
+ ret = journalfile_check_superblock(file);
1377
if (ret) {
1378
info("DBENGINE: invalid journal file '%s' ; superblock check failed.", path);
1379
goto error;
1384
journalfile->file = file;
1385
journalfile->pos = file_size;
1386
1171
- journalfile->data = netdata_mmap(path, file_size, MAP_SHARED, 0, !(datafile->fileno == ctx->last_fileno));
1387
+ journalfile->data = netdata_mmap(path, file_size, MAP_SHARED, 0, !(datafile->fileno == ctx->last_fileno), NULL);
1388
info("DBENGINE: loading journal file '%s' using %s.", path, journalfile->data?"MMAP":"uv_fs_read");
1389
1174
- max_id = iterate_transactions(ctx, journalfile);
1390
+ max_id = journalfile_iterate_transactions(ctx, journalfile);
1391
1392
ctx->commit_log.transaction_id = MAX(ctx->commit_log.transaction_id, max_id + 1);
1393
1401
return 0;
1402
}
1403
1188
- pgc_open_cache_to_journal_v2(open_cache, (Word_t) ctx, (int) datafile->fileno, ctx->page_type, do_migrate_to_v2_callback, (void *) datafile->journalfile);
1404
+ pgc_open_cache_to_journal_v2(open_cache, (Word_t) ctx, (int) datafile->fileno, ctx->page_type,
1405
+ journalfile_migrate_to_v2_callback, (void *) datafile->journalfile);
1406
1407
if (is_last_file)
1408
ctx->create_new_datafile_pair = true;