corrected initcounter; added unregister 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, PersistenceNotifyRegPolicy_e regPolicy)
584 {
585    int rval = 0;
586    DBusError error;
587    dbus_error_init (&error);
588    char ruleChanged[DbusMatchRuleSize];
589    char ruleDeleted[DbusMatchRuleSize];
590    char ruleCreated[DbusMatchRuleSize];
591
592    // add match for  c h a n g e
593    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'",
594             key, ldbid, user_no, seat_no);
595    // add match for  d e l e t e
596    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'",
597             key, ldbid, user_no, seat_no);
598    // add match for  c r e a t e
599    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'",
600             key, ldbid, user_no, seat_no);
601
602    if(regPolicy == Notify_register)
603    {
604       // assign callback
605       gChangeNotifyCallback = callback;
606
607       dbus_bus_add_match(get_dbus_connection(), ruleChanged, &error);
608       dbus_bus_add_match(get_dbus_connection(), ruleDeleted, &error);
609       dbus_bus_add_match(get_dbus_connection(), ruleCreated, &error);
610    }
611    else if(regPolicy == Notify_unregister)
612    {
613       // remove callback
614       gChangeNotifyCallback = NULL;
615
616       dbus_bus_remove_match(get_dbus_connection(), ruleChanged, &error);
617       dbus_bus_remove_match(get_dbus_connection(), ruleDeleted, &error);
618       dbus_bus_remove_match(get_dbus_connection(), ruleCreated, &error);
619    }
620
621    return rval;
622 }
623
624
625 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, pclNotifyStatus_e reason)
626 {
627    DBusMessage* message;
628    dbus_bool_t ret;
629    int rval = 0;
630    char ldbid_array[DbusSubMatchSize] = {0};
631    char user_array[DbusSubMatchSize]  = {0};
632    char seat_array[DbusSubMatchSize]  = {0};
633    const char* ldbid_ptr = ldbid_array;
634    const char* user_ptr = user_array;
635    const char* seat_ptr = seat_array;
636
637    char* changeSignal = "PersistenceResChange";
638    char* deleteSignal = "PersistenceResDelete";
639    char* createSignal = "PersistenceResCreate";
640    char* theReason = NULL;
641
642    DBusConnection* conn = get_dbus_connection();
643
644
645    // dbus_bus_add_match is used for the notification mechanism,
646    // and this works only for type DBUS_TYPE_STRING as message arguments
647    // this is the reason to use string instead of integer types directly
648    snprintf(ldbid_array, DbusSubMatchSize, "%d", context->ldbid);
649    snprintf(user_array,  DbusSubMatchSize, "%d", context->user_no);
650    snprintf(seat_array,  DbusSubMatchSize, "%d", context->seat_no);
651
652    switch(reason)
653    {
654       case pclNotifyStatus_deleted:
655          theReason = deleteSignal;
656          break;
657       case  pclNotifyStatus_created:
658          theReason = createSignal;
659          break;
660       case pclNotifyStatus_changed:
661          theReason = changeSignal;
662          break;
663       default:
664          theReason = changeSignal;
665          break;
666    }
667
668    if(theReason != NULL)
669    {
670       message = dbus_message_new_signal("/org/genivi/persistence/adminconsumer",    // const char *path,
671                                         "org.genivi.persistence.adminconsumer",     // const char *interface,
672                                         theReason);                                 // const char *name
673
674       ret = dbus_message_append_args(message,
675                                DBUS_TYPE_STRING, &key,
676                                DBUS_TYPE_STRING, &ldbid_ptr,
677                                DBUS_TYPE_STRING, &user_ptr,
678                                DBUS_TYPE_STRING, &seat_ptr,
679                                DBUS_TYPE_INVALID);
680       if(ret == TRUE)
681       {
682          // Send the signal
683          if(conn != NULL)
684          {
685             if(dbus_connection_send(conn, message, 0) == TRUE)
686             {
687                // Free the signal now we have finished with it
688                dbus_message_unref(message);
689             }
690             else
691             {
692                rval = EPERS_NOTIFY_SIG;
693             }
694          }
695          else
696          {
697             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!!"));
698          }
699       }
700       else
701       {
702          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_send_Notification_Signal ==> ERROR dbus_message_append_args"));
703          rval = EPERS_NOTIFY_SIG;
704       }
705    }
706    else
707    {
708       rval = EPERS_NOTIFY_SIG;
709    }
710
711    return rval;
712 }
713
714
715 //---------------------------------------------------------------------------------------------------------
716 // C U R S O R    F U N C T I O N S
717 //---------------------------------------------------------------------------------------------------------
718
719 int get_cursor_handle()
720 {
721    int handle = 0;
722
723    if(pthread_mutex_lock(&gMtx) == 0)
724    {
725       if(gFreeCursorHandleIdxHead > 0)   // check if we have a free spot in the array before the current max
726       {
727          handle = gFreeCursorHandleArray[--gFreeCursorHandleIdxHead];
728       }
729       else
730       {
731          if(gHandleIdx < MaxPersHandle-1)
732          {
733             handle = gHandleIdx++;  // no free spot before current max, increment handle index
734          }
735          else
736          {
737             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("get_cursor_handle ==> Reached maximum of open handles:"), DLT_INT(MaxPersHandle));
738             handle = -1;
739          }
740       }
741       pthread_mutex_unlock(&gMtx);
742    }
743    return handle;
744 }
745
746
747 void close_cursor_handle(int handlerDB)
748 {
749    if(pthread_mutex_lock(&gMtx) == 0)
750    {
751       if(gFreeCursorHandleIdxHead < MaxPersHandle)
752       {
753          gFreeCursorHandleArray[gFreeCursorHandleIdxHead++] = handlerDB;
754       }
755       pthread_mutex_unlock(&gMtx);
756    }
757 }
758
759
760
761 int pers_db_cursor_create(char* dbPath)
762 {
763    int handle = -1;
764    itzam_state  state = ITZAM_FAILED;
765
766    handle = get_cursor_handle();
767
768    if(handle < MaxPersHandle && handle >= 0)
769    {
770       // open database
771       state = itzam_btree_open(&gCursorArray[handle].m_btree, dbPath, itzam_comparator_string, error_handler, 1/*recover*/, 0/*read_only*/);
772       if (state != ITZAM_OKAY)
773       {
774          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_create ==> itzam_btree_open"), DLT_STRING(STATE_MESSAGES[state]));
775       }
776       else
777       {
778          itzam_state  state;
779
780          state = itzam_btree_cursor_create(&gCursorArray[handle].m_cursor, &gCursorArray[handle].m_btree);
781          if(state == ITZAM_OKAY)
782          {
783             gCursorArray[handle].m_empty = 0;
784          }
785          else
786          {
787             gCursorArray[handle].m_empty = 1;
788          }
789       }
790    }
791    return handle;
792 }
793
794
795
796 int pers_db_cursor_next(unsigned int handlerDB)
797 {
798    int rval = -1;
799    //if(handlerDB < MaxPersHandle && handlerDB >= 0)
800    if(handlerDB < MaxPersHandle )
801    {
802       if(gCursorArray[handlerDB].m_empty != 1)
803       {
804          itzam_bool success;
805          success = itzam_btree_cursor_next(&gCursorArray[handlerDB].m_cursor);
806
807          if(success == itzam_true)
808          {
809             rval = 0;
810          }
811          else
812          {
813             rval = EPERS_LAST_ENTRY_IN_DB;
814          }
815       }
816       else
817       {
818          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_next ==> invalid handle: "), DLT_INT(handlerDB));
819       }
820    }
821    else
822    {
823       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_next ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
824    }
825    return rval;
826 }
827
828
829
830 int pers_db_cursor_get_key(unsigned int handlerDB, char * bufKeyName_out, int bufSize)
831 {
832    int rval = -1;
833    KeyValuePair_s search;
834
835    if(handlerDB < MaxPersHandle)
836    {
837       if(gCursorArray[handlerDB].m_empty != 1)
838       {
839          int length = 0;
840          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
841          length = strlen(search.m_key);
842          if(length < bufSize)
843          {
844             memcpy(bufKeyName_out, search.m_key, length);
845             rval = 0;
846          }
847          else
848          {
849             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_key  ==> buffer to small » keySize: "), DLT_INT(bufSize));
850          }
851       }
852       else
853       {
854          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_key  ==>  invalid handle:"), DLT_INT(handlerDB));
855       }
856    }
857    else
858    {
859       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_key ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
860    }
861    return rval;
862 }
863
864
865
866 int pers_db_cursor_get_data(unsigned int handlerDB, char * bufData_out, int bufSize)
867 {
868    int rval = -1;
869    KeyValuePair_s search;
870
871    if(handlerDB < MaxPersHandle)
872    {
873       if(gCursorArray[handlerDB].m_empty != 1)
874       {
875          int length = 0;
876          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
877
878          length = strlen(search.m_data);
879          if(length < bufSize)
880          {
881             memcpy(bufData_out, search.m_data, length);
882             rval = 0;
883          }
884          else
885          {
886             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_data  ==> buffer to small » keySize: "), DLT_INT(bufSize));
887          }
888       }
889       else
890       {
891          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data  ==>  invalid handle:"), DLT_INT(handlerDB));
892       }
893    }
894    else
895    {
896       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
897    }
898    return rval;
899 }
900
901
902
903 int pers_db_cursor_get_data_size(unsigned int handlerDB)
904 {
905    int size = -1;
906    KeyValuePair_s search;
907
908    if(handlerDB < MaxPersHandle)
909    {
910       if(gCursorArray[handlerDB].m_empty != 1)
911       {
912          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
913          size = strlen(search.m_data);
914       }
915       else
916       {
917          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_data_size  ==>  invalid handle:"), DLT_INT(handlerDB));
918       }
919    }
920    else
921    {
922       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data  ==>  handle bigger than max:"), DLT_INT(MaxPersHandle));
923    }
924    return size;
925 }
926
927
928
929 int pers_db_cursor_destroy(unsigned int handlerDB)
930 {
931    int rval = -1;
932    if(handlerDB < MaxPersHandle)
933    {
934       itzam_btree_cursor_free(&gCursorArray[handlerDB].m_cursor);
935       gCursorArray[handlerDB].m_empty = 1;
936
937       itzam_state state = ITZAM_FAILED;
938       state = itzam_btree_close(&gCursorArray[handlerDB].m_btree);
939       if (state != ITZAM_OKAY)
940       {
941             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_destroy  ==>  itzam_btree_close: Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
942       }
943
944       close_cursor_handle(handlerDB);
945
946       rval = 0;
947    }
948    return rval;
949 }
950
951
952
953
954 //-----------------------------------------------------------------------------
955 // code to print database content (for debugging)
956 //-----------------------------------------------------------------------------
957 // walk the database
958 /*
959 KeyValuePair_s  rec;
960 itzam_btree_cursor cursor;
961 state = itzam_btree_cursor_create(&cursor, &btree);
962 if(state == ITZAM_OKAY)
963 {
964   printf("==> Database content ==> db size: %d\n", (int)itzam_btree_count(&btree));
965   do
966   {
967      // get the key pointed to by the cursor
968      state = itzam_btree_cursor_read(&cursor,(void *)&rec);
969      if (state == ITZAM_OKAY)
970      {
971        printf("   Key: %s \n     ==> data: %s\n", rec.m_key, rec.m_data);
972      }
973      else
974         fprintf(stderr, "\nItzam problem: %s\n", STATE_MESSAGES[state]);
975   }
976   while (itzam_btree_cursor_next(&cursor));
977
978   state = itzam_btree_cursor_free(&cursor);
979 }
980 */
981 //-----------------------------------------------------------------------------
982
983
984
985
986