diff options
Diffstat (limited to 'src/persistence_client_library_db_access.c')
-rw-r--r-- | src/persistence_client_library_db_access.c | 696 |
1 files changed, 696 insertions, 0 deletions
diff --git a/src/persistence_client_library_db_access.c b/src/persistence_client_library_db_access.c new file mode 100644 index 0000000..4d60c91 --- /dev/null +++ b/src/persistence_client_library_db_access.c @@ -0,0 +1,696 @@ +/****************************************************************************** + * Project Persistency + * (c) copyright 2012 + * Company XS Embedded GmbH + *****************************************************************************/ +/****************************************************************************** + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +******************************************************************************/ + /** + * @file persistence_client_library_data_access.c + * @ingroup Persistence client library + * @author Ingo Huerner + * @brief Implementation of persistence database access + * Library provides an API to access persistent data + * @see + */ + +#include "../include_protected/persistence_client_library_db_access.h" +#include "persistence_client_library_custom_loader.h" +#include "persistence_client_library_itzam_errors.h" + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + + +/// definition of a key-value pair stored in the database +typedef struct _KeyValuePair_s +{ + char m_key[DbKeySize]; /// the key + char m_data[DbValueSize]; /// the data + unsigned int m_data_size; /// the size of the data +} +KeyValuePair_s; + + +// definition of a cursor entry +typedef struct _CursorEntry_s +{ + itzam_btree_cursor m_cursor; + itzam_btree m_btree; + int m_empty; +} +CursorEntry_s; + +// cursor array handle +CursorEntry_s gCursorArray[MaxPersHandle]; + +/// handle index +static int gHandleIdx = 1; + +/// free handle array +int gFreeCursorHandleArray[MaxPersHandle]; +// free head index +int gFreeCursorHandleIdxHead = 0; + +// mutex to controll access to the cursor array +pthread_mutex_t gMtx = PTHREAD_MUTEX_INITIALIZER; + + +/// btree array +static itzam_btree gBtree[DbTableSize][PersistencePolicy_LastEntry]; +static int gBtreeCreated[DbTableSize][PersistencePolicy_LastEntry] = { {0} }; + + +itzam_btree* pers_db_open(PersistenceInfo_s* info, const char* dbPath) +{ + int arrayIdx = 0; + itzam_btree* btree = NULL; + + // create array index: index is a combination of resource config table type and group + arrayIdx = info->configKey.storage + info->context.ldbid ; + + if(arrayIdx <= DbTableSize) + { + if(gBtreeCreated[arrayIdx][info->configKey.policy] == 0) + { + itzam_state state = ITZAM_FAILED; + state = itzam_btree_open(&gBtree[arrayIdx][info->configKey.policy], dbPath, + itzam_comparator_string, error_handler, 0/*recover*/, 0/*read_only*/); + if (state != ITZAM_OKAY) + { + fprintf(stderr, "pers_db_open ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]); + } + gBtreeCreated[arrayIdx][info->configKey.policy] = 1; + } + // assign database + btree = &gBtree[arrayIdx][info->configKey.policy]; + } + else + { + printf("btree_get ==> invalid storage type\n"); + } + return btree; +} + + + +void pers_db_close(PersistenceInfo_s* info) +{ + int arrayIdx = info->configKey.storage + info->context.ldbid; + + if(info->configKey.storage <= PersistenceStorage_shared ) + { + itzam_state state = ITZAM_FAILED; + state = itzam_btree_close(&gBtree[arrayIdx][info->configKey.policy]); + if (state != ITZAM_OKAY) + { + fprintf(stderr, "pers_db_close ==> Close Itzam problem: %s\n", STATE_MESSAGES[state]); + } + gBtreeCreated[arrayIdx][info->configKey.policy] = 0; + } + else + { + printf("pers_db_close ==> invalid storage type\n"); + } +} + + + +void pers_db_close_all() +{ + int i = 0; + + for(i=0; i<DbTableSize; i++) + { + // close write cached database + if(gBtreeCreated[i][PersistencePolicy_wc] == 1) + { + itzam_state state = ITZAM_FAILED; + state = itzam_btree_close(&gBtree[i][PersistencePolicy_wc]); + if (state != ITZAM_OKAY) + { + fprintf(stderr, "pers_db_close_all ==> Close WC: Itzam problem: %s\n", STATE_MESSAGES[state]); + } + gBtreeCreated[i][PersistencePolicy_wc] = 0; + } + + // close write through database + if(gBtreeCreated[i][PersistencePolicy_wt] == 1) + { + itzam_state state = ITZAM_FAILED; + state = itzam_btree_close(&gBtree[i][PersistencePolicy_wt]); + if (state != ITZAM_OKAY) + { + fprintf(stderr, "pers_db_close_all ==> Close WT: Itzam problem: %s\n", STATE_MESSAGES[state]); + } + gBtreeCreated[i][PersistencePolicy_wt] = 0; + } + } +} + + + +int pers_db_read_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size) +{ + int read_size = -1; + + if( PersistenceStorage_shared == info->configKey.storage + || PersistenceStorage_local == info->configKey.storage) + { + itzam_btree* btree = NULL; + itzam_state state = ITZAM_FAILED; + KeyValuePair_s search; + + btree = pers_db_open(info, dbPath); + if(btree != NULL) + { + if(itzam_true == itzam_btree_find(btree, key, &search)) + { + read_size = search.m_data_size; + if(read_size > buffer_size) + { + read_size = buffer_size; // truncate data size to buffer size + } + memcpy(buffer, search.m_data, read_size); + } + else + { + read_size = EPERS_NOKEY; + } + + // + // workaround till lifecycle is working correctly + // + pers_db_close(info); + } + else + { + read_size = EPERS_NOPRCTABLE; + fprintf(stderr, "\npersistence_get_data ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]); + } + } + else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library + { + int idx = custom_client_name_to_id(dbPath, 1); + char workaroundPath[128]; // workaround, because /sys/ can not be accessed on host!!!! + snprintf(workaroundPath, 128, "%s%s", "/Data", dbPath ); + + if( (idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_get_data != NULL) ) + { + gPersCustomFuncs[idx].custom_plugin_get_data(key, (char*)buffer, buffer_size); + } + else + { + read_size = EPERS_NOPLUGINFUNCT; + } + } + return read_size; +} + + + +int pers_db_write_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size) +{ + int write_size = -1; + + if( PersistenceStorage_shared == info->configKey.storage + || PersistenceStorage_local == info->configKey.storage) + { + write_size = buffer_size; + itzam_btree* btree = NULL; + itzam_state state = ITZAM_FAILED; + KeyValuePair_s insert; + + btree = pers_db_open(info, dbPath); + if(btree != NULL) + { + int keySize = 0; + keySize = (int)strlen((const char*)key); + if(keySize < DbKeySize) + { + int dataSize = 0; + dataSize = (int)strlen( (const char*)buffer); + if(dataSize < DbValueSize) + { + // key + memset(insert.m_key, 0, DbKeySize); + memcpy(insert.m_key, key, keySize); + if(itzam_true == itzam_btree_find(btree, key, &insert)) + { + // key already available, so delete "old" key + state = itzam_btree_remove(btree, (const void *)&insert); + } + + // data + memset(insert.m_data, 0, DbValueSize); + memcpy(insert.m_data, buffer, dataSize); + + // data size + insert.m_data_size = buffer_size; + + state = itzam_btree_insert(btree,(const void *)&insert); + if (state != ITZAM_OKAY) + { + fprintf(stderr, "\npersistence_set_data ==> Insert Itzam problem: %s\n", STATE_MESSAGES[state]); + write_size = EPERS_DB_ERROR_INTERNAL; + } + } + else + { + fprintf(stderr, "\npersistence_set_data ==> set_value_to_table_itzam => data to long » size %d | maxSize: %d\n", dataSize, DbKeySize); + write_size = EPERS_DB_VALUE_SIZE; + } + + // + // workaround till lifecycle is working correctly + // + pers_db_close(info); + } + else + { + fprintf(stderr, "\nset_value_to_table_itzam => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize); + write_size = EPERS_DB_KEY_SIZE; + } + } + else + { + write_size = EPERS_NOPRCTABLE; + fprintf(stderr, "\npersistence_set_data ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]); + } + } + else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library + { + int idx = custom_client_name_to_id(dbPath, 1); + if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) ) + { + gPersCustomFuncs[idx].custom_plugin_set_data(key, (char*)buffer, buffer_size); + } + else + { + write_size = EPERS_NOPLUGINFUNCT; + } + } + return write_size; +} + + + +int pers_db_get_key_size(char* dbPath, char* key, PersistenceInfo_s* info) +{ + int read_size = -1; + + if( PersistenceStorage_shared == info->configKey.storage + || PersistenceStorage_local == info->configKey.storage) + { + int keySize = 0; + itzam_btree* btree = NULL; + itzam_state state = ITZAM_FAILED; + KeyValuePair_s search; + + btree = pers_db_open(info, dbPath); + if(btree != NULL) + { + keySize = (int)strlen((const char*)key); + if(keySize < DbKeySize) + { + memset(search.m_key,0, DbKeySize); + memcpy(search.m_key, key, keySize); + if(itzam_true == itzam_btree_find(btree, key, &search)) + { + read_size = strlen(search.m_data); + } + else + { + read_size = EPERS_NOKEY; + } + } + else + { + fprintf(stderr, "persistence_get_data_size => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize); + read_size = EPERS_DB_KEY_SIZE; + } + // + // workaround till lifecycle is working correctly + // + pers_db_close(info); + } + else + { + read_size = EPERS_NOPRCTABLE; + fprintf(stderr, "\npersistence_get_data_size ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]); + } + } + else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library + { + int idx = custom_client_name_to_id(dbPath, 1); + if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) ) + { + gPersCustomFuncs[idx].custom_plugin_get_size(key); + } + else + { + read_size = EPERS_NOPLUGINFUNCT; + } + } + return read_size; +} + + + +int pers_db_delete_key(char* dbPath, char* dbKey, PersistenceInfo_s* info) +{ + int ret = 0; + if(PersistenceStorage_custom != info->configKey.storage) + { + itzam_btree* btree = NULL; + KeyValuePair_s delete; + + //printf("delete_key_from_table_itzam => Path: \"%s\" | key: \"%s\" \n", dbPath, key); + btree = pers_db_open(info, dbPath); + if(btree != NULL) + { + int keySize = 0; + keySize = (int)strlen((const char*)dbKey); + if(keySize < DbKeySize) + { + itzam_state state; + + memset(delete.m_key,0, DbKeySize); + memcpy(delete.m_key, dbKey, keySize); + state = itzam_btree_remove(btree, (const void *)&delete); + if (state != ITZAM_OKAY) + { + fprintf(stderr, "persistence_delete_data ==> Remove Itzam problem: %s\n", STATE_MESSAGES[state]); + ret = EPERS_DB_ERROR_INTERNAL; + } + } + else + { + fprintf(stderr, "persistence_delete_data => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize); + ret = EPERS_DB_KEY_SIZE; + } + // + // workaround till lifecycle is working correctly + // + pers_db_close(info); + } + else + { + fprintf(stderr, "persistence_delete_data => no prct table\n"); + ret = EPERS_NOPRCTABLE; + } + } + else // custom storage implementation via custom library + { + int idx = custom_client_name_to_id(dbPath, 1); + if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) ) + { + gPersCustomFuncs[idx].custom_plugin_delete_data(dbKey); + } + else + { + ret = EPERS_NOPLUGINFUNCT; + } + } + return ret; +} + + +int persistence_reg_notify_on_change(char* dbPath, char* key) +{ + int rval = -1; + + return rval; +} + + + +//--------------------------------------------------------------------------------------------------------- +// C U R S O R F U N C T I O N S +//--------------------------------------------------------------------------------------------------------- + +int get_cursor_handle() +{ + int handle = 0; + + if(pthread_mutex_lock(&gMtx) == 0) + { + if(gFreeCursorHandleIdxHead > 0) // check if we have a free spot in the array before the current max + { + handle = gFreeCursorHandleArray[--gFreeCursorHandleIdxHead]; + } + else + { + if(gHandleIdx < MaxPersHandle-1) + { + handle = gHandleIdx++; // no free spot before current max, increment handle index + } + else + { + handle = -1; + printf("get_persistence_handle_idx => Reached maximum of open handles: %d \n", MaxPersHandle); + } + } + pthread_mutex_unlock(&gMtx); + } + return handle; +} + + +void close_cursor_handle(int handlerDB) +{ + if(pthread_mutex_lock(&gMtx) == 0) + { + if(gFreeCursorHandleIdxHead < MaxPersHandle) + { + gFreeCursorHandleArray[gFreeCursorHandleIdxHead++] = handlerDB; + } + pthread_mutex_unlock(&gMtx); + } +} + + + +int pers_db_cursor_create(char* dbPath) +{ + int handle = -1; + itzam_state state = ITZAM_FAILED; + + handle = get_cursor_handle(); + + if(handle < MaxPersHandle && handle >= 0) + { + // open database + state = itzam_btree_open(&gCursorArray[handle].m_btree, dbPath, itzam_comparator_string, error_handler, 0/*recover*/, 0/*read_only*/); + if (state != ITZAM_OKAY) + { + fprintf(stderr, "pers_db_open ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]); + } + else + { + itzam_state state; + + state = itzam_btree_cursor_create(&gCursorArray[handle].m_cursor, &gCursorArray[handle].m_btree); + if(state == ITZAM_OKAY) + { + gCursorArray[handle].m_empty = 0; + } + else + { + gCursorArray[handle].m_empty = 1; + } + } + } + return handle; +} + + + +int pers_db_cursor_next(unsigned int handlerDB) +{ + int rval = -1; + if(handlerDB < MaxPersHandle && handlerDB >= 0) + { + if(gCursorArray[handlerDB].m_empty != 1) + { + itzam_bool success; + success = itzam_btree_cursor_next(&gCursorArray[handlerDB].m_cursor); + + if(success == itzam_true) + { + rval = 0; + } + else + { + rval = EPERS_LAST_ENTRY_IN_DB; + } + } + else + { + printf("persistence_db_cursor_get_key ==> invalid handle: %u \n", handlerDB); + } + } + else + { + printf("persistence_db_cursor_get_key ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle); + } + return rval; +} + + + +int pers_db_cursor_get_key(unsigned int handlerDB, char * bufKeyName_out, int bufSize) +{ + int rval = -1; + KeyValuePair_s search; + + if(handlerDB < MaxPersHandle) + { + if(gCursorArray[handlerDB].m_empty != 1) + { + int length = 0; + itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search); + length = strlen(search.m_key); + if(length < bufSize) + { + memcpy(bufKeyName_out, search.m_key, length); + rval = 0; + } + else + { + printf("persistence_db_cursor_get_key ==> buffer to small » keySize: %d | bufSize: %d \n", length, bufSize); + } + } + else + { + printf("persistence_db_cursor_get_key ==> invalid handle: %u \n", handlerDB); + } + } + else + { + printf("persistence_db_cursor_get_key ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle); + } + return rval; +} + + + +int pers_db_cursor_get_key_data(unsigned int handlerDB, char * bufData_out, int bufSize) +{ + int rval = -1; + KeyValuePair_s search; + + if(handlerDB < MaxPersHandle) + { + if(gCursorArray[handlerDB].m_empty != 1) + { + int length = 0; + itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search); + + length = strlen(search.m_data); + if(length < bufSize) + { + memcpy(bufData_out, search.m_data, length); + rval = 0; + } + else + { + printf("persistence_db_cursor_get_data ==> buffer to small » keySize: %d | bufSize: %d \n", length, bufSize); + } + } + else + { + printf("persistence_db_cursor_get_data ==> invalid handle: %u \n", handlerDB); + } + } + else + { + printf("persistence_db_cursor_get_data ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle); + } + return rval; +} + + + +int pers_db_cursor_get_data_size(unsigned int handlerDB) +{ + int size = -1; + KeyValuePair_s search; + + if(handlerDB < MaxPersHandle) + { + if(gCursorArray[handlerDB].m_empty != 1) + { + itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search); + size = strlen(search.m_data); + } + else + { + printf("persistence_db_cursor_get_data ==> invalid handle: %u \n", handlerDB); + } + } + else + { + printf("persistence_db_cursor_get_data ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle); + } + return size; +} + + + +int pers_db_cursor_destroy(unsigned int handlerDB) +{ + int rval = -1; + if(handlerDB < MaxPersHandle) + { + itzam_btree_cursor_free(&gCursorArray[handlerDB].m_cursor); + gCursorArray[handlerDB].m_empty = 1; + + itzam_btree_close(&gCursorArray[handlerDB].m_btree); + close_cursor_handle(handlerDB); + + rval = 0; + } + return rval; +} + + + + +//----------------------------------------------------------------------------- +// code to print database content (for debugging) +//----------------------------------------------------------------------------- +// walk the database +/* +KeyValuePair_s rec; +itzam_btree_cursor cursor; +state = itzam_btree_cursor_create(&cursor, &btree); +if(state == ITZAM_OKAY) +{ + printf("==> Database content ==> db size: %d\n", (int)itzam_btree_count(&btree)); + do + { + // get the key pointed to by the cursor + state = itzam_btree_cursor_read(&cursor,(void *)&rec); + if (state == ITZAM_OKAY) + { + printf(" Key: %s \n ==> data: %s\n", rec.m_key, rec.m_data); + } + else + fprintf(stderr, "\nItzam problem: %s\n", STATE_MESSAGES[state]); + } + while (itzam_btree_cursor_next(&cursor)); + + state = itzam_btree_cursor_free(&cursor); +} +*/ +//----------------------------------------------------------------------------- + + + + + |