/*----------------------------------------------------------------------------*/ /*ncache.h*/ /*----------------------------------------------------------------------------*/ /*The implementation of the cache of nodes*/ /*----------------------------------------------------------------------------*/ /*Based on the code of unionfs translator.*/ /*----------------------------------------------------------------------------*/ /*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. Written by Sergiu Ivanov . This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.*/ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ #define _GNU_SOURCE 1 /*----------------------------------------------------------------------------*/ #include "ncache.h" /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /*--------Global Variables----------------------------------------------------*/ /*The global cache chain*/ ncache_t ncache; /*----------------------------------------------------------------------------*/ /*Cache size (may be overwritten by the user)*/ int ncache_size = NCACHE_SIZE; /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /*--------Functions-----------------------------------------------------------*/ /*Initializes the node cache*/ void ncache_init ( int size_max ) { /*Reset the LRU and MRU ends of the list*/ ncache.mru = ncache.lru = NULL; /*Set the maximal size according to the parameter*/ ncache.size_max = size_max; /*The cache is empty so far; remark that*/ ncache.size_current = 0; /*Init the lock*/ mutex_init(&ncache.lock); }/*ncache_init*/ /*----------------------------------------------------------------------------*/ /*Looks up the lnode and stores the result in `node`; creates a new entry in the cache if the lookup fails*/ error_t ncache_node_lookup ( lnode_t * lnode, /*search for this*/ node_t ** node /*put the result here*/ ) { error_t err = 0; /*Obtain the pointer to the node corresponding to `lnode`*/ node_t * n = lnode->node; /*If a node has already been created for the given lnode*/ if(n != NULL) { /*count a new reference to 'n'*/ netfs_nref(n); } else { /*create a new node for the given lnode and store the result in `n`*/ err = node_create(lnode, &n); } /*If no errors have occurred during the previous operations*/ if(!err) { /*lock the mutex in the looked up node*/ mutex_lock(&n->lock); /*store the lookup result in `node`*/ *node = n; } /*Return the result of operations*/ return err; }/*ncache_node_lookup*/ /*----------------------------------------------------------------------------*/ /*Removes the given node from the cache*/ static void ncache_node_remove ( node_t * node ) { /*Obtain the pointer to the netnode (this contains the information specific of us)*/ struct netnode * nn = node->nn; /*If there exists a successor of this node in the cache chain*/ if(nn->ncache_next) /*remove the reference in the successor*/ nn->ncache_next->nn->ncache_prev = nn->ncache_prev; /*If there exists a predecessor of this node in the cache chain*/ if(nn->ncache_prev) /*remove the reference in the predecessor*/ nn->ncache_prev->nn->ncache_next = nn->ncache_next; /*If the node was located at the MRU end of the list*/ if(ncache.mru == node) /*shift the MRU end to the next node*/ ncache.mru = nn->ncache_next; /*If the node was located at the LRU end of the list*/ if(ncache.lru == node) /*shift the LRU end to the previous node*/ ncache.lru = nn->ncache_prev; /*Invalidate the references inside the node*/ nn->ncache_next = nn->ncache_prev = NULL; /*Count the removal of a node*/ --ncache.size_current; }/*ncache_node_remove*/ /*----------------------------------------------------------------------------*/ /*Resets the node cache*/ void ncache_reset(void) { /*The node being currently deleted*/ node_t * node; /*Acquire a lock on the cache*/ mutex_lock(&ncache.lock); /*Remove the whole cache chain*/ for(node = ncache.mru; node != NULL; ncache_node_remove(node), node = ncache.mru); /*Release the lock*/ mutex_unlock(&ncache.lock); }/*ncache_reset*/ /*----------------------------------------------------------------------------*/ /*Adds the given node to the cache*/ void ncache_node_add ( node_t * node /*the node to add*/ ) { /*Acquire a lock on the cache*/ mutex_lock(&ncache.lock); /*If there already are some nodes in the cache and it is enabled*/ if((ncache.size_max > 0) || (ncache.size_current > 0)) { /*If the node to be added is not at the MRU end already*/ if(ncache.mru != node) { /*If the node is correctly integrated in the cache*/ if((node->nn->ncache_next != NULL) && (node->nn->ncache_prev != NULL)) /*remove the old entry*/ ncache_node_remove(node); else /*add a new reference to the node*/ netfs_nref(node); /*put the node at the MRU end of the cache chain*/ node->nn->ncache_next = ncache.mru; node->nn->ncache_prev = NULL; /*setup the pointer in the old MRU end, if it exists*/ if(ncache.mru != NULL) ncache.mru->nn->ncache_prev = node; /*setup the LRU end of the cache chain, if it did not exist previously*/ if(ncache.lru == NULL) ncache.lru = node; /*shift the MRU end to the new node*/ ncache.mru = node; /*count the addition*/ ++ncache.size_current; } } /*While the size of the cache is exceeding the maximal size*/ node_t * old_lru; for ( old_lru = ncache.lru; ncache.size_current > ncache.size_max; old_lru = ncache.lru ) { /*remove the current LRU end of the list from the cache*/ ncache_node_remove(old_lru); /*release the reference to the node owned by this thread*/ netfs_nrele(old_lru); } /*Release the lock on the cache*/ mutex_unlock(&ncache.lock); }/*ncache_node_add*/ /*----------------------------------------------------------------------------*/