@cryptotaxi247 / netdata-1 / commits / 7387e0594

Try to keep all pages from extents read from disk in the cache. (#10558)

Markos Fountoulakis committed Feb 24, 2021 at 16:25 UTC 7387e05943ead3d08fe08da2acbb2826bc0c34a4
3 files changed +93 -10
database/engine/pagecache.c
+68
@@ -699,6 +699,74 @@ void pg_cache_get_filtered_info_prev(struct rrdengine_instance *ctx, struct pg_c
699 }
700 uv_rwlock_rdunlock(&page_index->lock);
701 }
702 +
703 +/**
704 + * Searches for an unallocated page without triggering disk I/O. Attempts to reserve the page and get a reference.
705 + * @param ctx DB context
706 + * @param id lookup by UUID
707 + * @param start_time exact starting time in usec
708 + * @param ret_page_indexp Sets the page index pointer (*ret_page_indexp) for the given UUID.
709 + * @return the page descriptor or NULL on failure. It can fail if:
710 + * 1. The page is already allocated to the page cache.
711 + * 2. It did not succeed to get a reference.
712 + * 3. It did not succeed to reserve a spot in the page cache.
713 + */
714 +struct rrdeng_page_descr *pg_cache_lookup_unpopulated_and_lock(struct rrdengine_instance *ctx, uuid_t *id,
715 + usec_t start_time)
716 +{
717 + struct page_cache *pg_cache = &ctx->pg_cache;
718 + struct rrdeng_page_descr *descr = NULL;
719 + struct page_cache_descr *pg_cache_descr = NULL;
720 + unsigned long flags;
721 + Pvoid_t *PValue;
722 + struct pg_cache_page_index *page_index = NULL;
723 + Word_t Index;
724 +
725 + uv_rwlock_rdlock(&pg_cache->metrics_index.lock);
726 + PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, id, sizeof(uuid_t));
727 + if (likely(NULL != PValue)) {
728 + page_index = *PValue;
729 + }
730 + uv_rwlock_rdunlock(&pg_cache->metrics_index.lock);
731 +
732 + if ((NULL == PValue) || !pg_cache_try_reserve_pages(ctx, 1)) {
733 + /* Failed to find page or failed to reserve a spot in the cache */
734 + return NULL;
735 + }
736 +
737 + uv_rwlock_rdlock(&page_index->lock);
738 + Index = (Word_t)(start_time / USEC_PER_SEC);
739 + PValue = JudyLGet(page_index->JudyL_array, Index, PJE0);
740 + if (likely(NULL != PValue)) {
741 + descr = *PValue;
742 + }
743 + if (NULL == PValue || 0 == descr->page_length) {
744 + /* Failed to find non-empty page */
745 + uv_rwlock_rdunlock(&page_index->lock);
746 +
747 + pg_cache_release_pages(ctx, 1);
748 + return NULL;
749 + }
750 +
751 + rrdeng_page_descr_mutex_lock(ctx, descr);
752 + pg_cache_descr = descr->pg_cache_descr;
753 + flags = pg_cache_descr->flags;
754 + uv_rwlock_rdunlock(&page_index->lock);
755 +
756 + if ((flags & RRD_PAGE_POPULATED) || !pg_cache_try_get_unsafe(descr, 1)) {
757 + /* Failed to get reference or page is already populated */
758 + rrdeng_page_descr_mutex_unlock(ctx, descr);
759 +
760 + pg_cache_release_pages(ctx, 1);
761 + return NULL;
762 + }
763 + /* success */
764 + rrdeng_page_descr_mutex_unlock(ctx, descr);
765 + rrd_stat_atomic_add(&ctx->stats.pg_cache_misses, 1);
766 +
767 + return descr;
768 +}
769 +
770 /**
771 * Searches for pages in a time range and triggers disk I/O if necessary and possible.
772 * Does not get a reference.
database/engine/pagecache.h
+2
@@ -172,6 +172,8 @@ extern usec_t pg_cache_oldest_time_in_range(struct rrdengine_instance *ctx, uuid
172 extern void pg_cache_get_filtered_info_prev(struct rrdengine_instance *ctx, struct pg_cache_page_index *page_index,
173 usec_t point_in_time, pg_cache_page_info_filter_t *filter,
174 struct rrdeng_page_info *page_info);
175 +extern struct rrdeng_page_descr *pg_cache_lookup_unpopulated_and_lock(struct rrdengine_instance *ctx, uuid_t *id,
176 + usec_t start_time);
177 extern unsigned
178 pg_cache_preload(struct rrdengine_instance *ctx, uuid_t *id, usec_t start_time, usec_t end_time,
179 struct rrdeng_page_info **page_info_arrayp, struct pg_cache_page_index **ret_page_indexp);
database/engine/rrdengine.c
+23 -10
@@ -305,19 +305,32 @@ after_crc_check:
305 }
306 }
307
308 - for (i = 0 ; i < xt_io_descr->descr_count; ++i) {
309 - page = mallocz(RRDENG_BLOCK_SIZE);
310 - descr = xt_io_descr->descr_array[i];
311 - for (j = 0, page_offset = 0; j < count; ++j) {
308 + for (i = 0, page_offset = 0; i < count; page_offset += header->descr[i++].page_length) {
309 + uint8_t is_prefetched_page;
310 + descr = NULL;
311 + for (j = 0 ; j < xt_io_descr->descr_count; ++j) {
312 + struct rrdeng_page_descr *descrj;
313 +
314 + descrj = xt_io_descr->descr_array[j];
315 /* care, we don't hold the descriptor mutex */
313 - if (!uuid_compare(*(uuid_t *) header->descr[j].uuid, *descr->id) &&
314 - header->descr[j].page_length == descr->page_length &&
315 - header->descr[j].start_time == descr->start_time &&
316 - header->descr[j].end_time == descr->end_time) {
316 + if (!uuid_compare(*(uuid_t *) header->descr[i].uuid, *descrj->id) &&
317 + header->descr[i].page_length == descrj->page_length &&
318 + header->descr[i].start_time == descrj->start_time &&
319 + header->descr[i].end_time == descrj->end_time) {
320 + descr = descrj;
321 break;
322 }
319 - page_offset += header->descr[j].page_length;
323 }
324 + is_prefetched_page = 0;
325 + if (!descr) { /* This extent page has not been requested. Try populating it for locality (best effort). */
326 + descr = pg_cache_lookup_unpopulated_and_lock(ctx, (uuid_t *)header->descr[i].uuid,
327 + header->descr[i].start_time);
328 + if (!descr)
329 + continue; /* Failed to reserve a suitable page */
330 + is_prefetched_page = 1;
331 + }
332 + page = mallocz(RRDENG_BLOCK_SIZE);
333 +
334 /* care, we don't hold the descriptor mutex */
335 if (have_read_error) {
336 /* Applications should make sure NULL values match 0 as does SN_EMPTY_SLOT */
@@ -334,7 +347,7 @@ after_crc_check:
347 pg_cache_descr->flags &= ~RRD_PAGE_READ_PENDING;
348 rrdeng_page_descr_mutex_unlock(ctx, descr);
349 pg_cache_replaceQ_insert(ctx, descr);
337 - if (xt_io_descr->release_descr) {
350 + if (xt_io_descr->release_descr || is_prefetched_page) {
351 pg_cache_put(ctx, descr);
352 } else {
353 debug(D_RRDENGINE, "%s: Waking up waiters.", __func__);