@@ -67,38 +67,6 @@ static struct evictionPoolEntry *EvictionPoolLRU;
6767 * Implementation of eviction, aging and LRU
6868 * --------------------------------------------------------------------------*/
6969
70- /* Return the LRU clock, based on the clock resolution. This is a time
71- * in a reduced-bits format that can be used to set and check the
72- * object->lru field of serverObject structures. */
73- unsigned int getLRUClock (void ) {
74- return (mstime () / LRU_CLOCK_RESOLUTION ) & LRU_CLOCK_MAX ;
75- }
76-
77- /* This function is used to obtain the current LRU clock.
78- * If the current resolution is lower than the frequency we refresh the
79- * LRU clock (as it should be in production servers) we return the
80- * precomputed value, otherwise we need to resort to a system call. */
81- unsigned int LRU_CLOCK (void ) {
82- unsigned int lruclock ;
83- if (1000 / server .hz <= LRU_CLOCK_RESOLUTION ) {
84- lruclock = server .lruclock ;
85- } else {
86- lruclock = getLRUClock ();
87- }
88- return lruclock ;
89- }
90-
91- /* Given an object returns the min number of milliseconds the object was never
92- * requested, using an approximated LRU algorithm. */
93- unsigned long long estimateObjectIdleTime (robj * o ) {
94- unsigned long long lruclock = LRU_CLOCK ();
95- if (lruclock >= o -> lru ) {
96- return (lruclock - o -> lru ) * LRU_CLOCK_RESOLUTION ;
97- } else {
98- return (lruclock + (LRU_CLOCK_MAX - o -> lru )) * LRU_CLOCK_RESOLUTION ;
99- }
100- }
101-
10270/* LRU approximation algorithm
10371 *
10472 * The server uses an approximation of the LRU algorithm that runs in constant
@@ -158,17 +126,8 @@ int evictionPoolPopulate(serverDb *db, kvstore *samplekvs, struct evictionPoolEn
158126 /* Calculate the idle time according to the policy. This is called
159127 * idle just because the code initially handled LRU, but is in fact
160128 * just a score where a higher score means better candidate. */
161- if (server .maxmemory_policy & MAXMEMORY_FLAG_LRU ) {
162- idle = estimateObjectIdleTime (o );
163- } else if (server .maxmemory_policy & MAXMEMORY_FLAG_LFU ) {
164- /* When we use an LRU policy, we sort the keys by idle time
165- * so that we expire keys starting from greater idle time.
166- * However when the policy is an LFU one, we have a frequency
167- * estimation, and we want to evict keys with lower frequency
168- * first. So inside the pool we put objects using the inverted
169- * frequency subtracting the actual frequency to the maximum
170- * frequency of 255. */
171- idle = 255 - LFUDecrAndReturn (o );
129+ if (server .maxmemory_policy & (MAXMEMORY_FLAG_LRU | MAXMEMORY_FLAG_LFU )) {
130+ idle = objectGetIdleness (o );
172131 } else if (server .maxmemory_policy == MAXMEMORY_VOLATILE_TTL ) {
173132 /* In this case the sooner the expire the better. */
174133 idle = ULLONG_MAX - objectGetExpire (o );
@@ -230,88 +189,6 @@ int evictionPoolPopulate(serverDb *db, kvstore *samplekvs, struct evictionPoolEn
230189 return count ;
231190}
232191
233- /* ----------------------------------------------------------------------------
234- * LFU (Least Frequently Used) implementation.
235-
236- * We have 24 total bits of space in each object in order to implement
237- * an LFU (Least Frequently Used) eviction policy, since we re-use the
238- * LRU field for this purpose.
239- *
240- * We split the 24 bits into two fields:
241- *
242- * 16 bits 8 bits
243- * +------------------+--------+
244- * + Last access time | LOG_C |
245- * +------------------+--------+
246- *
247- * LOG_C is a logarithmic counter that provides an indication of the access
248- * frequency. However this field must also be decremented otherwise what used
249- * to be a frequently accessed key in the past, will remain ranked like that
250- * forever, while we want the algorithm to adapt to access pattern changes.
251- *
252- * So the remaining 16 bits are used in order to store the "access time",
253- * a reduced-precision Unix time (we take 16 bits of the time converted
254- * in minutes since we don't care about wrapping around) where the LOG_C
255- * counter decays every minute by default (depends on lfu-decay-time).
256- *
257- * New keys don't start at zero, in order to have the ability to collect
258- * some accesses before being trashed away, so they start at LFU_INIT_VAL.
259- * The logarithmic increment performed on LOG_C takes care of LFU_INIT_VAL
260- * when incrementing the key, so that keys starting at LFU_INIT_VAL
261- * (or having a smaller value) have a very high chance of being incremented
262- * on access. (The chance depends on counter and lfu-log-factor.)
263- *
264- * During decrement, the value of the logarithmic counter is decremented by
265- * one when lfu-decay-time minutes elapsed.
266- * --------------------------------------------------------------------------*/
267-
268- /* Return the current time in minutes, just taking the least significant
269- * 16 bits. The returned time is suitable to be stored as LDT (last access
270- * time) for the LFU implementation. */
271- unsigned long LFUGetTimeInMinutes (void ) {
272- return (server .unixtime / 60 ) & 65535 ;
273- }
274-
275- /* Given an object ldt (last access time), compute the minimum number of minutes
276- * that elapsed since the last access. Handle overflow (ldt greater than
277- * the current 16 bits minutes time) considering the time as wrapping
278- * exactly once. */
279- unsigned long LFUTimeElapsed (unsigned long ldt ) {
280- unsigned long now = LFUGetTimeInMinutes ();
281- if (now >= ldt ) return now - ldt ;
282- return 65535 - ldt + now ;
283- }
284-
285- /* Logarithmically increment a counter. The greater is the current counter value
286- * the less likely is that it gets really incremented. Saturate it at 255. */
287- uint8_t LFULogIncr (uint8_t counter ) {
288- if (counter == 255 ) return 255 ;
289- double r = (double )rand () / RAND_MAX ;
290- double baseval = counter - LFU_INIT_VAL ;
291- if (baseval < 0 ) baseval = 0 ;
292- double p = 1.0 / (baseval * server .lfu_log_factor + 1 );
293- if (r < p ) counter ++ ;
294- return counter ;
295- }
296-
297- /* If the object's ldt (last access time) is reached, decrement the LFU counter but
298- * do not update LFU fields of the object, we update the access time
299- * and counter in an explicit way when the object is really accessed.
300- * And we will decrement the counter according to the times of
301- * elapsed time than server.lfu_decay_time.
302- * Return the object frequency counter.
303- *
304- * This function is used in order to scan the dataset for the best object
305- * to fit: as we check for the candidate, we incrementally decrement the
306- * counter of the scanned objects if needed. */
307- unsigned long LFUDecrAndReturn (robj * o ) {
308- unsigned long ldt = o -> lru >> 8 ;
309- unsigned long counter = o -> lru & 255 ;
310- unsigned long num_periods = server .lfu_decay_time ? LFUTimeElapsed (ldt ) / server .lfu_decay_time : 0 ;
311- if (num_periods ) counter = (num_periods > counter ) ? 0 : counter - num_periods ;
312- return counter ;
313- }
314-
315192/* We don't want to count AOF buffers and replicas output buffers as
316193 * used memory: the eviction should use mostly data size, because
317194 * it can cause feedback-loop when we push DELs into them, putting
0 commit comments