My Project
hash_filo.h
00001 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software Foundation,
00014    51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
00015 
00016 
00017 /*
00018 ** A class for static sized hash tables where old entries are deleted in
00019 ** first-in-last-out to usage.
00020 */
00021 
00022 #ifndef  HASH_FILO_H
00023 #define  HASH_FILO_H
00024 
00025 #include "hash.h"        /* my_hash_get_key, my_hash_free_key, HASH */
00026 #include "mysqld.h"      /* key_hash_filo_lock */
00027 
00028 struct hash_filo_element
00029 {
00030 private:
00031   hash_filo_element *next_used,*prev_used;
00032 public:
00033   hash_filo_element() {}
00034   hash_filo_element *next()
00035   { return next_used; }
00036   hash_filo_element *prev()
00037   { return prev_used; }
00038   
00039   friend class hash_filo;
00040 };
00041 
00042 
00043 class hash_filo
00044 {
00045 private:
00046   const uint key_offset, key_length;
00047   const my_hash_get_key get_key;
00049   uint m_size;
00050   my_hash_free_key free_element;
00051   bool init;
00052   CHARSET_INFO *hash_charset;
00053 
00054   hash_filo_element *first_link,*last_link;
00055 public:
00056   mysql_mutex_t lock;
00057   HASH cache;
00058 
00059   hash_filo(uint size, uint key_offset_arg , uint key_length_arg,
00060             my_hash_get_key get_key_arg, my_hash_free_key free_element_arg,
00061             CHARSET_INFO *hash_charset_arg)
00062     : key_offset(key_offset_arg), key_length(key_length_arg),
00063     get_key(get_key_arg), m_size(size),
00064     free_element(free_element_arg),init(0),
00065     hash_charset(hash_charset_arg),
00066     first_link(NULL),
00067     last_link(NULL)
00068   {
00069     memset(&cache, 0, sizeof(cache));
00070   }
00071 
00072   ~hash_filo()
00073   {
00074     if (init)
00075     {
00076       if (cache.array.buffer)   /* Avoid problems with thread library */
00077         (void) my_hash_free(&cache);
00078       mysql_mutex_destroy(&lock);
00079     }
00080   }
00081   void clear(bool locked=0)
00082   {
00083     if (!init)
00084     {
00085       init=1;
00086       mysql_mutex_init(key_hash_filo_lock, &lock, MY_MUTEX_INIT_FAST);
00087     }
00088     if (!locked)
00089       mysql_mutex_lock(&lock);
00090     first_link= NULL;
00091     last_link= NULL;
00092     (void) my_hash_free(&cache);
00093     (void) my_hash_init(&cache, hash_charset, m_size, key_offset, 
00094                         key_length, get_key, free_element,0);
00095     if (!locked)
00096       mysql_mutex_unlock(&lock);
00097   }
00098 
00099   hash_filo_element *first()
00100   {
00101     mysql_mutex_assert_owner(&lock);
00102     return first_link;
00103   }
00104 
00105   hash_filo_element *last()
00106   {
00107     mysql_mutex_assert_owner(&lock);
00108     return last_link;
00109   }
00110 
00111   hash_filo_element *search(uchar* key, size_t length)
00112   {
00113     mysql_mutex_assert_owner(&lock);
00114 
00115     hash_filo_element *entry=(hash_filo_element*)
00116       my_hash_search(&cache,(uchar*) key,length);
00117     if (entry)
00118     {                                           // Found; link it first
00119       DBUG_ASSERT(first_link != NULL);
00120       DBUG_ASSERT(last_link != NULL);
00121       if (entry != first_link)
00122       {                                         // Relink used-chain
00123         if (entry == last_link)
00124         {
00125           last_link= last_link->prev_used;
00126           /*
00127             The list must have at least 2 elements,
00128             otherwise entry would be equal to first_link.
00129           */
00130           DBUG_ASSERT(last_link != NULL);
00131           last_link->next_used= NULL;
00132         }
00133         else
00134         {
00135           DBUG_ASSERT(entry->next_used != NULL);
00136           DBUG_ASSERT(entry->prev_used != NULL);
00137           entry->next_used->prev_used = entry->prev_used;
00138           entry->prev_used->next_used = entry->next_used;
00139         }
00140         entry->prev_used= NULL;
00141         entry->next_used= first_link;
00142 
00143         first_link->prev_used= entry;
00144         first_link=entry;
00145       }
00146     }
00147     return entry;
00148   }
00149 
00150   my_bool add(hash_filo_element *entry)
00151   {
00152     if (!m_size) return 1;
00153     if (cache.records == m_size)
00154     {
00155       hash_filo_element *tmp=last_link;
00156       last_link= last_link->prev_used;
00157       if (last_link != NULL)
00158       {
00159         last_link->next_used= NULL;
00160       }
00161       else
00162       {
00163         /* Pathological case, m_size == 1 */
00164         first_link= NULL;
00165       }
00166       my_hash_delete(&cache,(uchar*) tmp);
00167     }
00168     if (my_hash_insert(&cache,(uchar*) entry))
00169     {
00170       if (free_element)
00171         (*free_element)(entry);         // This should never happen
00172       return 1;
00173     }
00174     entry->prev_used= NULL;
00175     entry->next_used= first_link;
00176     if (first_link != NULL)
00177       first_link->prev_used= entry;
00178     else
00179       last_link= entry;
00180     first_link= entry;
00181 
00182     return 0;
00183   }
00184 
00185   uint size()
00186   { return m_size; }
00187 
00188   void resize(uint new_size)
00189   {
00190     mysql_mutex_lock(&lock);
00191     m_size= new_size;
00192     clear(true);
00193     mysql_mutex_unlock(&lock);
00194   }
00195 };
00196 
00197 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines