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