496
wal_globals.protected.available--;
497
}
498
499
- uint64_t transaction_id = ctx->commit_log.transaction_id++;
499
+ uint64_t transaction_id = __atomic_fetch_add(&ctx->atomic.transaction_id, 1, __ATOMIC_RELAXED);
500
netdata_spinlock_unlock(&wal_globals.protected.spinlock);
501
502
if(unlikely(!wal)) {
566
struct {
567
SPINLOCK spinlock;
568
size_t waiting;
569
- struct rrdeng_cmd *waiting_items_by_priority[STORAGE_PRIO_MAX_DONT_USE];
570
- size_t executed_by_priority[STORAGE_PRIO_MAX_DONT_USE];
569
+ struct rrdeng_cmd *waiting_items_by_priority[STORAGE_PRIORITY_INTERNAL_MAX_DONT_USE];
570
+ size_t executed_by_priority[STORAGE_PRIORITY_INTERNAL_MAX_DONT_USE];
571
} queue;
572
573
605
}
606
}
607
608
+static inline STORAGE_PRIORITY rrdeng_enq_cmd_map_opcode_to_priority(enum rrdeng_opcode opcode, STORAGE_PRIORITY priority) {
609
+ if(unlikely(priority >= STORAGE_PRIORITY_INTERNAL_MAX_DONT_USE))
610
+ priority = STORAGE_PRIORITY_BEST_EFFORT;
611
+
612
+ switch(opcode) {
613
+ case RRDENG_OPCODE_PREP_QUERY:
614
+ priority = STORAGE_PRIORITY_INTERNAL_QUERY_PREP;
615
+ break;
616
+
617
+ default:
618
+ break;
619
+ }
620
+
621
+ return priority;
622
+}
623
+
624
void rrdeng_enqueue_epdl_cmd(struct rrdeng_cmd *cmd) {
625
epdl_cmd_queued(cmd->data, cmd);
626
}
633
netdata_spinlock_lock(&rrdeng_cmd_globals.queue.spinlock);
634
635
struct rrdeng_cmd *cmd = get_cmd_cb(data);
620
- if(cmd && cmd->priority > priority) {
621
- DOUBLE_LINKED_LIST_REMOVE_UNSAFE(rrdeng_cmd_globals.queue.waiting_items_by_priority[cmd->priority], cmd, cache.prev, cache.next);
622
- DOUBLE_LINKED_LIST_APPEND_UNSAFE(rrdeng_cmd_globals.queue.waiting_items_by_priority[priority], cmd, cache.prev, cache.next);
623
- cmd->priority = priority;
636
+ if(cmd) {
637
+ priority = rrdeng_enq_cmd_map_opcode_to_priority(cmd->opcode, priority);
638
+
639
+ if (cmd->priority > priority) {
640
+ DOUBLE_LINKED_LIST_REMOVE_UNSAFE(rrdeng_cmd_globals.queue.waiting_items_by_priority[cmd->priority], cmd, cache.prev, cache.next);
641
+ DOUBLE_LINKED_LIST_APPEND_UNSAFE(rrdeng_cmd_globals.queue.waiting_items_by_priority[priority], cmd, cache.prev, cache.next);
642
+ cmd->priority = priority;
643
+ }
644
}
645
646
netdata_spinlock_unlock(&rrdeng_cmd_globals.queue.spinlock);
650
enum storage_priority priority, enqueue_callback_t enqueue_cb, dequeue_callback_t dequeue_cb) {
651
struct rrdeng_cmd *cmd = NULL;
652
633
- if(unlikely(priority >= STORAGE_PRIO_MAX_DONT_USE))
634
- priority = STORAGE_PRIORITY_NORMAL;
653
+ priority = rrdeng_enq_cmd_map_opcode_to_priority(opcode, priority);
654
655
netdata_spinlock_lock(&rrdeng_cmd_globals.cache.spinlock);
656
if(likely(rrdeng_cmd_globals.cache.available_items)) {
694
static inline struct rrdeng_cmd rrdeng_deq_cmd(void) {
695
struct rrdeng_cmd *cmd = NULL;
696
678
- STORAGE_PRIORITY max_priority = work_request_full() ? STORAGE_PRIORITY_CRITICAL : STORAGE_PRIORITY_BEST_EFFORT;
697
+ STORAGE_PRIORITY max_priority = work_request_full() ? STORAGE_PRIORITY_INTERNAL_DBENGINE : STORAGE_PRIORITY_BEST_EFFORT;
698
699
// find an opcode to execute from the queue
700
netdata_spinlock_lock(&rrdeng_cmd_globals.queue.spinlock);
682
- for(STORAGE_PRIORITY priority = STORAGE_PRIORITY_CRITICAL; priority <= max_priority ; priority++) {
701
+ for(STORAGE_PRIORITY priority = STORAGE_PRIORITY_INTERNAL_DBENGINE; priority <= max_priority ; priority++) {
702
cmd = rrdeng_cmd_globals.queue.waiting_items_by_priority[priority];
703
if(cmd) {
704
705
// avoid starvation of lower priorities
687
- if(unlikely(priority > STORAGE_PRIORITY_CRITICAL &&
706
+ if(unlikely(priority >= STORAGE_PRIORITY_HIGH &&
707
priority < STORAGE_PRIORITY_BEST_EFFORT &&
708
++rrdeng_cmd_globals.queue.executed_by_priority[priority] % 50 == 0 &&
709
rrdeng_cmd_has_waiting_opcodes_in_lower_priorities(priority + 1, max_priority))) {
812
completion_mark_complete(completion);
813
814
if(ctx_is_available_for_queries(ctx))
796
- rrdeng_enq_cmd(ctx, RRDENG_OPCODE_DATABASE_ROTATE, NULL, NULL, STORAGE_PRIORITY_CRITICAL, NULL, NULL);
815
+ rrdeng_enq_cmd(ctx, RRDENG_OPCODE_DATABASE_ROTATE, NULL, NULL, STORAGE_PRIORITY_INTERNAL_DBENGINE, NULL, NULL);
816
}
817
818
static void extent_flushed_to_open_tp_worker(struct rrdengine_instance *ctx __maybe_unused, void *data __maybe_unused, struct completion *completion __maybe_unused, uv_work_t *uv_work_req __maybe_unused) {
856
datafile->writers.flushed_to_open_running--;
857
netdata_spinlock_unlock(&datafile->writers.spinlock);
858
840
- if(datafile->fileno != __atomic_load_n(&ctx->last_fileno, __ATOMIC_RELAXED) && still_running)
859
+ if(datafile->fileno != ctx_last_fileno_get(ctx) && still_running)
860
// we just finished a flushing on a datafile that is not the active one
842
- rrdeng_enq_cmd(ctx, RRDENG_OPCODE_JOURNAL_FILE_INDEX, datafile, NULL, STORAGE_PRIORITY_CRITICAL, NULL, NULL);
861
+ rrdeng_enq_cmd(ctx, RRDENG_OPCODE_JOURNAL_FILE_INDEX, datafile, NULL, STORAGE_PRIORITY_INTERNAL_DBENGINE, NULL, NULL);
862
}
863
864
// Main event loop callback
875
876
datafile->writers.flushed_to_open_running++;
877
rrdeng_enq_cmd(xt_io_descr->ctx, RRDENG_OPCODE_FLUSHED_TO_OPEN, uv_fs_request, xt_io_descr->completion,
859
- STORAGE_PRIORITY_CRITICAL, NULL, NULL);
878
+ STORAGE_PRIORITY_INTERNAL_DBENGINE, NULL, NULL);
879
880
netdata_spinlock_unlock(&datafile->writers.spinlock);
881
895
struct extent_buffer *eb = NULL;
896
void *compressed_buf = NULL;
897
Word_t Index;
879
- uint8_t compression_algorithm = ctx->global_compress_alg;
898
+ uint8_t compression_algorithm = ctx->config.global_compress_alg;
899
struct rrdengine_datafile *datafile;
900
/* persistent structures */
901
struct rrdeng_df_extent_header *header;
915
if (completion)
916
completion_mark_complete(completion);
917
899
- __atomic_sub_fetch(&ctx->worker_config.atomics.extents_currently_being_flushed, 1, __ATOMIC_RELAXED);
918
+ __atomic_sub_fetch(&ctx->atomic.extents_currently_being_flushed, 1, __ATOMIC_RELAXED);
919
return 0;
920
}
921
993
static SPINLOCK sp = NETDATA_SPINLOCK_INITIALIZER;
994
netdata_spinlock_lock(&sp);
995
if(create_new_datafile_pair(ctx) == 0)
977
- rrdeng_enq_cmd(ctx, RRDENG_OPCODE_JOURNAL_FILE_INDEX, datafile, NULL, STORAGE_PRIORITY_CRITICAL, NULL,
996
+ rrdeng_enq_cmd(ctx, RRDENG_OPCODE_JOURNAL_FILE_INDEX, datafile, NULL, STORAGE_PRIORITY_INTERNAL_DBENGINE, NULL,
997
NULL);
998
netdata_spinlock_unlock(&sp);
999
1029
++ctx->stats.io_write_extents;
1030
commit_data_extent(ctx, xt_io_descr);
1031
datafile->pos += real_io_size;
1013
- ctx->disk_space += real_io_size;
1014
- ctx->last_flush_fileno = datafile->fileno;
1032
+ ctx_current_disk_space_increase(ctx, real_io_size);
1033
+ ctx_last_flush_fileno_set(ctx, datafile->fileno);
1034
1035
ret = uv_fs_write(&rrdeng_main.loop, &xt_io_descr->uv_fs_request, datafile->file, &xt_io_descr->iov,
1036
1, xt_io_descr->pos, extent_flush_io_callback);
1043
}
1044
1045
static void after_database_rotate(struct rrdengine_instance *ctx __maybe_unused, void *data __maybe_unused, struct completion *completion __maybe_unused, uv_work_t* req __maybe_unused, int status __maybe_unused) {
1027
- ctx->worker_config.now_deleting_files = false;
1046
+ __atomic_store_n(&ctx->atomic.now_deleting_files, false, __ATOMIC_RELAXED);
1047
}
1048
1049
struct uuid_first_time_s {
1228
DATAFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL DATAFILE_EXTENSION
1229
"' to be available for deletion, "
1230
"it is in use currently by %u users.",
1212
- ctx->dbfiles_path, ctx->datafiles.first->tier, ctx->datafiles.first->fileno, datafile->users.lockers);
1231
+ ctx->config.dbfiles_path, ctx->datafiles.first->tier, ctx->datafiles.first->fileno, datafile->users.lockers);
1232
1233
__atomic_add_fetch(&rrdeng_cache_efficiency_stats.datafile_deletion_spin, 1, __ATOMIC_RELAXED);
1234
sleep_usec(1 * USEC_PER_SEC);
1239
info("DBENGINE: deleting data file '%s/"
1240
DATAFILE_PREFIX RRDENG_FILE_NUMBER_PRINT_TMPL DATAFILE_EXTENSION
1241
"'.",
1223
- ctx->dbfiles_path, ctx->datafiles.first->tier, ctx->datafiles.first->fileno);
1242
+ ctx->config.dbfiles_path, ctx->datafiles.first->tier, ctx->datafiles.first->fileno);
1243
1244
if(worker)
1245
worker_is_busy(UV_EVENT_DATAFILE_DELETE);
1276
freez(journal_file);
1277
freez(datafile);
1278
1260
- ctx->disk_space -= deleted_bytes;
1279
+ ctx_current_disk_space_decrease(ctx, deleted_bytes);
1280
info("DBENGINE: reclaimed %u bytes of disk space.", deleted_bytes);
1281
1282
if (rrdeng_ctx_exceeded_disk_quota(ctx))
1264
- rrdeng_enq_cmd(ctx, RRDENG_OPCODE_DATABASE_ROTATE, NULL, NULL, STORAGE_PRIORITY_CRITICAL, NULL, NULL);
1283
+ rrdeng_enq_cmd(ctx, RRDENG_OPCODE_DATABASE_ROTATE, NULL, NULL, STORAGE_PRIORITY_INTERNAL_DBENGINE, NULL, NULL);
1284
1285
rrdcontext_db_rotation();
1286
}
1295
1296
static void flush_all_hot_and_dirty_pages_of_section_tp_worker(struct rrdengine_instance *ctx __maybe_unused, void *data __maybe_unused, struct completion *completion __maybe_unused, uv_work_t *uv_work_req __maybe_unused) {
1297
pgc_flush_all_hot_and_dirty_pages(main_cache, (Word_t)ctx);
1279
- completion_mark_complete(&ctx->quiesce_completion);
1298
+ completion_mark_complete(&ctx->quiesce.completion);
1299
+}
1300
+
1301
+static void after_populate_mrg(struct rrdengine_instance *ctx __maybe_unused, void *data __maybe_unused, struct completion *completion __maybe_unused, uv_work_t* req __maybe_unused, int status __maybe_unused) {
1302
+ ;
1303
+}
1304
+
1305
+static void populate_mrg_tp_worker(struct rrdengine_instance *ctx __maybe_unused, void *data __maybe_unused, struct completion *completion __maybe_unused, uv_work_t *uv_work_req __maybe_unused) {
1306
+ do {
1307
+ struct rrdengine_datafile *datafile = NULL;
1308
+
1309
+ // find a datafile to work
1310
+ uv_rwlock_rdlock(&ctx->datafiles.rwlock);
1311
+ for(datafile = ctx->datafiles.first; datafile ; datafile = datafile->next) {
1312
+ if(!netdata_spinlock_trylock(&datafile->populate_mrg.spinlock))
1313
+ continue;
1314
+
1315
+ if(datafile->populate_mrg.populated) {
1316
+ netdata_spinlock_unlock(&datafile->populate_mrg.spinlock);
1317
+ continue;
1318
+ }
1319
+
1320
+ // we have the spinlock and it is not populated
1321
+ break;
1322
+ }
1323
+ uv_rwlock_rdunlock(&ctx->datafiles.rwlock);
1324
+
1325
+ if(!datafile)
1326
+ break;
1327
+
1328
+ journalfile_v2_populate_retention_to_mrg(ctx, datafile->journalfile);
1329
+ datafile->populate_mrg.populated = true;
1330
+ netdata_spinlock_unlock(&datafile->populate_mrg.spinlock);
1331
+
1332
+ } while(1);
1333
+
1334
+ completion_mark_complete(completion);
1335
}
1336
1337
static void after_ctx_shutdown(struct rrdengine_instance *ctx __maybe_unused, void *data __maybe_unused, struct completion *completion __maybe_unused, uv_work_t* req __maybe_unused, int status __maybe_unused) {
1339
}
1340
1341
static void ctx_shutdown_tp_worker(struct rrdengine_instance *ctx __maybe_unused, void *data __maybe_unused, struct completion *completion __maybe_unused, uv_work_t *uv_work_req __maybe_unused) {
1287
- completion_wait_for(&ctx->quiesce_completion);
1288
- completion_destroy(&ctx->quiesce_completion);
1342
+ completion_wait_for(&ctx->quiesce.completion);
1343
+ completion_destroy(&ctx->quiesce.completion);
1344
1290
- while(__atomic_load_n(&ctx->worker_config.atomics.extents_currently_being_flushed, __ATOMIC_RELAXED) ||
1291
- __atomic_load_n(&ctx->inflight_queries, __ATOMIC_RELAXED))
1345
+ while(__atomic_load_n(&ctx->atomic.extents_currently_being_flushed, __ATOMIC_RELAXED) ||
1346
+ __atomic_load_n(&ctx->atomic.inflight_queries, __ATOMIC_RELAXED))
1347
sleep_usec(1 * USEC_PER_MS);
1348
1349
completion_mark_complete(completion);
1376
}
1377
1378
unsigned rrdeng_target_data_file_size(struct rrdengine_instance *ctx) {
1324
- unsigned target_size = ctx->max_disk_space / TARGET_DATAFILES;
1379
+ unsigned target_size = ctx->config.max_disk_space / TARGET_DATAFILES;
1380
target_size = MIN(target_size, MAX_DATAFILE_SIZE);
1381
target_size = MAX(target_size, MIN_DATAFILE_SIZE);
1382
return target_size;
1384
1385
bool rrdeng_ctx_exceeded_disk_quota(struct rrdengine_instance *ctx)
1386
{
1332
- uint64_t estimated_disk_space = ctx->disk_space + rrdeng_target_data_file_size(ctx) -
1387
+ uint64_t estimated_disk_space = ctx_current_disk_space_get(ctx) + rrdeng_target_data_file_size(ctx) -
1388
(ctx->datafiles.first->prev ? ctx->datafiles.first->prev->pos : 0);
1389
1335
- return estimated_disk_space > ctx->max_disk_space;
1390
+ return estimated_disk_space > ctx->config.max_disk_space;
1391
}
1392
1393
/* return 0 on success */
1438
unsigned count = 0;
1439
worker_is_busy(UV_EVENT_JOURNAL_INDEX_WAIT);
1440
1386
- while (ctx->worker_config.now_deleting_files && count++ < MAX_RETRIES_TO_START_INDEX)
1441
+ while (__atomic_load_n(&ctx->atomic.now_deleting_files, __ATOMIC_RELAXED) && count++ < MAX_RETRIES_TO_START_INDEX)
1442
sleep_usec(100 * USEC_PER_MS);
1443
1444
if (count == MAX_RETRIES_TO_START_INDEX) {
1449
struct rrdengine_datafile *datafile = ctx->datafiles.first;
1450
worker_is_busy(UV_EVENT_JOURNAL_INDEX);
1451
count = 0;
1397
- while (datafile && datafile->fileno != ctx->last_fileno && datafile->fileno != ctx->last_flush_fileno) {
1452
+ while (datafile && datafile->fileno != ctx_last_fileno_get(ctx) && datafile->fileno != ctx_last_flush_fileno_get(ctx)) {
1453
1454
netdata_spinlock_lock(&datafile->writers.spinlock);
1455
bool available = (datafile->writers.running || datafile->writers.flushed_to_open_running) ? false : true;
1460
1461
if (unlikely(!journalfile_v2_data_available(datafile->journalfile))) {
1462
info("DBENGINE: journal file %u is ready to be indexed", datafile->fileno);
1408
- pgc_open_cache_to_journal_v2(open_cache, (Word_t) ctx, (int) datafile->fileno, ctx->page_type,
1463
+ pgc_open_cache_to_journal_v2(open_cache, (Word_t) ctx, (int) datafile->fileno, ctx->config.page_type,
1464
journalfile_migrate_to_v2_callback, (void *) datafile->journalfile);
1465
count++;
1466
}
1490
}
1491
1492
static void after_journal_v2_indexing(struct rrdengine_instance *ctx __maybe_unused, void *data __maybe_unused, struct completion *completion __maybe_unused, uv_work_t* req __maybe_unused, int status __maybe_unused) {
1438
- ctx->worker_config.migration_to_v2_running = false;
1439
- rrdeng_enq_cmd(ctx, RRDENG_OPCODE_DATABASE_ROTATE, NULL, NULL, STORAGE_PRIORITY_CRITICAL, NULL, NULL);
1493
+ __atomic_store_n(&ctx->atomic.migration_to_v2_running, false, __ATOMIC_RELAXED);
1494
+ rrdeng_enq_cmd(ctx, RRDENG_OPCODE_DATABASE_ROTATE, NULL, NULL, STORAGE_PRIORITY_INTERNAL_DBENGINE, NULL, NULL);
1495
}
1496
1497
struct rrdeng_buffer_sizes rrdeng_get_buffer_sizes(void) {
1522
worker_set_metric(RRDENG_WORKS_DISPATCHED, (NETDATA_DOUBLE)__atomic_load_n(&work_request_globals.atomics.dispatched, __ATOMIC_RELAXED));
1523
worker_set_metric(RRDENG_WORKS_EXECUTING, (NETDATA_DOUBLE)__atomic_load_n(&work_request_globals.atomics.executing, __ATOMIC_RELAXED));
1524
1470
- rrdeng_enq_cmd(NULL, RRDENG_OPCODE_FLUSH_INIT, NULL, NULL, STORAGE_PRIORITY_CRITICAL, NULL, NULL);
1471
- rrdeng_enq_cmd(NULL, RRDENG_OPCODE_EVICT_INIT, NULL, NULL, STORAGE_PRIORITY_CRITICAL, NULL, NULL);
1525
+ rrdeng_enq_cmd(NULL, RRDENG_OPCODE_FLUSH_INIT, NULL, NULL, STORAGE_PRIORITY_INTERNAL_DBENGINE, NULL, NULL);
1526
+ rrdeng_enq_cmd(NULL, RRDENG_OPCODE_EVICT_INIT, NULL, NULL, STORAGE_PRIORITY_INTERNAL_DBENGINE, NULL, NULL);
1527
1528
rrdeng_cmd_cleanup1();
1529
work_request_cleanup1();
1542
time_t now_s = now_monotonic_sec();
1543
if(now_s - last_run_s >= 10) {
1544
last_run_s = now_s;
1490
- journalfile_v2_data_unmount_cleanup(now_s, storage_tiers);
1545
+ journalfile_v2_data_unmount_cleanup(now_s);
1546
}
1547
}
1548
1553
worker_is_idle();
1554
}
1555
1501
-bool rrdeng_dbengine_spawn(struct rrdengine_instance *ctx) {
1556
+bool rrdeng_dbengine_spawn(struct rrdengine_instance *ctx __maybe_unused) {
1557
static bool spawned = false;
1558
1559
if(!spawned) {
1587
spawned = true;
1588
}
1589
1535
- ctx->worker_config.now_deleting_files = false;
1536
- ctx->worker_config.migration_to_v2_running = false;
1537
- ctx->worker_config.atomics.extents_currently_being_flushed = 0;
1538
-
1590
return true;
1591
}
1592
1718
case RRDENG_OPCODE_JOURNAL_FILE_INDEX: {
1719
struct rrdengine_instance *ctx = cmd.ctx;
1720
struct rrdengine_datafile *datafile = cmd.data;
1670
- if(!ctx->worker_config.migration_to_v2_running) {
1671
-
1672
- ctx->worker_config.migration_to_v2_running = true;
1673
- if (!work_dispatch(ctx, datafile, NULL, opcode, journal_v2_indexing_tp_worker, after_journal_v2_indexing))
1674
- ctx->worker_config.migration_to_v2_running = false;
1721
+ if(!__atomic_load_n(&ctx->atomic.migration_to_v2_running, __ATOMIC_RELAXED)) {
1722
1723
+ __atomic_store_n(&ctx->atomic.migration_to_v2_running, true, __ATOMIC_RELAXED);
1724
+ work_dispatch(ctx, datafile, NULL, opcode, journal_v2_indexing_tp_worker, after_journal_v2_indexing);
1725
}
1726
break;
1727
}
1728
1729
case RRDENG_OPCODE_DATABASE_ROTATE: {
1730
struct rrdengine_instance *ctx = cmd.ctx;
1682
- if (!ctx->worker_config.now_deleting_files &&
1731
+ if (!__atomic_load_n(&ctx->atomic.now_deleting_files, __ATOMIC_RELAXED) &&
1732
ctx->datafiles.first->next != NULL &&
1733
ctx->datafiles.first->next->next != NULL &&
1734
rrdeng_ctx_exceeded_disk_quota(ctx)) {
1735
1687
- ctx->worker_config.now_deleting_files = true;
1688
- if(!work_dispatch(ctx, NULL, NULL, opcode, database_rotate_tp_worker, after_database_rotate))
1689
- ctx->worker_config.now_deleting_files = false;
1690
-
1736
+ __atomic_store_n(&ctx->atomic.now_deleting_files, true, __ATOMIC_RELAXED);
1737
+ work_dispatch(ctx, NULL, NULL, opcode, database_rotate_tp_worker, after_database_rotate);
1738
}
1739
break;
1740
}
1741
1742
+ case RRDENG_OPCODE_CTX_POPULATE_MRG: {
1743
+ struct rrdengine_instance *ctx = cmd.ctx;
1744
+ struct completion *completion = cmd.completion;
1745
+ work_dispatch(ctx, NULL, completion, opcode, populate_mrg_tp_worker, after_populate_mrg);
1746
+ break;
1747
+ }
1748
+
1749
case RRDENG_OPCODE_CTX_QUIESCE: {
1750
// a ctx will shutdown shortly
1751
struct rrdengine_instance *ctx = cmd.ctx;
1698
- __atomic_store_n(&ctx->quiesce, SET_QUIESCE, __ATOMIC_RELEASE);
1752
+ __atomic_store_n(&ctx->quiesce.enabled, true, __ATOMIC_RELEASE);
1753
work_dispatch(ctx, NULL, NULL, opcode,
1754
flush_all_hot_and_dirty_pages_of_section_tp_worker,
1755
after_flush_all_hot_and_dirty_pages_of_section);