usermode/library/common/chhash.c

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2011 Computer Sciences Department, 
00003     University of Wisconsin -- Madison
00004 
00005     ----------------------------------------------------------------------
00006 
00007     This file is part of Mnemosyne: Lightweight Persistent Memory, 
00008     originally developed at the University of Wisconsin -- Madison.
00009 
00010     Mnemosyne was originally developed primarily by Haris Volos
00011     with contributions from Andres Jaan Tack.
00012 
00013     ----------------------------------------------------------------------
00014 
00015     Mnemosyne is free software; you can redistribute it and/or
00016     modify it under the terms of the GNU General Public License
00017     as published by the Free Software Foundation, version 2
00018     of the License.
00019  
00020     Mnemosyne is distributed in the hope that it will be useful,
00021     but WITHOUT ANY WARRANTY; without even the implied warranty of
00022     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023     GNU General Public License for more details.
00024 
00025     You should have received a copy of the GNU General Public License
00026     along with this program; if not, write to the Free Software
00027     Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00028     Boston, MA  02110-1301, USA.
00029 
00030 ### END HEADER ###
00031 */
00032 
00039 #include "debug.h"
00040 #include "result.h"
00041 #include "util.h"
00042 #include "chhash.h"
00043 
00044 typedef struct m_chhash_bucket_list_s m_chhash_bucket_list_t;
00045 
00046 struct m_chhash_bucket_s {
00047         struct m_chhash_bucket_s *next;
00048         struct m_chhash_bucket_s *prev;
00049         m_chhash_key_t           key;
00050         m_chhash_value_t         value;
00051 };
00052 
00053 struct m_chhash_bucket_list_s {
00054         m_mutex_t         mutex;
00055         m_chhash_bucket_t *head;
00056         m_chhash_bucket_t *free;
00057 };
00058 
00059 struct m_chhash_s {
00060         unsigned int           tbl_size;
00061         m_chhash_bucket_list_t *tbl;
00062         bool                   mtsafe;
00063 };
00064 
00065 
00066 m_result_t 
00067 m_chhash_create(m_chhash_t** hp, unsigned int table_size, bool mtsafe)
00068 {
00069         int i;
00070 
00071         *hp = (m_chhash_t *) MALLOC(sizeof(m_chhash_t));
00072         if (*hp == NULL) 
00073         {
00074                 return M_R_NOMEMORY;
00075         }
00076         (*hp)->tbl = (m_chhash_bucket_list_t*) CALLOC (table_size,
00077                                                        sizeof(m_chhash_bucket_list_t));
00078         if ((*hp)->tbl == NULL) 
00079         {
00080                 FREE(*hp);
00081                 return M_R_NOMEMORY;
00082         }
00083 
00084         for (i=0; i<table_size; i++) 
00085         {
00086                 M_MUTEX_INIT(&(*hp)->tbl[i].mutex, NULL);
00087                 (*hp)->tbl[i].head = NULL;
00088                 (*hp)->tbl[i].free = NULL;
00089         }
00090         (*hp)->tbl_size = table_size;
00091         (*hp)->mtsafe = mtsafe;
00092 
00093         return M_R_SUCCESS;
00094 }
00095 
00096 
00097 m_result_t
00098 m_chhash_destroy(m_chhash_t** hp)
00099 {
00100         m_chhash_bucket_t *bucket;
00101         m_chhash_bucket_t *next_bucket;
00102         int               i;
00103 
00104         if (*hp == NULL) 
00105         {
00106                 return M_R_SUCCESS;
00107         }
00108         for (i=0; i<(*hp)->tbl_size; i++) {
00109                 for (bucket = (*hp)->tbl[i].head; bucket; bucket = next_bucket) {
00110                         next_bucket = bucket->next;
00111                         FREE(bucket);
00112                 }
00113                 for (bucket = (*hp)->tbl[i].free; bucket; bucket = next_bucket) {
00114                         next_bucket = bucket->next;
00115                         FREE(bucket);
00116                 }
00117         }
00118 
00119         FREE((*hp)->tbl);
00120         FREE(*hp);
00121         
00122         return M_R_SUCCESS;
00123 }
00124 
00125 
00126 static void 
00127 bucket_list_add(m_chhash_bucket_t **head, m_chhash_bucket_t *bucket)
00128 {
00129         if (*head)
00130         {
00131                 (*head)->prev = bucket;
00132         }
00133         bucket->next = *head;
00134         bucket->prev = NULL;
00135         (*head) = bucket;
00136 }
00137 
00138 
00139 static void 
00140 bucket_list_remove(m_chhash_bucket_t **head, m_chhash_bucket_t *bucket)
00141 {
00142         if (*head == bucket) 
00143         {
00144                 *head = bucket->next;
00145                 bucket->prev = NULL;
00146         } else {
00147                 bucket->prev->next = bucket->next;
00148                 if (bucket->next) 
00149                 {
00150                         bucket->next->prev = bucket->prev;
00151                 }       
00152         }       
00153 }
00154 
00155 
00156 m_result_t
00157 m_chhash_add(m_chhash_t* h, 
00158              m_chhash_key_t key, 
00159              m_chhash_value_t value)
00160 {
00161         m_result_t             result;
00162         m_chhash_bucket_t      *bucket;
00163         m_chhash_bucket_list_t *bucket_list = &h->tbl[key % h->tbl_size];
00164 
00165         if (h->mtsafe == true) 
00166         {
00167                 M_MUTEX_LOCK(&(bucket_list->mutex));
00168         }
00169 
00170         for (bucket = bucket_list->head; 
00171              bucket != NULL; 
00172              bucket = bucket->next) 
00173         {
00174                 if (bucket->key == key) 
00175                 {
00176                         result = M_R_EXISTS;
00177                         goto done;
00178                 }
00179         }
00180         if (bucket_list->free) 
00181         {
00182                 bucket = bucket_list->free;
00183                 bucket_list_remove(&bucket_list->free, bucket);
00184         } else {
00185                 bucket = (m_chhash_bucket_t *) MALLOC(sizeof(m_chhash_bucket_t));
00186         }       
00187         bucket->key = key;
00188         bucket->value = value;
00189         bucket_list_add(&bucket_list->head, bucket);
00190         result = M_R_SUCCESS;
00191 
00192 done:
00193         if (h->mtsafe == true) 
00194         {
00195                 M_MUTEX_UNLOCK(&(bucket_list->mutex));
00196         }
00197         return result;
00198 }
00199 
00200 
00201 m_result_t
00202 m_chhash_lookup(m_chhash_t* h,
00203                 m_chhash_key_t key, 
00204                 m_chhash_value_t *value)
00205 {
00206         m_result_t             result;
00207         m_chhash_bucket_t      *bucket;
00208         m_chhash_bucket_list_t *bucket_list;
00209 
00210         bucket_list = &h->tbl[key % h->tbl_size];
00211 
00212         if (h->mtsafe == true) 
00213         {
00214                 M_MUTEX_LOCK(&(bucket_list->mutex));
00215         }
00216 
00217         for (bucket = bucket_list->head; 
00218              bucket != NULL; 
00219              bucket = bucket->next) 
00220         {
00221                 if (bucket->key == key) 
00222                 {
00223                         if (value) 
00224                         {
00225                                 *value = bucket->value; 
00226                         }       
00227                         result = M_R_SUCCESS;
00228                         goto done;
00229                 }
00230         }
00231         result = M_R_NOTEXISTS;
00232 
00233 done:
00234         if (h->mtsafe == true) 
00235         {
00236                 M_MUTEX_UNLOCK(&(bucket_list->mutex));
00237         }
00238         return result;
00239 
00240 }
00241 
00242 
00243 m_result_t
00244 m_chhash_remove(m_chhash_t* h,
00245                 m_chhash_key_t key, 
00246                 m_chhash_value_t *value)
00247 {
00248         m_result_t             result;
00249         m_chhash_bucket_t      *bucket;
00250         m_chhash_bucket_list_t *bucket_list;
00251 
00252         bucket_list = &h->tbl[key % h->tbl_size];
00253 
00254         if (h->mtsafe == true) 
00255         {
00256                 M_MUTEX_LOCK(&(bucket_list->mutex));
00257         }
00258 
00259         for (bucket = bucket_list->head; 
00260              bucket != NULL; 
00261              bucket = bucket->next) 
00262         {
00263                 if (bucket->key == key) 
00264                 {
00265                         if (value) 
00266                         {
00267                                 *value = bucket->value; 
00268                         }       
00269                         bucket_list_remove(&bucket_list->head, bucket);
00270                         bucket_list_add(&bucket_list->free, bucket);
00271                         result = M_R_SUCCESS;
00272                         goto done;
00273                 }
00274         }
00275         result = M_R_NOTEXISTS;
00276 done:
00277         if (h->mtsafe == true) 
00278         {
00279                 M_MUTEX_UNLOCK(&(bucket_list->mutex));
00280         }
00281         return result;
00282 }
00283 
00284 /* Iterator is not multithreaded safe */
00285 
00286 void
00287 m_chhash_iter_init(m_chhash_t *chhash, m_chhash_iter_t *iter)
00288 {
00289         unsigned int            i;
00290         m_chhash_bucket_t *bucket;
00291 
00292         iter->chhash = chhash;
00293         iter->index = 0;
00294         iter->bucket = NULL;
00295 
00296         for (i=0; i<chhash->tbl_size; i++) {
00297                 if (bucket = chhash->tbl[i].head) {
00298                         iter->bucket = bucket;
00299                         iter->index = i;
00300                         break;
00301                 }
00302         }
00303 }
00304 
00305 
00306 m_result_t
00307 m_chhash_iter_next(m_chhash_iter_t *iter, 
00308                    m_chhash_key_t *key, 
00309                    m_chhash_value_t *value)
00310 {
00311         unsigned int            i;
00312         m_chhash_bucket_t *bucket;
00313         m_chhash_t        *chhash = iter->chhash;
00314 
00315         if (iter->bucket == NULL) {
00316                 *key = 0;
00317                 *value = NULL;
00318                 return M_R_NULLITER;
00319         } 
00320 
00321         *key = iter->bucket->key;
00322         *value = iter->bucket->value;
00323 
00324         if (iter->bucket->next) {
00325                 iter->bucket = iter->bucket->next;
00326         } else {        
00327                 iter->bucket = NULL;
00328                 for (i=iter->index+1; i<chhash->tbl_size; i++) {
00329                         if (bucket = chhash->tbl[i].head) {
00330                                 iter->bucket = bucket;
00331                                 iter->index = i;
00332                                 break;
00333                         }
00334                 }
00335         }
00336         return M_R_SUCCESS;
00337 
00338 }
00339 
00340 
00341 void 
00342 m_chhash_print(m_chhash_t *h) {
00343         int i;
00344         m_chhash_bucket_list_t *bucket_list;
00345         m_chhash_bucket_t      *bucket;
00346 
00347         fprintf(M_DEBUG_OUT, "HASH TABLE: %p\n", h);
00348         for (i=0;i<h->tbl_size; i++)
00349         {
00350                 bucket_list = &h->tbl[i];
00351                 if (bucket = bucket_list->head) {
00352                         fprintf(M_DEBUG_OUT, "[%d]: head", i);
00353                         for (; bucket != NULL; bucket=bucket->next)
00354                         {
00355                                 fprintf(M_DEBUG_OUT, " --> (%u, %p)", bucket->key, bucket->value);
00356                         }
00357                         fprintf(M_DEBUG_OUT, "\n");
00358                 }
00359                 if (bucket = bucket_list->free) {
00360                         fprintf(M_DEBUG_OUT, "[%d]: free", i);
00361                         for (; bucket != NULL; bucket=bucket->next)
00362                         {
00363                                 fprintf(M_DEBUG_OUT, " --> (%u, %p)", bucket->key, bucket->value);
00364                         }
00365                         fprintf(M_DEBUG_OUT, "\n");
00366                 }
00367         }
00368 }

Generated on Sat Apr 23 11:43:34 2011 for Mnemosyne by  doxygen 1.4.7