summaryrefslogtreecommitdiff
path: root/netfs-sample/ncache.c
diff options
context:
space:
mode:
authorroot <root@(null).(none)>2009-05-03 17:20:00 +0200
committerroot <root@(null).(none)>2009-05-03 17:20:00 +0200
commite0faf22f31c48fb27b43c1825897d26e58feafc4 (patch)
tree65a09372b31e08a3a865bd0a88cd2718bafcd643 /netfs-sample/ncache.c
This is my initial working version.
There is a bug in boot in this version: subhurd sometimes cannot boot.
Diffstat (limited to 'netfs-sample/ncache.c')
-rw-r--r--netfs-sample/ncache.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/netfs-sample/ncache.c b/netfs-sample/ncache.c
new file mode 100644
index 00000000..12462d31
--- /dev/null
+++ b/netfs-sample/ncache.c
@@ -0,0 +1,221 @@
+/*----------------------------------------------------------------------------*/
+/*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 <unlimitedscolobb@gmail.com>.
+
+ 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*/
+/*----------------------------------------------------------------------------*/