11
struct page_details_control *pdc;
12
struct rrdengine_datafile *datafile;
13
14
+ struct rrdeng_cmd *cmd;
15
+
16
+ struct {
17
+ struct extent_page_details_list *prev;
18
+ struct extent_page_details_list *next;
19
+ } query;
20
+
21
struct {
22
struct extent_page_details_list *prev;
23
struct extent_page_details_list *next;
472
if(pages_matched && statistics_counter)
473
__atomic_add_fetch(statistics_counter, pages_matched, __ATOMIC_RELAXED);
474
}
468
-
475
+/*
476
static bool epdl_check_if_pages_are_already_in_cache(struct rrdengine_instance *ctx, EPDL *epdl, PDC_PAGE_STATUS tags)
477
{
478
size_t count_remaining = 0;
508
509
return count_remaining == 0;
510
}
511
+*/
512
513
// ----------------------------------------------------------------------------
514
// PDC logic
595
return false;
596
}
597
598
+void epdl_cmd_queued(void *epdl_ptr, struct rrdeng_cmd *cmd) {
599
+ EPDL *epdl = epdl_ptr;
600
+ epdl->cmd = cmd;
601
+}
602
+
603
+void epdl_cmd_dequeued(void *epdl_ptr) {
604
+ EPDL *epdl = epdl_ptr;
605
+ epdl->cmd = NULL;
606
+}
607
+
608
+static struct rrdeng_cmd *epdl_get_cmd(void *epdl_ptr) {
609
+ EPDL *epdl = epdl_ptr;
610
+ return epdl->cmd;
611
+}
612
+
613
+static bool epdl_pending_add(EPDL *epdl) {
614
+ bool added_new;
615
+
616
+ netdata_spinlock_lock(&epdl->datafile->extent_queries.spinlock);
617
+ Pvoid_t *PValue = JudyLIns(&epdl->datafile->extent_queries.pending_epdl_by_extent_offset_judyL, epdl->extent_offset, PJE0);
618
+ internal_fatal(!PValue || PValue == PJERR, "DBENGINE: corrupted pending extent judy");
619
+
620
+ EPDL *base = *PValue;
621
+
622
+ if(!base)
623
+ added_new = true;
624
+ else {
625
+ added_new = false;
626
+ __atomic_add_fetch(&rrdeng_cache_efficiency_stats.pages_load_extent_merged, 1, __ATOMIC_RELAXED);
627
+
628
+ if(base->pdc->priority > epdl->pdc->priority)
629
+ rrdeng_req_cmd(epdl_get_cmd, base, epdl->pdc->priority);
630
+ }
631
+
632
+ DOUBLE_LINKED_LIST_APPEND_UNSAFE(base, epdl, query.prev, query.next);
633
+ *PValue = base;
634
+
635
+ netdata_spinlock_unlock(&epdl->datafile->extent_queries.spinlock);
636
+
637
+ return added_new;
638
+}
639
+
640
+static void epdl_pending_del(EPDL *epdl) {
641
+ netdata_spinlock_lock(&epdl->datafile->extent_queries.spinlock);
642
+ int rc = JudyLDel(&epdl->datafile->extent_queries.pending_epdl_by_extent_offset_judyL, epdl->extent_offset, PJE0);
643
+ (void)rc;
644
+ internal_fatal(!rc, "DBENGINE: epdl not found in pending list");
645
+ netdata_spinlock_unlock(&epdl->datafile->extent_queries.spinlock);
646
+}
647
+
648
void pdc_to_epdl_router(struct rrdengine_instance *ctx, PDC *pdc, execute_extent_page_details_list_t exec_first_extent_list, execute_extent_page_details_list_t exec_rest_extent_list)
649
{
650
Pvoid_t *PValue;
732
pdc_acquire(pdc); // we do this for the next worker: do_read_extent_work()
733
epdl->pdc = pdc;
734
677
- if(extent_list_no++ == 0)
678
- exec_first_extent_list(ctx, epdl, pdc->priority);
679
- else
680
- exec_rest_extent_list(ctx, epdl, pdc->priority);
735
+ if(epdl_pending_add(epdl)) {
736
+ if (extent_list_no++ == 0)
737
+ exec_first_extent_list(ctx, epdl, pdc->priority);
738
+ else
739
+ exec_rest_extent_list(ctx, epdl, pdc->priority);
740
+ }
741
}
742
PDCJudyLFreeArray(&deol->extent_pd_list_by_extent_offset_JudyL, PJE0);
743
deol_release(deol);
748
pdc_release_and_destroy_if_unreferenced(pdc, true, true);
749
}
750
691
-static bool datafile_get_exclusive_access_to_extent(EPDL *epdl) {
692
- struct rrdengine_datafile *df = epdl->datafile;
693
- bool is_it_mine = false;
694
-
695
- while(!is_it_mine) {
696
- netdata_spinlock_lock(&df->extent_exclusive_access.spinlock);
697
- if(!df->users.available) {
698
- netdata_spinlock_unlock(&df->extent_exclusive_access.spinlock);
699
- return false;
700
- }
701
- Pvoid_t *PValue = JudyLIns(&df->extent_exclusive_access.extents_JudyL, epdl->extent_offset, PJE0);
702
- if (!*PValue) {
703
- *(Word_t *) PValue = gettid();
704
- df->extent_exclusive_access.lockers++;
705
- is_it_mine = true;
706
- }
707
- netdata_spinlock_unlock(&df->extent_exclusive_access.spinlock);
708
-
709
- if(!is_it_mine) {
710
- static const struct timespec ns = { .tv_sec = 0, .tv_nsec = 1 };
711
- nanosleep(&ns, NULL);
712
- }
713
- }
714
- return true;
715
-}
716
-
717
-static void datafile_release_exclusive_access_to_extent(EPDL *epdl) {
718
- struct rrdengine_datafile *df = epdl->datafile;
719
-
720
- netdata_spinlock_lock(&df->extent_exclusive_access.spinlock);
721
-
722
-#ifdef NETDATA_INTERNAL_CHECKS
723
- Pvoid_t *PValue = JudyLGet(df->extent_exclusive_access.extents_JudyL, epdl->extent_offset, PJE0);
724
- if (*(Word_t *) PValue != (Word_t)gettid())
725
- fatal("DBENGINE: exclusive extent access is not mine");
726
-#endif
727
-
728
- int rc = JudyLDel(&df->extent_exclusive_access.extents_JudyL, epdl->extent_offset, PJE0);
729
- if (!rc)
730
- fatal("DBENGINE: cannot find my exclusive access");
731
-
732
- df->extent_exclusive_access.lockers--;
733
- netdata_spinlock_unlock(&df->extent_exclusive_access.spinlock);
734
-}
735
-
751
static void fill_page_with_nulls(void *page, uint32_t page_length, uint8_t type) {
752
switch(type) {
753
case PAGE_METRICS: {
858
return vd;
859
}
860
861
+static struct page_details *epdl_to_pd_load_list(EPDL *epdl, Word_t metric_id, time_t start_time_s) {
862
+ struct page_details *pd_list = NULL;
863
+
864
+ for(EPDL *ep = epdl; ep ;ep = ep->query.next) {
865
+ Pvoid_t *pd_by_start_time_s_judyL = PDCJudyLGet(ep->page_details_by_metric_id_JudyL, metric_id, PJE0);
866
+ internal_fatal(pd_by_start_time_s_judyL == PJERR, "DBENGINE: corrupted extent metrics JudyL");
867
+
868
+ if (pd_by_start_time_s_judyL && *pd_by_start_time_s_judyL) {
869
+ Pvoid_t *pd_pptr = PDCJudyLGet(*pd_by_start_time_s_judyL, start_time_s, PJE0);
870
+ internal_fatal(pd_pptr == PJERR, "DBENGINE: corrupted metric page details JudyHS");
871
+
872
+ if (pd_pptr && *pd_pptr) {
873
+ struct page_details *pd = *pd_pptr;
874
+ internal_fatal(metric_id != pd->metric_id, "DBENGINE: metric ids do not match");
875
+
876
+ DOUBLE_LINKED_LIST_APPEND_UNSAFE(pd_list, pd, load.prev, load.next);
877
+ }
878
+ }
879
+ }
880
+
881
+ return pd_list;
882
+}
883
+
884
static bool epdl_populate_pages_from_extent_data(
885
struct rrdengine_instance *ctx,
886
void *data,
887
size_t data_length,
888
EPDL *epdl,
851
- bool preload_all_pages,
889
bool worker,
890
PDC_PAGE_STATUS tags,
891
bool cached_extent)
973
}
974
}
975
976
+ if(worker)
977
+ worker_is_busy(UV_EVENT_PAGE_LOOKUP);
978
+
979
size_t stats_data_from_main_cache = 0;
980
size_t stats_data_from_extent = 0;
981
size_t stats_load_compressed = 0;
982
size_t stats_load_uncompressed = 0;
983
size_t stats_load_invalid_page = 0;
984
size_t stats_cache_hit_while_inserting = 0;
945
- size_t stats_cache_hit_before_allocation = 0;
985
986
uint32_t page_offset = 0, page_length;
987
time_t now_s = now_realtime_sec();
996
continue;
997
}
998
960
- if(worker)
961
- worker_is_busy(UV_EVENT_METRIC_LOOKUP);
962
-
999
METRIC *metric = mrg_metric_get_and_acquire(main_mrg, &header->descr[i].uuid, (Word_t)ctx);
1000
Word_t metric_id = (Word_t)metric;
1001
if(!metric) {
1006
}
1007
mrg_metric_release(main_mrg, metric);
1008
973
- if(worker)
974
- worker_is_busy(UV_EVENT_PAGE_LOOKUP);
975
-
976
- struct page_details *pd = NULL;
977
- Pvoid_t *pd_by_start_time_s_judyL = PDCJudyLGet(epdl->page_details_by_metric_id_JudyL, metric_id, PJE0);
978
- internal_fatal(pd_by_start_time_s_judyL == PJERR, "DBENGINE: corrupted extent metrics JudyL");
979
-
980
- if(pd_by_start_time_s_judyL && *pd_by_start_time_s_judyL) {
981
- Pvoid_t *pd_pptr = PDCJudyLGet(*pd_by_start_time_s_judyL, start_time_s, PJE0);
982
- internal_fatal(pd_pptr == PJERR, "DBENGINE: corrupted metric page details JudyHS");
983
-
984
- if(pd_pptr && *pd_pptr) {
985
- pd = *pd_pptr;
986
- internal_fatal(metric_id != pd->metric_id, "DBENGINE: metric ids do not match");
987
- }
988
- }
989
-
990
- if(!pd && !preload_all_pages)
1009
+ struct page_details *pd_list = epdl_to_pd_load_list(epdl, metric_id, start_time_s);
1010
+ if(likely(!pd_list))
1011
continue;
1012
1013
VALIDATED_PAGE_DESCRIPTOR vd = validate_extent_page_descr(
1014
&header->descr[i], now_s,
995
- (pd) ? pd->update_every_s : 0,
1015
+ (pd_list) ? pd_list->update_every_s : 0,
1016
have_read_error);
1017
1018
if(worker)
1019
worker_is_busy(UV_EVENT_PAGE_POPULATION);
1020
1001
- PGC_PAGE *page = pgc_page_get_and_acquire(main_cache, (Word_t)ctx, metric_id, start_time_s, PGC_SEARCH_EXACT);
1002
- if (!page) {
1003
- void *page_data = dbengine_page_alloc(ctx, vd.page_length);
1021
+ void *page_data = dbengine_page_alloc(ctx, vd.page_length);
1022
+
1023
+ if (unlikely(!vd.data_on_disk_valid)) {
1024
+ fill_page_with_nulls(page_data, vd.page_length, vd.type);
1025
+ stats_load_invalid_page++;
1026
+ }
1027
+
1028
+ else if (RRD_NO_COMPRESSION == header->compression_algorithm) {
1029
+ memcpy(page_data, data + payload_offset + page_offset, (size_t) vd.page_length);
1030
+ stats_load_uncompressed++;
1031
+ }
1032
+
1033
+ else {
1034
+ if(unlikely(page_offset + vd.page_length > uncompressed_payload_length)) {
1035
+ error_limit_static_global_var(erl, 10, 0);
1036
+ error_limit(&erl,
1037
+ "DBENGINE: page %u offset %u + page length %zu exceeds the uncompressed buffer size %u",
1038
+ i, page_offset, vd.page_length, uncompressed_payload_length);
1039
1005
- if (unlikely(!vd.data_on_disk_valid)) {
1040
fill_page_with_nulls(page_data, vd.page_length, vd.type);
1041
stats_load_invalid_page++;
1042
}
1009
-
1010
- else if (RRD_NO_COMPRESSION == header->compression_algorithm) {
1011
- memcpy(page_data, data + payload_offset + page_offset, (size_t) vd.page_length);
1012
- stats_load_uncompressed++;
1013
- }
1014
-
1043
else {
1016
- if(unlikely(page_offset + vd.page_length > uncompressed_payload_length)) {
1017
- error_limit_static_global_var(erl, 10, 0);
1018
- error_limit(&erl,
1019
- "DBENGINE: page %u offset %u + page length %zu exceeds the uncompressed buffer size %u",
1020
- i, page_offset, vd.page_length, uncompressed_payload_length);
1021
-
1022
- fill_page_with_nulls(page_data, vd.page_length, vd.type);
1023
- stats_load_invalid_page++;
1024
- }
1025
- else {
1026
- memcpy(page_data, uncompressed_buf + page_offset, vd.page_length);
1027
- stats_load_compressed++;
1028
- }
1044
+ memcpy(page_data, uncompressed_buf + page_offset, vd.page_length);
1045
+ stats_load_compressed++;
1046
}
1030
-
1031
- PGC_ENTRY page_entry = {
1032
- .hot = false,
1033
- .section = (Word_t)ctx,
1034
- .metric_id = metric_id,
1035
- .start_time_s = vd.start_time_s,
1036
- .end_time_s = vd.end_time_s,
1037
- .update_every_s = vd.update_every_s,
1038
- .size = (size_t) vd.page_length,
1039
- .data = page_data
1040
- };
1041
-
1042
- bool added = true;
1043
- page = pgc_page_add_and_acquire(main_cache, page_entry, &added);
1044
- if (false == added) {
1045
- dbengine_page_free(page_data);
1046
- stats_cache_hit_while_inserting++;
1047
- stats_data_from_main_cache++;
1048
- }
1049
- else
1050
- stats_data_from_extent++;
1047
}
1052
- else {
1053
- stats_cache_hit_before_allocation++;
1048
+
1049
+ PGC_ENTRY page_entry = {
1050
+ .hot = false,
1051
+ .section = (Word_t)ctx,
1052
+ .metric_id = metric_id,
1053
+ .start_time_s = vd.start_time_s,
1054
+ .end_time_s = vd.end_time_s,
1055
+ .update_every_s = vd.update_every_s,
1056
+ .size = (size_t) vd.page_length,
1057
+ .data = page_data
1058
+ };
1059
+
1060
+ bool added = true;
1061
+ PGC_PAGE *page = pgc_page_add_and_acquire(main_cache, page_entry, &added);
1062
+ if (false == added) {
1063
+ dbengine_page_free(page_data);
1064
+ stats_cache_hit_while_inserting++;
1065
stats_data_from_main_cache++;
1066
}
1067
+ else
1068
+ stats_data_from_extent++;
1069
+
1070
+ struct page_details *pd = pd_list;
1071
+ do {
1072
+ if(pd != pd_list)
1073
+ pgc_page_dup(main_cache, page);
1074
1057
- if (pd) {
1075
pd->page = page;
1076
pd->page_length = pgc_page_data_size(main_cache, page);
1077
pdc_page_status_set(pd, PDC_PAGE_READY | tags);
1061
- }
1062
- else
1063
- pgc_page_release(main_cache, page);
1078
+
1079
+ pd = pd->load.next;
1080
+ } while(pd);
1081
+
1082
+ if(worker)
1083
+ worker_is_busy(UV_EVENT_PAGE_LOOKUP);
1084
}
1085
1086
if(stats_data_from_main_cache)
1088
1089
if(cached_extent)
1090
__atomic_add_fetch(&rrdeng_cache_efficiency_stats.pages_data_source_extent_cache, stats_data_from_extent, __ATOMIC_RELAXED);
1071
- else
1091
+ else {
1092
__atomic_add_fetch(&rrdeng_cache_efficiency_stats.pages_data_source_disk, stats_data_from_extent, __ATOMIC_RELAXED);
1073
-
1074
- if(stats_cache_hit_before_allocation)
1075
- __atomic_add_fetch(&rrdeng_cache_efficiency_stats.pages_load_ok_loaded_but_cache_hit_before_allocation, stats_cache_hit_before_allocation, __ATOMIC_RELAXED);
1093
+ __atomic_add_fetch(&rrdeng_cache_efficiency_stats.extents_loaded_from_disk, 1, __ATOMIC_RELAXED);
1094
+ }
1095
1096
if(stats_cache_hit_while_inserting)
1097
__atomic_add_fetch(&rrdeng_cache_efficiency_stats.pages_load_ok_loaded_but_cache_hit_while_inserting, stats_cache_hit_while_inserting, __ATOMIC_RELAXED);
1114
}
1115
1116
void epdl_find_extent_and_populate_pages(struct rrdengine_instance *ctx, EPDL *epdl, bool worker) {
1098
- struct page_details_control *pdc = epdl->pdc;
1099
-
1100
- bool extent_exclusive = false;
1101
-
1102
- if(pdc->preload_all_extent_pages) {
1103
- if (!datafile_get_exclusive_access_to_extent(epdl)) {
1104
- __atomic_add_fetch(&rrdeng_cache_efficiency_stats.pages_load_fail_datafile_not_available, 1, __ATOMIC_RELAXED);
1105
- goto cleanup;
1117
+ epdl_pending_del(epdl);
1118
+
1119
+ bool should_stop = __atomic_load_n(&epdl->pdc->workers_should_stop, __ATOMIC_RELAXED);
1120
+ for(EPDL *ep = epdl->query.next; ep ;ep = ep->query.next) {
1121
+ internal_fatal(ep->datafile != epdl->datafile, "DBENGINE: datafiles do not match");
1122
+ internal_fatal(ep->extent_offset != epdl->extent_offset, "DBENGINE: extent offsets do not match");
1123
+ internal_fatal(ep->extent_size != epdl->extent_size, "DBENGINE: extent sizes do not match");
1124
+ internal_fatal(ep->file != epdl->file, "DBENGINE: files do not match");
1125
+
1126
+ PDC *pdc = ep->pdc;
1127
+ if(!__atomic_load_n(&pdc->workers_should_stop, __ATOMIC_RELAXED)) {
1128
+ should_stop = false;
1129
+ break;
1130
}
1107
- extent_exclusive = true;
1131
}
1132
1110
- if (epdl_check_if_pages_are_already_in_cache(ctx, epdl, PDC_PAGE_PRELOADED_WORKER))
1111
- goto cleanup;
1112
-
1113
- if(__atomic_load_n(&pdc->workers_should_stop, __ATOMIC_RELAXED))
1133
+ if(should_stop)
1134
goto cleanup;
1135
1136
if(worker)
1203
// Need to decompress and then process the pagelist
1204
bool extent_used = epdl_populate_pages_from_extent_data(
1205
ctx, extent_compressed_data, epdl->extent_size,
1186
- epdl, pdc->preload_all_extent_pages,
1187
- worker, loaded_pages_tag, extent_found_in_cache);
1206
+ epdl, worker, loaded_pages_tag, extent_found_in_cache);
1207
1208
if(extent_used) {
1209
// since the extent was used, all the pages that are not
1217
not_loaded_pages_tag |= PDC_PAGE_FAILED_TO_MAP_EXTENT;
1218
1219
1201
- // mark all pending pages as failed
1202
- epdl_mark_all_not_loaded_pages_as_failed(
1203
- epdl, not_loaded_pages_tag,
1204
- &rrdeng_cache_efficiency_stats.pages_load_fail_cant_mmap_extent);
1205
-
1220
if(extent_cache_page)
1221
pgc_page_release(extent_cache, extent_cache_page);
1222
1209
- cleanup:
1210
- if(extent_exclusive)
1211
- datafile_release_exclusive_access_to_extent(epdl);
1223
+ // mark all pending pages as failed
1224
+ for(EPDL *ep = epdl; ep ;ep = ep->query.next) {
1225
+ epdl_mark_all_not_loaded_pages_as_failed(
1226
+ ep, not_loaded_pages_tag,
1227
+ &rrdeng_cache_efficiency_stats.pages_load_fail_cant_mmap_extent);
1228
+ }
1229
+
1230
+cleanup:
1231
+ for(EPDL *ep = epdl, *next = NULL; ep ; ep = next) {
1232
+ next = ep->query.next;
1233
1213
- completion_mark_complete_a_job(&epdl->pdc->page_completion);
1214
- pdc_release_and_destroy_if_unreferenced(pdc, true, false);
1234
+ completion_mark_complete_a_job(&ep->pdc->page_completion);
1235
+ pdc_release_and_destroy_if_unreferenced(ep->pdc, true, false);
1236
1216
- // Free the Judy that holds the requested pagelist and the extents
1217
- epdl_destroy(epdl);
1237
+ // Free the Judy that holds the requested pagelist and the extents
1238
+ epdl_destroy(ep);
1239
+ }
1240
1241
if(worker)
1242
worker_is_idle();