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