master
c 738 lines 26.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2 #include "rrdengine.h"
3
4 #ifdef OS_WINDOWS
5 void sync_uv_file_data(uv_file file)
6 {
7 uv_fs_t req;
8 (void) uv_fs_fsync(NULL, &req, file, NULL);
9 uv_fs_req_cleanup(&req);
10 }
11 #endif
12
13 void datafile_list_insert(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile)
14 {
15 netdata_rwlock_wrlock(&ctx->datafiles.rwlock);
16 Pvoid_t *Pvalue = JudyLIns(&ctx->datafiles.JudyL, (Word_t ) datafile->fileno, PJE0);
17 if(!Pvalue || Pvalue == PJERR)
18 fatal("DBENGINE: cannot insert datafile %u of tier %d into the datafiles list",
19 datafile->fileno, ctx->config.tier);
20 *Pvalue = datafile;
21
22 #ifdef OS_WINDOWS
23 sync_uv_file_data(datafile->file);
24 sync_uv_file_data(datafile->journalfile->file);
25 datafile->writers.last_sync_time = now_realtime_sec();
26 #endif
27
28 netdata_rwlock_wrunlock(&ctx->datafiles.rwlock);
29 }
30
31 void datafile_list_delete_unsafe(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile)
32 {
33 (void) JudyLDel(&ctx->datafiles.JudyL, (Word_t)datafile->fileno, PJE0);
34 }
35
36
37 static struct rrdengine_datafile *datafile_alloc_and_init(struct rrdengine_instance *ctx, unsigned tier, unsigned fileno)
38 {
39 fatal_assert(tier == 1);
40
41 struct rrdengine_datafile *datafile = callocz(1, sizeof(struct rrdengine_datafile));
42
43 datafile->tier = tier;
44 datafile->fileno = fileno;
45 fatal_assert(0 == netdata_rwlock_init(&datafile->extent_rwlock));
46 datafile->ctx = ctx;
47 datafile->magic1 = datafile->magic2 = DATAFILE_MAGIC;
48
49 datafile->users.available = true;
50 datafile->users.pending_deletion = false;
51
52 spinlock_init(&datafile->users.spinlock);
53 spinlock_init(&datafile->writers.spinlock);
54 rw_spinlock_init(&datafile->extent_epdl.spinlock);
55
56 return datafile;
57 }
58
59 ALWAYS_INLINE bool datafile_acquire(struct rrdengine_datafile *df, DATAFILE_ACQUIRE_REASONS reason)
60 {
61 bool ret = false;
62
63 spinlock_lock(&df->users.spinlock);
64
65 if(df->users.available && reason < DATAFILE_ACQUIRE_MAX) {
66 bool allow = true;
67
68 if(df->users.pending_deletion) {
69 if(reason == DATAFILE_ACQUIRE_OPEN_CACHE) {
70 // Hold writers.spinlock to read the writer counters, ensuring proper
71 // memory ordering on weakly-ordered architectures (ARM) - consistent
72 // with all other read sites in the codebase.
73 spinlock_lock(&df->writers.spinlock);
74 size_t writers_running = df->writers.running;
75 size_t flushed_to_open_running = df->writers.flushed_to_open_running;
76 spinlock_unlock(&df->writers.spinlock);
77 allow = (writers_running || flushed_to_open_running);
78 }
79 else
80 allow = false;
81 }
82
83 if(allow) {
84 ret = true;
85 df->users.lockers++;
86 df->users.lockers_by_reason[reason]++;
87 }
88 }
89
90 spinlock_unlock(&df->users.spinlock);
91
92 return ret;
93 }
94
95 void datafile_release_with_trace(struct rrdengine_datafile *df, DATAFILE_ACQUIRE_REASONS reason, const char *func) {
96 spinlock_lock(&df->users.spinlock);
97 if(!df->users.lockers)
98 fatal("DBENGINE DATAFILE: cannot release datafile %u of tier %u - it is not acquired, called from %s() with reason %u",
99 df->fileno, df->tier, func, reason);
100
101 df->users.lockers--;
102 df->users.lockers_by_reason[reason]--;
103 spinlock_unlock(&df->users.spinlock);
104 }
105
106 bool datafile_acquire_for_deletion(struct rrdengine_datafile *df, bool is_shutdown)
107 {
108 bool can_be_deleted = false;
109 bool marked_pending = false;
110 bool should_evict_open_pages = false;
111
112 spinlock_lock(&df->users.spinlock);
113
114 if(!df->users.pending_deletion) {
115 df->users.pending_deletion = true;
116 marked_pending = true;
117 }
118
119 // Hold writers.spinlock to read the writer counters, ensuring proper memory ordering
120 // on weakly-ordered architectures (ARM). Without this, stale reads could cause premature
121 // deletion while a writer is still active - writers use these counters (not lockers) for
122 // their lifecycle, so lockers alone cannot protect against this race.
123 spinlock_lock(&df->writers.spinlock);
124 size_t writers_running = df->writers.running;
125 size_t flushed_to_open_running = df->writers.flushed_to_open_running;
126 spinlock_unlock(&df->writers.spinlock);
127
128 if(!writers_running && !flushed_to_open_running && !df->users.lockers) {
129 can_be_deleted = true;
130 df->users.available = false;
131 }
132 else if(df->users.lockers)
133 should_evict_open_pages = true;
134 spinlock_unlock(&df->users.spinlock);
135
136 if(marked_pending)
137 netdata_log_info("DBENGINE: tier %d: " DATAFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL " is pending deletion (%s)",
138 datafile_ctx(df)->config.tier, df->tier, df->fileno, is_shutdown ? "shutdown" : "runtime");
139
140 if(can_be_deleted)
141 return true;
142
143 if(should_evict_open_pages)
144 pgc_open_evict_clean_pages_of_datafile(open_cache, df);
145
146 usec_t time_to_scan_ut = now_monotonic_usec();
147 size_t clean_pages_in_open_cache = pgc_count_clean_pages_having_data_ptr(open_cache, (Word_t)datafile_ctx(df), df);
148 size_t hot_pages_in_open_cache = pgc_count_hot_pages_having_data_ptr(open_cache, (Word_t)datafile_ctx(df), df);
149 time_to_scan_ut = now_monotonic_usec() - time_to_scan_ut;
150
151 spinlock_lock(&df->users.spinlock);
152
153 spinlock_lock(&df->writers.spinlock);
154 writers_running = df->writers.running;
155 flushed_to_open_running = df->writers.flushed_to_open_running;
156 spinlock_unlock(&df->writers.spinlock);
157
158 if(!writers_running && !flushed_to_open_running) {
159 if(df->users.available) {
160 df->users.available = false;
161 netdata_log_info("DBENGINE: tier %d: " DATAFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL " entered deletion phase-2 (new users blocked)",
162 datafile_ctx(df)->config.tier, df->tier, df->fileno);
163 }
164
165 if(!df->users.lockers)
166 can_be_deleted = true;
167
168 else if(!clean_pages_in_open_cache && !hot_pages_in_open_cache) {
169 time_t now_s = now_monotonic_sec();
170
171 if(!df->users.time_to_evict) {
172 df->users.time_to_evict = now_s + (is_shutdown ? DATAFILE_DELETE_TIMEOUT_SHORT : DATAFILE_DELETE_TIMEOUT_LONG);
173 internal_error(true, "DBENGINE: datafile %u of tier %d pending deletion has %u lockers "
174 "(oc:%u, pd:%u, rt:%u, ix:%u), writers %zu/%zu, open-cache clean/hot %zu/%zu "
175 "- will force-delete shortly (scanned in %"PRIu64" usecs)",
176 df->fileno, datafile_ctx(df)->config.tier,
177 df->users.lockers,
178 df->users.lockers_by_reason[DATAFILE_ACQUIRE_OPEN_CACHE],
179 df->users.lockers_by_reason[DATAFILE_ACQUIRE_PAGE_DETAILS],
180 df->users.lockers_by_reason[DATAFILE_ACQUIRE_RETENTION],
181 df->users.lockers_by_reason[DATAFILE_ACQUIRE_INDEXING],
182 writers_running,
183 flushed_to_open_running,
184 clean_pages_in_open_cache,
185 hot_pages_in_open_cache,
186 time_to_scan_ut);
187 }
188 else if(now_s > df->users.time_to_evict) {
189 can_be_deleted = true;
190 internal_error(true, "DBENGINE: datafile %u of tier %d pending deletion has %u lockers "
191 "(oc:%u, pd:%u, rt:%u, ix:%u), writers %zu/%zu, open-cache clean/hot %zu/%zu "
192 "- forcing delete now (scanned in %"PRIu64" usecs)",
193 df->fileno, datafile_ctx(df)->config.tier,
194 df->users.lockers,
195 df->users.lockers_by_reason[DATAFILE_ACQUIRE_OPEN_CACHE],
196 df->users.lockers_by_reason[DATAFILE_ACQUIRE_PAGE_DETAILS],
197 df->users.lockers_by_reason[DATAFILE_ACQUIRE_RETENTION],
198 df->users.lockers_by_reason[DATAFILE_ACQUIRE_INDEXING],
199 writers_running,
200 flushed_to_open_running,
201 clean_pages_in_open_cache,
202 hot_pages_in_open_cache,
203 time_to_scan_ut);
204 }
205 }
206 }
207
208 if(!can_be_deleted)
209 internal_error(true, "DBENGINE: datafile %u of tier %d pending deletion has %u lockers "
210 "(oc:%u, pd:%u, rt:%u, ix:%u), writers %zu/%zu, open-cache clean/hot %zu/%zu "
211 "(scanned in %"PRIu64" usecs)",
212 df->fileno, datafile_ctx(df)->config.tier,
213 df->users.lockers,
214 df->users.lockers_by_reason[DATAFILE_ACQUIRE_OPEN_CACHE],
215 df->users.lockers_by_reason[DATAFILE_ACQUIRE_PAGE_DETAILS],
216 df->users.lockers_by_reason[DATAFILE_ACQUIRE_RETENTION],
217 df->users.lockers_by_reason[DATAFILE_ACQUIRE_INDEXING],
218 writers_running,
219 flushed_to_open_running,
220 clean_pages_in_open_cache,
221 hot_pages_in_open_cache,
222 time_to_scan_ut);
223
224 spinlock_unlock(&df->users.spinlock);
225
226 return can_be_deleted;
227 }
228
229 void generate_datafilepath(struct rrdengine_datafile *datafile, char *str, size_t maxlen)
230 {
231 (void) snprintfz(str, maxlen - 1, "%s/" DATAFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL DATAFILE_EXTENSION,
232 datafile_ctx(datafile)->config.dbfiles_path, datafile->tier, datafile->fileno);
233 }
234
235 int close_data_file(struct rrdengine_datafile *datafile)
236 {
237 struct rrdengine_instance *ctx = datafile_ctx(datafile);
238 int ret;
239 char path[RRDENG_PATH_MAX];
240 generate_datafilepath(datafile, path, sizeof(path));
241 CLOSE_FILE(ctx, path, datafile->file, ret);
242 return ret;
243 }
244
245 int unlink_data_file(struct rrdengine_datafile *datafile)
246 {
247 struct rrdengine_instance *ctx = datafile_ctx(datafile);
248 int ret;
249 char path[RRDENG_PATH_MAX];
250
251 generate_datafilepath(datafile, path, sizeof(path));
252
253 UNLINK_FILE(ctx, path, ret);
254 if (ret == 0)
255 __atomic_add_fetch(&ctx->stats.datafile_deletions, 1, __ATOMIC_RELAXED);
256
257 return ret;
258 }
259
260 int destroy_data_file_unsafe(struct rrdengine_datafile *datafile)
261 {
262 struct rrdengine_instance *ctx = datafile_ctx(datafile);
263 int ret;
264 char path[RRDENG_PATH_MAX];
265
266 generate_datafilepath(datafile, path, sizeof(path));
267
268 CLOSE_FILE(ctx, path, datafile->file, ret);
269 ret = unlink_data_file(datafile);
270
271 return ret;
272 }
273
274 int create_data_file(struct rrdengine_datafile *datafile)
275 {
276 struct rrdengine_instance *ctx = datafile_ctx(datafile);
277 uv_fs_t req;
278 uv_file file;
279 int ret, fd;
280 struct rrdeng_df_sb *superblock = NULL;
281 uv_buf_t iov;
282 char path[RRDENG_PATH_MAX];
283
284 generate_datafilepath(datafile, path, sizeof(path));
285 fd = open_file_for_io(path, O_CREAT | O_RDWR | O_TRUNC, &file, dbengine_use_direct_io);
286 if (fd < 0) {
287 ctx_fs_error(ctx);
288 return fd;
289 }
290 datafile->file = file;
291
292 (void)posix_memalignz((void *)&superblock, RRDFILE_ALIGNMENT, sizeof(*superblock));
293 memset(superblock, 0, sizeof(*superblock));
294 (void) strncpy(superblock->magic_number, RRDENG_DF_MAGIC, RRDENG_MAGIC_SZ);
295 (void) strncpy(superblock->version, RRDENG_DF_VER, RRDENG_VER_SZ);
296 superblock->tier = 1;
297
298 iov = uv_buf_init((void *)superblock, sizeof(*superblock));
299
300 int retries = 10;
301 ret = -1;
302 while (ret < 0 && --retries) {
303 ret = uv_fs_write(NULL, &req, file, &iov, 1, 0, NULL);
304 uv_fs_req_cleanup(&req);
305 if (ret < 0) {
306 if (ret == -ENOSPC || ret == -EBADF || ret == -EACCES || ret == -EROFS || ret == -EINVAL)
307 break;
308 sleep_usec(300 * USEC_PER_MS);
309 }
310 }
311
312 posix_memalign_freez(superblock);
313 if (ret < 0) {
314 (void) destroy_data_file_unsafe(datafile);
315 ctx_io_error(ctx);
316 nd_log_limit_static_global_var(dbengine_erl, 10, 0);
317 nd_log_limit(&dbengine_erl, NDLS_DAEMON, NDLP_ERR, "DBENGINE: Failed to create datafile %s", path);
318 return ret;
319 }
320
321 __atomic_add_fetch(&ctx->stats.datafile_creations, 1, __ATOMIC_RELAXED);
322 datafile->pos = sizeof(*superblock);
323 ctx_io_write_op_bytes(ctx, sizeof(*superblock));
324
325 return 0;
326 }
327
328 static int check_data_file_superblock(uv_file file)
329 {
330 int ret;
331 struct rrdeng_df_sb *superblock = NULL;
332 uv_buf_t iov;
333 uv_fs_t req;
334
335 (void)posix_memalignz((void *)&superblock, RRDFILE_ALIGNMENT, sizeof(*superblock));
336 iov = uv_buf_init((void *)superblock, sizeof(*superblock));
337
338 ret = uv_fs_read(NULL, &req, file, &iov, 1, 0, NULL);
339 if (ret < 0) {
340 netdata_log_error("DBENGINE: uv_fs_read: %s", uv_strerror(ret));
341 uv_fs_req_cleanup(&req);
342 goto error;
343 }
344 fatal_assert(req.result >= 0);
345 uv_fs_req_cleanup(&req);
346
347 if (strncmp(superblock->magic_number, RRDENG_DF_MAGIC, RRDENG_MAGIC_SZ) ||
348 strncmp(superblock->version, RRDENG_DF_VER, RRDENG_VER_SZ) ||
349 superblock->tier != 1) {
350 netdata_log_error("DBENGINE: file has invalid superblock.");
351 ret = UV_EINVAL;
352 } else {
353 ret = 0;
354 }
355 error:
356 posix_memalign_freez(superblock);
357 return ret;
358 }
359
360 static int load_data_file(struct rrdengine_datafile *datafile)
361 {
362 struct rrdengine_instance *ctx = datafile_ctx(datafile);
363 uv_file file;
364 int ret, fd, error;
365 uint64_t file_size;
366 char path[RRDENG_PATH_MAX];
367
368 generate_datafilepath(datafile, path, sizeof(path));
369 fd = open_file_for_io(path, O_RDWR, &file, dbengine_use_direct_io);
370 if (fd < 0) {
371 ctx_fs_error(ctx);
372 return fd;
373 }
374
375 nd_log_daemon(NDLP_DEBUG, "DBENGINE: initializing data file \"%s\".", path);
376
377 ret = check_file_properties(file, &file_size, sizeof(struct rrdeng_df_sb));
378 if (ret)
379 goto err_exit;
380 file_size = ALIGN_BYTES_CEILING(file_size);
381
382 ret = check_data_file_superblock(file);
383 if (ret)
384 goto err_exit;
385
386 ctx_io_read_op_bytes(ctx, sizeof(struct rrdeng_df_sb));
387
388 datafile->file = file;
389 datafile->pos = file_size;
390
391 nd_log_daemon(NDLP_DEBUG, "DBENGINE: data file \"%s\" initialized (size:%" PRIu64 ").", path, file_size);
392
393 return 0;
394
395 err_exit:
396 error = ret;
397 CLOSE_FILE(ctx, path, file, ret);
398 return error;
399 }
400
401 static int scan_data_files_cmp(const void *a, const void *b)
402 {
403 struct rrdengine_datafile *file1, *file2;
404 char path1[RRDENG_PATH_MAX], path2[RRDENG_PATH_MAX];
405
406 file1 = *(struct rrdengine_datafile **)a;
407 file2 = *(struct rrdengine_datafile **)b;
408 generate_datafilepath(file1, path1, sizeof(path1));
409 generate_datafilepath(file2, path2, sizeof(path2));
410 return strcmp(path1, path2);
411 }
412
413 /* Returns number of datafiles that were loaded or < 0 on error */
414 static int scan_data_files(struct rrdengine_instance *ctx)
415 {
416 int ret, matched_files, failed_to_load, i;
417 unsigned tier, fileno;
418 uv_fs_t req;
419 uv_dirent_t dent;
420 struct rrdengine_datafile **datafiles, *datafile;
421 struct rrdengine_journalfile *journalfile;
422
423 ret = uv_fs_scandir(NULL, &req, ctx->config.dbfiles_path, 0, NULL);
424 if (ret < 0) {
425 fatal_assert(req.result < 0);
426 uv_fs_req_cleanup(&req);
427 netdata_log_error("DBENGINE: uv_fs_scandir(%s): %s", ctx->config.dbfiles_path, uv_strerror(ret));
428 ctx_fs_error(ctx);
429 return ret;
430 }
431 netdata_log_info("DBENGINE: tier %d: found %d files in path %s", ctx->config.tier, ret, ctx->config.dbfiles_path);
432
433 Pvoid_t datafiles_JudyL = NULL;
434 Pvoid_t journafile_JudyL = NULL;
435 datafiles = callocz(MIN(ret, MAX_DATAFILES), sizeof(*datafiles));
436 bool validate_files = true;
437 for (matched_files = 0 ; UV_EOF != uv_fs_scandir_next(&req, &dent) && matched_files < MAX_DATAFILES ; ) {
438 ret = sscanf(dent.name, DATAFILE_PREFIX RRDENG_FILE_NUMBER_SCAN_TMPL DATAFILE_EXTENSION, &tier, &fileno);
439
440 // This is a datafile
441 if (2 == ret) {
442 datafile = datafile_alloc_and_init(ctx, tier, fileno);
443 datafiles[matched_files++] = datafile;
444 Pvoid_t *Pvalue = JudyLIns(&datafiles_JudyL, (Word_t)fileno, PJE0);
445 if (!Pvalue || Pvalue == PJERR)
446 validate_files = false;
447 continue;
448 }
449
450 // Check for journal v1 or v2
451 char expected_name[RRDENG_PATH_MAX];
452 ret = sscanf(dent.name, WALFILE_PREFIX RRDENG_FILE_NUMBER_SCAN_TMPL WALFILE_EXTENSION, &tier, &fileno);
453 bool unknown_file = true;
454 if (2 == ret) {
455 (void) snprintfz(expected_name, sizeof(expected_name), WALFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL WALFILE_EXTENSION,
456 1U, fileno);
457
458 unknown_file = (strcmp(dent.name, expected_name) != 0);
459 if (unknown_file) {
460 (void) snprintfz(expected_name, sizeof(expected_name), WALFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL WALFILE_EXTENSION_V2,
461 1U, fileno);
462 unknown_file = (strcmp(dent.name, expected_name) != 0);
463 }
464
465 if (!unknown_file)
466 (void) JudyLIns(&journafile_JudyL, (Word_t)fileno, PJE0);
467 }
468
469 if (unknown_file)
470 nd_log_daemon(NDLP_WARNING, "Unknown file detected : \"%s/%s\"", ctx->config.dbfiles_path, dent.name);
471 }
472 uv_fs_req_cleanup(&req);
473
474 if (0 == matched_files) {
475 freez(datafiles);
476 return 0;
477 }
478
479 if (matched_files == MAX_DATAFILES)
480 netdata_log_error("DBENGINE: warning: hit maximum database engine file limit of %d files", MAX_DATAFILES);
481
482 qsort(datafiles, matched_files, sizeof(*datafiles), scan_data_files_cmp);
483
484 ctx->atomic.last_fileno = datafiles[matched_files - 1]->fileno;
485
486 // Remove journal files that do not have a matching data file
487 // by scanning the judy array of the journal files
488 if (validate_files) {
489 bool first_then_next = true;
490 Word_t idx = 0;
491 Pvoid_t *PValue;
492 size_t deleted_journals = 0;
493 while ((PValue = JudyLFirstThenNext(journafile_JudyL, &idx, &first_then_next))) {
494 char path[RRDENG_PATH_MAX];
495 if (unlikely(!JudyLGet(datafiles_JudyL, (Word_t)idx, PJE0))) {
496 (void)snprintfz(
497 path,
498 sizeof(path),
499 "%s/" WALFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL WALFILE_EXTENSION,
500 datafile_ctx(datafile)->config.dbfiles_path,
501 1U,
502 (unsigned)idx);
503
504 UNLINK_FILE(ctx, path, ret);
505 if (ret == 0) {
506 netdata_log_info("DBENGINE: deleting journal file without matching data file: %s", path);
507 __atomic_add_fetch(&ctx->stats.journalfile_deletions, 1, __ATOMIC_RELAXED);
508 deleted_journals++;
509 }
510
511 (void)snprintfz(
512 path,
513 sizeof(path),
514 "%s/" WALFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL WALFILE_EXTENSION_V2,
515 datafile_ctx(datafile)->config.dbfiles_path,
516 1U,
517 (unsigned)idx);
518
519 UNLINK_FILE(ctx, path, ret);
520 if (ret == 0) {
521 netdata_log_info("DBENGINE: deleting journal file without matching data file: %s", path);
522 __atomic_add_fetch(&ctx->stats.journalfile_deletions, 1, __ATOMIC_RELAXED);
523 deleted_journals++;
524 }
525 }
526 }
527
528 if (deleted_journals)
529 netdata_log_info("DBENGINE: deleted %zu journal files without matching data files", deleted_journals);
530 }
531
532 (void) JudyLFreeArray(&journafile_JudyL, NULL);
533 (void) JudyLFreeArray(&datafiles_JudyL, NULL);
534
535
536 netdata_log_info("DBENGINE: tier %d: loading %d data/journal files...", ctx->config.tier, matched_files);
537 for (failed_to_load = 0, i = 0 ; i < matched_files ; ++i) {
538 uint8_t must_delete_pair = 0;
539
540 datafile = datafiles[i];
541 ret = load_data_file(datafile);
542 if (0 != ret)
543 must_delete_pair = 1;
544
545 journalfile = journalfile_alloc_and_init(datafile);
546 ret = journalfile_load(ctx, journalfile, datafile);
547 if (0 != ret) {
548 if (!must_delete_pair) /* If datafile is still open close it */
549 close_data_file(datafile);
550 must_delete_pair = 1;
551 }
552
553 if (must_delete_pair) {
554 char path[RRDENG_PATH_MAX];
555
556 netdata_log_error("DBENGINE: deleting invalid data and journal file pair.");
557 ret = journalfile_unlink(journalfile);
558 if (!ret) {
559 journalfile_v1_generate_path(datafile, path, sizeof(path));
560 netdata_log_info("DBENGINE: deleted journal file \"%s\".", path);
561 }
562 ret = unlink_data_file(datafile);
563 if (!ret) {
564 generate_datafilepath(datafile, path, sizeof(path));
565 netdata_log_info("DBENGINE: deleted data file \"%s\".", path);
566 }
567 freez(journalfile);
568 freez(datafile);
569 ++failed_to_load;
570 continue;
571 }
572
573 ctx_current_disk_space_increase(ctx, datafile->pos + journalfile->unsafe.pos);
574 datafile_list_insert(ctx, datafile);
575 }
576
577 matched_files -= failed_to_load;
578 freez(datafiles);
579
580 return matched_files;
581 }
582
583 /* Creates a datafile and a journalfile pair */
584 int create_new_datafile_pair(struct rrdengine_instance *ctx)
585 {
586 __atomic_add_fetch(&rrdeng_cache_efficiency_stats.datafile_creation_started, 1, __ATOMIC_RELAXED);
587
588 struct rrdengine_datafile *datafile;
589 struct rrdengine_journalfile *journalfile;
590 unsigned fileno = ctx_last_fileno_get(ctx) + 1;
591 int ret;
592
593 nd_log(NDLS_DAEMON, NDLP_DEBUG,
594 "DBENGINE: creating new data and journal files in path \"%s\"",
595 ctx->config.dbfiles_path);
596
597 datafile = datafile_alloc_and_init(ctx, 1, fileno);
598 ret = create_data_file(datafile);
599 if(ret)
600 goto error_after_datafile;
601
602 journalfile = journalfile_alloc_and_init(datafile);
603 ret = journalfile_create(journalfile, datafile);
604 if (ret)
605 goto error_after_journalfile;
606
607 nd_log(NDLS_DAEMON, NDLP_INFO,
608 "DBENGINE: tier %d: created " DATAFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL " (.ndf, .njf).",
609 ctx->config.tier, datafile->tier, datafile->fileno);
610
611 ctx_current_disk_space_increase(ctx, datafile->pos + journalfile->unsafe.pos);
612 datafile_list_insert(ctx, datafile);
613 ctx_last_fileno_increment(ctx);
614
615 return 0;
616
617 error_after_journalfile:
618 (void) destroy_data_file_unsafe(datafile);
619 freez(journalfile);
620
621 error_after_datafile:
622 freez(datafile);
623 return ret;
624 }
625
626 /* Page cache must already be initialized.
627 * Return 0 on success.
628 */
629 int init_data_files(struct rrdengine_instance *ctx)
630 {
631 int ret;
632
633 ret = scan_data_files(ctx);
634 if (ret < 0) {
635 netdata_log_error("DBENGINE: failed to scan path \"%s\".", ctx->config.dbfiles_path);
636 return ret;
637 } else if (0 == ret) {
638 netdata_log_info("DBENGINE: data files not found, creating in path \"%s\".", ctx->config.dbfiles_path);
639 ctx->atomic.last_fileno = 0;
640 ret = create_new_datafile_pair(ctx);
641 if (ret) {
642 netdata_log_error("DBENGINE: failed to create data and journal files in path \"%s\".", ctx->config.dbfiles_path);
643 return ret;
644 }
645 }
646 else {
647 if (ctx->loading.create_new_datafile_pair)
648 create_new_datafile_pair(ctx);
649 }
650
651 pgc_reset_hot_max(open_cache);
652 ctx->loading.create_new_datafile_pair = false;
653 return 0;
654 }
655
656 void cleanup_datafile_epdl_structures(struct rrdengine_datafile *datafile)
657 {
658 rw_spinlock_write_lock(&datafile->extent_epdl.spinlock);
659 bool first = true;
660 Word_t idx = 0;
661 Pvoid_t *PValue;
662 while ((PValue = JudyLFirstThenNext(datafile->extent_epdl.epdl_per_extent, &idx, &first))) {
663 EPDL_EXTENT *e = *PValue;
664 internal_error(e->base, "DBENGINE: unexpected active EPDLs during datafile cleanup");
665 epdl_extent_release(e);
666 *PValue = NULL;
667 }
668 JudyLFreeArray(&datafile->extent_epdl.epdl_per_extent, PJE0);
669 rw_spinlock_write_unlock(&datafile->extent_epdl.spinlock);
670 }
671
672 void finalize_data_files(struct rrdengine_instance *ctx)
673 {
674 bool logged = false;
675
676 if (!ctx->datafiles.JudyL)
677 return;
678
679 while(__atomic_load_n(&ctx->atomic.extents_currently_being_flushed, __ATOMIC_RELAXED)) {
680 if(!logged) {
681 netdata_log_info("Waiting for inflight flush to finish on tier %d...", ctx->config.tier);
682 logged = true;
683 }
684 sleep_usec(100 * USEC_PER_MS);
685 }
686
687 bool first_then_next = true;
688 Pvoid_t *PValue;
689 Word_t Index = 0;
690
691 while ((PValue = JudyLFirstThenNext(ctx->datafiles.JudyL, &Index, &first_then_next))) {
692 struct rrdengine_datafile *datafile = *PValue;
693 struct rrdengine_journalfile *journalfile = datafile->journalfile;
694
695 logged = false;
696 size_t iterations = 10;
697 while(!datafile_acquire_for_deletion(datafile, true) && --iterations > 0) {
698 if(!logged) {
699 netdata_log_info("Waiting to acquire data file %u of tier %d to close it...", datafile->fileno, ctx->config.tier);
700 logged = true;
701 }
702 sleep_usec(100 * USEC_PER_MS);
703 }
704
705 logged = false;
706 bool available = false;
707 do {
708 netdata_rwlock_wrlock(&ctx->datafiles.rwlock);
709 spinlock_lock(&datafile->writers.spinlock);
710 available = (datafile->writers.running || datafile->writers.flushed_to_open_running) ? false : true;
711
712 if(!available) {
713 spinlock_unlock(&datafile->writers.spinlock);
714 netdata_rwlock_wrunlock(&ctx->datafiles.rwlock);
715 if(!logged) {
716 netdata_log_info("Waiting for writers to data file %u of tier %d to finish...", datafile->fileno, ctx->config.tier);
717 logged = true;
718 }
719 sleep_usec(100 * USEC_PER_MS);
720 }
721 } while(!available);
722
723 journalfile_close(journalfile, datafile);
724 close_data_file(datafile);
725 datafile_list_delete_unsafe(ctx, datafile);
726 spinlock_unlock(&datafile->writers.spinlock);
727 netdata_rwlock_wrunlock(&ctx->datafiles.rwlock);
728
729 // Clean up EPDL_EXTENT structures
730 cleanup_datafile_epdl_structures(datafile);
731
732 memset(journalfile, 0, sizeof(*journalfile));
733 memset(datafile, 0, sizeof(*datafile));
734
735 freez(journalfile);
736 freez(datafile);
737 }
738 }