::flx::gc::generic::pointer_data_t flx_collector_t::get_pointer_data (void *p) { ::flx::gc::generic::pointer_data_t pdat; pdat.head = NULL; pdat.max_elements = 0ul; pdat.used_elements = 0ul; pdat.shape = NULL; pdat.pointer = p; Word_t cand = (Word_t)p; Word_t head = cand; Word_t *ppshape = (Word_t*)JudyLLast(j_shape,&head, &je); if(ppshape==(Word_t*)PPJERR)judyerror("get_pointer_data"); if(ppshape == NULL) return pdat; // no lower object gc_shape_t *pshape = (gc_shape_t*)(*ppshape & ~1UL); unsigned long max_slots = get_count((void*)head); unsigned long used_slots = get_used((void*)head); unsigned long n = max_slots * pshape->count * pshape->amt; if(cand >= (Word_t)(void*)((unsigned char*)(void*)head+n)) return pdat; // not interior pdat.head = (void*)head; pdat.max_elements = max_slots; pdat.used_elements = used_slots; pdat.shape = pshape; return pdat; }
/* Update metric oldest and latest timestamps when removing old values */ void pg_cache_update_metric_times(struct pg_cache_page_index *page_index) { Pvoid_t *firstPValue, *lastPValue; Word_t firstIndex, lastIndex; struct rrdeng_page_cache_descr *descr; usec_t oldest_time = INVALID_TIME; usec_t latest_time = INVALID_TIME; uv_rwlock_rdlock(&page_index->lock); /* Find first page in range */ firstIndex = (Word_t)0; firstPValue = JudyLFirst(page_index->JudyL_array, &firstIndex, PJE0); if (likely(NULL != firstPValue)) { descr = *firstPValue; oldest_time = descr->start_time; } lastIndex = (Word_t)-1; lastPValue = JudyLLast(page_index->JudyL_array, &lastIndex, PJE0); if (likely(NULL != lastPValue)) { descr = *lastPValue; latest_time = descr->end_time; } uv_rwlock_rdunlock(&page_index->lock); if (unlikely(NULL == firstPValue)) { assert(NULL == lastPValue); page_index->oldest_time = page_index->latest_time = INVALID_TIME; return; } page_index->oldest_time = oldest_time; page_index->latest_time = latest_time; }
void flx_collector_t::scan_object(void *p, int reclimit) { Word_t reachable = (parity & 1UL) ^ 1UL; again: if(debug) fprintf(stderr,"Scan object %p, reachable bit value = %d\n",p,(int)reachable); Word_t cand = (Word_t)p; Word_t head=cand; Word_t *ppshape = (Word_t*)JudyLLast(j_shape,&head,&je); if(ppshape==(Word_t*)PPJERR)judyerror("scan_object"); if(ppshape == NULL) return; // no lower object /* if(debug) { fprintf(stderr,"Found candidate object %p, &shape=%p, shape(1) %p\n",(void*)fp,(void*)w,(void*)(*w)); fprintf(stderr," .. type=%s!\n",((gc_shape_t*)(*w & ~1UL))->cname); } */ if( (*ppshape & 1UL) == reachable) return; // already handled gc_shape_t *pshape = (gc_shape_t*)(*ppshape & ~1UL); unsigned long n = get_count((void*)head) * pshape->count * pshape->amt; if(cand >= (Word_t)(void*)((unsigned char*)(void*)head+n)) return; // not interior if(debug) fprintf(stderr,"MARKING object %p, shape %p, type=%s\n",(void*)head,pshape,pshape->cname); *ppshape = (*ppshape & ~1uL) | reachable; if(pshape->flags & gc_flags_conservative) { unsigned long n_used = get_used((void*)head) * pshape->count; // end of object, rounded down to size of a void* void **end = (void**)( (unsigned char*)(void*)head + n_used * n / sizeof(void*) * sizeof(void*) ); for ( void **i = (void**)head; i != end; i = i+1) { //if(debug) // fprintf(stderr, "Check if *%p=%p is a pointer\n",i,*(void**)i); if(reclimit==0) Judy1Set(&j_tmp,(Word_t)*i,&je); else scan_object(*i,reclimit -1); } } else { unsigned long dyncount = get_used((void*)head); if(pshape->scanner) { void *r = pshape->scanner(this, pshape, (void*)head,dyncount,reclimit); if (r) { p = r; goto again; } } } }
/* * Searches for a page and gets a reference. * When point_in_time is INVALID_TIME get any page. * If index is NULL lookup by UUID (id). */ struct rrdeng_page_cache_descr * pg_cache_lookup(struct rrdengine_instance *ctx, struct pg_cache_page_index *index, uuid_t *id, usec_t point_in_time) { struct page_cache *pg_cache = &ctx->pg_cache; struct rrdeng_page_cache_descr *descr = NULL; unsigned long flags; Pvoid_t *PValue; struct pg_cache_page_index *page_index; Word_t Index; uint8_t page_not_in_cache; if (unlikely(NULL == index)) { uv_rwlock_rdlock(&pg_cache->metrics_index.lock); PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, id, sizeof(uuid_t)); if (likely(NULL != PValue)) { page_index = *PValue; } uv_rwlock_rdunlock(&pg_cache->metrics_index.lock); if (NULL == PValue) { return NULL; } } else { page_index = index; } pg_cache_reserve_pages(ctx, 1); page_not_in_cache = 0; uv_rwlock_rdlock(&page_index->lock); while (1) { Index = (Word_t)(point_in_time / USEC_PER_SEC); PValue = JudyLLast(page_index->JudyL_array, &Index, PJE0); if (likely(NULL != PValue)) { descr = *PValue; } if (NULL == PValue || 0 == descr->page_length || (INVALID_TIME != point_in_time && !is_point_in_time_in_page(descr, point_in_time))) { /* non-empty page not found */ uv_rwlock_rdunlock(&page_index->lock); pg_cache_release_pages(ctx, 1); return NULL; } uv_mutex_lock(&descr->mutex); flags = descr->flags; if ((flags & RRD_PAGE_POPULATED) && pg_cache_try_get_unsafe(descr, 0)) { /* success */ uv_mutex_unlock(&descr->mutex); debug(D_RRDENGINE, "%s: Page was found in memory.", __func__); break; } if (!(flags & RRD_PAGE_POPULATED) && pg_cache_try_get_unsafe(descr, 1)) { struct rrdeng_cmd cmd; uv_rwlock_rdunlock(&page_index->lock); cmd.opcode = RRDENG_READ_PAGE; cmd.read_page.page_cache_descr = descr; rrdeng_enq_cmd(&ctx->worker_config, &cmd); debug(D_RRDENGINE, "%s: Waiting for page to be asynchronously read from disk:", __func__); if(unlikely(debug_flags & D_RRDENGINE)) print_page_cache_descr(descr); while (!(descr->flags & RRD_PAGE_POPULATED)) { pg_cache_wait_event_unsafe(descr); } /* success */ /* Downgrade exclusive reference to allow other readers */ descr->flags &= ~RRD_PAGE_LOCKED; pg_cache_wake_up_waiters_unsafe(descr); uv_mutex_unlock(&descr->mutex); rrd_stat_atomic_add(&ctx->stats.pg_cache_misses, 1); return descr; } uv_rwlock_rdunlock(&page_index->lock); debug(D_RRDENGINE, "%s: Waiting for page to be unlocked:", __func__); if(unlikely(debug_flags & D_RRDENGINE)) print_page_cache_descr(descr); if (!(flags & RRD_PAGE_POPULATED)) page_not_in_cache = 1; pg_cache_wait_event_unsafe(descr); uv_mutex_unlock(&descr->mutex); /* reset scan to find again */ uv_rwlock_rdlock(&page_index->lock); } uv_rwlock_rdunlock(&page_index->lock); if (!(flags & RRD_PAGE_DIRTY)) pg_cache_replaceQ_set_hot(ctx, descr); pg_cache_release_pages(ctx, 1); if (page_not_in_cache) rrd_stat_atomic_add(&ctx->stats.pg_cache_misses, 1); else rrd_stat_atomic_add(&ctx->stats.pg_cache_hits, 1); return descr; }
/* * Searches for a page and triggers disk I/O if necessary and possible. * Does not get a reference. * Returns page index pointer for given metric UUID. */ struct pg_cache_page_index * pg_cache_preload(struct rrdengine_instance *ctx, uuid_t *id, usec_t start_time, usec_t end_time) { struct page_cache *pg_cache = &ctx->pg_cache; struct rrdeng_page_cache_descr *descr = NULL, *preload_array[PAGE_CACHE_MAX_PRELOAD_PAGES]; int i, j, k, count, found; unsigned long flags; Pvoid_t *PValue; struct pg_cache_page_index *page_index; Word_t Index; uint8_t failed_to_reserve; uv_rwlock_rdlock(&pg_cache->metrics_index.lock); PValue = JudyHSGet(pg_cache->metrics_index.JudyHS_array, id, sizeof(uuid_t)); if (likely(NULL != PValue)) { page_index = *PValue; } uv_rwlock_rdunlock(&pg_cache->metrics_index.lock); if (NULL == PValue) { debug(D_RRDENGINE, "%s: No page was found to attempt preload.", __func__); return NULL; } uv_rwlock_rdlock(&page_index->lock); /* Find first page in range */ found = 0; Index = (Word_t)(start_time / USEC_PER_SEC); PValue = JudyLLast(page_index->JudyL_array, &Index, PJE0); if (likely(NULL != PValue)) { descr = *PValue; if (is_page_in_time_range(descr, start_time, end_time)) { found = 1; } } if (!found) { Index = (Word_t)(start_time / USEC_PER_SEC); PValue = JudyLFirst(page_index->JudyL_array, &Index, PJE0); if (likely(NULL != PValue)) { descr = *PValue; if (is_page_in_time_range(descr, start_time, end_time)) { found = 1; } } } if (!found) { uv_rwlock_rdunlock(&page_index->lock); debug(D_RRDENGINE, "%s: No page was found to attempt preload.", __func__); return page_index; } for (count = 0 ; descr != NULL && is_page_in_time_range(descr, start_time, end_time); PValue = JudyLNext(page_index->JudyL_array, &Index, PJE0), descr = unlikely(NULL == PValue) ? NULL : *PValue) { /* Iterate all pages in range */ if (unlikely(0 == descr->page_length)) continue; uv_mutex_lock(&descr->mutex); flags = descr->flags; if (pg_cache_can_get_unsafe(descr, 0)) { if (flags & RRD_PAGE_POPULATED) { /* success */ uv_mutex_unlock(&descr->mutex); debug(D_RRDENGINE, "%s: Page was found in memory.", __func__); continue; } } if (!(flags & RRD_PAGE_POPULATED) && pg_cache_try_get_unsafe(descr, 1)) { preload_array[count++] = descr; if (PAGE_CACHE_MAX_PRELOAD_PAGES == count) { uv_mutex_unlock(&descr->mutex); break; } } uv_mutex_unlock(&descr->mutex); }; uv_rwlock_rdunlock(&page_index->lock); failed_to_reserve = 0; for (i = 0 ; i < count && !failed_to_reserve ; ++i) { struct rrdeng_cmd cmd; struct rrdeng_page_cache_descr *next; descr = preload_array[i]; if (NULL == descr) { continue; } if (!pg_cache_try_reserve_pages(ctx, 1)) { failed_to_reserve = 1; break; } cmd.opcode = RRDENG_READ_EXTENT; cmd.read_extent.page_cache_descr[0] = descr; /* don't use this page again */ preload_array[i] = NULL; for (j = 0, k = 1 ; j < count ; ++j) { next = preload_array[j]; if (NULL == next) { continue; } if (descr->extent == next->extent) { /* same extent, consolidate */ if (!pg_cache_try_reserve_pages(ctx, 1)) { failed_to_reserve = 1; break; } cmd.read_extent.page_cache_descr[k++] = next; /* don't use this page again */ preload_array[j] = NULL; } } cmd.read_extent.page_count = k; rrdeng_enq_cmd(&ctx->worker_config, &cmd); } if (failed_to_reserve) { debug(D_RRDENGINE, "%s: Failed to reserve enough memory, canceling I/O.", __func__); for (i = 0 ; i < count ; ++i) { descr = preload_array[i]; if (NULL == descr) { continue; } pg_cache_put(descr); } } if (!count) { /* no such page */ debug(D_RRDENGINE, "%s: No page was eligible to attempt preload.", __func__); } return page_index; }