All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
target/Linux-x86_64/include/citrusleaf/cf_rchash.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2008-2013 by Aerospike.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  *****************************************************************************/
22 #pragma once
23 
24 /*
25  * A general purpose hashtable implementation
26  * Uses locks, so only moderately fast
27  * Just, hopefully, the last hash table you'll ever need
28  * And you can keep adding cool things to it
29  */
30 
31 #include <citrusleaf/alloc.h>
32 #include <citrusleaf/cf_types.h>
33 #include <inttypes.h>
34 #include <stdint.h>
35 #include <pthread.h>
36 #include <stdbool.h>
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 /******************************************************************************
43  * CONSTANTS
44  ******************************************************************************/
45 
46 #define CF_RCHASH_ERR_FOUND -4
47 #define CF_RCHASH_ERR_NOTFOUND -3
48 #define CF_RCHASH_ERR_BUFSZ -2
49 #define CF_RCHASH_ERR -1
50 #define CF_RCHASH_OK 0
51 
52 /**
53  * support resizes (will sometimes hang for long periods)
54  */
55 #define CF_RCHASH_CR_RESIZE 0x01
56 
57 /**
58  * support 'grab' call (requires more memory)
59  */
60 #define CF_RCHASH_CR_GRAB 0x02
61 
62 /**
63  * support multithreaded access with a single big lock
64  */
65 #define CF_RCHASH_CR_MT_BIGLOCK 0x04
66 
67 /**
68  * support multithreaded access with a pool of object loccks
69  */
70 #define CF_RCHASH_CR_MT_MANYLOCK 0x08
71 
72 /**
73  *don't calculate the size on every call, which makes 'getsize' expensive if you ever call it
74  */
75 #define CF_RCHASH_CR_NOSIZE 0x10
76 
77 /**
78  * support resizes (will sometimes hang for long periods)
79  */
80 #define CF_RCHASH_CR_RESIZE 0x01
81 
82 /**
83  * support multithreaded access with a single big lock
84  */
85 #define CF_RCHASH_CR_MT_BIGLOCK 0x04
86 
87 /**
88  * support multithreaded access with a pool of object loccks
89  */
90 #define CF_RCHASH_CR_MT_LOCKPOOL 0x08
91 
92 /**
93  * indicate that a delete should be done during reduction
94  */
95 #define CF_RCHASH_REDUCE_DELETE (1)
96 
97 /******************************************************************************
98  * TYPES
99  ******************************************************************************/
100 
101 typedef struct cf_rchash_s cf_rchash;
102 typedef struct cf_rchash_elem_v_s cf_rchash_elem_v;
103 typedef struct cf_rchash_elem_f_s cf_rchash_elem_f;
104 
105 /**
106  * A generic call for hash functions the user can create
107  */
108 typedef uint32_t (*cf_rchash_hash_fn) (void *value, uint32_t value_len);
109 
110 /**
111  * Typedef for a "reduce" fuction that is called on every node
112  * (Note about return value: some kinds of reduces can manipulate the hash table,
113  * allowing deletion. See the particulars of the reduce call.)
114  */
115 typedef int (*cf_rchash_reduce_fn) (void *key, uint32_t keylen, void *object, void *udata);
116 
117 /**
118  * need a destructor for the object.
119  *
120  * Importantly - since the hash table knows about the reference-counted nature of
121  * the stored objects, a 'delete' will have to decrement the reference count, thus
122  * likely will need to call a function to clean the internals of the object.
123  * this destructor should not free the object, and will be called only when the reference
124  * count is 0. If you don't have any internal state in the object, you can pass NULL
125  * as the destructor.
126  *
127  * This function is also called if there's a 'reduce' that returns 'delete'
128  */
129 typedef void (*cf_rchash_destructor_fn) (void *object);
130 
131 /**
132  * Simple (and slow) element is when
133  * everything is variable (although a very nicely packed structure for 32 or 64
134  */
135 struct cf_rchash_elem_v_s {
136  cf_rchash_elem_v * next;
137  void * object; // this is a reference counted object
138  uint32_t key_len;
139  void * key;
140 };
141 
142 /**
143  * When the key size is fixed, life can be simpler
144  */
145 struct cf_rchash_elem_f_s {
146  cf_rchash_elem_f * next;
147  void * object; // this is a reference counted object
148  uint8_t key[];
149 };
150 
151 
152 /**
153  * An interesting tradeoff regarding 'get_size'
154  * In the case of many-locks, there's no real size at any given instant,
155  * because the hash is parallelized. Yet, the overhead of creating
156  * an atomic for the elements is silly.
157  * Thus, when 'manylock', the elements field is not useful because
158  * its not protected by a lock - it will *typically* get boned up.
159  * Thus, get_size has to slowly troop through the hashset
160  * This seems reasonable because 'get_size' with many lock can't be important,
161  * since it's always an estimate anyway.
162  */
163 struct cf_rchash_s {
164  uint32_t elements; // INVALID IF MANYLOCK
165  uint32_t key_len; // if key_len == 0, then use the variable size functions
166  uint flags;
169  uint table_len; // number of elements currently in the table
170  void * table;
171  pthread_mutex_t biglock;
172  int lock_table_len;
173  int buckets_per_lock; // precompute: buckets / locks
174  pthread_mutex_t * lock_table;
175 };
176 
177 
178 /******************************************************************************
179  * FUNCTIONS
180  ******************************************************************************/
181 
182 /*
183  * Create a hash table
184  * Pass in the hash function (required)
185  * the key length if static (if not static pass 0
186  * the value length if static (if not static pass 0
187  * The initial table size
188  * a set of flags
189  */
190 int cf_rchash_create(cf_rchash **h, cf_rchash_hash_fn h_fn, cf_rchash_destructor_fn d_fn, uint32_t key_len, uint32_t sz, uint flags);
191 
192 int cf_rchash_set_nlocks(cf_rchash *h, int n_locks);
193 
194 
195 /* Place a value into the hash
196  * Value will be copied into the hash
197  */
198 int cf_rchash_put(cf_rchash *h, void *key, uint32_t key_len, void *value);
199 
200 int cf_rchash_put_unique(cf_rchash *h, void *key, uint32_t key_len, void *value);
201 
202 /* If you think you know how much space it will take,
203  * call with the buffer you want filled
204  * If you're wrong about the space, you'll get a BUFSZ error, but the *value_len
205  * will be filled in with the value you should have passed
206  */
207 int cf_rchash_get(cf_rchash *h, void *key, uint32_t key_len, void **object);
208 
209 /*
210 ** Got a key you want removed - this is the function to call
211 */
212 int cf_rchash_delete(cf_rchash *h, void *key, uint32_t key_len);
213 
214 /*
215 ** Get the number of elements currently in the hash
216 */
217 uint32_t cf_rchash_get_size(cf_rchash *h);
218 
219 
220 /*
221 ** Map/Reduce pattern - call the callback on every element in the hash
222 ** Warning: the entire traversal can hold the lock in the 'biglock' case,
223 ** so make the reduce_fn lightweight! Consider queuing or soemthing if you
224 ** want to do something fancy
225 */
226 void cf_rchash_reduce(cf_rchash *h, cf_rchash_reduce_fn reduce_fn, void *udata);
227 
228 /*
229 ** Map/Reduce pattern - call the callback on every element in the hash
230 ** This instance allows deletion of hash elements during the reduce:
231 ** return -1 to cause the deletion of the element visisted
232 */
233 void cf_rchash_reduce_delete(cf_rchash *h, cf_rchash_reduce_fn reduce_fn, void *udata);
234 
235 
236 /*
237  * Destroy the entire hash - all memory will be freed
238  */
239 void cf_rchash_destroy(cf_rchash *h);
240 
241 /******************************************************************************/
242 
243 #ifdef __cplusplus
244 } // end extern "C"
245 #endif