flat_file_dictionary_handler.c
Go to the documentation of this file.
1 /******************************************************************************/
36 /******************************************************************************/
37 
39 
54  ion_dict_cursor_t *cursor,
55  ion_record_t *record
56 ) {
57  ion_flat_file_t *flat_file = (ion_flat_file_t *) cursor->dictionary->instance;
58  ion_flat_file_cursor_t *flat_file_cursor = (ion_flat_file_cursor_t *) cursor;
59 
60  if (cursor->status == cs_cursor_uninitialized) {
61  return cursor->status;
62  }
63  else if (cursor->status == cs_end_of_results) {
64  return cursor->status;
65  }
66  else if ((cursor->status == cs_cursor_initialized) || (cursor->status == cs_cursor_active)) {
67  if (cursor->status == cs_cursor_active) {
68  ion_flat_file_row_t throwaway_row;
70 
71  switch (cursor->predicate->type) {
72  case predicate_equality: {
73  err = flat_file_scan(flat_file, flat_file_cursor->current_location + 1, &flat_file_cursor->current_location, &throwaway_row, ION_FLAT_FILE_SCAN_FORWARDS, flat_file_predicate_key_match, cursor->predicate->statement.equality.equality_value);
74 
75  break;
76  }
77 
78  case predicate_range: {
79  err = flat_file_scan(flat_file, flat_file_cursor->current_location + 1, &flat_file_cursor->current_location, &throwaway_row, ION_FLAT_FILE_SCAN_FORWARDS, flat_file_predicate_within_bounds, cursor->predicate->statement.range.lower_bound, cursor->predicate->statement.range.upper_bound);
80 
81  break;
82  }
83 
84  case predicate_all_records: {
85  err = flat_file_scan(flat_file, flat_file_cursor->current_location + 1, &flat_file_cursor->current_location, &throwaway_row, ION_FLAT_FILE_SCAN_FORWARDS, flat_file_predicate_not_empty);
86 
87  break;
88  }
89 
90  case predicate_predicate: {
91  break;
92  }
93  }
94 
95  if (err_file_hit_eof == err) {
96  cursor->status = cs_end_of_results;
97  return cursor->status;
98  }
99  else if (err_ok != err) {
101  return cursor->status;
102  }
103  }
104  else {
105  /* The status is cs_cursor_initialized */
106  cursor->status = cs_cursor_active;
107  }
108 
110  ion_err_t err = flat_file_read_row(flat_file, flat_file_cursor->current_location, &row);
111 
112  if (err_ok != err) {
113  return cs_invalid_index;
114  }
115 
116  /*Copy both key and value into user provided struct */
117  memcpy(record->key, row.key, cursor->dictionary->instance->record.key_size);
118  memcpy(record->value, row.value, cursor->dictionary->instance->record.value_size);
119 
120  return cursor->status;
121  }
122 
123  return cs_invalid_cursor;
124 }
125 
133 void
135  ion_dict_cursor_t **cursor
136 ) {
137  (*cursor)->predicate->destroy(&(*cursor)->predicate);
138  free(*cursor);
139  *cursor = NULL;
140 }
141 
160 ion_err_t
162  ion_dictionary_handler_t *handler,
166 ) {
167  return ffdict_create_dictionary(config->id, config->type, config->key_size, config->value_size, config->dictionary_size, compare, handler, dictionary);
168 }
169 
177 ion_err_t
180 ) {
181  ion_err_t err = flat_file_close((ion_flat_file_t *) dictionary->instance);
182 
183  free(dictionary->instance);
184  dictionary->instance = NULL;
185 
186  if (err_ok != err) {
187  return err;
188  }
189 
190  return err_ok;
191 }
192 
208 ion_err_t
212  ion_dict_cursor_t **cursor
213 ) {
214  *cursor = malloc(sizeof(ion_flat_file_cursor_t));
215 
216  ion_flat_file_t *flat_file = (ion_flat_file_t *) dictionary->instance;
217 
218  if (NULL == *cursor) {
219  return err_out_of_memory;
220  }
221 
222  (*cursor)->dictionary = dictionary;
223  (*cursor)->status = cs_cursor_uninitialized;
224 
225  (*cursor)->destroy = ffdict_destroy_cursor;
226  (*cursor)->next = ffdict_next;
227 
228  (*cursor)->predicate = malloc(sizeof(ion_predicate_t));
229 
230  if (NULL == (*cursor)->predicate) {
231  free(*cursor);
232  return err_out_of_memory;
233  }
234 
235  (*cursor)->predicate->type = predicate->type;
236  (*cursor)->predicate->destroy = predicate->destroy;
237 
238  ion_key_size_t key_size = dictionary->instance->record.key_size;
239 
240  switch (predicate->type) {
241  case predicate_equality: {
242  ion_key_t target_key = predicate->statement.equality.equality_value;
243 
244  (*cursor)->predicate->statement.equality.equality_value = malloc(key_size);
245 
246  if (NULL == (*cursor)->predicate->statement.equality.equality_value) {
247  free((*cursor)->predicate);
248  free(*cursor);
249  return err_out_of_memory;
250  }
251 
252  memcpy((*cursor)->predicate->statement.equality.equality_value, target_key, key_size);
253 
254  ion_fpos_t loc = -1;
256  ion_err_t scan_result = flat_file_scan(flat_file, -1, &loc, &row, ION_FLAT_FILE_SCAN_FORWARDS, flat_file_predicate_key_match, target_key);
257 
258  if (err_file_hit_eof == scan_result) {
259  /* If this happens, that means the target key doesn't exist */
260  (*cursor)->status = cs_end_of_results;
261  return err_ok;
262  }
263  else if (err_ok == scan_result) {
264  (*cursor)->status = cs_cursor_initialized;
265 
266  ion_flat_file_cursor_t *flat_file_cursor = (ion_flat_file_cursor_t *) (*cursor);
267 
268  flat_file_cursor->current_location = loc;
269  return err_ok;
270  }
271  else {
272  /* File scan hit an error condition */
273  return scan_result;
274  }
275 
276  break;
277  }
278 
279  case predicate_range: {
280  (*cursor)->predicate->statement.range.lower_bound = malloc(key_size);
281 
282  if (NULL == (*cursor)->predicate->statement.range.lower_bound) {
283  free((*cursor)->predicate);
284  free(*cursor);
285  return err_out_of_memory;
286  }
287 
288  memcpy((*cursor)->predicate->statement.range.lower_bound, predicate->statement.range.lower_bound, key_size);
289 
290  (*cursor)->predicate->statement.range.upper_bound = malloc(key_size);
291 
292  if (NULL == (*cursor)->predicate->statement.range.upper_bound) {
293  free((*cursor)->predicate->statement.range.lower_bound);
294  free((*cursor)->predicate);
295  free(*cursor);
296  return err_out_of_memory;
297  }
298 
299  memcpy((*cursor)->predicate->statement.range.upper_bound, predicate->statement.range.upper_bound, key_size);
300 
301  /* Find the first satisfactory key. */
302  ion_fpos_t loc = -1;
304  ion_err_t scan_result = flat_file_scan(flat_file, -1, &loc, &row, ION_FLAT_FILE_SCAN_FORWARDS, flat_file_predicate_within_bounds, (*cursor)->predicate->statement.range.lower_bound, (*cursor)->predicate->statement.range.upper_bound);
305 
306  if (err_file_hit_eof == scan_result) {
307  /* This means the returned node is smaller than the lower bound, which means that there are no valid records to return */
308  (*cursor)->status = cs_end_of_results;
309  return err_ok;
310  }
311  else if (err_ok == scan_result) {
312  (*cursor)->status = cs_cursor_initialized;
313 
314  ion_flat_file_cursor_t *flat_file_cursor = (ion_flat_file_cursor_t *) (*cursor);
315 
316  flat_file_cursor->current_location = loc;
317  return err_ok;
318  }
319  else {
320  /* Scan failed due to external error */
321  return scan_result;
322  }
323 
324  break;
325  }
326 
327  case predicate_all_records: {
328  ion_flat_file_cursor_t *flat_file_cursor = (ion_flat_file_cursor_t *) (*cursor);
329 
330  ion_fpos_t loc = -1;
332  ion_err_t scan_result = flat_file_scan(flat_file, -1, &loc, &row, ION_FLAT_FILE_SCAN_FORWARDS, flat_file_predicate_not_empty);
333 
334  if (err_file_hit_eof == scan_result) {
335  (*cursor)->status = cs_end_of_results;
336  }
337  else if (err_ok == scan_result) {
338  flat_file_cursor->current_location = loc;
339  (*cursor)->status = cs_cursor_initialized;
340  }
341  else {
342  /* Scan failure */
343  return scan_result;
344  }
345 
346  return err_ok;
347  break;
348  }
349 
350  case predicate_predicate: {
351  break;
352  }
353 
354  default: {
355  return err_invalid_predicate;
356  break;
357  }
358  }
359 
360  return err_ok;
361 }
362 
363 void
365  ion_dictionary_handler_t *handler
366 ) {
367  handler->insert = ffdict_insert;
369  handler->get = ffdict_get;
370  handler->update = ffdict_update;
371  handler->find = ffdict_find;
372  handler->remove = ffdict_delete;
377 }
378 
382  ion_key_t key,
383  ion_value_t value
384 ) {
385  return flat_file_insert((ion_flat_file_t *) dictionary->instance, key, value);
386 }
387 
391  ion_key_t key,
392  ion_value_t value
393 ) {
394  return flat_file_get((ion_flat_file_t *) dictionary->instance, key, value);
395 }
396 
397 ion_err_t
400  ion_key_type_t key_type,
401  ion_key_size_t key_size,
402  ion_value_size_t value_size,
403  ion_dictionary_size_t dictionary_size,
404  ion_dictionary_compare_t compare,
405  ion_dictionary_handler_t *handler,
407 ) {
408  dictionary->instance = malloc(sizeof(ion_flat_file_t));
409 
410  if (NULL == dictionary->instance) {
411  return err_out_of_memory;
412  }
413 
414  dictionary->instance->compare = compare;
416 
417  ion_err_t result = flat_file_initialize((ion_flat_file_t *) dictionary->instance, id, key_type, key_size, value_size, dictionary_size);
418 
419  if ((err_ok == result) && (NULL != handler)) {
420  dictionary->handler = handler;
421  }
422 
423  return result;
424 }
425 
429  ion_key_t key
430 ) {
431  return flat_file_delete((ion_flat_file_t *) dictionary->instance, key);
432 }
433 
434 ion_err_t
437 ) {
438  ion_err_t result = flat_file_destroy((ion_flat_file_t *) dictionary->instance);
439 
440  free(dictionary->instance);
441  dictionary->instance = NULL;
442  return result;
443 }
444 
445 ion_err_t
448 ) {
449  char filename[ION_MAX_FILENAME_LENGTH];
450 
451  dictionary_get_filename(id, "ffs", filename);
452 
453  if (0 != fremove(filename)) {
454  return err_file_delete_error;
455  }
456 
457  return err_ok;
458 }
459 
463  ion_key_t key,
464  ion_value_t value
465 ) {
466  return flat_file_update((ion_flat_file_t *) dictionary->instance, key, value);
467 }
ion_status_t ffdict_delete(ion_dictionary_t *dictionary, ion_key_t key)
Removes all instances of any record with key equal to key.
ion_status_t flat_file_get(ion_flat_file_t *flat_file, ion_key_t key, ion_value_t value)
Fetches the record stored with the given key.
Definition: flat_file.c:439
ion_status_t(* insert)(ion_dictionary_t *, ion_key_t, ion_value_t)
enum ION_KEY_TYPE ion_key_type_t
This is the available key types for ION_DB. All types will be based on system defines.
ion_record_info_t record
Container for the rows written in the flat file data file.
Metadata container that holds flat file specific information.
ion_predicate_t * predicate
ion_status_t ffdict_update(ion_dictionary_t *dictionary, ion_key_t key, ion_value_t value)
Updates all records stored at key to have value equal to value.
ion_err_t ffdict_destroy_dictionary(ion_dictionary_id_t id)
Cleans up all files created by the dictionary, and frees any allocated memory, for an already closed ...
ion_err_t flat_file_destroy(ion_flat_file_t *flat_file)
Destroys and cleans up any implementation specific memory or files.
Definition: flat_file.c:134
int ion_value_size_t
The size (length) of a dictionary value in bytes.
Definition: kv_system.h:256
ion_err_t flat_file_initialize(ion_flat_file_t *flat_file, ion_dictionary_id_t id, ion_key_type_t key_type, ion_key_size_t key_size, ion_value_size_t value_size, ion_dictionary_size_t dictionary_size)
Initializes the flat file implementation and creates all necessary files.
Definition: flat_file.c:40
ion_predicate_statement_t statement
ion_dictionary_handler_t * handler
ion_status_t flat_file_update(ion_flat_file_t *flat_file, ion_key_t key, ion_value_t value)
Updates all records stored with the given key to have value.
Definition: flat_file.c:560
ion_err_t ffdict_find(ion_dictionary_t *dictionary, ion_predicate_t *predicate, ion_dict_cursor_t **cursor)
Initializes a cursor query and returns an allocated cursor object.
ion_dictionary_parent_t * instance
Function declarations at the dictionary interface level for the flat file store.
ion_value_t value
Definition: kv_system.h:318
ion_status_t(* remove)(ion_dictionary_t *, ion_key_t)
ion_dictionary_t * dictionary
ion_err_t(* destroy_dictionary)(ion_dictionary_id_t id)
Struct used to maintain key and value.
Definition: kv_system.h:315
unsigned int ion_dictionary_id_t
A type used to identify dictionaries, specifically in the master table.
unsigned int ion_dictionary_size_t
The implementation specific size of the dictionary.
Definition: kv_system.h:264
ion_err_t ffdict_open_dictionary(ion_dictionary_handler_t *handler, ion_dictionary_t *dictionary, ion_dictionary_config_info_t *config, ion_dictionary_compare_t compare)
Re-instances a previously created flat file store instance and prepares it to be used again...
Struct containing details for opening a dictionary previously created.
ion_boolean_t flat_file_predicate_within_bounds(ion_flat_file_t *flat_file, ion_flat_file_row_t *row, va_list *args)
Predicate function to return any row that has a key such that lower_bound <= key <= upper_bound holds...
Definition: flat_file.c:291
ion_cursor_status_t status
#define key(k)
Definition: bpp_tree.c:75
ion_err_t ffdict_close_dictionary(ion_dictionary_t *dictionary)
Closes this flat file store and persists everything to disk to be brought back later using dictionary...
ion_status_t flat_file_delete(ion_flat_file_t *flat_file, ion_key_t key)
Deletes all records stored with the given key.
Definition: flat_file.c:495
#define fremove(x)
Definition: kv_system.h:56
ion_key_t key
Definition: kv_system.h:316
char(* ion_dictionary_compare_t)(ion_key_t, ion_key_t, ion_key_size_t)
Function pointer type for dictionary comparison methods.
char ion_err_t
The error type used to store error codes.
Definition: kv_system.h:226
ion_status_t ffdict_get(ion_dictionary_t *dictionary, ion_key_t key, ion_value_t value)
Performs a "get" operation on the dictionary to retrieve a single record.
ion_err_t flat_file_read_row(ion_flat_file_t *flat_file, ion_fpos_t location, ion_flat_file_row_t *row)
Reads the row specified by the given location into the buffer.
Definition: flat_file.c:350
int dictionary_get_filename(ion_dictionary_id_t id, char *ext, char *filename)
Given the ID, implementation specific extension, and a buffer to write to, writes back the formatted ...
Definition: dictionary.c:41
void * ion_key_t
A dictionary key.
Definition: kv_system.h:241
void(* destroy)(ion_predicate_t **)
ion_status_t(* update)(ion_dictionary_t *, ion_key_t, ion_value_t)
ion_equality_statement_t equality
void * ion_value_t
A dictionary value.
Definition: kv_system.h:246
ion_err_t flat_file_scan(ion_flat_file_t *flat_file, ion_fpos_t start_location, ion_fpos_t *location, ion_flat_file_row_t *row, ion_byte_t scan_direction, ion_flat_file_predicate_t predicate,...)
Performs a linear scan of the flat file writing the first location seen that satisfies the given pred...
Definition: flat_file.c:157
A dictionary contains information regarding an instance of the storage element and the associated han...
ion_predicate_type_t type
A supertype for dictionary cursor objects.
ion_err_t(* close_dictionary)(ion_dictionary_t *)
#define ION_MAX_FILENAME_LENGTH
Since the arduino conforms to 8.3 syntax, that&#39;s 8 + 3 = 11 + 1 (null terminator) characters...
Definition: kv_system.h:73
ion_err_t(* open_dictionary)(ion_dictionary_handler_t *, ion_dictionary_t *, ion_dictionary_config_info_t *, ion_dictionary_compare_t)
Implementation cursor type for the flat file store cursor.
ion_err_t(* create_dictionary)(ion_dictionary_id_t, ion_key_type_t, ion_key_size_t, ion_value_size_t, ion_dictionary_size_t, ion_dictionary_compare_t, ion_dictionary_handler_t *, ion_dictionary_t *)
ion_cursor_status_t ffdict_next(ion_dict_cursor_t *cursor, ion_record_t *record)
Fetches the next record to be returned from a cursor that has already been initialized.
void ffdict_init(ion_dictionary_handler_t *handler)
Given the handler instance, bind the appropriate flat file functions.
ion_err_t(* delete_dictionary)(ion_dictionary_t *)
ion_key_size_t key_size
Definition: kv_system.h:307
ion_err_t ffdict_delete_dictionary(ion_dictionary_t *dictionary)
Cleans up all files created by the dictionary, and frees any allocated memory.
void ffdict_destroy_cursor(ion_dict_cursor_t **cursor)
Destroys and frees the given cursor.
A supertype for cursor predicate objects.
ion_err_t flat_file_close(ion_flat_file_t *flat_file)
Closes and frees any memory associated with the flat file.
Definition: flat_file.c:624
ion_dictionary_type_t type
ion_err_t(* find)(ion_dictionary_t *, ion_predicate_t *, ion_dict_cursor_t **)
#define ION_FLAT_FILE_SCAN_FORWARDS
Signals to flat_file_scan to scan in a forward direction.
ion_status_t ffdict_insert(ion_dictionary_t *dictionary, ion_key_t key, ion_value_t value)
Given a record ( key, value ), insert it into the dictionary.
ion_err_t ffdict_create_dictionary(ion_dictionary_id_t id, ion_key_type_t key_type, ion_key_size_t key_size, ion_value_size_t value_size, ion_dictionary_size_t dictionary_size, ion_dictionary_compare_t compare, ion_dictionary_handler_t *handler, ion_dictionary_t *dictionary)
Creates an instance of a flat file backed dictionary.
ion_boolean_t flat_file_predicate_key_match(ion_flat_file_t *flat_file, ion_flat_file_row_t *row, va_list *args)
Predicate function to return any row that has an exact match to the given target key.
Definition: flat_file.c:280
long ion_fpos_t
A file position type.
Definition: kv_system.h:237
ion_dictionary_compare_t compare
ion_dictionary_size_t dictionary_size
int ion_key_size_t
The size (length) of a dictionary key in bytes.
Definition: kv_system.h:251
ion_status_t flat_file_insert(ion_flat_file_t *flat_file, ion_key_t key, ion_value_t value)
Inserts the given record into the flat file store.
Definition: flat_file.c:388
ion_boolean_t flat_file_predicate_not_empty(ion_flat_file_t *flat_file, ion_flat_file_row_t *row, va_list *args)
Predicate function to return any row that is not empty or deleted.
Definition: flat_file.c:268
ion_range_statement_t range
ion_dictionary_status_t status
ion_value_size_t value_size
Definition: kv_system.h:309
ion_status_t(* get)(ion_dictionary_t *, ion_key_t, ion_value_t)
A dictionary_handler is responsible for dealing with the specific interface for an underlying diction...
char ion_cursor_status_t
A type for the status of a cursor.
A status object that describes the result of a dictionary operation.
Definition: kv_system.h:290