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