1 #ifndef __GSK_TABLE_H_
2 #define __GSK_TABLE_H_
3 
4 /* GskTable.
5  *
6  * A efficient on-disk table, meaning a mapping from an
7  * uninterpreted piece of binary-data to a value.
8  * When multiple values are added with the same
9  * key, they are merged, using user-definable semantics.
10  *
11  * application notes:
12  * - you may store data in the directory, but it the filename
13  *   must begin with a capital letter.
14  */
15 typedef struct _GskTableReader GskTableReader;
16 
17 #include "gskmempool.h"
18 
19 typedef struct
20 {
21   guint len;
22   guint8 *data;
23   guint alloced;
24 } GskTableBuffer;
25 
26 /* --- public table buffer api -- needed for defining merge functions --- */
27 /* calls realloc so beginning of buffer is preserved */
28 G_INLINE_FUNC guint8 *gsk_table_buffer_set_len (GskTableBuffer *buffer,
29                                                 guint           len);
30 
31 /* returns pointer to new area in buffer */
32 G_INLINE_FUNC guint8 *gsk_table_buffer_append  (GskTableBuffer *buffer,
33                                                 guint           len);
34 
35 
36 typedef  int (*GskTableCompareFunc)      (guint         a_key_len,
37                                           const guint8 *a_key_data,
38                                           guint         b_key_len,
39                                           const guint8 *b_key_data,
40                                           gpointer      user_data);
41 typedef  int (*GskTableCompareFuncNoLen) (const guint8 *a_key_data,
42                                           const guint8 *b_key_data,
43                                           gpointer      user_data);
44 typedef enum
45 {
46   GSK_TABLE_MERGE_RETURN_A,
47   GSK_TABLE_MERGE_RETURN_B,
48   GSK_TABLE_MERGE_SUCCESS,
49   GSK_TABLE_MERGE_DROP,
50 } GskTableMergeResult;
51 typedef GskTableMergeResult (*GskTableMergeFunc) (guint         key_len,
52                                                   const guint8 *key_data,
53                                                   guint         a_len,
54                                                   const guint8 *a_data,
55                                                   guint         b_len,
56                                                   const guint8 *b_data,
57                                                   GskTableBuffer *output,
58                                                   gpointer      user_data);
59 typedef GskTableMergeResult (*GskTableMergeFuncNoLen) (const guint8 *key_data,
60                                                        const guint8 *a_data,
61                                                        const guint8 *b_data,
62                                                        GskTableBuffer *output,
63                                                        gpointer      user_data);
64 
65 /* used for merges that go back to the beginning of the indexer */
66 typedef enum
67 {
68   GSK_TABLE_SIMPLIFY_IDENTITY,
69   GSK_TABLE_SIMPLIFY_SUCCESS,
70   GSK_TABLE_SIMPLIFY_DELETE
71 } GskTableSimplifyResult;
72 typedef GskTableSimplifyResult (*GskTableSimplifyFunc)(guint         key_len,
73                                                        const guint8 *key_data,
74                                                        guint         value_len,
75                                                        const guint8 *value_data,
76                                                        GskTableBuffer*val_out,
77                                                        gpointer      user_data);
78 typedef GskTableSimplifyResult (*GskTableSimplifyFuncNoLen)
79                                                       (const guint8 *key_data,
80                                                        const guint8 *value_data,
81                                                        GskTableBuffer*val_out,
82                                                        gpointer      user_data);
83 
84 /* only used for querying */
85 typedef gboolean          (*GskTableValueIsStableFunc)(guint         key_len,
86                                                        const guint8 *key_data,
87                                                        guint         value_len,
88                                                        const guint8 *value_data,
89                                                        gpointer      user_data);
90 
91 typedef enum
92 {
93   GSK_TABLE_JOURNAL_NONE,
94   GSK_TABLE_JOURNAL_OCCASIONALLY,
95   GSK_TABLE_JOURNAL_DEFAULT
96 } GskTableJournalMode;
97 
98 typedef struct _GskTableOptions GskTableOptions;
99 struct _GskTableOptions
100 {
101   /* compare configuration */
102   GskTableCompareFunc compare;
103   GskTableCompareFuncNoLen compare_no_len;
104 
105   /* merging configuration */
106   GskTableMergeFunc merge;
107   GskTableMergeFuncNoLen merge_no_len;
108 
109   /* final merging */
110   GskTableSimplifyFunc simplify;
111   GskTableSimplifyFuncNoLen simplify_no_len;
112 
113   /* query stability */
114   GskTableValueIsStableFunc is_stable;
115 
116   /* user data */
117   gpointer user_data;
118   GDestroyNotify destroy_user_data;
119 
120   /* journalling mode */
121   GskTableJournalMode journal_mode;
122 
123   /* tunables */
124   gsize max_in_memory_entries;
125   gsize max_in_memory_bytes;
126 };
127 
128 GskTableOptions     *gsk_table_options_new    (void);
129 void                 gsk_table_options_destroy(GskTableOptions *options);
130 
131 void gsk_table_options_set_replacement_semantics (GskTableOptions *options);
132 
133 typedef enum
134 {
135   GSK_TABLE_MAY_EXIST = (1<<0),
136   GSK_TABLE_MAY_CREATE = (1<<1)
137 } GskTableNewFlags;
138 
139 typedef struct _GskTable GskTable;
140 
141 /* NOTE: hinting options will be ignored if the table already exists. */
142 GskTable *  gsk_table_new         (const char            *dir,
143                                    const GskTableOptions *options,
144                                    GskTableNewFlags       flags,
145 	          	           GError               **error);
146 gboolean    gsk_table_add         (GskTable              *table,
147                                    guint                  key_len,
148 	          	           const guint8          *key_data,
149                                    guint                  value_len,
150 	          	           const guint8          *value_data,
151                                    GError               **error);
152 gboolean    gsk_table_query       (GskTable              *table,
153                                    guint                  key_len,
154 			           const guint8          *key_data,
155                                    gboolean              *found_value_out,
156 			           guint                 *value_len_out,
157 			           guint8               **value_data_out,
158                                    GError               **error);
159 const char *gsk_table_peek_dir    (GskTable              *table);
160 void        gsk_table_destroy     (GskTable              *table);
161 
162 
163 struct _GskTableReader
164 {
165   gboolean eof;
166   GError *error;
167   guint key_len;
168   const guint8 *key_data;
169   guint value_len;
170   const guint8 *value_data;
171 
172   void     (*advance) (GskTableReader *reader);
173   void     (*destroy) (GskTableReader *reader);
174 };
175 typedef enum
176 {
177   GSK_TABLE_BOUND_NONE,
178   GSK_TABLE_BOUND_STRICT,
179   GSK_TABLE_BOUND_INCLUSIVE
180 } GskTableBoundType;
181 GskTableReader *gsk_table_make_reader_with_bounds (GskTable *table,
182                                        GskTableBoundType start_bound_type,
183                                        guint start_bound_len,
184                                        const guint8 *start_bound_data,
185                                        GskTableBoundType end_bound_type,
186                                        guint end_bound_len,
187                                        const guint8 *end_bound_data,
188                                        GError  **error);
189 #define gsk_table_make_reader(table, error) \
190   gsk_table_make_reader_with_bounds (table, \
191                                      GSK_TABLE_BOUND_NONE, 0, NULL, \
192                                      GSK_TABLE_BOUND_NONE, 0, NULL, \
193                                      error)
194 
195 G_INLINE_FUNC void     gsk_table_reader_advance (GskTableReader *reader);
196 G_INLINE_FUNC void     gsk_table_reader_destroy (GskTableReader *reader);
197 
198 
199 
200 
201 
202 /* --- protected parts of the table-buffer api --- */
203 /* this stuff is used throughout the implementation:
204    we also cavalierly access 'len', 'data' and 'alloced'
205    and assume that they have the expected properties.
206    we do not modify 'data' or 'alloced' and we always
207    ensure that len < alloced. */
208 
209 #define GSK_TABLE_BUFFER_INIT   { 0, NULL, 0 }
210 G_INLINE_FUNC void    gsk_table_buffer_init         (GskTableBuffer *buffer);
211 
212 G_INLINE_FUNC void    gsk_table_buffer_clear        (GskTableBuffer *buffer);
213 
214 G_INLINE_FUNC void    gsk_table_buffer_ensure_size  (GskTableBuffer *buffer,
215                                                      guint           min_size);
216 G_INLINE_FUNC void    gsk_table_buffer_ensure_extra (GskTableBuffer *buffer,
217                                                      guint           addl_size);
218 
219 
220 #if defined (G_CAN_INLINE) || defined (__GSK_DEFINE_INLINES__)
gsk_table_buffer_init(GskTableBuffer * buffer)221 G_INLINE_FUNC void    gsk_table_buffer_init    (GskTableBuffer *buffer)
222 {
223   buffer->len = 0;
224   buffer->data = NULL;
225   buffer->alloced = 0;
226 }
227 
228 /* calls realloc so beginning of buffer is preserved */
229 G_INLINE_FUNC void
gsk_table_buffer_ensure_size(GskTableBuffer * buffer,guint min_size)230 gsk_table_buffer_ensure_size (GskTableBuffer *buffer,
231                               guint           min_size)
232 {
233   if (G_UNLIKELY (buffer->alloced < min_size))
234     {
235       guint new_size = buffer->alloced ? buffer->alloced * 2 : 32;
236       while (new_size < min_size)
237         new_size += new_size;
238       buffer->data = g_realloc (buffer->data, new_size);
239       buffer->alloced = new_size;
240     }
241 }
242 
243 G_INLINE_FUNC guint8 *
gsk_table_buffer_set_len(GskTableBuffer * buffer,guint len)244 gsk_table_buffer_set_len (GskTableBuffer *buffer,
245                           guint           len)
246 {
247   gsk_table_buffer_ensure_size (buffer, len);
248   buffer->len = len;
249   return buffer->data;
250 }
251 
252 /* returns pointer to new area in buffer */
253 G_INLINE_FUNC guint8 *
gsk_table_buffer_append(GskTableBuffer * buffer,guint len)254 gsk_table_buffer_append  (GskTableBuffer *buffer,
255                           guint           len)
256 {
257   guint old_len = buffer->len;
258   return gsk_table_buffer_set_len (buffer, old_len + len) + old_len;
259 }
260 
261 G_INLINE_FUNC void
gsk_table_buffer_clear(GskTableBuffer * buffer)262 gsk_table_buffer_clear   (GskTableBuffer *buffer)
263 {
264   g_free (buffer->data);
265 }
266 
267 G_INLINE_FUNC void
gsk_table_buffer_ensure_extra(GskTableBuffer * buffer,guint extra_bytes)268 gsk_table_buffer_ensure_extra (GskTableBuffer *buffer,
269                                guint           extra_bytes)
270 {
271   gsk_table_buffer_ensure_size (buffer, buffer->len + extra_bytes);
272 }
273 G_INLINE_FUNC void
gsk_table_reader_advance(GskTableReader * reader)274 gsk_table_reader_advance (GskTableReader *reader)
275 {
276   reader->advance (reader);
277 }
278 G_INLINE_FUNC void
gsk_table_reader_destroy(GskTableReader * reader)279 gsk_table_reader_destroy (GskTableReader *reader)
280 {
281   reader->destroy (reader);
282 }
283 #endif
284 
285 #endif
286