nfs-ganesha 1.4
|
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 /* @} */