static const StoreEntry * heap_walkNext(RemovalPolicyWalker * walker) { HeapWalkData *heap_walk = walker->_data; RemovalPolicy *policy = walker->_policy; HeapPolicyData *heap = policy->_data; StoreEntry *entry; if (heap_walk->current >= heap_nodes(heap->heap)) return NULL; /* done */ entry = (StoreEntry *) heap_peep(heap->heap, heap_walk->current++); return entry; }
static StoreEntry * heap_purgeNext(RemovalPurgeWalker * walker) { HeapPurgeData *heap_walker = walker->_data; RemovalPolicy *policy = walker->_policy; HeapPolicyData *heap = policy->_data; StoreEntry *entry; heap_key age; try_again: if (!heap_nodes(heap->heap) > 0) return NULL; /* done */ age = heap_peepminkey(heap->heap); entry = heap_extractmin(heap->heap); if (storeEntryLocked(entry)) { storeLockObject(entry); linklistPush(&heap_walker->locked_entries, entry); goto try_again; } heap_walker->min_age = age; SET_POLICY_NODE(entry, NULL); return entry; }
/* * Compute the heap skew for HEAP, a measure of how out-of-order the * elements in the heap are. The skew of a heap node is the difference * between its current position in the heap and where it would be if the * heap were in sorted order. To compute this we have to sort the heap. At * the end if the flag REPLACE is non-zero the heap will be returned in * sorted order (with skew == 0). Note: using REPLACE does not help the * performance of the heap, so only do this if you really want to have a * sorted heap. It is faster not to replace. */ float calc_heap_skew(heap * heap, int replace) { heap_node **nodes; long id, diff, skew = 0; #ifdef HEAP_DEBUG_SKEW long skewsq = 0; #endif /* HEAP_DEBUG_SKEW */ float norm = 0; unsigned long max; /* * Lock the heap to copy it. If replacing it need to keep the heap locked * until we are all done. */ mutex_lock(hp->lock); max = heap_nodes(heap); /* * Copy the heap nodes to a new storage area for offline sorting. */ nodes = xmalloc(max * sizeof(heap_node *)); memcpy(nodes, heap->nodes, max * sizeof(heap_node *)); if (replace == 0) { /* * Unlock the heap to allow updates from other threads before the sort. * This allows other heap operations to proceed concurrently with the * heap skew computation on the heap at the time of the call ... */ mutex_unlock(hp->lock); } qsort(nodes, max, sizeof(heap_node *), compare_heap_keys); for (id = 0; id < max; id++) { diff = id - nodes[id]->id; skew += abs(diff); #ifdef HEAP_DEBUG_SKEW skewsq += diff * diff; #ifdef HEAP_DEBUG_ALL printf("%d\tKey = %f, diff = %d\n", id, nodes[id]->key, diff); #endif /* HEAP_DEBUG */ #endif /* HEAP_DEBUG_SKEW */ } if (replace != 0) { /* * Replace the original heap with the newly sorted heap and let it * continue. Then compute the skew using the copy of the previous heap * which we maintain as private data. */ memcpy(heap->nodes, nodes, max * sizeof(heap_node *)); for (id = 0; id < max; id++) { /* * Fix up all the ID values in the copied nodes. */ heap->nodes[id]->id = id; } mutex_unlock(hp->lock); } /* * The skew value is normalized to a range of [0..1]; the distribution * appears to be a skewed Gaussian distribution. For random insertions * into a heap the normalized skew will be slightly less than 0.5. The * maximum value of skew/N^2 (for any value of N) is about 0.39 and is * fairly stable. */ norm = skew * 2.56 / (max * max); /* * Free the nodes array; note this is just an array of pointers, not data! */ xfree(nodes); return norm; }
int storeDirWriteCleanLogs(int reopen) { StoreEntry *e = NULL; int n = 0; struct timeval start; double dt; SwapDir *sd; int dirn; int N = Config.cacheSwap.n_configured; #if HEAP_REPLACEMENT int node; #else dlink_node *m; #endif if (store_dirs_rebuilding) { debug(20, 1) ("Not currently OK to rewrite swap log.\n"); debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.\n"); return 0; } debug(20, 1) ("storeDirWriteCleanLogs: Starting...\n"); getCurrentTime(); start = current_time; for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { sd = &Config.cacheSwap.swapDirs[dirn]; if (sd->log.clean.open(sd) < 0) { debug(20, 1) ("log.clean.open() failed for dir #%d\n", sd->index); continue; } } #if HEAP_REPLACEMENT if (NULL == store_heap) return 0; for (node = 0; node < heap_nodes(store_heap); node++) #else for (m = store_list.tail; m; m = m->prev) #endif { #if HEAP_REPLACEMENT e = (StoreEntry *) heap_peep(store_heap, node); #else e = m->data; #endif if (e->swap_file_number < 0) continue; if (e->swap_status != SWAPOUT_DONE) continue; if (e->swap_file_sz <= 0) continue; if (EBIT_TEST(e->flags, RELEASE_REQUEST)) continue; if (EBIT_TEST(e->flags, KEY_PRIVATE)) continue; if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) continue; dirn = storeDirNumber(e->swap_file_number); sd = &Config.cacheSwap.swapDirs[dirn]; if (NULL == sd->log.clean.write) continue; sd->log.clean.write(e, sd); if ((++n & 0xFFFF) == 0) { getCurrentTime(); debug(20, 1) (" %7d entries written so far.\n", n); } } /* flush */ for (dirn = 0; dirn < N; dirn++) { sd = &Config.cacheSwap.swapDirs[dirn]; if (NULL == sd->log.clean.write) continue; sd->log.clean.write(NULL, sd); } if (reopen) storeDirOpenSwapLogs(); getCurrentTime(); dt = tvSubDsec(start, current_time); debug(20, 1) (" Finished. Wrote %d entries.\n", n); debug(20, 1) (" Took %3.1f seconds (%6.1f entries/sec).\n", dt, (double) n / (dt > 0.0 ? dt : 1.0)); return n; }