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