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