nfs-ganesha 1.4

LRU_List.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  * ---------------------------------------
00024  */
00025 
00095 #ifdef HAVE_CONFIG_H
00096 #include "config.h"
00097 #endif
00098 
00099 #include <assert.h>
00100 #include <stdlib.h>
00101 #include <string.h>
00102 #include "LRU_List.h"
00103 #include "abstract_mem.h"
00104 #include "log.h"
00105 
00106 #ifndef TRUE
00107 #define TRUE 1
00108 #endif
00109 
00110 #ifndef FALSE
00111 #define FALSE 0
00112 #endif
00113 
00114 
00115 /* ------ This group contains all the functions used to manipulate the LRU from outside this module ----- */
00116 
00136 LRU_list_t *LRU_Init(LRU_parameter_t lru_param, LRU_status_t * pstatus)
00137 {
00138   LRU_list_t *plru = NULL;
00139   char *name __attribute__((unused)) = "Unamed";
00140 
00141   if (lru_param.lp_name != NULL)
00142     name = lru_param.lp_name;
00143 
00144   /* Sanity check */
00145   if((plru = gsh_malloc(sizeof(LRU_list_t))) == NULL)
00146     {
00147       *pstatus = LRU_LIST_MALLOC_ERROR;
00148       return NULL;
00149     }
00150 
00151   plru->nb_entry = 0;
00152   plru->nb_invalid = 0;
00153   plru->nb_call_gc = 0;
00154   plru->MRU = plru->LRU = NULL;
00155   plru->parameter = lru_param;
00156 
00157   /* Pre allocate entries */
00158   plru->lru_entry_pool = pool_init("LRU Entry Pool",
00159                                    sizeof(LRU_entry_t),
00160                                    pool_basic_substrate,
00161                                    NULL, NULL, NULL);
00162   if(!(plru->lru_entry_pool))
00163     {
00164       *pstatus = LRU_LIST_MALLOC_ERROR;
00165       return NULL;
00166     }
00167 
00168   *pstatus = LRU_LIST_SUCCESS;
00169   return plru;
00170 }                               /* LRU_Init */
00171 
00186 int LRU_invalidate(LRU_list_t * plru, LRU_entry_t * pentry)
00187 {
00188   if(pentry->valid_state != LRU_ENTRY_INVALID)
00189     {
00190       pentry->valid_state = LRU_ENTRY_INVALID;
00191       plru->nb_invalid += 1;
00192     }
00193 
00194   return LRU_LIST_SUCCESS;
00195 }                               /* LRU_invalidate */
00196 
00210 LRU_entry_t *LRU_new_entry(LRU_list_t * plru, LRU_status_t * pstatus)
00211 {
00212   LRU_entry_t *new_entry = NULL;
00213 
00214   LogDebug(COMPONENT_LRU,
00215            "==> LRU_new_entry: nb_entry = %d nb_entry_prealloc = %d",
00216            plru->nb_entry, plru->parameter.nb_entry_prealloc);
00217 
00218   new_entry = pool_alloc(plru->lru_entry_pool, NULL);
00219   if(new_entry == NULL)
00220     {
00221       *pstatus = LRU_LIST_MALLOC_ERROR;
00222       return NULL;
00223     }
00224 
00225   new_entry->valid_state = LRU_ENTRY_VALID;
00226   new_entry->next = NULL;       /* Entry is added as the MRU entry */
00227 
00228   if(plru->MRU == NULL)
00229     {
00230       new_entry->prev = NULL;
00231       plru->LRU = new_entry;
00232     }
00233   else
00234     {
00235       new_entry->prev = plru->MRU;
00236       plru->MRU->next = new_entry;
00237     }
00238 
00239   plru->nb_entry += 1;
00240   plru->nb_call_gc += 1;
00241   plru->MRU = new_entry;
00242 
00243   *pstatus = LRU_LIST_SUCCESS;
00244   return new_entry;
00245 }                               /* LRU_new_entry */
00246 
00247 
00252 static inline void _LRU_remove_entry(LRU_list_t * plru, LRU_entry_t * const pentry)
00253 {
00254     if(pentry->prev != NULL)
00255         pentry->prev->next = pentry->next;
00256     else {
00257         assert(pentry == plru->LRU); // we remove the list head
00258         plru->LRU = pentry->next;
00259     }
00260 
00261     if(pentry->next != NULL)
00262         pentry->next->prev = pentry->prev;
00263     else {
00264         assert(pentry == plru->MRU);    // we remove the MRU
00265         plru->MRU = NULL;
00266     }
00267     plru->nb_entry --;
00268     /* Put it back to pre-allocated pool */
00269     pool_free(plru->lru_entry_pool, pentry);
00270 }
00271 
00282 int LRU_pop_entry (LRU_list_t * plru, LRU_entry_t  *out_entry)
00283 {
00284     LRU_entry_t * const pentry = plru->LRU;
00285     void  *pdata __attribute__((unused));
00286 
00287     if (plru->nb_entry == 0) {
00288         return LRU_LIST_EMPTY_LIST;
00289     }
00290     memcpy(out_entry, pentry, sizeof(*out_entry));
00291     pdata = pentry->buffdata.pdata;
00292     _LRU_remove_entry(plru, pentry);
00293     return LRU_LIST_SUCCESS;
00294 }
00295 
00307 int LRU_gc_invalid(LRU_list_t * plru, void *cleanparam)
00308 {
00309   LRU_entry_t *pentry = NULL;
00310   LRU_entry_t *pentrynext = NULL;
00311   int rc = 0;
00312 
00313   if(plru == NULL)
00314     return LRU_LIST_EMPTY_LIST;
00315 
00316   if(plru->nb_invalid == 0)
00317     return LRU_LIST_SUCCESS;    /* Nothing to be done in this case */
00318 
00319   if(plru->MRU == NULL)
00320     return LRU_LIST_EMPTY_LIST;
00321 
00322   if(plru->MRU->prev == NULL)   /* One entry only, returns success (the MRU cannot be invalid) */
00323     return LRU_LIST_SUCCESS;
00324 
00325   /* Do nothing if not enough calls were done */
00326   if(plru->nb_call_gc < plru->parameter.nb_call_gc_invalid)
00327     return LRU_LIST_SUCCESS;
00328   plru->nb_call_gc = 0;
00329 
00330   /* From the LRU to the entry BEFORE the MRU */
00331   rc = LRU_LIST_SUCCESS;
00332 
00333   for(pentry = plru->LRU; pentry != plru->MRU; pentry = pentrynext)
00334     {
00335       pentrynext = pentry->next;
00336 
00337       if(pentry->valid_state == LRU_ENTRY_INVALID)
00338         {
00339           if(plru->parameter.clean_entry(pentry, cleanparam) != 0)
00340             {
00341               LogDebug(COMPONENT_LRU, "Error cleaning pentry %p", pentry);
00342               rc = LRU_LIST_BAD_RELEASE_ENTRY;
00343             }
00344 
00345           _LRU_remove_entry(plru, pentry);
00346           plru->nb_invalid --;
00347         }
00348     }
00349 
00350   return rc;
00351 }                               /* LRU_gc_invalid */
00352 
00369 int LRU_invalidate_by_function(LRU_list_t * plru,
00370                                int (*testfunc) (LRU_entry_t *, void *addparam),
00371                                void *addparam)
00372 {
00373   LRU_entry_t *pentry = NULL;
00374   LRU_entry_t *pentry_next = NULL;
00375   int rc = 0;
00376 
00377   if(plru == NULL)
00378     return LRU_LIST_EMPTY_LIST;
00379 
00380   if(plru->nb_entry == 0)
00381     return LRU_LIST_SUCCESS;    /* Nothing to be done in this case */
00382 
00383   if(plru->MRU == NULL)
00384     return LRU_LIST_EMPTY_LIST;
00385 
00386   if(plru->MRU->prev == NULL)   /* One entry only, returns success (the MRU cannot be set invalid) */
00387     return LRU_LIST_SUCCESS;
00388 
00389   /* From the LRU to the entry BEFORE the MRU */
00390   rc = LRU_LIST_SUCCESS;
00391 
00392   for(pentry = plru->LRU; pentry != plru->MRU; pentry = pentry_next)
00393     {
00394       pentry_next = pentry->next;
00395       if(pentry->valid_state != LRU_ENTRY_INVALID)
00396         {
00397           /* Use test function on the entry to know if it should be set invalid or not */
00398           if(testfunc(pentry, addparam) == LRU_LIST_SET_INVALID)
00399             {
00400               if((rc = LRU_invalidate(plru, pentry)) != LRU_LIST_SUCCESS)
00401                 break;          /* end of loop, error will be returned */
00402             }
00403         }
00404     }
00405 
00406   return rc;
00407 }                               /* LRU_invalidate_by_function */
00408 
00426 int LRU_apply_function(LRU_list_t * plru, int (*myfunc) (LRU_entry_t *, void *addparam),
00427                        void *addparam)
00428 {
00429   LRU_entry_t *pentry = NULL;
00430   int rc = 0;
00431 
00432   if(plru == NULL)
00433     return LRU_LIST_EMPTY_LIST;
00434 
00435   if(plru->nb_entry == 0)
00436     return LRU_LIST_SUCCESS;    /* Nothing to be done in this case */
00437 
00438   if(plru->MRU == NULL)
00439     return LRU_LIST_EMPTY_LIST;
00440 
00441   if(plru->MRU->prev == NULL)   /* One entry only, returns success (the MRU cannot be set invalid) */
00442     return LRU_LIST_SUCCESS;
00443 
00444   /* From the LRU to the entry BEFORE the MRU */
00445   rc = LRU_LIST_SUCCESS;
00446   for(pentry = plru->MRU->prev; pentry != NULL; pentry = pentry->prev)
00447     {
00448       if(pentry->valid_state != LRU_ENTRY_INVALID)
00449         {
00450           /* Use test function on the entry to know if it should be set invalid or not */
00451           if(myfunc(pentry, addparam) == FALSE)
00452             {
00453               break;            /* end of loop */
00454             }
00455         }
00456     }                           /* for */
00457 
00458   return rc;
00459 
00460 }                               /* LRU_apply_function */
00461 
00473 void LRU_Print(LRU_list_t * plru)
00474 {
00475   LRU_entry_t *pentry = NULL;
00476   char dispdata[LRU_DISPLAY_STRLEN];
00477 
00478   for(pentry = plru->LRU; pentry != NULL; pentry = pentry->next)
00479     {
00480       plru->parameter.entry_to_str(pentry->buffdata, dispdata);
00481       LogFullDebug(COMPONENT_LRU,
00482                    "Entry value = %s, valid_state = %d",
00483                    dispdata, pentry->valid_state);
00484     }
00485   LogFullDebug(COMPONENT_LRU, "-----------------------------------------");
00486 }                               /* LRU_Print */
00487 
00488 /* @} */