Added notifications for custom keys; added creat path function
[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                itzam_btree_transaction_commit(btree);
388                // transaction end
389                // -----------------------------------------------------------------------------
390
391                if(PersistenceStorage_shared == info->configKey.storage)
392                {
393                   write_size = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_changed);
394                }
395             }
396             else
397             {
398                DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> data to long » size:"), DLT_INT(dataSize), DLT_INT(DbValueSize) );
399                write_size = EPERS_DB_VALUE_SIZE;
400             }
401          }
402          else
403          {
404             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> key to long » size"), DLT_INT(keySize), DLT_INT(DbKeySize) );
405             write_size = EPERS_DB_KEY_SIZE;
406          }
407       }
408       else
409       {
410          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
411          write_size = EPERS_NOPRCTABLE;
412       }
413    }
414    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
415    {
416       int idx = custom_client_name_to_id(dbPath, 1);
417       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_set_data != NULL) )
418       {
419          char pathKeyString[128] = {0};
420          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
421          {
422             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
423          }
424          else
425          {
426             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
427          }
428          write_size = gPersCustomFuncs[idx].custom_plugin_set_data(pathKeyString, (char*)buffer, buffer_size);
429
430          if(write_size >= 0)  // success ==> send deleted notification
431          {
432             write_size = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_changed);
433          }
434       }
435       else
436       {
437          write_size = EPERS_NOPLUGINFUNCT;
438       }
439    }
440    return write_size;
441 }
442
443
444
445 int pers_db_get_key_size(char* dbPath, char* key, PersistenceInfo_s* info)
446 {
447    int read_size = -1;
448
449    if(   PersistenceStorage_shared == info->configKey.storage
450       || PersistenceStorage_local == info->configKey.storage)
451    {
452       int keySize = 0;
453       itzam_btree*  btree = NULL;
454       KeyValuePair_s search;
455
456       btree = pers_db_open(info, dbPath);
457       if(btree != NULL)
458       {
459          keySize = (int)strlen((const char*)key);
460          if(keySize < DbKeySize)
461          {
462             memset(search.m_key,0, DbKeySize);
463             memcpy(search.m_key, key, keySize);
464             if(itzam_true == itzam_btree_find(btree, key, &search))
465             {
466                read_size = search.m_data_size;
467             }
468             else
469             {
470                read_size = EPERS_NOKEY;
471             }
472          }
473          else
474          {
475             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_get_key_size ==> key to long"), DLT_INT(keySize), DLT_INT(DbKeySize));
476             read_size = EPERS_DB_KEY_SIZE;
477          }
478       }
479       else
480       {
481          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_get_key_size ==> no config table"), DLT_STRING(dbPath), DLT_STRING(key));
482          read_size = EPERS_NOPRCTABLE;
483       }
484    }
485    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
486    {
487       int idx = custom_client_name_to_id(dbPath, 1);
488       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_get_size != NULL) )
489       {
490          char pathKeyString[128] = {0};
491          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
492          {
493             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
494          }
495          else
496          {
497             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
498          }
499          read_size = gPersCustomFuncs[idx].custom_plugin_get_size(pathKeyString);
500       }
501       else
502       {
503          read_size = EPERS_NOPLUGINFUNCT;
504       }
505    }
506    return read_size;
507 }
508
509
510
511 int pers_db_delete_key(char* dbPath, char* key, PersistenceInfo_s* info)
512 {
513    int ret = 0;
514    if(PersistenceStorage_custom != info->configKey.storage)
515    {
516       itzam_btree*  btree = NULL;
517       KeyValuePair_s delete;
518
519       btree = pers_db_open(info, dbPath);
520       if(btree != NULL)
521       {
522          int keySize = 0;
523          keySize = (int)strlen((const char*)key);
524          if(keySize < DbKeySize)
525          {
526             // -----------------------------------------------------------------------------
527             // transaction start
528             itzam_btree_transaction_start(btree);
529
530             itzam_state  state;
531
532             memset(delete.m_key,0, DbKeySize);
533             memcpy(delete.m_key, key, keySize);
534             state = itzam_btree_remove(btree, (const void *)&delete);
535             if (state != ITZAM_OKAY)
536             {
537                DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_delete_key ==> itzam_btree_remove => Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
538                ret = EPERS_DB_ERROR_INTERNAL;
539             }
540             itzam_btree_transaction_commit(btree);
541             // transaction end
542             // -----------------------------------------------------------------------------
543
544             if(PersistenceStorage_shared == info->configKey.storage)
545             {
546                ret = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted);
547             }
548          }
549          else
550          {
551             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_delete_key ==> key to long"), DLT_INT(keySize), DLT_INT(DbKeySize));
552             ret = EPERS_DB_KEY_SIZE;
553          }
554       }
555       else
556       {
557          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_delete_key ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
558          ret = EPERS_NOPRCTABLE;
559       }
560    }
561    else   // custom storage implementation via custom library
562    {
563       int idx = custom_client_name_to_id(dbPath, 1);
564       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_delete_data != NULL) )
565       {
566          char pathKeyString[128] = {0};
567          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
568          {
569             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
570          }
571          else
572          {
573             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
574          }
575          ret = gPersCustomFuncs[idx].custom_plugin_delete_data(pathKeyString);
576          if(ret >= 0)   // success ==> send deleted notification
577          {
578             ret = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted);
579          }
580       }
581       else
582       {
583          ret = EPERS_NOPLUGINFUNCT;
584       }
585    }
586    return ret;
587 }
588
589
590 int persistence_notify_on_change(char* dbPath, char* key, unsigned int ldbid, unsigned int user_no, unsigned int seat_no,
591                                  pclChangeNotifyCallback_t callback, PersNotifyRegPolicy_e regPolicy)
592 {
593    int rval = 0;
594    char ruleChanged[DbusMatchRuleSize];
595    char ruleDeleted[DbusMatchRuleSize];
596    char ruleCreated[DbusMatchRuleSize];
597    DBusConnection* conn = get_dbus_connection();
598
599    // add match for  c h a n g e
600    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'",
601             key, ldbid, user_no, seat_no);
602    // add match for  d e l e t e
603    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'",
604             key, ldbid, user_no, seat_no);
605    // add match for  c r e a t e
606    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'",
607             key, ldbid, user_no, seat_no);
608
609    if(regPolicy == Notify_register)
610    {
611       // assign callback
612       gChangeNotifyCallback = callback;
613
614       dbus_bus_add_match(conn, ruleChanged, NULL);
615       dbus_bus_add_match(conn, ruleDeleted, NULL);
616       dbus_bus_add_match(conn, ruleCreated, NULL);
617    }
618    else if(regPolicy == Notify_unregister)
619    {
620       // remove callback
621       gChangeNotifyCallback = NULL;
622
623       dbus_bus_remove_match(conn, ruleChanged, NULL);
624       dbus_bus_remove_match(conn, ruleDeleted, NULL);
625       dbus_bus_remove_match(conn, ruleCreated, NULL);
626    }
627
628    dbus_connection_flush(conn);  // flush the connection to add the match
629
630    return rval;
631 }
632
633
634 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, pclNotifyStatus_e reason)
635 {
636    DBusMessage* message;
637    dbus_bool_t ret;
638    int rval = 0;
639    char ldbid_array[DbusSubMatchSize] = {0};
640    char user_array[DbusSubMatchSize]  = {0};
641    char seat_array[DbusSubMatchSize]  = {0};
642    const char* ldbid_ptr = ldbid_array;
643    const char* user_ptr = user_array;
644    const char* seat_ptr = seat_array;
645
646    char* changeSignal = "PersistenceResChange";
647    char* deleteSignal = "PersistenceResDelete";
648    char* createSignal = "PersistenceResCreate";
649    char* theReason = NULL;
650
651    DBusConnection* conn = get_dbus_connection();
652
653
654    // dbus_bus_add_match is used for the notification mechanism,
655    // and this works only for type DBUS_TYPE_STRING as message arguments
656    // this is the reason to use string instead of integer types directly
657    snprintf(ldbid_array, DbusSubMatchSize, "%d", context->ldbid);
658    snprintf(user_array,  DbusSubMatchSize, "%d", context->user_no);
659    snprintf(seat_array,  DbusSubMatchSize, "%d", context->seat_no);
660
661    switch(reason)
662    {
663       case pclNotifyStatus_deleted:
664          theReason = deleteSignal;
665          break;
666       case  pclNotifyStatus_created:
667          theReason = createSignal;
668          break;
669       case pclNotifyStatus_changed:
670          theReason = changeSignal;
671          break;
672       default:
673          theReason = changeSignal;
674          break;
675    }
676
677    if(theReason != NULL)
678    {
679       message = dbus_message_new_signal("/org/genivi/persistence/adminconsumer",    // const char *path,
680                                         "org.genivi.persistence.adminconsumer",     // const char *interface,
681                                         theReason);                                 // const char *name
682
683       ret = dbus_message_append_args(message,
684                                DBUS_TYPE_STRING, &key,
685                                DBUS_TYPE_STRING, &ldbid_ptr,
686                                DBUS_TYPE_STRING, &user_ptr,
687                                DBUS_TYPE_STRING, &seat_ptr,
688                                DBUS_TYPE_INVALID);
689       if(ret == TRUE)
690       {
691          // Send the signal
692          if(conn != NULL)
693          {
694             if(dbus_connection_send(conn, message, 0) == TRUE)
695             {
696                // Free the signal now we have finished with it
697                dbus_message_unref(message);
698             }
699             else
700             {
701                rval = EPERS_NOTIFY_SIG;
702             }
703          }
704          else
705          {
706             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!!"));
707          }
708       }
709       else
710       {
711          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_send_Notification_Signal ==> ERROR dbus_message_append_args"));
712          rval = EPERS_NOTIFY_SIG;
713       }
714    }
715    else
716    {
717       rval = EPERS_NOTIFY_SIG;
718    }
719
720    return rval;
721 }
722
723
724 //---------------------------------------------------------------------------------------------------------
725 // C U R S O R    F U N C T I O N S
726 //---------------------------------------------------------------------------------------------------------
727
728 int get_cursor_handle()
729 {
730    int handle = 0;
731
732    if(pthread_mutex_lock(&gMtx) == 0)
733    {
734       if(gFreeCursorHandleIdxHead > 0)   // check if we have a free spot in the array before the current max
735       {
736          handle = gFreeCursorHandleArray[--gFreeCursorHandleIdxHead];
737       }
738       else
739       {
740          if(gHandleIdx < MaxPersHandle-1)
741          {
742             handle = gHandleIdx++;  // no free spot before current max, increment handle index
743          }
744          else
745          {
746             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("get_cursor_handle ==> Reached maximum of open handles:"), DLT_INT(MaxPersHandle));
747             handle = -1;
748          }
749       }
750       pthread_mutex_unlock(&gMtx);
751    }
752    return handle;
753 }
754
755
756 void close_cursor_handle(int handlerDB)
757 {
758    if(pthread_mutex_lock(&gMtx) == 0)
759    {
760       if(gFreeCursorHandleIdxHead < MaxPersHandle)
761       {
762          gFreeCursorHandleArray[gFreeCursorHandleIdxHead++] = handlerDB;
763       }
764       pthread_mutex_unlock(&gMtx);
765    }
766 }
767
768
769
770 int pers_db_cursor_create(char* dbPath)
771 {
772    int handle = -1;
773    itzam_state  state = ITZAM_FAILED;
774
775    handle = get_cursor_handle();
776
777    if(handle < MaxPersHandle && handle >= 0)
778    {
779       // open database
780       state = itzam_btree_open(&gCursorArray[handle].m_btree, dbPath, itzam_comparator_string, error_handler, 1/*recover*/, 0/*read_only*/);
781       if (state != ITZAM_OKAY)
782       {
783          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_create ==> itzam_btree_open"), DLT_STRING(STATE_MESSAGES[state]));
784       }
785       else
786       {
787          itzam_state  state;
788
789          state = itzam_btree_cursor_create(&gCursorArray[handle].m_cursor, &gCursorArray[handle].m_btree);
790          if(state == ITZAM_OKAY)
791          {
792             gCursorArray[handle].m_empty = 0;
793          }
794          else
795          {
796             gCursorArray[handle].m_empty = 1;
797          }
798       }
799    }
800    return handle;
801 }
802
803
804
805 int pers_db_cursor_next(unsigned int handlerDB)
806 {
807    int rval = -1;
808    //if(handlerDB < MaxPersHandle && handlerDB >= 0)
809    if(handlerDB < MaxPersHandle )
810    {
811       if(gCursorArray[handlerDB].m_empty != 1)
812       {
813          itzam_bool success;
814          success = itzam_btree_cursor_next(&gCursorArray[handlerDB].m_cursor);
815
816          if(success == itzam_true)
817          {
818             rval = 0;
819          }
820          else
821          {
822             rval = EPERS_LAST_ENTRY_IN_DB;
823          }
824       }
825       else
826       {
827          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_next ==> invalid handle: "), DLT_INT(handlerDB));
828       }
829    }
830    else
831    {
832       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_next ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
833    }
834    return rval;
835 }
836
837
838
839 int pers_db_cursor_get_key(unsigned int handlerDB, char * bufKeyName_out, int bufSize)
840 {
841    int rval = -1;
842    KeyValuePair_s search;
843
844    if(handlerDB < MaxPersHandle)
845    {
846       if(gCursorArray[handlerDB].m_empty != 1)
847       {
848          int length = 0;
849          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
850          length = strlen(search.m_key);
851          if(length < bufSize)
852          {
853             memcpy(bufKeyName_out, search.m_key, length);
854             rval = 0;
855          }
856          else
857          {
858             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_key  ==> buffer to small » keySize: "), DLT_INT(bufSize));
859          }
860       }
861       else
862       {
863          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_key  ==>  invalid handle:"), DLT_INT(handlerDB));
864       }
865    }
866    else
867    {
868       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_key ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
869    }
870    return rval;
871 }
872
873
874
875 int pers_db_cursor_get_data(unsigned int handlerDB, char * bufData_out, int bufSize)
876 {
877    int rval = -1;
878    KeyValuePair_s search;
879
880    if(handlerDB < MaxPersHandle)
881    {
882       if(gCursorArray[handlerDB].m_empty != 1)
883       {
884          int length = 0;
885          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
886
887          length = strlen(search.m_data);
888          if(length < bufSize)
889          {
890             memcpy(bufData_out, search.m_data, length);
891             rval = 0;
892          }
893          else
894          {
895             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_data  ==> buffer to small » keySize: "), DLT_INT(bufSize));
896          }
897       }
898       else
899       {
900          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data  ==>  invalid handle:"), DLT_INT(handlerDB));
901       }
902    }
903    else
904    {
905       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
906    }
907    return rval;
908 }
909
910
911
912 int pers_db_cursor_get_data_size(unsigned int handlerDB)
913 {
914    int size = -1;
915    KeyValuePair_s search;
916
917    if(handlerDB < MaxPersHandle)
918    {
919       if(gCursorArray[handlerDB].m_empty != 1)
920       {
921          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
922          size = strlen(search.m_data);
923       }
924       else
925       {
926          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_data_size  ==>  invalid handle:"), DLT_INT(handlerDB));
927       }
928    }
929    else
930    {
931       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data  ==>  handle bigger than max:"), DLT_INT(MaxPersHandle));
932    }
933    return size;
934 }
935
936
937
938 int pers_db_cursor_destroy(unsigned int handlerDB)
939 {
940    int rval = -1;
941    if(handlerDB < MaxPersHandle)
942    {
943       itzam_btree_cursor_free(&gCursorArray[handlerDB].m_cursor);
944       gCursorArray[handlerDB].m_empty = 1;
945
946       itzam_state state = ITZAM_FAILED;
947       state = itzam_btree_close(&gCursorArray[handlerDB].m_btree);
948       if (state != ITZAM_OKAY)
949       {
950             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_destroy  ==>  itzam_btree_close: Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
951       }
952
953       close_cursor_handle(handlerDB);
954
955       rval = 0;
956    }
957    return rval;
958 }
959
960
961
962
963 //-----------------------------------------------------------------------------
964 // code to print database content (for debugging)
965 //-----------------------------------------------------------------------------
966 // walk the database
967 /*
968 KeyValuePair_s  rec;
969 itzam_btree_cursor cursor;
970 state = itzam_btree_cursor_create(&cursor, &btree);
971 if(state == ITZAM_OKAY)
972 {
973   printf("==> Database content ==> db size: %d\n", (int)itzam_btree_count(&btree));
974   do
975   {
976      // get the key pointed to by the cursor
977      state = itzam_btree_cursor_read(&cursor,(void *)&rec);
978      if (state == ITZAM_OKAY)
979      {
980        printf("   Key: %s \n     ==> data: %s\n", rec.m_key, rec.m_data);
981      }
982      else
983         fprintf(stderr, "\nItzam problem: %s\n", STATE_MESSAGES[state]);
984   }
985   while (itzam_btree_cursor_next(&cursor));
986
987   state = itzam_btree_cursor_free(&cursor);
988 }
989 */
990 //-----------------------------------------------------------------------------
991
992
993
994
995