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 "../include_protected/persistence_client_library_rc_table.h"
22 #include "persistence_client_library_custom_loader.h"
23 #include "persistence_client_library_itzam_errors.h"
30 /// definition of a key-value pair stored in the database
31 typedef struct _KeyValuePair_s
33 char m_key[DbKeySize]; /// the key
34 char m_data[DbValueSize]; /// the data
35 unsigned int m_data_size; /// the size of the data
40 // definition of a cursor entry
41 typedef struct _CursorEntry_s
43 itzam_btree_cursor m_cursor;
49 // cursor array handle
50 CursorEntry_s gCursorArray[MaxPersHandle];
53 static int gHandleIdx = 1;
56 int gFreeCursorHandleArray[MaxPersHandle];
58 int gFreeCursorHandleIdxHead = 0;
60 // mutex to controll access to the cursor array
61 pthread_mutex_t gMtx = PTHREAD_MUTEX_INITIALIZER;
65 static itzam_btree gBtree[DbTableSize][PersistencePolicy_LastEntry];
66 static int gBtreeCreated[DbTableSize][PersistencePolicy_LastEntry] = { {0} };
69 itzam_btree* pers_db_open(PersistenceInfo_s* info, const char* dbPath)
72 itzam_btree* btree = NULL;
74 // create array index: index is a combination of resource config table type and group
75 arrayIdx = info->configKey.storage + info->context.ldbid ;
77 //if(arrayIdx <= DbTableSize)
78 if(arrayIdx < DbTableSize)
80 if(gBtreeCreated[arrayIdx][info->configKey.policy] == 0)
82 itzam_state state = ITZAM_FAILED;
83 state = itzam_btree_open(&gBtree[arrayIdx][info->configKey.policy], dbPath,
84 itzam_comparator_string, error_handler, 0/*recover*/, 0/*read_only*/);
85 if (state != ITZAM_OKAY)
87 fprintf(stderr, "pers_db_open ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
89 gBtreeCreated[arrayIdx][info->configKey.policy] = 1;
92 btree = &gBtree[arrayIdx][info->configKey.policy];
96 printf("btree_get ==> invalid storage type\n");
103 void pers_db_close(PersistenceInfo_s* info)
105 int arrayIdx = info->configKey.storage + info->context.ldbid;
107 if(info->configKey.storage <= PersistenceStorage_shared )
109 itzam_state state = ITZAM_FAILED;
110 state = itzam_btree_close(&gBtree[arrayIdx][info->configKey.policy]);
111 if (state != ITZAM_OKAY)
113 fprintf(stderr, "pers_db_close ==> Close Itzam problem: %s\n", STATE_MESSAGES[state]);
115 gBtreeCreated[arrayIdx][info->configKey.policy] = 0;
119 printf("pers_db_close ==> invalid storage type\n");
125 void pers_db_close_all()
129 for(i=0; i<DbTableSize; i++)
131 // close write cached database
132 if(gBtreeCreated[i][PersistencePolicy_wc] == 1)
134 itzam_state state = ITZAM_FAILED;
135 state = itzam_btree_close(&gBtree[i][PersistencePolicy_wc]);
136 if (state != ITZAM_OKAY)
138 fprintf(stderr, "pers_db_close_all ==> Close WC: Itzam problem: %s\n", STATE_MESSAGES[state]);
140 gBtreeCreated[i][PersistencePolicy_wc] = 0;
143 // close write through database
144 if(gBtreeCreated[i][PersistencePolicy_wt] == 1)
146 itzam_state state = ITZAM_FAILED;
147 state = itzam_btree_close(&gBtree[i][PersistencePolicy_wt]);
148 if (state != ITZAM_OKAY)
150 fprintf(stderr, "pers_db_close_all ==> Close WT: Itzam problem: %s\n", STATE_MESSAGES[state]);
152 gBtreeCreated[i][PersistencePolicy_wt] = 0;
159 int pers_db_read_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
163 if( PersistenceStorage_shared == info->configKey.storage
164 || PersistenceStorage_local == info->configKey.storage)
166 itzam_btree* btree = NULL;
167 itzam_state state = ITZAM_FAILED;
168 KeyValuePair_s search;
170 btree = pers_db_open(info, dbPath);
173 if(itzam_true == itzam_btree_find(btree, key, &search))
175 read_size = search.m_data_size;
176 if(read_size > buffer_size)
178 read_size = buffer_size; // truncate data size to buffer size
180 memcpy(buffer, search.m_data, read_size);
184 read_size = EPERS_NOKEY;
188 // workaround till lifecycle is working correctly
194 read_size = EPERS_NOPRCTABLE;
195 fprintf(stderr, "\npersistence_get_data ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
198 else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library
200 int idx = custom_client_name_to_id(dbPath, 1);
201 char workaroundPath[128]; // workaround, because /sys/ can not be accessed on host!!!!
202 snprintf(workaroundPath, 128, "%s%s", "/Data", dbPath );
204 if( (idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_get_data != NULL) )
206 gPersCustomFuncs[idx].custom_plugin_get_data(key, (char*)buffer, buffer_size);
210 read_size = EPERS_NOPLUGINFUNCT;
218 int pers_db_write_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
222 if( PersistenceStorage_shared == info->configKey.storage
223 || PersistenceStorage_local == info->configKey.storage)
225 write_size = buffer_size;
226 itzam_btree* btree = NULL;
227 itzam_state state = ITZAM_FAILED;
228 KeyValuePair_s insert;
230 btree = pers_db_open(info, dbPath);
234 keySize = (int)strlen((const char*)key);
235 if(keySize < DbKeySize)
238 dataSize = (int)strlen( (const char*)buffer);
239 if(dataSize < DbValueSize)
242 memset(insert.m_key, 0, DbKeySize);
243 memcpy(insert.m_key, key, keySize);
244 if(itzam_true == itzam_btree_find(btree, key, &insert))
246 // key already available, so delete "old" key
247 state = itzam_btree_remove(btree, (const void *)&insert);
251 memset(insert.m_data, 0, DbValueSize);
252 memcpy(insert.m_data, buffer, dataSize);
255 insert.m_data_size = buffer_size;
257 state = itzam_btree_insert(btree,(const void *)&insert);
258 if (state != ITZAM_OKAY)
260 fprintf(stderr, "\npersistence_set_data ==> Insert Itzam problem: %s\n", STATE_MESSAGES[state]);
261 write_size = EPERS_DB_ERROR_INTERNAL;
266 fprintf(stderr, "\npersistence_set_data ==> set_value_to_table_itzam => data to long » size %d | maxSize: %d\n", dataSize, DbKeySize);
267 write_size = EPERS_DB_VALUE_SIZE;
271 // workaround till lifecycle is working correctly
277 fprintf(stderr, "\nset_value_to_table_itzam => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize);
278 write_size = EPERS_DB_KEY_SIZE;
283 write_size = EPERS_NOPRCTABLE;
284 fprintf(stderr, "\npersistence_set_data ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
287 else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library
289 int idx = custom_client_name_to_id(dbPath, 1);
290 if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) )
292 gPersCustomFuncs[idx].custom_plugin_set_data(key, (char*)buffer, buffer_size);
296 write_size = EPERS_NOPLUGINFUNCT;
304 int pers_db_get_key_size(char* dbPath, char* key, PersistenceInfo_s* info)
308 if( PersistenceStorage_shared == info->configKey.storage
309 || PersistenceStorage_local == info->configKey.storage)
312 itzam_btree* btree = NULL;
313 itzam_state state = ITZAM_FAILED;
314 KeyValuePair_s search;
316 btree = pers_db_open(info, dbPath);
319 keySize = (int)strlen((const char*)key);
320 if(keySize < DbKeySize)
322 memset(search.m_key,0, DbKeySize);
323 memcpy(search.m_key, key, keySize);
324 if(itzam_true == itzam_btree_find(btree, key, &search))
326 read_size = strlen(search.m_data);
330 read_size = EPERS_NOKEY;
335 fprintf(stderr, "persistence_get_data_size => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize);
336 read_size = EPERS_DB_KEY_SIZE;
339 // workaround till lifecycle is working correctly
345 read_size = EPERS_NOPRCTABLE;
346 fprintf(stderr, "\npersistence_get_data_size ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
349 else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library
351 int idx = custom_client_name_to_id(dbPath, 1);
352 if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) )
354 gPersCustomFuncs[idx].custom_plugin_get_size(key);
358 read_size = EPERS_NOPLUGINFUNCT;
366 int pers_db_delete_key(char* dbPath, char* dbKey, PersistenceInfo_s* info)
369 if(PersistenceStorage_custom != info->configKey.storage)
371 itzam_btree* btree = NULL;
372 KeyValuePair_s delete;
374 //printf("delete_key_from_table_itzam => Path: \"%s\" | key: \"%s\" \n", dbPath, key);
375 btree = pers_db_open(info, dbPath);
379 keySize = (int)strlen((const char*)dbKey);
380 if(keySize < DbKeySize)
384 memset(delete.m_key,0, DbKeySize);
385 memcpy(delete.m_key, dbKey, keySize);
386 state = itzam_btree_remove(btree, (const void *)&delete);
387 if (state != ITZAM_OKAY)
389 fprintf(stderr, "persistence_delete_data ==> Remove Itzam problem: %s\n", STATE_MESSAGES[state]);
390 ret = EPERS_DB_ERROR_INTERNAL;
395 fprintf(stderr, "persistence_delete_data => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize);
396 ret = EPERS_DB_KEY_SIZE;
399 // workaround till lifecycle is working correctly
405 fprintf(stderr, "persistence_delete_data => no prct table\n");
406 ret = EPERS_NOPRCTABLE;
409 else // custom storage implementation via custom library
411 int idx = custom_client_name_to_id(dbPath, 1);
412 if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) )
414 gPersCustomFuncs[idx].custom_plugin_delete_data(dbKey);
418 ret = EPERS_NOPLUGINFUNCT;
425 int persistence_reg_notify_on_change(char* dbPath, char* key)
434 //---------------------------------------------------------------------------------------------------------
435 // C U R S O R F U N C T I O N S
436 //---------------------------------------------------------------------------------------------------------
438 int get_cursor_handle()
442 if(pthread_mutex_lock(&gMtx) == 0)
444 if(gFreeCursorHandleIdxHead > 0) // check if we have a free spot in the array before the current max
446 handle = gFreeCursorHandleArray[--gFreeCursorHandleIdxHead];
450 if(gHandleIdx < MaxPersHandle-1)
452 handle = gHandleIdx++; // no free spot before current max, increment handle index
457 printf("get_persistence_handle_idx => Reached maximum of open handles: %d \n", MaxPersHandle);
460 pthread_mutex_unlock(&gMtx);
466 void close_cursor_handle(int handlerDB)
468 if(pthread_mutex_lock(&gMtx) == 0)
470 if(gFreeCursorHandleIdxHead < MaxPersHandle)
472 gFreeCursorHandleArray[gFreeCursorHandleIdxHead++] = handlerDB;
474 pthread_mutex_unlock(&gMtx);
480 int pers_db_cursor_create(char* dbPath)
483 itzam_state state = ITZAM_FAILED;
485 handle = get_cursor_handle();
487 if(handle < MaxPersHandle && handle >= 0)
490 state = itzam_btree_open(&gCursorArray[handle].m_btree, dbPath, itzam_comparator_string, error_handler, 0/*recover*/, 0/*read_only*/);
491 if (state != ITZAM_OKAY)
493 fprintf(stderr, "pers_db_open ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
499 state = itzam_btree_cursor_create(&gCursorArray[handle].m_cursor, &gCursorArray[handle].m_btree);
500 if(state == ITZAM_OKAY)
502 gCursorArray[handle].m_empty = 0;
506 gCursorArray[handle].m_empty = 1;
515 int pers_db_cursor_next(unsigned int handlerDB)
518 //if(handlerDB < MaxPersHandle && handlerDB >= 0)
519 if(handlerDB < MaxPersHandle )
521 if(gCursorArray[handlerDB].m_empty != 1)
524 success = itzam_btree_cursor_next(&gCursorArray[handlerDB].m_cursor);
526 if(success == itzam_true)
532 rval = EPERS_LAST_ENTRY_IN_DB;
537 printf("persistence_db_cursor_get_key ==> invalid handle: %u \n", handlerDB);
542 printf("persistence_db_cursor_get_key ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
549 int pers_db_cursor_get_key(unsigned int handlerDB, char * bufKeyName_out, int bufSize)
552 KeyValuePair_s search;
554 if(handlerDB < MaxPersHandle)
556 if(gCursorArray[handlerDB].m_empty != 1)
559 itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
560 length = strlen(search.m_key);
563 memcpy(bufKeyName_out, search.m_key, length);
568 printf("persistence_db_cursor_get_key ==> buffer to small » keySize: %d | bufSize: %d \n", length, bufSize);
573 printf("persistence_db_cursor_get_key ==> invalid handle: %u \n", handlerDB);
578 printf("persistence_db_cursor_get_key ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
585 int pers_db_cursor_get_data(unsigned int handlerDB, char * bufData_out, int bufSize)
588 KeyValuePair_s search;
590 if(handlerDB < MaxPersHandle)
592 if(gCursorArray[handlerDB].m_empty != 1)
595 itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
597 length = strlen(search.m_data);
600 memcpy(bufData_out, search.m_data, length);
605 printf("persistence_db_cursor_get_data ==> buffer to small » keySize: %d | bufSize: %d \n", length, bufSize);
610 printf("persistence_db_cursor_get_data ==> invalid handle: %u \n", handlerDB);
615 printf("persistence_db_cursor_get_data ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
622 int pers_db_cursor_get_data_size(unsigned int handlerDB)
625 KeyValuePair_s search;
627 if(handlerDB < MaxPersHandle)
629 if(gCursorArray[handlerDB].m_empty != 1)
631 itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
632 size = strlen(search.m_data);
636 printf("persistence_db_cursor_get_data ==> invalid handle: %u \n", handlerDB);
641 printf("persistence_db_cursor_get_data ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
648 int pers_db_cursor_destroy(unsigned int handlerDB)
651 if(handlerDB < MaxPersHandle)
653 itzam_btree_cursor_free(&gCursorArray[handlerDB].m_cursor);
654 gCursorArray[handlerDB].m_empty = 1;
656 itzam_state state = ITZAM_FAILED;
657 state = itzam_btree_close(&gCursorArray[handlerDB].m_btree);
658 if (state != ITZAM_OKAY)
660 fprintf(stderr, "pers_db_cursor_destroy ==> Close: Itzam problem: %s\n", STATE_MESSAGES[state]);
663 close_cursor_handle(handlerDB);
673 //-----------------------------------------------------------------------------
674 // code to print database content (for debugging)
675 //-----------------------------------------------------------------------------
679 itzam_btree_cursor cursor;
680 state = itzam_btree_cursor_create(&cursor, &btree);
681 if(state == ITZAM_OKAY)
683 printf("==> Database content ==> db size: %d\n", (int)itzam_btree_count(&btree));
686 // get the key pointed to by the cursor
687 state = itzam_btree_cursor_read(&cursor,(void *)&rec);
688 if (state == ITZAM_OKAY)
690 printf(" Key: %s \n ==> data: %s\n", rec.m_key, rec.m_data);
693 fprintf(stderr, "\nItzam problem: %s\n", STATE_MESSAGES[state]);
695 while (itzam_btree_cursor_next(&cursor));
697 state = itzam_btree_cursor_free(&cursor);
700 //-----------------------------------------------------------------------------