SIONlib  1.7.1
Scalable I/O library for parallel access to task-local files
sion_keyvalue_table.c
Go to the documentation of this file.
1 /****************************************************************************
2 ** SIONLIB http://www.fz-juelich.de/jsc/sionlib **
3 *****************************************************************************
4 ** Copyright (c) 2008-2016 **
5 ** Forschungszentrum Juelich, Juelich Supercomputing Centre **
6 ** **
7 ** See the file COPYRIGHT in the package base directory for details **
8 ****************************************************************************/
9 
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <time.h>
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <assert.h>
24 
25 
26 #include "sion.h"
27 #include "sion_debug.h"
28 #include "sion_error_handler.h"
29 #include "sion_internal.h"
30 #include "sion_printts.h"
31 #include "sion_keyvalue_table.h"
32 
33 typedef enum {
34  KEYVALUE_TABLE_ENTRY_STATE_USED,
35  KEYVALUE_TABLE_ENTRY_STATE_FREE,
36  KEYVALUE_TABLE_ENTRY_STATE_UNKNOWN
37 } sion_keyvalue_table_entry_state_t;
38 
40 
42  int used;
43  int size;
44  int num_added_entries;
45 
46  /* for iterator by index */
47  int iterator_lastreadindex;
48  _sion_keyvalue_table_entry* iterator_lastreadentry;
49 
50  /* for iterator by store orde */
51  _sion_keyvalue_table_entry* iterator_next;
52  _sion_keyvalue_table_entry* iterator_head;
53  _sion_keyvalue_table_entry* iterator_tail;
54 
56 };
57 
59  sion_keyvalue_table_entry_state_t state;
60  sion_table_key_t key;
61  _sion_keyvalue_table_entry *iterator_next;
63  void *data;
64 };
65 
66 #define HASH_FCT_SIMPLE_not
67 #define HASH_FCT_SPLIT
68 
69 #define DFUNCTION "_sion_keyvalue_table_hash_fct"
70 unsigned int _sion_keyvalue_table_hash_fct(sion_table_key_t key, int tab_size) {
71  unsigned int index=0;
72 
73 #if defined(HASH_FCT_SIMPLE)
74  /* simple modulo */
75  {
76  index = (unsigned int) key % tab_size;
77  }
78 #elif defined(HASH_FCT_SPLIT)
79  {
80  /* split modulo */
81  uint32_t upper =( uint32_t) (key >> 32);
82  uint32_t lower =( uint32_t) (key & 0xffffffff);
83  DPRINTFP((2, DFUNCTION, -1, "key %ld -> %d %d \n",(long) key, (int) upper, (int) lower));
84  index = (unsigned int) (
85  (unsigned int) upper % tab_size
86  + (unsigned int) lower % tab_size
87  ) % tab_size;
88  }
89 #endif
90 
91  return(index);
92 }
93 #undef DFUNCTION
94 
95 #define DFUNCTION "_sion_keyvalue_table_init"
96 _sion_keyvalue_table* _sion_keyvalue_table_init(int size) {
97  _sion_keyvalue_table* table=NULL;
98  _sion_keyvalue_table_entry* entries=NULL;
99  int i;
100 
101  DPRINTFP((2, DFUNCTION, -1, "enter init size=%d\n",size));
102 
103  table = malloc(sizeof(_sion_keyvalue_table));
104  if (table == NULL) {
105  _sion_errorprint(0,_SION_ERROR_RETURN,"cannot allocate internal keyvalue table of size %lu , aborting ...\n", (unsigned long) sizeof(_sion_keyvalue_table));
106  return(NULL);
107  }
108 
109  entries = malloc(size * sizeof(_sion_keyvalue_table_entry));
110  if (entries == NULL) {
111  _sion_errorprint(0,_SION_ERROR_RETURN,"cannot allocate internal keyvalue table entries of size %lu , aborting ...\n", (unsigned long) size);
112  free(table);
113  return(NULL);
114  }
115  table->entries=entries;
116 
117  table->size=size;
118  table->used=0;
119  table->num_added_entries=0;
120  table->iterator_lastreadindex=-1;
121  table->iterator_lastreadentry=NULL;
122  table->iterator_next=NULL;
123  table->iterator_head=NULL;
124  table->iterator_tail=NULL;
125  for(i=0;i<table->size;i++) {
126  table->entries[i].state=KEYVALUE_TABLE_ENTRY_STATE_FREE;
127  table->entries[i].key=0;
128  table->entries[i].iterator_next=NULL;
129  table->entries[i].next=NULL;
130  table->entries[i].data=NULL;
131  }
132 
133 
134  DPRINTFP((2, DFUNCTION, -1, "leave\n"));
135  return (table);
136 }
137 #undef DFUNCTION
138 
139 #define DFUNCTION "_sion_keyvalue_table_destroy"
140 int _sion_keyvalue_table_destroy(_sion_keyvalue_table** table) {
141  size_t rc=SION_SUCCESS;
142  int i;
143  _sion_keyvalue_table_entry *entry,*next_entry;
144 
145  DPRINTFP((2, DFUNCTION, -1, "enter\n"));
146  if((*table)->entries) {
147 
148 
149  for(i=0;i<(*table)->size;i++) {
150  /* free entry data */
151  if(((*table)->entries[i].state!=KEYVALUE_TABLE_ENTRY_STATE_FREE) && ((*table)->entries[i].data!=NULL)) {
152  _SION_SAFE_FREE((*table)->entries[i].data, NULL);
153  }
154  /* free linked list */
155  entry=(*table)->entries[i].next;
156  while (entry != NULL) {
157  if((entry->state!=KEYVALUE_TABLE_ENTRY_STATE_FREE) && (entry->data!=NULL)) {
158  _SION_SAFE_FREE(entry->data, NULL);
159  }
160  next_entry=entry->next;
161  _SION_SAFE_FREE(entry, NULL);
162  entry = next_entry;
163  }
164  }
165 
166  free((*table)->entries);
167  (*table)->entries=NULL;
168  }
169  free(*table);
170  *table = NULL;
171 
172 
173  DPRINTFP((2, DFUNCTION, -1, "leave rc=%d\n",rc));
174  return (rc);
175 }
176 #undef DFUNCTION
177 
178 #define DFUNCTION "_sion_keyvalue_table_store"
179 int _sion_keyvalue_table_store(_sion_keyvalue_table* table, sion_table_key_t key, void *data) {
180  size_t rc=SION_SUCCESS;
181  unsigned int index;
182  _sion_keyvalue_table_entry *new_entry;
183 
184  DPRINTFP((2, DFUNCTION, -1, "enter\n"));
185 
186  index = _sion_keyvalue_table_hash_fct(key,table->size);
187  DPRINTFP((2, DFUNCTION, -1, "store entry with key %ld index=%d\n", (long) key, index));
188 
189  new_entry = &table->entries[index];
190  if (new_entry->state != KEYVALUE_TABLE_ENTRY_STATE_FREE) {
191  while (new_entry->next != NULL) {
192  new_entry = new_entry->next;
193  }
194  new_entry->next = (_sion_keyvalue_table_entry*) malloc(sizeof(_sion_keyvalue_table_entry));
195  if (new_entry->next == NULL) {
196  return(_sion_errorprint(SION_NOT_SUCCESS,_SION_ERROR_RETURN,"cannot allocate internal keyvalue table entry, aborting ...\n"));
197  }
198  DPRINTFP((2, DFUNCTION, -1, "add new entry to next list\n"));
199  table->num_added_entries++;
200  new_entry = new_entry->next;
201  }
202  table->used++;
203 
204  new_entry->state= KEYVALUE_TABLE_ENTRY_STATE_USED;
205  new_entry->key = key;
206  new_entry->data = data;
207  new_entry->next = NULL;
208  new_entry->iterator_next = NULL;
209 
210  if ( (table->iterator_head==NULL) && (table->iterator_tail==NULL) ) {
211  /* first entry */
212  table->iterator_next=table->iterator_head=table->iterator_tail=new_entry;
213  } else {
214  table->iterator_tail->iterator_next=new_entry;
215  table->iterator_tail=table->iterator_tail->iterator_next; /* advance tail */
216  }
217 
218 
219  DPRINTFP((2, DFUNCTION, -1, "new entry successfully added (key %ld index=%d)\n", (long) key, index));
220  DPRINTFP((2, DFUNCTION, -1, "TABLE[slots %d of %d, +%d, total %d] \n", table->used - table->num_added_entries,table->size,table->num_added_entries,table->used));
221 
222  DPRINTFP((2, DFUNCTION, -1, "leave rc=%d\n",rc));
223  return (rc);
224 }
225 #undef DFUNCTION
226 
227 #define DFUNCTION "_sion_keyvalue_table_lookup"
228 void * _sion_keyvalue_table_lookup(_sion_keyvalue_table* table, sion_table_key_t key) {
229  unsigned int index;
231 
232  DPRINTFP((2, DFUNCTION, -1, "enter\n"));
233 
234  index = _sion_keyvalue_table_hash_fct(key,table->size);
235  DPRINTFP((2, DFUNCTION, -1, "lookup entry with key %ld index=%d\n", (long) key, index));
236 
237  entry = &(table->entries[index]);
238  while (entry != NULL) {
239 
240  DPRINTFP((2, DFUNCTION, -1, "search: state=%ld\n",(long) entry->state ));
241 
242  if (entry->state == KEYVALUE_TABLE_ENTRY_STATE_USED) {
243  if(entry->key == key) {
244  DPRINTFP((2, DFUNCTION, -1, "key found %ld in key list\n",(long) entry->key ));
245  return(entry->data);
246  } else {
247  DPRINTFP((2, DFUNCTION, -1, "skip this key another key found %ld in list\n",(long) entry->key ));
248  entry = entry->next;
249  }
250  } else {
251  /* slot is empty */
252  return(NULL);
253  }
254  }
255  DPRINTFP((2, DFUNCTION, -1, "leave:entry not found\n"));
256  return(NULL);
257 
258 }
259 #undef DFUNCTION
260 
261 #define DFUNCTION "_sion_keyvalue_table_iterator_reset"
262 int _sion_keyvalue_table_iterator_reset(_sion_keyvalue_table* table) {
263 
264  int rc=SION_SUCCESS;
265 
266  DPRINTFP((2, DFUNCTION, -1, "enter\n"));
267  table->iterator_lastreadindex=-1;
268  table->iterator_lastreadentry=NULL;
269  table->iterator_next=table->iterator_head;
270  DPRINTFP((2, DFUNCTION, -1, "leave\n"));
271 
272  return(rc);
273 }
274 #undef DFUNCTION
275 
276 #define DFUNCTION "_sion_keyvalue_table_iterator_next_in_store_order"
277 int _sion_keyvalue_table_iterator_next_in_store_order(_sion_keyvalue_table* table, sion_table_key_t *key, void **data) {
279 
280  DPRINTFP((2, DFUNCTION, -1, "enter\n"));
281  if(table->used==0) {
282  return(SION_NOT_SUCCESS);
283  }
284  entry=table->iterator_next;
285 
286  if(entry != NULL) {
287  *key=entry->key;
288  *data=entry->data;
289  DPRINTFP((2, DFUNCTION, -1, "found entry with key %ld\n",(long) *key));
290  table->iterator_next=entry->iterator_next; /* move forward in iterator list */
291  return(SION_SUCCESS);
292  } else {
293  return(SION_NOT_SUCCESS);
294  }
295 }
296 #undef DFUNCTION
297 
298 #define DFUNCTION "_sion_keyvalue_table_iterator_next"
299 int _sion_keyvalue_table_iterator_next(_sion_keyvalue_table* table, sion_table_key_t *key, void **data) {
300 
301  DPRINTFP((2, DFUNCTION, -1, "enter\n"));
302  if(table->used==0) {
303  return(SION_NOT_SUCCESS);
304  }
305  if(table->iterator_lastreadindex==-1) {
306  /* search first entry which must be there (used>0) */
307  DPRINTFP((2, DFUNCTION, -1, "start first\n"));
308  table->iterator_lastreadindex++;
309  while(table->iterator_lastreadindex < table->size) {
310  if (table->entries[table->iterator_lastreadindex].state == KEYVALUE_TABLE_ENTRY_STATE_USED) {
311  table->iterator_lastreadentry = &table->entries[table->iterator_lastreadindex];
312  break;
313  }
314  table->iterator_lastreadindex++;
315  }
316  DPRINTFP((2, DFUNCTION, -1, "start first, found entry at index %d\n",table->iterator_lastreadindex));
317 
318  } else {
319 
320  /* another entry in list? */
321  if(table->iterator_lastreadentry->next != NULL) {
322  table->iterator_lastreadentry=table->iterator_lastreadentry->next;
323  DPRINTFP((2, DFUNCTION, -1, "found another entry in list at index %d\n",table->iterator_lastreadindex));
324  } else {
325  /* search forward */
326  table->iterator_lastreadindex++;
327  while(table->iterator_lastreadindex < table->size) {
328  if (table->entries[table->iterator_lastreadindex].state == KEYVALUE_TABLE_ENTRY_STATE_USED) {
329  table->iterator_lastreadentry = &table->entries[table->iterator_lastreadindex];
330  DPRINTFP((2, DFUNCTION, -1, "found entry at another index %d\n",table->iterator_lastreadindex));
331  break;
332  }
333  table->iterator_lastreadindex++;
334  }
335  }
336  }
337  if(table->iterator_lastreadindex < table->size) {
338  *key=table->iterator_lastreadentry->key;
339  *data=table->iterator_lastreadentry->data;
340  DPRINTFP((2, DFUNCTION, -1, "leave: entry found\n"));
341  return(SION_SUCCESS);
342  } else {
343  DPRINTFP((2, DFUNCTION, -1, "leave: next entry not found\n"));
344  return(SION_NOT_SUCCESS);
345  }
346 }
347 #undef DFUNCTION
348 
349 #define DFUNCTION "_sion_keyvalue_table_get_size"
350 int _sion_keyvalue_table_get_size(_sion_keyvalue_table* table) {
351  size_t help_bytes, bytes=0;
352  int i;
354 
355  DPRINTFP((2, DFUNCTION, -1, "enter\n"));
356 
357  help_bytes= sizeof(_sion_keyvalue_table);
358  DPRINTFP((2, DFUNCTION, -1, " sizeof key_table= %5d\n", help_bytes));
359  bytes+=help_bytes;
360 
361  if(table->entries) {
362 
363  help_bytes= table->size*sizeof(_sion_keyvalue_table_entry);
364  DPRINTFP((2, DFUNCTION, -1, " sizeof key_entries= %5d\n", help_bytes));
365  bytes+=help_bytes;
366 
367  help_bytes=0;
368  for(i=0;i<table->size;i++) {
369  entry=table->entries[i].next;
370  while (entry != NULL) {
371  help_bytes+=sizeof(_sion_keyvalue_table_entry);
372  entry = entry->next;
373  }
374  }
375 
376  DPRINTFP((2, DFUNCTION, -1, " sizeof key_addentries= %5d\n", help_bytes));
377  bytes+=help_bytes;
378 
379  }
380 
381  DPRINTFP((2, DFUNCTION, -1, "leave bytes=%d\n",bytes));
382  return (bytes);
383 }
384 #undef DFUNCTION
Sion Time Stamp Header.