MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
hash_filo.h
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 
17 /*
18 ** A class for static sized hash tables where old entries are deleted in
19 ** first-in-last-out to usage.
20 */
21 
22 #ifndef HASH_FILO_H
23 #define HASH_FILO_H
24 
25 #include "hash.h" /* my_hash_get_key, my_hash_free_key, HASH */
26 #include "mysqld.h" /* key_hash_filo_lock */
27 
29 {
30 private:
31  hash_filo_element *next_used,*prev_used;
32 public:
34  hash_filo_element *next()
35  { return next_used; }
36  hash_filo_element *prev()
37  { return prev_used; }
38 
39  friend class hash_filo;
40 };
41 
42 
43 class hash_filo
44 {
45 private:
46  const uint key_offset, key_length;
47  const my_hash_get_key get_key;
49  uint m_size;
50  my_hash_free_key free_element;
51  bool init;
52  CHARSET_INFO *hash_charset;
53 
54  hash_filo_element *first_link,*last_link;
55 public:
56  mysql_mutex_t lock;
57  HASH cache;
58 
59  hash_filo(uint size, uint key_offset_arg , uint key_length_arg,
60  my_hash_get_key get_key_arg, my_hash_free_key free_element_arg,
61  CHARSET_INFO *hash_charset_arg)
62  : key_offset(key_offset_arg), key_length(key_length_arg),
63  get_key(get_key_arg), m_size(size),
64  free_element(free_element_arg),init(0),
65  hash_charset(hash_charset_arg),
66  first_link(NULL),
67  last_link(NULL)
68  {
69  memset(&cache, 0, sizeof(cache));
70  }
71 
72  ~hash_filo()
73  {
74  if (init)
75  {
76  if (cache.array.buffer) /* Avoid problems with thread library */
77  (void) my_hash_free(&cache);
78  mysql_mutex_destroy(&lock);
79  }
80  }
81  void clear(bool locked=0)
82  {
83  if (!init)
84  {
85  init=1;
86  mysql_mutex_init(key_hash_filo_lock, &lock, MY_MUTEX_INIT_FAST);
87  }
88  if (!locked)
89  mysql_mutex_lock(&lock);
90  first_link= NULL;
91  last_link= NULL;
92  (void) my_hash_free(&cache);
93  (void) my_hash_init(&cache, hash_charset, m_size, key_offset,
94  key_length, get_key, free_element,0);
95  if (!locked)
96  mysql_mutex_unlock(&lock);
97  }
98 
99  hash_filo_element *first()
100  {
102  return first_link;
103  }
104 
105  hash_filo_element *last()
106  {
108  return last_link;
109  }
110 
111  hash_filo_element *search(uchar* key, size_t length)
112  {
114 
116  my_hash_search(&cache,(uchar*) key,length);
117  if (entry)
118  { // Found; link it first
119  DBUG_ASSERT(first_link != NULL);
120  DBUG_ASSERT(last_link != NULL);
121  if (entry != first_link)
122  { // Relink used-chain
123  if (entry == last_link)
124  {
125  last_link= last_link->prev_used;
126  /*
127  The list must have at least 2 elements,
128  otherwise entry would be equal to first_link.
129  */
130  DBUG_ASSERT(last_link != NULL);
131  last_link->next_used= NULL;
132  }
133  else
134  {
135  DBUG_ASSERT(entry->next_used != NULL);
136  DBUG_ASSERT(entry->prev_used != NULL);
137  entry->next_used->prev_used = entry->prev_used;
138  entry->prev_used->next_used = entry->next_used;
139  }
140  entry->prev_used= NULL;
141  entry->next_used= first_link;
142 
143  first_link->prev_used= entry;
144  first_link=entry;
145  }
146  }
147  return entry;
148  }
149 
150  my_bool add(hash_filo_element *entry)
151  {
152  if (!m_size) return 1;
153  if (cache.records == m_size)
154  {
155  hash_filo_element *tmp=last_link;
156  last_link= last_link->prev_used;
157  if (last_link != NULL)
158  {
159  last_link->next_used= NULL;
160  }
161  else
162  {
163  /* Pathological case, m_size == 1 */
164  first_link= NULL;
165  }
166  my_hash_delete(&cache,(uchar*) tmp);
167  }
168  if (my_hash_insert(&cache,(uchar*) entry))
169  {
170  if (free_element)
171  (*free_element)(entry); // This should never happen
172  return 1;
173  }
174  entry->prev_used= NULL;
175  entry->next_used= first_link;
176  if (first_link != NULL)
177  first_link->prev_used= entry;
178  else
179  last_link= entry;
180  first_link= entry;
181 
182  return 0;
183  }
184 
185  uint size()
186  { return m_size; }
187 
188  void resize(uint new_size)
189  {
190  mysql_mutex_lock(&lock);
191  m_size= new_size;
192  clear(true);
193  mysql_mutex_unlock(&lock);
194  }
195 };
196 
197 #endif