Improved quality, by fixing issues detected by Coverity Scan:
[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 <string.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29
30 /// definition of a key-value pair stored in the database
31 typedef struct _KeyValuePair_s
32 {
33     char m_key[DbKeySize];       /// the key
34     char m_data[DbValueSize];    /// the data
35     unsigned int m_data_size;   /// the size of the data
36 }
37 KeyValuePair_s;
38
39
40 // definition of a cursor entry
41 typedef struct _CursorEntry_s
42 {
43    itzam_btree_cursor m_cursor;
44    itzam_btree        m_btree;
45    int                m_empty;
46 }
47 CursorEntry_s;
48
49 // cursor array handle
50 CursorEntry_s gCursorArray[MaxPersHandle];
51
52 /// handle index
53 static int gHandleIdx = 1;
54
55 /// free handle array
56 int gFreeCursorHandleArray[MaxPersHandle];
57 // free head index
58 int gFreeCursorHandleIdxHead = 0;
59
60 // mutex to controll access to the cursor array
61 pthread_mutex_t gMtx = PTHREAD_MUTEX_INITIALIZER;
62
63
64 /// btree array
65 static itzam_btree gBtree[DbTableSize][PersistencePolicy_LastEntry];
66 static int gBtreeCreated[DbTableSize][PersistencePolicy_LastEntry] = { {0} };
67
68
69 itzam_btree* pers_db_open(PersistenceInfo_s* info, const char* dbPath)
70 {
71    int arrayIdx = 0;
72    itzam_btree* btree = NULL;
73
74    // create array index: index is a combination of resource config table type and group
75    arrayIdx = info->configKey.storage + info->context.ldbid ;
76
77    //if(arrayIdx <= DbTableSize)
78    if(arrayIdx < DbTableSize)
79    {
80       if(gBtreeCreated[arrayIdx][info->configKey.policy] == 0)
81       {
82          itzam_state  state = ITZAM_FAILED;
83          state = itzam_btree_open(&gBtree[arrayIdx][info->configKey.policy], dbPath,
84                                   itzam_comparator_string, error_handler, 0/*recover*/, 0/*read_only*/);
85          if (state != ITZAM_OKAY)
86          {
87             fprintf(stderr, "pers_db_open ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
88          }
89          gBtreeCreated[arrayIdx][info->configKey.policy] = 1;
90       }
91       // assign database
92       btree = &gBtree[arrayIdx][info->configKey.policy];
93    }
94    else
95    {
96       printf("btree_get ==> invalid storage type\n");
97    }
98    return btree;
99 }
100
101
102
103 void pers_db_close(PersistenceInfo_s* info)
104 {
105    int arrayIdx = info->configKey.storage + info->context.ldbid;
106
107    if(info->configKey.storage <= PersistenceStorage_shared )
108    {
109       itzam_state  state = ITZAM_FAILED;
110       state = itzam_btree_close(&gBtree[arrayIdx][info->configKey.policy]);
111       if (state != ITZAM_OKAY)
112       {
113          fprintf(stderr, "pers_db_close ==> Close Itzam problem: %s\n", STATE_MESSAGES[state]);
114       }
115       gBtreeCreated[arrayIdx][info->configKey.policy] = 0;
116    }
117    else
118    {
119       printf("pers_db_close ==> invalid storage type\n");
120    }
121 }
122
123
124
125 void pers_db_close_all()
126 {
127    int i = 0;
128
129    for(i=0; i<DbTableSize; i++)
130    {
131       // close write cached database
132       if(gBtreeCreated[i][PersistencePolicy_wc] == 1)
133       {
134          itzam_state  state = ITZAM_FAILED;
135          state = itzam_btree_close(&gBtree[i][PersistencePolicy_wc]);
136          if (state != ITZAM_OKAY)
137          {
138             fprintf(stderr, "pers_db_close_all ==> Close WC: Itzam problem: %s\n", STATE_MESSAGES[state]);
139          }
140          gBtreeCreated[i][PersistencePolicy_wc] = 0;
141       }
142
143       // close write through database
144       if(gBtreeCreated[i][PersistencePolicy_wt] == 1)
145       {
146          itzam_state  state = ITZAM_FAILED;
147          state = itzam_btree_close(&gBtree[i][PersistencePolicy_wt]);
148          if (state != ITZAM_OKAY)
149          {
150             fprintf(stderr, "pers_db_close_all ==> Close WT: Itzam problem: %s\n", STATE_MESSAGES[state]);
151          }
152          gBtreeCreated[i][PersistencePolicy_wt] = 0;
153       }
154    }
155 }
156
157
158
159 int pers_db_read_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
160 {
161    int read_size = -1;
162
163    if(   PersistenceStorage_shared == info->configKey.storage
164       || PersistenceStorage_local == info->configKey.storage)
165    {
166       itzam_btree* btree = NULL;
167       itzam_state  state = ITZAM_FAILED;
168       KeyValuePair_s search;
169
170       btree = pers_db_open(info, dbPath);
171       if(btree != NULL)
172       {
173          if(itzam_true == itzam_btree_find(btree, key, &search))
174          {
175             read_size = search.m_data_size;
176             if(read_size > buffer_size)
177             {
178                read_size = buffer_size;   // truncate data size to buffer size
179             }
180             memcpy(buffer, search.m_data, read_size);
181          }
182          else
183          {
184             read_size = EPERS_NOKEY;
185          }
186
187          //
188          // workaround till lifecycle is working correctly
189          //
190          pers_db_close(info);
191       }
192       else
193       {
194          read_size = EPERS_NOPRCTABLE;
195          fprintf(stderr, "\npersistence_get_data ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
196       }
197    }
198    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
199    {
200       int idx =  custom_client_name_to_id(dbPath, 1);
201       char workaroundPath[128];  // workaround, because /sys/ can not be accessed on host!!!!
202       snprintf(workaroundPath, 128, "%s%s", "/Data", dbPath  );
203
204       if( (idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_get_data != NULL) )
205       {
206          gPersCustomFuncs[idx].custom_plugin_get_data(key, (char*)buffer, buffer_size);
207       }
208       else
209       {
210          read_size = EPERS_NOPLUGINFUNCT;
211       }
212    }
213    return read_size;
214 }
215
216
217
218 int pers_db_write_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
219 {
220    int write_size = -1;
221
222    if(   PersistenceStorage_shared == info->configKey.storage
223       || PersistenceStorage_local == info->configKey.storage)
224    {
225       write_size = buffer_size;
226       itzam_btree* btree = NULL;
227       itzam_state  state = ITZAM_FAILED;
228       KeyValuePair_s insert;
229
230       btree = pers_db_open(info, dbPath);
231       if(btree != NULL)
232       {
233          int keySize = 0;
234          keySize = (int)strlen((const char*)key);
235          if(keySize < DbKeySize)
236          {
237             int dataSize = 0;
238             dataSize = (int)strlen( (const char*)buffer);
239             if(dataSize < DbValueSize)
240             {
241                // key
242                memset(insert.m_key, 0, DbKeySize);
243                memcpy(insert.m_key, key, keySize);
244                if(itzam_true == itzam_btree_find(btree, key, &insert))
245                {
246                   // key already available, so delete "old" key
247                   state = itzam_btree_remove(btree, (const void *)&insert);
248                }
249
250                // data
251                memset(insert.m_data, 0, DbValueSize);
252                memcpy(insert.m_data, buffer, dataSize);
253
254                // data size
255                insert.m_data_size = buffer_size;
256
257                state = itzam_btree_insert(btree,(const void *)&insert);
258                if (state != ITZAM_OKAY)
259                {
260                   fprintf(stderr, "\npersistence_set_data ==> Insert Itzam problem: %s\n", STATE_MESSAGES[state]);
261                   write_size = EPERS_DB_ERROR_INTERNAL;
262                }
263             }
264             else
265             {
266                fprintf(stderr, "\npersistence_set_data ==> set_value_to_table_itzam => data to long » size %d | maxSize: %d\n", dataSize, DbKeySize);
267                write_size = EPERS_DB_VALUE_SIZE;
268             }
269
270             //
271             // workaround till lifecycle is working correctly
272             //
273             pers_db_close(info);
274          }
275          else
276          {
277             fprintf(stderr, "\nset_value_to_table_itzam => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize);
278             write_size = EPERS_DB_KEY_SIZE;
279          }
280       }
281       else
282       {
283          write_size = EPERS_NOPRCTABLE;
284          fprintf(stderr, "\npersistence_set_data ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
285       }
286    }
287    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
288    {
289       int idx = custom_client_name_to_id(dbPath, 1);
290       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) )
291       {
292          gPersCustomFuncs[idx].custom_plugin_set_data(key, (char*)buffer, buffer_size);
293       }
294       else
295       {
296          write_size = EPERS_NOPLUGINFUNCT;
297       }
298    }
299    return write_size;
300 }
301
302
303
304 int pers_db_get_key_size(char* dbPath, char* key, PersistenceInfo_s* info)
305 {
306    int read_size = -1;
307
308    if(   PersistenceStorage_shared == info->configKey.storage
309       || PersistenceStorage_local == info->configKey.storage)
310    {
311       int keySize = 0;
312       itzam_btree*  btree = NULL;
313       itzam_state  state = ITZAM_FAILED;
314       KeyValuePair_s search;
315
316       btree = pers_db_open(info, dbPath);
317       if(btree != NULL)
318       {
319          keySize = (int)strlen((const char*)key);
320          if(keySize < DbKeySize)
321          {
322             memset(search.m_key,0, DbKeySize);
323             memcpy(search.m_key, key, keySize);
324             if(itzam_true == itzam_btree_find(btree, key, &search))
325             {
326                read_size = strlen(search.m_data);
327             }
328             else
329             {
330                read_size = EPERS_NOKEY;
331             }
332          }
333          else
334          {
335             fprintf(stderr, "persistence_get_data_size => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize);
336             read_size = EPERS_DB_KEY_SIZE;
337          }
338          //
339          // workaround till lifecycle is working correctly
340          //
341          pers_db_close(info);
342       }
343       else
344       {
345          read_size = EPERS_NOPRCTABLE;
346          fprintf(stderr, "\npersistence_get_data_size ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
347       }
348    }
349    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
350    {
351       int idx = custom_client_name_to_id(dbPath, 1);
352       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) )
353       {
354          gPersCustomFuncs[idx].custom_plugin_get_size(key);
355       }
356       else
357       {
358          read_size = EPERS_NOPLUGINFUNCT;
359       }
360    }
361    return read_size;
362 }
363
364
365
366 int pers_db_delete_key(char* dbPath, char* dbKey, PersistenceInfo_s* info)
367 {
368    int ret = 0;
369    if(PersistenceStorage_custom != info->configKey.storage)
370    {
371       itzam_btree*  btree = NULL;
372       KeyValuePair_s delete;
373
374       //printf("delete_key_from_table_itzam => Path: \"%s\" | key: \"%s\" \n", dbPath, key);
375       btree = pers_db_open(info, dbPath);
376       if(btree != NULL)
377       {
378          int keySize = 0;
379          keySize = (int)strlen((const char*)dbKey);
380          if(keySize < DbKeySize)
381          {
382             itzam_state  state;
383
384             memset(delete.m_key,0, DbKeySize);
385             memcpy(delete.m_key, dbKey, keySize);
386             state = itzam_btree_remove(btree, (const void *)&delete);
387             if (state != ITZAM_OKAY)
388             {
389                fprintf(stderr, "persistence_delete_data ==> Remove Itzam problem: %s\n", STATE_MESSAGES[state]);
390                ret = EPERS_DB_ERROR_INTERNAL;
391             }
392          }
393          else
394          {
395             fprintf(stderr, "persistence_delete_data => key to long » size: %d | maxSize: %d\n", keySize, DbKeySize);
396             ret = EPERS_DB_KEY_SIZE;
397          }
398          //
399          // workaround till lifecycle is working correctly
400          //
401          pers_db_close(info);
402       }
403       else
404       {
405          fprintf(stderr, "persistence_delete_data => no prct table\n");
406          ret = EPERS_NOPRCTABLE;
407       }
408    }
409    else   // custom storage implementation via custom library
410    {
411       int idx = custom_client_name_to_id(dbPath, 1);
412       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) )
413       {
414          gPersCustomFuncs[idx].custom_plugin_delete_data(dbKey);
415       }
416       else
417       {
418          ret = EPERS_NOPLUGINFUNCT;
419       }
420    }
421    return ret;
422 }
423
424
425 int persistence_reg_notify_on_change(char* dbPath, char* key)
426 {
427    int rval = -1;
428
429    return rval;
430 }
431
432
433
434 //---------------------------------------------------------------------------------------------------------
435 // C U R S O R    F U N C T I O N S
436 //---------------------------------------------------------------------------------------------------------
437
438 int get_cursor_handle()
439 {
440    int handle = 0;
441
442    if(pthread_mutex_lock(&gMtx) == 0)
443    {
444       if(gFreeCursorHandleIdxHead > 0)   // check if we have a free spot in the array before the current max
445       {
446          handle = gFreeCursorHandleArray[--gFreeCursorHandleIdxHead];
447       }
448       else
449       {
450          if(gHandleIdx < MaxPersHandle-1)
451          {
452             handle = gHandleIdx++;  // no free spot before current max, increment handle index
453          }
454          else
455          {
456             handle = -1;
457             printf("get_persistence_handle_idx => Reached maximum of open handles: %d \n", MaxPersHandle);
458          }
459       }
460       pthread_mutex_unlock(&gMtx);
461    }
462    return handle;
463 }
464
465
466 void close_cursor_handle(int handlerDB)
467 {
468    if(pthread_mutex_lock(&gMtx) == 0)
469    {
470       if(gFreeCursorHandleIdxHead < MaxPersHandle)
471       {
472          gFreeCursorHandleArray[gFreeCursorHandleIdxHead++] = handlerDB;
473       }
474       pthread_mutex_unlock(&gMtx);
475    }
476 }
477
478
479
480 int pers_db_cursor_create(char* dbPath)
481 {
482    int handle = -1;
483    itzam_state  state = ITZAM_FAILED;
484
485    handle = get_cursor_handle();
486
487    if(handle < MaxPersHandle && handle >= 0)
488    {
489       // open database
490       state = itzam_btree_open(&gCursorArray[handle].m_btree, dbPath, itzam_comparator_string, error_handler, 0/*recover*/, 0/*read_only*/);
491       if (state != ITZAM_OKAY)
492       {
493          fprintf(stderr, "pers_db_open ==> Open Itzam problem: %s\n", STATE_MESSAGES[state]);
494       }
495       else
496       {
497          itzam_state  state;
498
499          state = itzam_btree_cursor_create(&gCursorArray[handle].m_cursor, &gCursorArray[handle].m_btree);
500          if(state == ITZAM_OKAY)
501          {
502             gCursorArray[handle].m_empty = 0;
503          }
504          else
505          {
506             gCursorArray[handle].m_empty = 1;
507          }
508       }
509    }
510    return handle;
511 }
512
513
514
515 int pers_db_cursor_next(unsigned int handlerDB)
516 {
517    int rval = -1;
518    //if(handlerDB < MaxPersHandle && handlerDB >= 0)
519    if(handlerDB < MaxPersHandle )
520    {
521       if(gCursorArray[handlerDB].m_empty != 1)
522       {
523          itzam_bool success;
524          success = itzam_btree_cursor_next(&gCursorArray[handlerDB].m_cursor);
525
526          if(success == itzam_true)
527          {
528             rval = 0;
529          }
530          else
531          {
532             rval = EPERS_LAST_ENTRY_IN_DB;
533          }
534       }
535       else
536       {
537          printf("persistence_db_cursor_get_key ==> invalid handle: %u \n", handlerDB);
538       }
539    }
540    else
541    {
542       printf("persistence_db_cursor_get_key ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
543    }
544    return rval;
545 }
546
547
548
549 int pers_db_cursor_get_key(unsigned int handlerDB, char * bufKeyName_out, int bufSize)
550 {
551    int rval = -1;
552    KeyValuePair_s search;
553
554    if(handlerDB < MaxPersHandle)
555    {
556       if(gCursorArray[handlerDB].m_empty != 1)
557       {
558          int length = 0;
559          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
560          length = strlen(search.m_key);
561          if(length < bufSize)
562          {
563             memcpy(bufKeyName_out, search.m_key, length);
564             rval = 0;
565          }
566          else
567          {
568             printf("persistence_db_cursor_get_key ==> buffer to small » keySize: %d | bufSize: %d \n", length, bufSize);
569          }
570       }
571       else
572       {
573          printf("persistence_db_cursor_get_key ==> invalid handle: %u \n", handlerDB);
574       }
575    }
576    else
577    {
578       printf("persistence_db_cursor_get_key ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
579    }
580    return rval;
581 }
582
583
584
585 int pers_db_cursor_get_data(unsigned int handlerDB, char * bufData_out, int bufSize)
586 {
587    int rval = -1;
588    KeyValuePair_s search;
589
590    if(handlerDB < MaxPersHandle)
591    {
592       if(gCursorArray[handlerDB].m_empty != 1)
593       {
594          int length = 0;
595          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
596
597          length = strlen(search.m_data);
598          if(length < bufSize)
599          {
600             memcpy(bufData_out, search.m_data, length);
601             rval = 0;
602          }
603          else
604          {
605             printf("persistence_db_cursor_get_data ==> buffer to small » keySize: %d | bufSize: %d \n", length, bufSize);
606          }
607       }
608       else
609       {
610          printf("persistence_db_cursor_get_data ==> invalid handle: %u \n", handlerDB);
611       }
612    }
613    else
614    {
615       printf("persistence_db_cursor_get_data ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
616    }
617    return rval;
618 }
619
620
621
622 int pers_db_cursor_get_data_size(unsigned int handlerDB)
623 {
624    int size = -1;
625    KeyValuePair_s search;
626
627    if(handlerDB < MaxPersHandle)
628    {
629       if(gCursorArray[handlerDB].m_empty != 1)
630       {
631          itzam_btree_cursor_read(&gCursorArray[handlerDB].m_cursor ,(void *)&search);
632          size = strlen(search.m_data);
633       }
634       else
635       {
636          printf("persistence_db_cursor_get_data ==> invalid handle: %u \n", handlerDB);
637       }
638    }
639    else
640    {
641       printf("persistence_db_cursor_get_data ==> handle bigger than max » handleDB: %u | max: : %d \n", handlerDB, MaxPersHandle);
642    }
643    return size;
644 }
645
646
647
648 int pers_db_cursor_destroy(unsigned int handlerDB)
649 {
650    int rval = -1;
651    if(handlerDB < MaxPersHandle)
652    {
653       itzam_btree_cursor_free(&gCursorArray[handlerDB].m_cursor);
654       gCursorArray[handlerDB].m_empty = 1;
655
656       itzam_state state = ITZAM_FAILED;
657       state = itzam_btree_close(&gCursorArray[handlerDB].m_btree);
658       if (state != ITZAM_OKAY)
659       {
660             fprintf(stderr, "pers_db_cursor_destroy ==> Close: Itzam problem: %s\n", STATE_MESSAGES[state]);
661       }
662
663       close_cursor_handle(handlerDB);
664
665       rval = 0;
666    }
667    return rval;
668 }
669
670
671
672
673 //-----------------------------------------------------------------------------
674 // code to print database content (for debugging)
675 //-----------------------------------------------------------------------------
676 // walk the database
677 /*
678 KeyValuePair_s  rec;
679 itzam_btree_cursor cursor;
680 state = itzam_btree_cursor_create(&cursor, &btree);
681 if(state == ITZAM_OKAY)
682 {
683   printf("==> Database content ==> db size: %d\n", (int)itzam_btree_count(&btree));
684   do
685   {
686      // get the key pointed to by the cursor
687      state = itzam_btree_cursor_read(&cursor,(void *)&rec);
688      if (state == ITZAM_OKAY)
689      {
690        printf("   Key: %s \n     ==> data: %s\n", rec.m_key, rec.m_data);
691      }
692      else
693         fprintf(stderr, "\nItzam problem: %s\n", STATE_MESSAGES[state]);
694   }
695   while (itzam_btree_cursor_next(&cursor));
696
697   state = itzam_btree_cursor_free(&cursor);
698 }
699 */
700 //-----------------------------------------------------------------------------
701
702
703
704
705