@@ -40,22 +40,19 @@ typedef struct FIFO_Reinsertion_params {
4040 cache_obj_t * q_tail ;
4141
4242 // points to the eviction position
43- cache_obj_t * next_to_exam ;
44- // the number of bytes to examine at each eviction round
45- int64_t n_exam_byte ;
46- // of the n_exam_byte examined, we keep n_keep_byte and evict the rest
47- int64_t n_keep_byte ;
48- // used to sort the objects collected in the current batch
43+ cache_obj_t * next_to_merge ;
44+ // the number of object to examine at each eviction
45+ int n_exam_obj ;
46+ // of the n_exam_obj, we keep n_keep_obj and evict the rest
47+ int n_keep_obj ;
48+
49+ double retain_ratio ;
50+ // used to sort the n_exam_obj objects
4951 struct sort_list_node * metric_list ;
50- // current allocated capacity (in entries) of metric_list
51- int metric_list_capacity ;
52- // the policy to determine which objects to keep
52+ // the policy to determine the n_keep_obj objects
5353 retain_policy_t retain_policy ;
54+
5455 int pos_in_metric_list ;
55- // number of objects in the eviction portion of the current sorted batch
56- int n_collected_in_batch ;
57- // number of bytes already evicted from the current sorted batch
58- int64_t bytes_evicted_in_batch ;
5956
6057 int64_t n_obj_rewritten ;
6158 int64_t n_byte_rewritten ;
@@ -125,30 +122,25 @@ cache_t *FIFO_Reinsertion_init(const common_cache_params_t ccache_params,
125122 memset (params , 0 , sizeof (FIFO_Reinsertion_params_t ));
126123 cache -> eviction_params = params ;
127124
128- params -> n_exam_byte = 100LL * 1024 * 1024 ; // 100 MB
129- params -> n_keep_byte = 25LL * 1024 * 1024 ; // 25 MB
125+ params -> n_exam_obj = 100 ;
126+ params -> retain_ratio = 0.25 ;
127+ params -> n_keep_obj = (int )(params -> n_exam_obj * params -> retain_ratio );
130128 params -> retain_policy = RETAIN_POLICY_RECENCY ;
131- params -> next_to_exam = NULL ;
129+ params -> next_to_merge = NULL ;
130+ params -> pos_in_metric_list = INT32_MAX ;
132131 params -> q_head = NULL ;
133132 params -> q_tail = NULL ;
134- params -> pos_in_metric_list = INT32_MAX ;
135- params -> n_collected_in_batch = 0 ;
136- params -> bytes_evicted_in_batch = 0 ;
137133
138134 if (cache_specific_params != NULL ) {
139135 FIFO_Reinsertion_parse_params (cache , cache_specific_params );
140136 }
141137
142- assert (params -> n_exam_byte > 0 && params -> n_keep_byte >= 0 );
143- assert (params -> n_keep_byte <= params -> n_exam_byte );
138+ assert (params -> n_exam_obj > 0 && params -> n_keep_obj >= 0 );
139+ assert (params -> n_keep_obj <= params -> n_exam_obj );
144140
145141 snprintf (cache -> cache_name , CACHE_NAME_ARRAY_LEN , "FIFO_Reinsertion_%s-%.4lf" ,
146- retain_policy_names [params -> retain_policy ],
147- (double )params -> n_keep_byte / (double )params -> n_exam_byte );
148- // initial capacity guess; grows on demand in the eviction routine
149- params -> metric_list_capacity = 1024 ;
150- params -> metric_list =
151- my_malloc_n (struct sort_list_node , params -> metric_list_capacity );
142+ retain_policy_names [params -> retain_policy ], params -> retain_ratio );
143+ params -> metric_list = my_malloc_n (struct sort_list_node , params -> n_exam_obj );
152144
153145 return cache ;
154146}
@@ -161,7 +153,7 @@ cache_t *FIFO_Reinsertion_init(const common_cache_params_t ccache_params,
161153static void FIFO_Reinsertion_free (cache_t * cache ) {
162154 FIFO_Reinsertion_params_t * params =
163155 (FIFO_Reinsertion_params_t * )cache -> eviction_params ;
164- my_free (sizeof (struct sort_list_node ) * params -> metric_list_capacity ,
156+ my_free (sizeof (struct sort_list_node ) * params -> n_exam_obj ,
165157 params -> metric_list );
166158 my_free (sizeof (FIFO_Reinsertion_params_t ), params );
167159 cache_struct_free (cache );
@@ -273,94 +265,84 @@ static void FIFO_Reinsertion_evict(cache_t *cache, const request_t *req) {
273265 FIFO_Reinsertion_params_t * params =
274266 (FIFO_Reinsertion_params_t * )cache -> eviction_params ;
275267 cache_obj_t * cache_obj = NULL ;
276- // Collect ~n_exam_byte objects, sort them, then:
277- // - reinsert the keep-set to head immediately (no cache-size change)
278- // - store the evict-set and drain it one object per call
279- const int64_t bytes_to_evict_per_batch =
280- params -> n_exam_byte - params -> n_keep_byte ;
281-
282- if (params -> pos_in_metric_list < params -> n_collected_in_batch &&
283- params -> bytes_evicted_in_batch < bytes_to_evict_per_batch ) {
268+ int n_evict = params -> n_exam_obj - params -> n_keep_obj ;
269+
270+ // check if we have objects identified to evict from a previous scan
271+ if (params -> pos_in_metric_list < n_evict ) {
284272 cache_obj = params -> metric_list [params -> pos_in_metric_list ++ ].cache_obj ;
285- params -> bytes_evicted_in_batch += cache_obj -> obj_size ;
286- remove_obj_from_list (& params -> q_head , & params -> q_tail , cache_obj );
287- cache_evict_base (cache , cache_obj , true);
273+ FIFO_Reinsertion_remove_obj (cache , cache_obj );
274+
275+ // if this was the last eviction in the batch, reinsert the kept objects
276+ if (params -> pos_in_metric_list >= n_evict ) {
277+ for (int i = n_evict ; i < params -> n_exam_obj ; i ++ ) {
278+ cache_obj = params -> metric_list [i ].cache_obj ;
279+ move_obj_to_head (& params -> q_head , & params -> q_tail , cache_obj );
280+ cache_obj -> FIFO_Reinsertion .freq =
281+ (cache_obj -> FIFO_Reinsertion .freq + 1 ) / 2 ;
282+
283+ params -> n_obj_rewritten += 1 ;
284+ params -> n_byte_rewritten += cache_obj -> obj_size ;
285+ }
286+ params -> pos_in_metric_list = INT32_MAX ;
287+ }
288288 return ;
289289 }
290290
291- if (cache -> get_occupied_byte (cache ) <= params -> n_exam_byte ) {
292- // cache is too small for a useful merge - fall back to plain FIFO
293- cache_obj = params -> q_tail ;
294- params -> next_to_exam = NULL ;
295- remove_obj_from_list (& params -> q_head , & params -> q_tail , cache_obj );
296- cache_evict_base (cache , cache_obj , true);
291+ if (cache -> n_obj <= params -> n_exam_obj ) {
292+ // just evict one object - this is fifo
293+ cache_obj = params -> next_to_merge ;
294+ if (cache_obj == NULL ) {
295+ cache_obj = params -> q_tail ;
296+ }
297+ params -> next_to_merge = cache_obj -> queue .prev ;
298+ FIFO_Reinsertion_remove_obj (cache , cache_obj );
297299 return ;
298300 }
299301
300- // collect ~n_exam_byte worth of objects from the merge cursor
302+ // collect metric for n_exam obj, we will keep objects with larger metric
301303 int n_loop = 0 ;
302- int64_t bytes_collected = 0 ;
303- int n_collected = 0 ;
304- cache_obj = params -> next_to_exam ;
305- while (bytes_collected < params -> n_exam_byte ) {
304+ cache_obj = params -> next_to_merge ;
305+ if (cache_obj == NULL ) {
306+ params -> next_to_merge = params -> q_tail ;
307+ cache_obj = params -> q_tail ;
308+ n_loop = 1 ;
309+ }
310+
311+ for (int i = 0 ; i < params -> n_exam_obj ; i ++ ) {
312+ assert (cache_obj != NULL );
313+ params -> metric_list [i ].metric = retain_metric (cache , cache_obj );
314+ params -> metric_list [i ].cache_obj = cache_obj ;
315+ cache_obj = cache_obj -> queue .prev ;
316+
306317 if (cache_obj == NULL ) {
307318 cache_obj = params -> q_tail ;
308- n_loop += 1 ;
309- DEBUG_ASSERT (n_loop <= 2 );
310- }
311-
312- // grow metric_list if needed
313- if (n_collected >= params -> metric_list_capacity ) {
314- int new_capacity = params -> metric_list_capacity * 2 ;
315- struct sort_list_node * new_list =
316- my_malloc_n (struct sort_list_node , new_capacity );
317- memcpy (new_list , params -> metric_list ,
318- sizeof (struct sort_list_node ) * params -> metric_list_capacity );
319- my_free (sizeof (struct sort_list_node ) * params -> metric_list_capacity ,
320- params -> metric_list );
321- params -> metric_list = new_list ;
322- params -> metric_list_capacity = new_capacity ;
319+ DEBUG_ASSERT (n_loop ++ <= 2 );
323320 }
324-
325- params -> metric_list [n_collected ].metric = retain_metric (cache , cache_obj );
326- params -> metric_list [n_collected ].cache_obj = cache_obj ;
327- bytes_collected += cache_obj -> obj_size ;
328- n_collected += 1 ;
329- cache_obj = cache_obj -> queue .prev ;
330321 }
331- params -> next_to_exam = cache_obj ;
322+ params -> next_to_merge = cache_obj ;
332323
333- // sort by metric ascending - low metric (least worth keeping) first
334- qsort (params -> metric_list , n_collected , sizeof (struct sort_list_node ),
324+ // sort metrics
325+ qsort (params -> metric_list , params -> n_exam_obj , sizeof (struct sort_list_node ),
335326 cmp_list_node );
336327
337- // find the split point: evict [0..n_evict), reinsert [n_evict..n_collected)
338- int n_evict = 0 ;
339- int64_t bytes_evict_counted = 0 ;
340- while (n_evict < n_collected && bytes_evict_counted < bytes_to_evict_per_batch ) {
341- bytes_evict_counted += params -> metric_list [n_evict ].cache_obj -> obj_size ;
342- n_evict ++ ;
343- }
344-
345- // reinsert the keep-set to head now (size unchanged, so safe to do eagerly)
346- for (int i = n_evict ; i < n_collected ; i ++ ) {
347- cache_obj = params -> metric_list [i ].cache_obj ;
348- move_obj_to_head (& params -> q_head , & params -> q_tail , cache_obj );
349- cache_obj -> FIFO_Reinsertion .freq =
350- (cache_obj -> FIFO_Reinsertion .freq + 1 ) / 2 ;
351- params -> n_obj_rewritten += 1 ;
352- params -> n_byte_rewritten += cache_obj -> obj_size ;
353- }
354-
355- // begin draining the evict-set one object per call
356- params -> n_collected_in_batch = n_evict ;
357- params -> bytes_evicted_in_batch = 0 ;
328+ // evict the first object, save state for subsequent calls
358329 params -> pos_in_metric_list = 1 ;
359-
360330 cache_obj = params -> metric_list [0 ].cache_obj ;
361- params -> bytes_evicted_in_batch += cache_obj -> obj_size ;
362- remove_obj_from_list (& params -> q_head , & params -> q_tail , cache_obj );
363- cache_evict_base (cache , cache_obj , true);
331+ FIFO_Reinsertion_remove_obj (cache , cache_obj );
332+
333+ // if only one object to evict in the batch, reinsert the kept objects now
334+ if (params -> pos_in_metric_list >= n_evict ) {
335+ for (int i = n_evict ; i < params -> n_exam_obj ; i ++ ) {
336+ cache_obj = params -> metric_list [i ].cache_obj ;
337+ move_obj_to_head (& params -> q_head , & params -> q_tail , cache_obj );
338+ cache_obj -> FIFO_Reinsertion .freq =
339+ (cache_obj -> FIFO_Reinsertion .freq + 1 ) / 2 ;
340+
341+ params -> n_obj_rewritten += 1 ;
342+ params -> n_byte_rewritten += cache_obj -> obj_size ;
343+ }
344+ params -> pos_in_metric_list = INT32_MAX ;
345+ }
364346}
365347
366348static void FIFO_Reinsertion_remove_obj (cache_t * cache , cache_obj_t * obj ) {
@@ -404,51 +386,20 @@ static bool FIFO_Reinsertion_remove(cache_t *cache, obj_id_t obj_id) {
404386static const char * FIFO_Reinsertion_current_params (
405387 FIFO_Reinsertion_params_t * params ) {
406388 static __thread char params_str [128 ];
407- snprintf (params_str , 128 ,
408- "n-exam-byte=%lld, n-keep-byte=%lld, retain-policy=%s" ,
409- (long long )params -> n_exam_byte , (long long )params -> n_keep_byte ,
389+ snprintf (params_str , 128 , "n-exam=%d, n-keep=%d, retain-policy=%s" ,
390+ params -> n_exam_obj , params -> n_keep_obj ,
410391 retain_policy_names [params -> retain_policy ]);
411392 return params_str ;
412393}
413394
414- /* Parse a human-readable byte size like "100", "100KB", "100MB", "2GB".
415- * Suffix is case-insensitive; binary (1024) units are used.
416- * Returns the parsed value, or aborts on parse error. */
417- static int64_t FIFO_Reinsertion_parse_byte_size (const char * value ) {
418- char * end = NULL ;
419- int64_t n = (int64_t )strtoll (value , & end , 0 );
420- if (end == value ) {
421- ERROR ("param parsing error: expected number, got \"%s\"\n" , value );
422- exit (1 );
423- }
424- while (* end == ' ' ) end ++ ;
425- if (* end == '\0' ) return n ;
426-
427- int64_t mult = 1 ;
428- if (strcasecmp (end , "B" ) == 0 ) {
429- mult = 1 ;
430- } else if (strcasecmp (end , "K" ) == 0 || strcasecmp (end , "KB" ) == 0 ) {
431- mult = 1024LL ;
432- } else if (strcasecmp (end , "M" ) == 0 || strcasecmp (end , "MB" ) == 0 ) {
433- mult = 1024LL * 1024 ;
434- } else if (strcasecmp (end , "G" ) == 0 || strcasecmp (end , "GB" ) == 0 ) {
435- mult = 1024LL * 1024 * 1024 ;
436- } else if (strcasecmp (end , "T" ) == 0 || strcasecmp (end , "TB" ) == 0 ) {
437- mult = 1024LL * 1024 * 1024 * 1024 ;
438- } else {
439- ERROR ("param parsing error: unknown size suffix \"%s\"\n" , end );
440- exit (1 );
441- }
442- return n * mult ;
443- }
444-
445395static void FIFO_Reinsertion_parse_params (cache_t * cache ,
446396 const char * cache_specific_params ) {
447397 FIFO_Reinsertion_params_t * params =
448398 (FIFO_Reinsertion_params_t * )cache -> eviction_params ;
449399
450400 char * params_str = strdup (cache_specific_params );
451401 char * old_params_str = params_str ;
402+ char * end ;
452403
453404 while (params_str != NULL && params_str [0 ] != '\0' ) {
454405 /* different parameters are separated by comma,
@@ -470,15 +421,21 @@ static void FIFO_Reinsertion_parse_params(cache_t *cache,
470421 params -> retain_policy = RETAIN_POLICY_BELADY ;
471422 else if (strcasecmp (value , "none" ) == 0 ) {
472423 params -> retain_policy = RETAIN_NONE ;
473- params -> n_keep_byte = 0 ;
424+ params -> n_keep_obj = 0 ;
474425 } else {
475426 ERROR ("unknown retain-policy %s\n" , value );
476427 exit (1 );
477428 }
478- } else if (strcasecmp (key , "n-exam-byte" ) == 0 ) {
479- params -> n_exam_byte = FIFO_Reinsertion_parse_byte_size (value );
480- } else if (strcasecmp (key , "n-keep-byte" ) == 0 ) {
481- params -> n_keep_byte = FIFO_Reinsertion_parse_byte_size (value );
429+ } else if (strcasecmp (key , "n-exam" ) == 0 ) {
430+ params -> n_exam_obj = (int )strtol (value , & end , 0 );
431+ if (strlen (end ) > 2 ) {
432+ ERROR ("param parsing error, find string \"%s\" after number\n" , end );
433+ }
434+ } else if (strcasecmp (key , "retain-ratio" ) == 0 ) {
435+ params -> retain_ratio = strtod (value , & end );
436+ if (strlen (end ) > 2 ) {
437+ ERROR ("param parsing error, find string \"%s\" after number\n" , end );
438+ }
482439 } else if (strcasecmp (key , "print" ) == 0 ) {
483440 printf ("%s parameters: %s\n" , cache -> cache_name ,
484441 FIFO_Reinsertion_current_params (params ));
0 commit comments