My Project
|
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