15ff7a69d93081824c9b82839076e7d90ef65fdc
[profile/ivi/persistence-client-library.git] / src / persistence_client_library_db_access.c
1 /******************************************************************************
2  * Project         Persistency
3  * (c) copyright   2012
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 ******************************************************************************/
11  /**
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
17  * @see            
18  */
19
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"
24
25 #include "persistence_client_library_dbus_service.h"
26
27 #include <dbus/dbus.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31
32
33 /// definition of a key-value pair stored in the database
34 typedef struct _KeyValuePair_s
35 {
36     char m_key[DbKeySize];       /// the key
37     char m_data[DbValueSize];    /// the data
38     unsigned int m_data_size;   /// the size of the data
39 }
40 KeyValuePair_s;
41
42
43 // definition of a cursor entry
44 typedef struct _CursorEntry_s
45 {
46    itzam_btree_cursor m_cursor;
47    itzam_btree        m_btree;
48    int                m_empty;
49 }
50 CursorEntry_s;
51
52 // cursor array handle
53 CursorEntry_s gCursorArray[MaxPersHandle];
54
55 /// handle index
56 static int gHandleIdx = 1;
57
58 /// free handle array
59 int gFreeCursorHandleArray[MaxPersHandle];
60 // free head index
61 int gFreeCursorHandleIdxHead = 0;
62
63 // mutex to controll access to the cursor array
64 pthread_mutex_t gMtx = PTHREAD_MUTEX_INITIALIZER;
65
66
67 /// btree array
68 static itzam_btree gBtree[DbTableSize][PersistencePolicy_LastEntry];
69 static int gBtreeCreated[DbTableSize][PersistencePolicy_LastEntry] = { {0} };
70
71
72 // function prototype
73 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, unsigned int reason);
74
75
76 itzam_btree* pers_db_open(PersistenceInfo_s* info, const char* dbPath)
77 {
78    int arrayIdx = 0;
79    itzam_btree* btree = NULL;
80
81    // create array index: index is a combination of resource config table type and group
82    arrayIdx = info->configKey.storage + info->context.ldbid ;
83
84    //if(arrayIdx <= DbTableSize)
85    if(arrayIdx < DbTableSize)
86    {
87       if(gBtreeCreated[arrayIdx][info->configKey.policy] == 0)
88       {
89          itzam_state  state = ITZAM_FAILED;
90          state = itzam_btree_open(&gBtree[arrayIdx][info->configKey.policy], dbPath,
91                                   itzam_comparator_string, error_handler, 0/*recover*/, 0/*read_only*/);
92          if (state != ITZAM_OKAY)
93          {
94             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_open ==> itzam_btree_open => Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
95          }
96          gBtreeCreated[arrayIdx][info->configKey.policy] = 1;
97       }
98       // assign database
99       btree = &gBtree[arrayIdx][info->configKey.policy];
100    }
101    else
102    {
103       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_open ==> invalid storage type"), DLT_STRING(dbPath));
104    }
105    return btree;
106 }
107
108
109
110 void pers_db_close(PersistenceInfo_s* info)
111 {
112    int arrayIdx = info->configKey.storage + info->context.ldbid;
113
114    if(info->configKey.storage <= PersistenceStorage_shared )
115    {
116       itzam_state  state = ITZAM_FAILED;
117       state = itzam_btree_close(&gBtree[arrayIdx][info->configKey.policy]);
118       if (state != ITZAM_OKAY)
119       {
120          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_close ==> itzam_btree_close => Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
121       }
122       gBtreeCreated[arrayIdx][info->configKey.policy] = 0;
123    }
124    else
125    {
126       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_close ==> invalid storage type"), DLT_INT(info->context.ldbid ));
127    }
128 }
129
130
131
132 void pers_db_close_all()
133 {
134    int i = 0;
135
136    for(i=0; i<DbTableSize; i++)
137    {
138       // close write cached database
139       if(gBtreeCreated[i][PersistencePolicy_wc] == 1)
140       {
141          itzam_state  state = ITZAM_FAILED;
142          state = itzam_btree_close(&gBtree[i][PersistencePolicy_wc]);
143          if (state != ITZAM_OKAY)
144          {
145             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_close_all ==> itzam_btree_close => Itzam problem:"), DLT_STRING(STATE_MESSAGES[state]) );
146          }
147          gBtreeCreated[i][PersistencePolicy_wc] = 0;
148       }
149
150       // close write through database
151       if(gBtreeCreated[i][PersistencePolicy_wt] == 1)
152       {
153          itzam_state  state = ITZAM_FAILED;
154          state = itzam_btree_close(&gBtree[i][PersistencePolicy_wt]);
155          if (state != ITZAM_OKAY)
156          {
157             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_close_all ==>itzam_btree_close => Itzam problem:"), DLT_STRING(STATE_MESSAGES[state]));
158          }
159          gBtreeCreated[i][PersistencePolicy_wt] = 0;
160       }
161    }
162 }
163
164
165
166 int pers_db_read_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
167 {
168    int read_size = -1;
169
170    if(   PersistenceStorage_shared == info->configKey.storage
171       || PersistenceStorage_local == info->configKey.storage)
172    {
173       itzam_btree* btree = NULL;
174       KeyValuePair_s search;
175
176       btree = pers_db_open(info, dbPath);
177       if(btree != NULL)
178       {
179          if(itzam_true == itzam_btree_find(btree, key, &search))
180          {
181             read_size = search.m_data_size;
182             if(read_size > buffer_size)
183             {
184                read_size = buffer_size;   // truncate data size to buffer size
185             }
186             memcpy(buffer, search.m_data, read_size);
187          }
188          else
189          {
190             read_size = EPERS_NOKEY;
191          }
192       }
193       else
194       {
195          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_read_key ==>no resource config table"), DLT_STRING(dbPath), DLT_STRING(key) );
196          read_size = EPERS_NOPRCTABLE;
197       }
198    }
199    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
200    {
201       int idx =  custom_client_name_to_id(dbPath, 1);
202       char workaroundPath[128];  // workaround, because /sys/ can not be accessed on host!!!!
203       snprintf(workaroundPath, 128, "%s%s", "/Data", dbPath  );
204
205       if( (idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_get_data != NULL) )
206       {
207          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
208          {
209             char pathKeyString[128];
210                    snprintf(pathKeyString, 128, "%s/%s", dbPath, key);
211             read_size = gPersCustomFuncs[idx].custom_plugin_get_data(pathKeyString, (char*)buffer, buffer_size);
212          }
213          else
214          {
215             read_size = gPersCustomFuncs[idx].custom_plugin_get_data(info->configKey.customID, (char*)buffer, buffer_size);
216          }
217       }
218       else
219       {
220          read_size = EPERS_NOPLUGINFUNCT;
221       }
222    }
223    return read_size;
224 }
225
226
227
228 int pers_db_write_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
229 {
230    int write_size = -1;
231
232    if(   PersistenceStorage_local == info->configKey.storage
233       || PersistenceStorage_shared == info->configKey.storage )
234    {
235       write_size = buffer_size;
236       itzam_btree* btree = NULL;
237       itzam_state  state = ITZAM_FAILED;
238       KeyValuePair_s insert;
239
240       btree = pers_db_open(info, dbPath);
241       if(btree != NULL)
242       {
243          int keySize = 0;
244          keySize = (int)strlen((const char*)key);
245          if(keySize < DbKeySize)
246          {
247             int dataSize = 0;
248             dataSize = (int)strlen( (const char*)buffer);
249             if(dataSize < DbValueSize)
250             {
251                // -----------------------------------------------------------------------------
252                // transaction start
253                itzam_btree_transaction_start(btree);
254
255                // key
256                memset(insert.m_key, 0, DbKeySize);
257                memcpy(insert.m_key, key, keySize);
258                if(itzam_true == itzam_btree_find(btree, key, &insert))
259                {
260                   // key already available, so delete "old" key
261                   state = itzam_btree_remove(btree, (const void *)&insert);
262                }
263
264                // data
265                memset(insert.m_data, 0, DbValueSize);
266                memcpy(insert.m_data, buffer, dataSize);
267
268                // data size
269                insert.m_data_size = buffer_size;
270
271                state = itzam_btree_insert(btree,(const void *)&insert);
272                if (state != ITZAM_OKAY)
273                {
274                   DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> itzam_btree_insert => Itzam problem"), DLT_STRING(STATE_MESSAGES[state]) );
275                   write_size = EPERS_DB_ERROR_INTERNAL;
276                }
277
278
279                itzam_btree_transaction_commit(btree);
280                // transaction end
281                // -----------------------------------------------------------------------------
282
283                if(PersistenceStorage_shared == info->configKey.storage)
284                {
285                   pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted);
286                }
287             }
288             else
289             {
290                DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> data to long » size:"), DLT_INT(dataSize), DLT_INT(DbValueSize) );
291                write_size = EPERS_DB_VALUE_SIZE;
292             }
293          }
294          else
295          {
296             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> key to long » size"), DLT_INT(keySize), DLT_INT(DbKeySize) );
297             write_size = EPERS_DB_KEY_SIZE;
298          }
299       }
300       else
301       {
302          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
303          write_size = EPERS_NOPRCTABLE;
304       }
305    }
306    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
307    {
308       int idx = custom_client_name_to_id(dbPath, 1);
309       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data != NULL) )
310       {
311          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
312          {
313             char pathKeyString[128];
314             snprintf(pathKeyString, 128, "%s/%s", dbPath, key);
315             write_size = gPersCustomFuncs[idx].custom_plugin_set_data(pathKeyString, (char*)buffer, buffer_size);
316          }
317          else
318             write_size = gPersCustomFuncs[idx].custom_plugin_set_data(info->configKey.customID, (char*)buffer, buffer_size);
319       }
320       else
321       {
322          write_size = EPERS_NOPLUGINFUNCT;
323       }
324    }
325    return write_size;
326 }
327
328
329
330 int pers_db_get_key_size(char* dbPath, char* key, PersistenceInfo_s* info)
331 {
332    int read_size = -1;
333
334    if(   PersistenceStorage_shared == info->configKey.storage
335       || PersistenceStorage_local == info->configKey.storage)
336    {
337       int keySize = 0;
338       itzam_btree*  btree = NULL;
339       KeyValuePair_s search;
340
341       btree = pers_db_open(info, dbPath);
342       if(btree != NULL)
343       {
344          keySize = (int)strlen((const char*)key);
345          if(keySize < DbKeySize)
346          {
347             memset(search.m_key,0, DbKeySize);
348             memcpy(search.m_key, key, keySize);
349             if(itzam_true == itzam_btree_find(btree, key, &search))
350             {
351                read_size = search.m_data_size;
352             }
353             else
354             {
355                read_size = EPERS_NOKEY;
356             }
357          }
358          else
359          {
360             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_get_key_size ==> key to long"), DLT_INT(keySize), DLT_INT(DbKeySize));
361             read_size = EPERS_DB_KEY_SIZE;
362          }
363       }
364       else
365       {
366          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_get_key_size ==> no config table"), DLT_STRING(dbPath), DLT_STRING(key));
367          read_size = EPERS_NOPRCTABLE;
368       }
369    }
370    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
371    {
372       int idx = custom_client_name_to_id(dbPath, 1);
373       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data != NULL) )
374       {
375          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
376          {
377             char pathKeyString[128];
378             snprintf(pathKeyString, 128, "%s/%s", dbPath, key);
379             read_size = gPersCustomFuncs[idx].custom_plugin_get_size(pathKeyString);
380          }
381          else
382             read_size = gPersCustomFuncs[idx].custom_plugin_get_size(info->configKey.customID);
383       }
384       else
385       {
386          read_size = EPERS_NOPLUGINFUNCT;
387       }
388    }
389    return read_size;
390 }
391
392
393
394 int pers_db_delete_key(char* dbPath, char* key, PersistenceInfo_s* info)
395 {
396    int ret = 0;
397    if(PersistenceStorage_custom != info->configKey.storage)
398    {
399       itzam_btree*  btree = NULL;
400       KeyValuePair_s delete;
401
402       btree = pers_db_open(info, dbPath);
403       if(btree != NULL)
404       {
405          int keySize = 0;
406          keySize = (int)strlen((const char*)key);
407          if(keySize < DbKeySize)
408          {
409             // -----------------------------------------------------------------------------
410             // transaction start
411             itzam_btree_transaction_start(btree);
412
413             itzam_state  state;
414
415             memset(delete.m_key,0, DbKeySize);
416             memcpy(delete.m_key, key, keySize);
417             state = itzam_btree_remove(btree, (const void *)&delete);
418             if (state != ITZAM_OKAY)
419             {
420                DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_delete_key ==> itzam_btree_remove => Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
421                ret = EPERS_DB_ERROR_INTERNAL;
422             }
423             itzam_btree_transaction_commit(btree);
424             // transaction end
425             // -----------------------------------------------------------------------------
426
427             if(PersistenceStorage_shared == info->configKey.storage)
428             {
429                pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_changed);
430             }
431          }
432          else
433          {
434             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_delete_key ==> key to long"), DLT_INT(keySize), DLT_INT(DbKeySize));
435             ret = EPERS_DB_KEY_SIZE;
436          }
437       }
438       else
439       {
440          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_delete_key ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
441          ret = EPERS_NOPRCTABLE;
442       }
443    }
444    else   // custom storage implementation via custom library
445    {
446       int idx = custom_client_name_to_id(dbPath, 1);
447       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data != NULL) )
448       {
449          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
450          {
451             char pathKeyString[128];
452             snprintf(pathKeyString, 128, "%s/%s", dbPath, key);
453             ret = gPersCustomFuncs[idx].custom_plugin_delete_data(pathKeyString);
454          }
455          else
456             ret = gPersCustomFuncs[idx].custom_plugin_delete_data(info->configKey.customID);
457       }
458       else
459       {
460          ret = EPERS_NOPLUGINFUNCT;
461       }
462    }
463    return ret;
464 }
465
466
467 int persistence_reg_notify_on_change(char* dbPath, char* key, unsigned int ldbid, unsigned int user_no, unsigned int seat_no,
468                                      pclChangeNotifyCallback_t callback)
469 {
470    int rval = 0;
471    DBusError error;
472    dbus_error_init (&error);
473    char ruleChanged[DbusMatchRuleSize];
474    char ruleDeleted[DbusMatchRuleSize];
475
476    // assign callback
477    gChangeNotifyCallback = callback;
478
479    // add match for  c h a n g e
480    snprintf(ruleChanged, DbusMatchRuleSize, "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceResChange',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%u',arg2='%u',arg3='%u'",
481             key, ldbid, user_no, seat_no);
482    dbus_bus_add_match(get_dbus_connection(), ruleChanged, &error);
483
484
485    // add match for  d e l e t e
486    snprintf(ruleDeleted, DbusMatchRuleSize, "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceResDelete',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%u',arg2='%u',arg3='%u'",
487             key, ldbid, user_no, seat_no);
488    dbus_bus_add_match(get_dbus_connection(), ruleDeleted, &error);
489
490
491    // add match for  c r e a t e
492    snprintf(ruleDeleted, DbusMatchRuleSize, "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceResCreate',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%u',arg2='%u',arg3='%u'",
493             key, ldbid, user_no, seat_no);
494    dbus_bus_add_match(get_dbus_connection(), ruleDeleted, &error);
495
496    return rval;
497 }
498
499
500 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, pclNotifyStatus_e reason)
501 {
502    DBusMessage* message;
503    dbus_bool_t ret;
504    int rval = 0;
505    char ldbid_array[DbusSubMatchSize];
506    char user_array[DbusSubMatchSize];
507    char seat_array[DbusSubMatchSize];
508    const char* ldbid_ptr = ldbid_array;
509    const char* user_ptr = user_array;
510    const char* seat_ptr = seat_array;
511
512    char* changeSignal = "PersistenceResChange";
513    char* deleteSignal = "PersistenceResDelete";
514    char* createSignal = "PersistenceResCreate";
515    char* theReason = NULL;
516
517    DBusConnection* conn = get_dbus_connection();
518
519    memset(ldbid_array, 0, DbusSubMatchSize);
520    memset(user_array, 0, DbusSubMatchSize);
521    memset(seat_array, 0, DbusSubMatchSize);
522
523
524    // dbus_bus_add_match is used for the notification mechanism,
525    // and this works only for type DBUS_TYPE_STRING as message arguments
526    // this is the reason to use string instead of integer types directly
527    snprintf(ldbid_array, DbusSubMatchSize, "%d", context->ldbid);
528    snprintf(user_array,  DbusSubMatchSize, "%d", context->user_no);
529    snprintf(seat_array,  DbusSubMatchSize, "%d", context->seat_no);
530
531    switch(reason)
532    {
533       case pclNotifyStatus_deleted:
534          theReason = deleteSignal;
535          break;
536       case  pclNotifyStatus_created:
537          theReason = createSignal;
538          break;
539       case pclNotifyStatus_changed:
540          theReason = changeSignal;
541          break;
542       default:
543          theReason = changeSignal;
544          break;
545    }
546
547    if(theReason != NULL)
548    {
549       message = dbus_message_new_signal("/org/genivi/persistence/adminconsumer",    // const char *path,
550                                         "org.genivi.persistence.adminconsumer",     // const char *interface,
551                                         theReason);                                 // const char *name
552
553       ret = dbus_message_append_args(message,
554                                DBUS_TYPE_STRING, &key,
555                                DBUS_TYPE_STRING, &ldbid_ptr,
556                                DBUS_TYPE_STRING, &user_ptr,
557                                DBUS_TYPE_STRING, &seat_ptr,
558                                DBUS_TYPE_INVALID);
559       if(ret == TRUE)
560       {
561          // Send the signal
562          if(conn != NULL)
563          {
564             if(dbus_connection_send(conn, message, 0) == TRUE)
565             {
566                // Free the signal now we have finished with it
567                dbus_message_unref(message);
568             }
569             else
570             {
571                rval = EPERS_NOTIFY_SIG;
572             }
573          }
574          else
575          {
576             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_send_Notification_Signal ==> E R R O R  C O N E C T I O N  NULL!!"));
577          }
578       }
579       else
580       {
581          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_send_Notification_Signal ==> ERROR dbus_message_append_args"));
582          rval = EPERS_NOTIFY_SIG;
583       }
584    }
585    else
586    {
587       rval = EPERS_NOTIFY_SIG;
588    }
589
590    return rval;
591 }
592
593
594 //---------------------------------------------------------------------------------------------------------
595 // C U R S O R    F U N C T I O N S
596 //---------------------------------------------------------------------------------------------------------
597
598 int get_cursor_handle()
599 {
600    int handle = 0;
601
602    if(pthread_mutex_lock(&gMtx) == 0)
603    {
604       if(gFreeCursorHandleIdxHead > 0)   // check if we have a free spot in the array before the current max
605       {
606          handle = gFreeCursorHandleArray[--gFreeCursorHandleIdxHead];
607       }
608       else
609       {
610          if(gHandleIdx < MaxPersHandle-1)
611          {
612             handle = gHandleIdx++;  // no free spot before current max, increment handle index
613          }
614          else
615          {
616             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("get_cursor_handle ==> Reached maximum of open handles:"), DLT_INT(MaxPersHandle));
617             handle = -1;
618          }
619       }
620       pthread_mutex_unlock(&gMtx);
621    }
622    return handle;
623 }
624
625
626 void close_cursor_handle(int handlerDB)
627 {
628    if(pthread_mutex_lock(&gMtx) == 0)
629    {
630       if(gFreeCursorHandleIdxHead < MaxPersHandle)
631       {
632          gFreeCursorHandleArray[gFreeCursorHandleIdxHead++] = handlerDB;
633       }
634       pthread_mutex_unlock(&gMtx);
635    }
636 }
637
638
639
640 int pers_db_cursor_create(char* dbPath)
641 {
642    int handle = -1;
643    itzam_state  state = ITZAM_FAILED;
644
645    handle = get_cursor_handle();
646
647    if(handle < MaxPersHandle && handle >= 0)
648    {
649       // open database
650       state = itzam_btree_open(&gCursorArray[handle].m_btree, dbPath, itzam_comparator_string, error_handler, 1/*recover*/, 0/*read_only*/);
651       if (state != ITZAM_OKAY)
652       {
653          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_create ==> itzam_btree_open"), DLT_STRING(STATE_MESSAGES[state]));
654       }
655       else
656       {
657          itzam_state  state;
658
659          state = itzam_btree_cursor_create(&gCursorArray[handle].m_cursor, &gCursorArray[handle].m_btree);
660          if(state == ITZAM_OKAY)
661          {
662             gCursorArray[handle].m_empty = 0;
663          }
664          else
665          {
666             gCursorArray[handle].m_empty = 1;
667          }
668       }
669    }
670    return handle;
671 }
672
673
674
675 int pers_db_cursor_next(unsigned int handlerDB)
676 {
677    int rval = -1;
678    //if(handlerDB < MaxPersHandle && handlerDB >= 0)
679    if(handlerDB < MaxPersHandle )
680    {
681       if(gCursorArray[handlerDB].m_empty != 1)
682       {
683          itzam_bool success;
684          success = itzam_btree_cursor_next(&gCursorArray[handlerDB].m_cursor);
685
686          if(success == itzam_true)
687          {
688             rval = 0;
689          }
690          else
691          {
692             rval = EPERS_LAST_ENTRY_IN_DB;
693          }
694       }
695       else
696       {
697          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_next ==> invalid handle: "), DLT_INT(handlerDB));
698       }
699    }
700    else
701    {
702       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_next ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
703    }
704    return rval;
705 }
706
707
708
709 int pers_db_cursor_get_key(unsigned int handlerDB, char * bufKeyName_out, int bufSize)
710 {
711    int rval = -1;
712    KeyValuePair_s search;
713
714    if(handlerDB < MaxPersHandle)
715    {
716       if(gCursorArray[handlerDB].m_empty != 1)
717       {
718          int length = 0;
719          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
720          length = strlen(search.m_key);
721          if(length < bufSize)
722          {
723             memcpy(bufKeyName_out, search.m_key, length);
724             rval = 0;
725          }
726          else
727          {
728             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_key  ==> buffer to small » keySize: "), DLT_INT(bufSize));
729          }
730       }
731       else
732       {
733          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_key  ==>  invalid handle:"), DLT_INT(handlerDB));
734       }
735    }
736    else
737    {
738       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_key ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
739    }
740    return rval;
741 }
742
743
744
745 int pers_db_cursor_get_data(unsigned int handlerDB, char * bufData_out, int bufSize)
746 {
747    int rval = -1;
748    KeyValuePair_s search;
749
750    if(handlerDB < MaxPersHandle)
751    {
752       if(gCursorArray[handlerDB].m_empty != 1)
753       {
754          int length = 0;
755          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
756
757          length = strlen(search.m_data);
758          if(length < bufSize)
759          {
760             memcpy(bufData_out, search.m_data, length);
761             rval = 0;
762          }
763          else
764          {
765             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_data  ==> buffer to small » keySize: "), DLT_INT(bufSize));
766          }
767       }
768       else
769       {
770          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data  ==>  invalid handle:"), DLT_INT(handlerDB));
771       }
772    }
773    else
774    {
775       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
776    }
777    return rval;
778 }
779
780
781
782 int pers_db_cursor_get_data_size(unsigned int handlerDB)
783 {
784    int size = -1;
785    KeyValuePair_s search;
786
787    if(handlerDB < MaxPersHandle)
788    {
789       if(gCursorArray[handlerDB].m_empty != 1)
790       {
791          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
792          size = strlen(search.m_data);
793       }
794       else
795       {
796          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_data_size  ==>  invalid handle:"), DLT_INT(handlerDB));
797       }
798    }
799    else
800    {
801       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data  ==>  handle bigger than max:"), DLT_INT(MaxPersHandle));
802    }
803    return size;
804 }
805
806
807
808 int pers_db_cursor_destroy(unsigned int handlerDB)
809 {
810    int rval = -1;
811    if(handlerDB < MaxPersHandle)
812    {
813       itzam_btree_cursor_free(&gCursorArray[handlerDB].m_cursor);
814       gCursorArray[handlerDB].m_empty = 1;
815
816       itzam_state state = ITZAM_FAILED;
817       state = itzam_btree_close(&gCursorArray[handlerDB].m_btree);
818       if (state != ITZAM_OKAY)
819       {
820             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_destroy  ==>  itzam_btree_close: Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
821       }
822
823       close_cursor_handle(handlerDB);
824
825       rval = 0;
826    }
827    return rval;
828 }
829
830
831
832
833 //-----------------------------------------------------------------------------
834 // code to print database content (for debugging)
835 //-----------------------------------------------------------------------------
836 // walk the database
837 /*
838 KeyValuePair_s  rec;
839 itzam_btree_cursor cursor;
840 state = itzam_btree_cursor_create(&cursor, &btree);
841 if(state == ITZAM_OKAY)
842 {
843   printf("==> Database content ==> db size: %d\n", (int)itzam_btree_count(&btree));
844   do
845   {
846      // get the key pointed to by the cursor
847      state = itzam_btree_cursor_read(&cursor,(void *)&rec);
848      if (state == ITZAM_OKAY)
849      {
850        printf("   Key: %s \n     ==> data: %s\n", rec.m_key, rec.m_data);
851      }
852      else
853         fprintf(stderr, "\nItzam problem: %s\n", STATE_MESSAGES[state]);
854   }
855   while (itzam_btree_cursor_next(&cursor));
856
857   state = itzam_btree_cursor_free(&cursor);
858 }
859 */
860 //-----------------------------------------------------------------------------
861
862
863
864
865