Static code analysis findings; mutex rework
[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 #include <errno.h>
32
33
34 /// definition of a key-value pair stored in the database
35 typedef struct _KeyValuePair_s
36 {
37     char m_key[DbKeySize];    /// the key
38     char m_data[DbValueSize];    /// the data
39     unsigned int m_data_size;   /// the size of the data
40 }
41 KeyValuePair_s;
42
43
44 // definition of a cursor entry
45 typedef struct _CursorEntry_s
46 {
47    itzam_btree_cursor m_cursor;
48    itzam_btree        m_btree;
49    int                m_empty;
50 }
51 CursorEntry_s;
52
53 // cursor array handle
54 CursorEntry_s gCursorArray[MaxPersHandle];
55
56 /// handle index
57 static int gHandleIdx = 1;
58
59 /// free handle array
60 int gFreeCursorHandleArray[MaxPersHandle];
61 // free head index
62 int gFreeCursorHandleIdxHead = 0;
63
64 // mutex to controll access to the cursor array
65 pthread_mutex_t gMtx = PTHREAD_MUTEX_INITIALIZER;
66
67
68 /// btree array
69 static itzam_btree gBtree[DbTableSize][PersistencePolicy_LastEntry];
70 static int gBtreeCreated[DbTableSize][PersistencePolicy_LastEntry] = { {0} };
71
72
73 // function prototype
74 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, unsigned int reason);
75 int pers_get_default_data(char* dbPath, char* key, char* buffer, unsigned int buffer_size);
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       int keyFound = 0;
221       itzam_state  state = ITZAM_FAILED;
222
223       btree = pers_db_open(info, dbPath);
224       if(btree != NULL)
225       {
226          KeyValuePair_s search;
227
228          if(itzam_true == itzam_btree_find(btree, key, &search))
229          {
230             read_size = search.m_data_size;
231             if(read_size > buffer_size)
232             {
233                read_size = buffer_size;   // truncate data size to buffer size
234             }
235             memcpy(buffer, search.m_data, read_size);
236             keyFound = 1;
237          }
238       }
239       if(keyFound == 0) // check for default values.
240       {
241          read_size = pers_get_default_data(dbPath, key, buffer, buffer_size);
242       }
243    }
244    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
245    {
246       int idx =  custom_client_name_to_id(dbPath, 1);
247       char workaroundPath[128];  // workaround, because /sys/ can not be accessed on host!!!!
248       snprintf(workaroundPath, 128, "%s%s", "/Data", dbPath  );
249
250       if( (idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_get_data != NULL) )
251       {
252          char pathKeyString[128] = {0};
253          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
254          {
255             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
256          }
257          else
258          {
259             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
260          }
261          read_size = gPersCustomFuncs[idx].custom_plugin_get_data(pathKeyString, (char*)buffer, buffer_size);
262
263          if(read_size < 0) // check if for custom storage default values are available
264          {
265             read_size = pers_get_default_data(dbPath, key, buffer, buffer_size);
266          }
267       }
268       else
269       {
270          read_size = EPERS_NOPLUGINFUNCT;
271       }
272    }
273    return read_size;
274 }
275
276
277
278 int pers_get_default_data(char* dbPath, char* key, char* buffer, unsigned int buffer_size)
279 {
280    int keyFound = 0;
281    int read_size = 0;
282    KeyValuePair_s search;
283
284    itzam_state  state = ITZAM_FAILED;
285    itzam_btree btreeConfDefault;
286    itzam_btree btreeDefault;
287
288    // 1. check if _configurable_ default data is available
289    // --------------------------------
290    if(pers_db_open_default(&btreeConfDefault, dbPath, 1) != -1)
291    {
292       if(itzam_true == itzam_btree_find(&btreeConfDefault, key, &search)) // read db
293       {
294          read_size = search.m_data_size;
295          if(read_size > buffer_size)
296          {
297             read_size = buffer_size;   // truncate data size to buffer size
298          }
299          memcpy(buffer, search.m_data, read_size);
300
301          keyFound = 1;
302       }
303       else
304       {
305          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));
306       }
307
308       state = itzam_btree_close(&btreeConfDefault);
309       if (state != ITZAM_OKAY)
310       {
311          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_read_key ==> default: itzam_btree_close => Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
312       }
313    }
314
315    // 2. check if default data is available
316    // --------------------------------
317    if(keyFound == 0)
318    {
319       if(pers_db_open_default(&btreeDefault, dbPath, 0) != -1)
320       {
321          if(itzam_true == itzam_btree_find(&btreeDefault, key, &search)) // read db
322          {
323             read_size = search.m_data_size;
324             if(read_size > buffer_size)
325             {
326                read_size = buffer_size;   // truncate data size to buffer size
327             }
328             memcpy(buffer, search.m_data, read_size);
329          }
330          else
331          {
332             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_read_key ==> 3. reasoure not found in both default db's"), DLT_STRING(key) );
333             read_size = EPERS_NOKEY;   // the key is not available neither in regular db nor in the default db's
334          }
335
336          state = itzam_btree_close(&btreeDefault);
337          if (state != ITZAM_OKAY)
338          {
339             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_read_key ==> default: itzam_btree_close => Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
340          }
341       }
342       else
343       {
344          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_read_key ==>no resource config table"), DLT_STRING(dbPath), DLT_STRING(key) );
345          read_size = EPERS_NOPRCTABLE;
346       }
347    }
348    return read_size;
349 }
350
351
352
353 int pers_db_write_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
354 {
355    int write_size = -1;
356
357    if(   PersistenceStorage_local == info->configKey.storage
358       || PersistenceStorage_shared == info->configKey.storage )
359    {
360       write_size = buffer_size;
361       itzam_btree* btree = NULL;
362       itzam_state  state = ITZAM_FAILED;
363       KeyValuePair_s insert;
364
365       btree = pers_db_open(info, dbPath);
366       if(btree != NULL)
367       {
368          int keySize = 0;
369          keySize = (int)strlen((const char*)key);
370          if(keySize < DbKeySize)
371          {
372             int dataSize = 0;
373             dataSize = (int)strlen( (const char*)buffer);
374             if(dataSize < DbValueSize)
375             {
376                // -----------------------------------------------------------------------------
377                // transaction start
378                itzam_btree_transaction_start(btree);
379
380                // key
381                memset(insert.m_key, 0, DbKeySize);
382                memcpy(insert.m_key, key, keySize);
383                if(itzam_true == itzam_btree_find(btree, key, &insert))
384                {
385                   // key already available, so delete "old" key
386                   state = itzam_btree_remove(btree, (const void *)&insert);
387                }
388
389                // data
390                memset(insert.m_data, 0, DbValueSize);
391                memcpy(insert.m_data, buffer, dataSize);
392
393                // data size
394                insert.m_data_size = buffer_size;
395
396                state = itzam_btree_insert(btree,(const void *)&insert);
397                if (state != ITZAM_OKAY)
398                {
399                   DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> itzam_btree_insert => Itzam problem"), DLT_STRING(STATE_MESSAGES[state]) );
400                   write_size = EPERS_DB_ERROR_INTERNAL;
401                }
402
403                itzam_btree_transaction_commit(btree);
404                // transaction end
405                // -----------------------------------------------------------------------------
406
407                if(PersistenceStorage_shared == info->configKey.storage)
408                {
409                   write_size = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_changed);
410                }
411             }
412             else
413             {
414                DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> data to long » size:"), DLT_INT(dataSize), DLT_INT(DbValueSize) );
415                write_size = EPERS_DB_VALUE_SIZE;
416             }
417          }
418          else
419          {
420             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> key to long » size"), DLT_INT(keySize), DLT_INT(DbKeySize) );
421             write_size = EPERS_DB_KEY_SIZE;
422          }
423       }
424       else
425       {
426          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_write_key ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
427          write_size = EPERS_NOPRCTABLE;
428       }
429    }
430    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
431    {
432       int idx = custom_client_name_to_id(dbPath, 1);
433       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_set_data != NULL) )
434       {
435          char pathKeyString[128] = {0};
436          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
437          {
438             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
439          }
440          else
441          {
442             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
443          }
444          write_size = gPersCustomFuncs[idx].custom_plugin_set_data(pathKeyString, (char*)buffer, buffer_size);
445
446          if(write_size >= 0)  // success ==> send deleted notification
447          {
448             write_size = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_changed);
449          }
450       }
451       else
452       {
453          write_size = EPERS_NOPLUGINFUNCT;
454       }
455    }
456    return write_size;
457 }
458
459
460
461 int pers_db_get_key_size(char* dbPath, char* key, PersistenceInfo_s* info)
462 {
463    int read_size = -1;
464
465    if(   PersistenceStorage_shared == info->configKey.storage
466       || PersistenceStorage_local == info->configKey.storage)
467    {
468       int keySize = 0;
469       itzam_btree*  btree = NULL;
470       KeyValuePair_s search;
471
472       btree = pers_db_open(info, dbPath);
473       if(btree != NULL)
474       {
475          keySize = (int)strlen((const char*)key);
476          if(keySize < DbKeySize)
477          {
478             memset(search.m_key,0, DbKeySize);
479             memcpy(search.m_key, key, keySize);
480             if(itzam_true == itzam_btree_find(btree, key, &search))
481             {
482                read_size = search.m_data_size;
483             }
484             else
485             {
486                read_size = EPERS_NOKEY;
487             }
488          }
489          else
490          {
491             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_get_key_size ==> key to long"), DLT_INT(keySize), DLT_INT(DbKeySize));
492             read_size = EPERS_DB_KEY_SIZE;
493          }
494       }
495       else
496       {
497          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_get_key_size ==> no config table"), DLT_STRING(dbPath), DLT_STRING(key));
498          read_size = EPERS_NOPRCTABLE;
499       }
500    }
501    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
502    {
503       int idx = custom_client_name_to_id(dbPath, 1);
504       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_get_size != NULL) )
505       {
506          char pathKeyString[128] = {0};
507          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
508          {
509             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
510          }
511          else
512          {
513             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
514          }
515          read_size = gPersCustomFuncs[idx].custom_plugin_get_size(pathKeyString);
516       }
517       else
518       {
519          read_size = EPERS_NOPLUGINFUNCT;
520       }
521    }
522    return read_size;
523 }
524
525
526
527 int pers_db_delete_key(char* dbPath, char* key, PersistenceInfo_s* info)
528 {
529    int ret = 0;
530    if(PersistenceStorage_custom != info->configKey.storage)
531    {
532       itzam_btree*  btree = NULL;
533       KeyValuePair_s delete;
534
535       btree = pers_db_open(info, dbPath);
536       if(btree != NULL)
537       {
538          int keySize = 0;
539          keySize = (int)strlen((const char*)key);
540          if(keySize < DbKeySize)
541          {
542             // -----------------------------------------------------------------------------
543             // transaction start
544             itzam_btree_transaction_start(btree);
545
546             itzam_state  state;
547
548             memset(delete.m_key,0, DbKeySize);
549             memcpy(delete.m_key, key, keySize);
550             state = itzam_btree_remove(btree, (const void *)&delete);
551             if (state != ITZAM_OKAY)
552             {
553                DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_delete_key ==> itzam_btree_remove => Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
554                ret = EPERS_DB_ERROR_INTERNAL;
555             }
556             itzam_btree_transaction_commit(btree);
557             // transaction end
558             // -----------------------------------------------------------------------------
559
560             if(PersistenceStorage_shared == info->configKey.storage)
561             {
562                ret = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted);
563             }
564          }
565          else
566          {
567             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_delete_key ==> key to long"), DLT_INT(keySize), DLT_INT(DbKeySize));
568             ret = EPERS_DB_KEY_SIZE;
569          }
570       }
571       else
572       {
573          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_delete_key ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
574          ret = EPERS_NOPRCTABLE;
575       }
576    }
577    else   // custom storage implementation via custom library
578    {
579       int idx = custom_client_name_to_id(dbPath, 1);
580       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_delete_data != NULL) )
581       {
582          char pathKeyString[128] = {0};
583          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
584          {
585             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
586          }
587          else
588          {
589             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
590          }
591          ret = gPersCustomFuncs[idx].custom_plugin_delete_data(pathKeyString);
592          if(ret >= 0)   // success ==> send deleted notification
593          {
594             ret = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted);
595          }
596       }
597       else
598       {
599          ret = EPERS_NOPLUGINFUNCT;
600       }
601    }
602    return ret;
603 }
604
605
606 int persistence_notify_on_change(char* key, unsigned int ldbid, unsigned int user_no, unsigned int seat_no,
607                                  pclChangeNotifyCallback_t callback, PersNotifyRegPolicy_e regPolicy)
608 {
609    int rval = 0;
610
611    if(regPolicy < Notify_lastEntry)
612    {
613       snprintf(gNotifykey, DbKeyMaxLen, "%s", key);
614       gNotifyLdbid  = ldbid;     // to do: pass correct ==> JUST TESTING!!!!
615       gNotifyUserNo = user_no;
616       gNotifySeatNo = seat_no;
617       gNotifyReason = regPolicy;
618
619       if(regPolicy == Notify_register)
620       {
621          // assign callback
622          gChangeNotifyCallback = callback;
623       }
624       else if(regPolicy == Notify_unregister)
625       {
626          // remove callback
627          gChangeNotifyCallback = NULL;
628       }
629
630       if(-1 == deliverToMainloop(CMD_REG_NOTIFY_SIGNAL, 0, 0))
631       {
632          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_notify_on_change => failed to write to pipe"), DLT_INT(errno));
633          rval = -1;
634       }
635    }
636    else
637    {
638       rval = -1;
639    }
640
641    return rval;
642 }
643
644
645
646
647
648
649 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, pclNotifyStatus_e reason)
650 {
651    int rval = 1;
652    if(reason < pclNotifyStatus_lastEntry)
653    {
654       snprintf(gNotifykey,  DbKeyMaxLen,       "%s", key);
655
656       gNotifyLdbid  = context->ldbid;     // to do: pass correct ==> JUST TESTING!!!!
657       gNotifyUserNo = context->user_no;
658       gNotifySeatNo = context->seat_no;
659       gNotifyReason = reason;
660
661       if(-1 == deliverToMainloop(CMD_SEND_NOTIFY_SIGNAL, 0,0) )
662       {
663          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_send_Notification_Signal => failed to write to pipe"), DLT_INT(errno));
664          rval = EPERS_NOTIFY_SIG;
665       }
666    }
667    else
668    {
669       rval = EPERS_NOTIFY_SIG;
670    }
671
672    return rval;
673 }
674
675
676 //---------------------------------------------------------------------------------------------------------
677 // C U R S O R    F U N C T I O N S
678 //---------------------------------------------------------------------------------------------------------
679
680 int get_cursor_handle()
681 {
682    int handle = 0;
683
684    if(pthread_mutex_lock(&gMtx) == 0)
685    {
686       if(gFreeCursorHandleIdxHead > 0)   // check if we have a free spot in the array before the current max
687       {
688          handle = gFreeCursorHandleArray[--gFreeCursorHandleIdxHead];
689       }
690       else
691       {
692          if(gHandleIdx < MaxPersHandle-1)
693          {
694             handle = gHandleIdx++;  // no free spot before current max, increment handle index
695          }
696          else
697          {
698             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("get_cursor_handle ==> Reached maximum of open handles:"), DLT_INT(MaxPersHandle));
699             handle = -1;
700          }
701       }
702       pthread_mutex_unlock(&gMtx);
703    }
704    return handle;
705 }
706
707
708 void close_cursor_handle(int handlerDB)
709 {
710    if(pthread_mutex_lock(&gMtx) == 0)
711    {
712       if(gFreeCursorHandleIdxHead < MaxPersHandle)
713       {
714          gFreeCursorHandleArray[gFreeCursorHandleIdxHead++] = handlerDB;
715       }
716       pthread_mutex_unlock(&gMtx);
717    }
718 }
719
720
721
722 int pers_db_cursor_create(char* dbPath)
723 {
724    int handle = -1;
725    itzam_state  state = ITZAM_FAILED;
726
727    handle = get_cursor_handle();
728
729    if(handle < MaxPersHandle && handle >= 0)
730    {
731       // open database
732       state = itzam_btree_open(&gCursorArray[handle].m_btree, dbPath, itzam_comparator_string, error_handler, 1/*recover*/, 0/*read_only*/);
733       if (state != ITZAM_OKAY)
734       {
735          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_create ==> itzam_btree_open"), DLT_STRING(STATE_MESSAGES[state]));
736       }
737       else
738       {
739          itzam_state  state;
740
741          state = itzam_btree_cursor_create(&gCursorArray[handle].m_cursor, &gCursorArray[handle].m_btree);
742          if(state == ITZAM_OKAY)
743          {
744             gCursorArray[handle].m_empty = 0;
745          }
746          else
747          {
748             gCursorArray[handle].m_empty = 1;
749          }
750       }
751    }
752    return handle;
753 }
754
755
756
757 int pers_db_cursor_next(unsigned int handlerDB)
758 {
759    int rval = -1;
760    //if(handlerDB < MaxPersHandle && handlerDB >= 0)
761    if(handlerDB < MaxPersHandle )
762    {
763       if(gCursorArray[handlerDB].m_empty != 1)
764       {
765          itzam_bool success;
766          success = itzam_btree_cursor_next(&gCursorArray[handlerDB].m_cursor);
767
768          if(success == itzam_true)
769          {
770             rval = 0;
771          }
772          else
773          {
774             rval = EPERS_LAST_ENTRY_IN_DB;
775          }
776       }
777       else
778       {
779          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_next ==> invalid handle: "), DLT_INT(handlerDB));
780       }
781    }
782    else
783    {
784       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_next ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
785    }
786    return rval;
787 }
788
789
790
791 int pers_db_cursor_get_key(unsigned int handlerDB, char * bufKeyName_out, int bufSize)
792 {
793    int rval = -1;
794    KeyValuePair_s search;
795
796    if(handlerDB < MaxPersHandle)
797    {
798       if(gCursorArray[handlerDB].m_empty != 1)
799       {
800          int length = 0;
801          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
802          length = strlen(search.m_key);
803          if(length < bufSize)
804          {
805             memcpy(bufKeyName_out, search.m_key, length);
806             rval = 0;
807          }
808          else
809          {
810             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_key  ==> buffer to small » keySize: "), DLT_INT(bufSize));
811          }
812       }
813       else
814       {
815          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_key  ==>  invalid handle:"), DLT_INT(handlerDB));
816       }
817    }
818    else
819    {
820       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_key ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
821    }
822    return rval;
823 }
824
825
826
827 int pers_db_cursor_get_data(unsigned int handlerDB, char * bufData_out, int bufSize)
828 {
829    int rval = -1;
830    KeyValuePair_s search;
831
832    if(handlerDB < MaxPersHandle)
833    {
834       if(gCursorArray[handlerDB].m_empty != 1)
835       {
836          int length = 0;
837          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
838
839          length = strlen(search.m_data);
840          if(length < bufSize)
841          {
842             memcpy(bufData_out, search.m_data, length);
843             rval = 0;
844          }
845          else
846          {
847             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_data  ==> buffer to small » keySize: "), DLT_INT(bufSize));
848          }
849       }
850       else
851       {
852          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data  ==>  invalid handle:"), DLT_INT(handlerDB));
853       }
854    }
855    else
856    {
857       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data ==> handle bigger than max:"), DLT_INT(MaxPersHandle));
858    }
859    return rval;
860 }
861
862
863
864 int pers_db_cursor_get_data_size(unsigned int handlerDB)
865 {
866    int size = -1;
867    KeyValuePair_s search;
868
869    if(handlerDB < MaxPersHandle)
870    {
871       if(gCursorArray[handlerDB].m_empty != 1)
872       {
873          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
874          size = strlen(search.m_data);
875       }
876       else
877       {
878          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_get_data_size  ==>  invalid handle:"), DLT_INT(handlerDB));
879       }
880    }
881    else
882    {
883       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_db_cursor_get_data  ==>  handle bigger than max:"), DLT_INT(MaxPersHandle));
884    }
885    return size;
886 }
887
888
889
890 int pers_db_cursor_destroy(unsigned int handlerDB)
891 {
892    int rval = -1;
893    if(handlerDB < MaxPersHandle)
894    {
895       itzam_btree_cursor_free(&gCursorArray[handlerDB].m_cursor);
896       gCursorArray[handlerDB].m_empty = 1;
897
898       itzam_state state = ITZAM_FAILED;
899       state = itzam_btree_close(&gCursorArray[handlerDB].m_btree);
900       if (state != ITZAM_OKAY)
901       {
902             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_cursor_destroy  ==>  itzam_btree_close: Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
903       }
904
905       close_cursor_handle(handlerDB);
906
907       rval = 0;
908    }
909    return rval;
910 }
911
912
913
914
915 //-----------------------------------------------------------------------------
916 // code to print database content (for debugging)
917 //-----------------------------------------------------------------------------
918 // walk the database
919 /*
920 KeyValuePair_s  rec;
921 itzam_btree_cursor cursor;
922 state = itzam_btree_cursor_create(&cursor, &btree);
923 if(state == ITZAM_OKAY)
924 {
925   printf("==> Database content ==> db size: %d\n", (int)itzam_btree_count(&btree));
926   do
927   {
928      // get the key pointed to by the cursor
929      state = itzam_btree_cursor_read(&cursor,(void *)&rec);
930      if (state == ITZAM_OKAY)
931      {
932        printf("   Key: %s \n     ==> data: %s\n", rec.m_key, rec.m_data);
933      }
934      else
935         fprintf(stderr, "\nItzam problem: %s\n", STATE_MESSAGES[state]);
936   }
937   while (itzam_btree_cursor_next(&cursor));
938
939   state = itzam_btree_cursor_free(&cursor);
940 }
941 */
942 //-----------------------------------------------------------------------------
943
944
945
946
947