1 /******************************************************************************
4 * Company XS Embedded GmbH
5 *****************************************************************************/
6 /******************************************************************************
7 * This Source Code Form is subject to the terms of the
8 * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
9 * with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 ******************************************************************************/
12 * @file persistence_client_library_data_access.c
13 * @ingroup Persistence client library
14 * @author Ingo Huerner
15 * @brief Implementation of persistence database access
16 * Library provides an API to access persistent data
20 #include "../include_protected/persistence_client_library_db_access.h"
21 #include "persistence_client_library_custom_loader.h"
22 #include "persistence_client_library_itzam_errors.h"
29 /// definition of a key-value pair stored in the database
30 typedef struct _KeyValuePair_s
32 char m_key[DbKeySize]; /// the key
33 char m_data[DbValueSize]; /// the data
34 unsigned int m_data_size; /// the size of the data
39 // definition of a cursor entry
40 typedef struct _CursorEntry_s
42 itzam_btree_cursor m_cursor;
48 // cursor array handle
49 CursorEntry_s gCursorArray[MaxPersHandle];
52 static int gHandleIdx = 1;
55 int gFreeCursorHandleArray[MaxPersHandle];
57 int gFreeCursorHandleIdxHead = 0;
59 // mutex to controll access to the cursor array
60 pthread_mutex_t gMtx = PTHREAD_MUTEX_INITIALIZER;
64 static itzam_btree gBtree[DbTableSize][PersistencePolicy_LastEntry];
65 static int gBtreeCreated[DbTableSize][PersistencePolicy_LastEntry] = { {0} };
68 itzam_btree* pers_db_open(PersistenceInfo_s* info, const char* dbPath)
71 itzam_btree* btree = NULL;
73 // create array index: index is a combination of resource config table type and group
74 arrayIdx = info->configKey.storage + info->context.ldbid ;
76 if(arrayIdx <= DbTableSize)
78 if(gBtreeCreated[arrayIdx][info->configKey.policy] == 0)
80 itzam_state state = ITZAM_FAILED;
81 state = itzam_btree_open(&gBtree[arrayIdx][info->configKey.policy], dbPath,
82 itzam_comparator_string, error_handler, 0/*recover*/, 0/*read_only*/);
83 if (state != ITZAM_OKAY)
85 fprintf(stderr, "pers_db_open ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
87 gBtreeCreated[arrayIdx][info->configKey.policy] = 1;
90 btree = &gBtree[arrayIdx][info->configKey.policy];
94 printf("btree_get ==> invalid storage type\n");
101 void pers_db_close(PersistenceInfo_s* info)
103 int arrayIdx = info->configKey.storage + info->context.ldbid;
105 if(info->configKey.storage <= PersistenceStorage_shared )
107 itzam_state state = ITZAM_FAILED;
108 state = itzam_btree_close(&gBtree[arrayIdx][info->configKey.policy]);
109 if (state != ITZAM_OKAY)
111 fprintf(stderr, "pers_db_close ==> Close Itzam problem: %s\n", STATE_MESSAGES[state]);
113 gBtreeCreated[arrayIdx][info->configKey.policy] = 0;
117 printf("pers_db_close ==> invalid storage type\n");
123 void pers_db_close_all()
127 for(i=0; i<DbTableSize; i++)
129 // close write cached database
130 if(gBtreeCreated[i][PersistencePolicy_wc] == 1)
132 itzam_state state = ITZAM_FAILED;
133 state = itzam_btree_close(&gBtree[i][PersistencePolicy_wc]);
134 if (state != ITZAM_OKAY)
136 fprintf(stderr, "pers_db_close_all ==> Close WC: Itzam problem: %s\n", STATE_MESSAGES[state]);
138 gBtreeCreated[i][PersistencePolicy_wc] = 0;
141 // close write through database
142 if(gBtreeCreated[i][PersistencePolicy_wt] == 1)
144 itzam_state state = ITZAM_FAILED;
145 state = itzam_btree_close(&gBtree[i][PersistencePolicy_wt]);
146 if (state != ITZAM_OKAY)
148 fprintf(stderr, "pers_db_close_all ==> Close WT: Itzam problem: %s\n", STATE_MESSAGES[state]);
150 gBtreeCreated[i][PersistencePolicy_wt] = 0;
157 int pers_db_read_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
161 if( PersistenceStorage_shared == info->configKey.storage
162 || PersistenceStorage_local == info->configKey.storage)
164 itzam_btree* btree = NULL;
165 itzam_state state = ITZAM_FAILED;
166 KeyValuePair_s search;
168 btree = pers_db_open(info, dbPath);
171 if(itzam_true == itzam_btree_find(btree, key, &search))
173 read_size = search.m_data_size;
174 if(read_size > buffer_size)
176 read_size = buffer_size; // truncate data size to buffer size
178 memcpy(buffer, search.m_data, read_size);
182 read_size = EPERS_NOKEY;
186 // workaround till lifecycle is working correctly
192 read_size = EPERS_NOPRCTABLE;
193 fprintf(stderr, "\npersistence_get_data ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
196 else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library
198 int idx = custom_client_name_to_id(dbPath, 1);
199 char workaroundPath[128]; // workaround, because /sys/ can not be accessed on host!!!!
200 snprintf(workaroundPath, 128, "%s%s", "/Data", dbPath );
202 if( (idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_get_data != NULL) )
204 gPersCustomFuncs[idx].custom_plugin_get_data(key, (char*)buffer, buffer_size);
208 read_size = EPERS_NOPLUGINFUNCT;
216 int pers_db_write_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
220 if( PersistenceStorage_shared == info->configKey.storage
221 || PersistenceStorage_local == info->configKey.storage)
223 write_size = buffer_size;
224 itzam_btree* btree = NULL;
225 itzam_state state = ITZAM_FAILED;
226 KeyValuePair_s insert;
228 btree = pers_db_open(info, dbPath);
232 keySize = (int)strlen((const char*)key);
233 if(keySize < DbKeySize)
236 dataSize = (int)strlen( (const char*)buffer);
237 if(dataSize < DbValueSize)
240 memset(insert.m_key, 0, DbKeySize);
241 memcpy(insert.m_key, key, keySize);
242 if(itzam_true == itzam_btree_find(btree, key, &insert))
244 // key already available, so delete "old" key
245 state = itzam_btree_remove(btree, (const void *)&insert);
249 memset(insert.m_data, 0, DbValueSize);
250 memcpy(insert.m_data, buffer, dataSize);
253 insert.m_data_size = buffer_size;
255 state = itzam_btree_insert(btree,(const void *)&insert);
256 if (state != ITZAM_OKAY)
258 fprintf(stderr, "\npersistence_set_data ==> Insert Itzam problem: %s\n", STATE_MESSAGES[state]);
259 write_size = EPERS_DB_ERROR_INTERNAL;
264 fprintf(stderr, "\npersistence_set_data ==> set_value_to_table_itzam => data to long » size %d | maxSize: %d\n", dataSize, DbKeySize);
265 write_size = EPERS_DB_VALUE_SIZE;
269 // workaround till lifecycle is working correctly
275 fprintf(stderr, "\nset_value_to_table_itzam => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize);
276 write_size = EPERS_DB_KEY_SIZE;
281 write_size = EPERS_NOPRCTABLE;
282 fprintf(stderr, "\npersistence_set_data ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
285 else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library
287 int idx = custom_client_name_to_id(dbPath, 1);
288 if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) )
290 gPersCustomFuncs[idx].custom_plugin_set_data(key, (char*)buffer, buffer_size);
294 write_size = EPERS_NOPLUGINFUNCT;
302 int pers_db_get_key_size(char* dbPath, char* key, PersistenceInfo_s* info)
306 if( PersistenceStorage_shared == info->configKey.storage
307 || PersistenceStorage_local == info->configKey.storage)
310 itzam_btree* btree = NULL;
311 itzam_state state = ITZAM_FAILED;
312 KeyValuePair_s search;
314 btree = pers_db_open(info, dbPath);
317 keySize = (int)strlen((const char*)key);
318 if(keySize < DbKeySize)
320 memset(search.m_key,0, DbKeySize);
321 memcpy(search.m_key, key, keySize);
322 if(itzam_true == itzam_btree_find(btree, key, &search))
324 read_size = strlen(search.m_data);
328 read_size = EPERS_NOKEY;
333 fprintf(stderr, "persistence_get_data_size => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize);
334 read_size = EPERS_DB_KEY_SIZE;
337 // workaround till lifecycle is working correctly
343 read_size = EPERS_NOPRCTABLE;
344 fprintf(stderr, "\npersistence_get_data_size ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
347 else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library
349 int idx = custom_client_name_to_id(dbPath, 1);
350 if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) )
352 gPersCustomFuncs[idx].custom_plugin_get_size(key);
356 read_size = EPERS_NOPLUGINFUNCT;
364 int pers_db_delete_key(char* dbPath, char* dbKey, PersistenceInfo_s* info)
367 if(PersistenceStorage_custom != info->configKey.storage)
369 itzam_btree* btree = NULL;
370 KeyValuePair_s delete;
372 //printf("delete_key_from_table_itzam => Path: \"%s\" | key: \"%s\" \n", dbPath, key);
373 btree = pers_db_open(info, dbPath);
377 keySize = (int)strlen((const char*)dbKey);
378 if(keySize < DbKeySize)
382 memset(delete.m_key,0, DbKeySize);
383 memcpy(delete.m_key, dbKey, keySize);
384 state = itzam_btree_remove(btree, (const void *)&delete);
385 if (state != ITZAM_OKAY)
387 fprintf(stderr, "persistence_delete_data ==> Remove Itzam problem: %s\n", STATE_MESSAGES[state]);
388 ret = EPERS_DB_ERROR_INTERNAL;
393 fprintf(stderr, "persistence_delete_data => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize);
394 ret = EPERS_DB_KEY_SIZE;
397 // workaround till lifecycle is working correctly
403 fprintf(stderr, "persistence_delete_data => no prct table\n");
404 ret = EPERS_NOPRCTABLE;
407 else // custom storage implementation via custom library
409 int idx = custom_client_name_to_id(dbPath, 1);
410 if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) )
412 gPersCustomFuncs[idx].custom_plugin_delete_data(dbKey);
416 ret = EPERS_NOPLUGINFUNCT;
423 int persistence_reg_notify_on_change(char* dbPath, char* key)
432 //---------------------------------------------------------------------------------------------------------
433 // C U R S O R F U N C T I O N S
434 //---------------------------------------------------------------------------------------------------------
436 int get_cursor_handle()
440 if(pthread_mutex_lock(&gMtx) == 0)
442 if(gFreeCursorHandleIdxHead > 0) // check if we have a free spot in the array before the current max
444 handle = gFreeCursorHandleArray[--gFreeCursorHandleIdxHead];
448 if(gHandleIdx < MaxPersHandle-1)
450 handle = gHandleIdx++; // no free spot before current max, increment handle index
455 printf("get_persistence_handle_idx => Reached maximum of open handles: %d \n", MaxPersHandle);
458 pthread_mutex_unlock(&gMtx);
464 void close_cursor_handle(int handlerDB)
466 if(pthread_mutex_lock(&gMtx) == 0)
468 if(gFreeCursorHandleIdxHead < MaxPersHandle)
470 gFreeCursorHandleArray[gFreeCursorHandleIdxHead++] = handlerDB;
472 pthread_mutex_unlock(&gMtx);
478 int pers_db_cursor_create(char* dbPath)
481 itzam_state state = ITZAM_FAILED;
483 handle = get_cursor_handle();
485 if(handle < MaxPersHandle && handle >= 0)
488 state = itzam_btree_open(&gCursorArray[handle].m_btree, dbPath, itzam_comparator_string, error_handler, 0/*recover*/, 0/*read_only*/);
489 if (state != ITZAM_OKAY)
491 fprintf(stderr, "pers_db_open ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
497 state = itzam_btree_cursor_create(&gCursorArray[handle].m_cursor, &gCursorArray[handle].m_btree);
498 if(state == ITZAM_OKAY)
500 gCursorArray[handle].m_empty = 0;
504 gCursorArray[handle].m_empty = 1;
513 int pers_db_cursor_next(unsigned int handlerDB)
516 if(handlerDB < MaxPersHandle && handlerDB >= 0)
518 if(gCursorArray[handlerDB].m_empty != 1)
521 success = itzam_btree_cursor_next(&gCursorArray[handlerDB].m_cursor);
523 if(success == itzam_true)
529 rval = EPERS_LAST_ENTRY_IN_DB;
534 printf("persistence_db_cursor_get_key ==> invalid handle: %u \n", handlerDB);
539 printf("persistence_db_cursor_get_key ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
546 int pers_db_cursor_get_key(unsigned int handlerDB, char * bufKeyName_out, int bufSize)
549 KeyValuePair_s search;
551 if(handlerDB < MaxPersHandle)
553 if(gCursorArray[handlerDB].m_empty != 1)
556 itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
557 length = strlen(search.m_key);
560 memcpy(bufKeyName_out, search.m_key, length);
565 printf("persistence_db_cursor_get_key ==> buffer to small » keySize: %d | bufSize: %d \n", length, bufSize);
570 printf("persistence_db_cursor_get_key ==> invalid handle: %u \n", handlerDB);
575 printf("persistence_db_cursor_get_key ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
582 int pers_db_cursor_get_key_data(unsigned int handlerDB, char * bufData_out, int bufSize)
585 KeyValuePair_s search;
587 if(handlerDB < MaxPersHandle)
589 if(gCursorArray[handlerDB].m_empty != 1)
592 itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
594 length = strlen(search.m_data);
597 memcpy(bufData_out, search.m_data, length);
602 printf("persistence_db_cursor_get_data ==> buffer to small » keySize: %d | bufSize: %d \n", length, bufSize);
607 printf("persistence_db_cursor_get_data ==> invalid handle: %u \n", handlerDB);
612 printf("persistence_db_cursor_get_data ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
619 int pers_db_cursor_get_data_size(unsigned int handlerDB)
622 KeyValuePair_s search;
624 if(handlerDB < MaxPersHandle)
626 if(gCursorArray[handlerDB].m_empty != 1)
628 itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
629 size = strlen(search.m_data);
633 printf("persistence_db_cursor_get_data ==> invalid handle: %u \n", handlerDB);
638 printf("persistence_db_cursor_get_data ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
645 int pers_db_cursor_destroy(unsigned int handlerDB)
648 if(handlerDB < MaxPersHandle)
650 itzam_btree_cursor_free(&gCursorArray[handlerDB].m_cursor);
651 gCursorArray[handlerDB].m_empty = 1;
653 itzam_btree_close(&gCursorArray[handlerDB].m_btree);
654 close_cursor_handle(handlerDB);
664 //-----------------------------------------------------------------------------
665 // code to print database content (for debugging)
666 //-----------------------------------------------------------------------------
670 itzam_btree_cursor cursor;
671 state = itzam_btree_cursor_create(&cursor, &btree);
672 if(state == ITZAM_OKAY)
674 printf("==> Database content ==> db size: %d\n", (int)itzam_btree_count(&btree));
677 // get the key pointed to by the cursor
678 state = itzam_btree_cursor_read(&cursor,(void *)&rec);
679 if (state == ITZAM_OKAY)
681 printf(" Key: %s \n ==> data: %s\n", rec.m_key, rec.m_data);
684 fprintf(stderr, "\nItzam problem: %s\n", STATE_MESSAGES[state]);
686 while (itzam_btree_cursor_next(&cursor));
688 state = itzam_btree_cursor_free(&cursor);
691 //-----------------------------------------------------------------------------