blob: dc4f19ab6f74eee58a539016e81a51d80f867638 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/******************************************************************************
2 *
3 * <:copyright-BRCM:2016:DUAL/GPL:standard
4 *
5 * Copyright (c) 2016 Broadcom
6 * All Rights Reserved
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed
10 * to you under the terms of the GNU General Public License version 2
11 * (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
12 * with the following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give
15 * you permission to link this software with independent modules, and
16 * to copy and distribute the resulting executable under terms of your
17 * choice, provided that you also meet, for each linked independent
18 * module, the terms and conditions of the license of that module.
19 * An independent module is a module which is not derived from this
20 * software. The special exception does not apply to any modifications
21 * of the software.
22 *
23 * Not withstanding the above, under no circumstances may you combine
24 * this software in any way with any other Broadcom software provided
25 * under a license other than the GPL, without Broadcom's express prior
26 * written consent.
27 *
28 * :>
29 *
30 *****************************************************************************/
31
32/*
33 * Data Base Engine
34 *
35 * Proprietary and confidential.
36 */
37#include <bcmos_system.h>
38#include <bcm_db_engine.h>
39
40/* DB trace level */
41bcmos_trace_level bcmdb_trace_level = BCMOS_TRACE_LEVEL_ERROR;
42
43#define BCMDB_TRACE(level, fmt, args...) \
44 do { \
45 if (level <= bcmdb_trace_level) \
46 bcmos_trace(level, "%s#%d> " fmt, __FUNCTION__, __LINE__, ## args); \
47 } while (0)
48
49/* Print error trace conditionally, depending on the current trace level */
50#define BCMDB_TRACE_ERROR(fmt, args...) \
51 BCMDB_TRACE(BCMOS_TRACE_LEVEL_ERROR, "DB ERR: %s#%d> " fmt, __FUNCTION__, __LINE__, ## args)
52
53/* Print warning trace conditionally, depending on the current trace level */
54#define BCMDB_TRACE_WARNING(fmt, args...) \
55 BCMDB_TRACE(BCMOS_TRACE_LEVEL_WARNING, "DB WARN: %s#%d> " fmt, __FUNCTION__, __LINE__, ## args)
56
57/* Print info trace conditionally, depending on the current trace level */
58#define BCMDB_TRACE_INFO(fmt, args...) \
59 BCMDB_TRACE(BCMOS_TRACE_LEVEL_INFO, "DB INFO: %s#%d> " fmt, __FUNCTION__, __LINE__, ## args)
60
61/* Enable debug prints */
62#define BCMDB_DEBUG
63
64#ifdef BCMDB_DEBUG
65
66/* Print debug trace conditionally, depending on the current trace level */
67#define BCMDB_TRACE_DEBUG(fmt, args...) \
68 BCMDB_TRACE(BCMOS_TRACE_LEVEL_DEBUG, "DB DBG: %s#%d> " fmt, __FUNCTION__, __LINE__, ## args)
69
70#else
71
72#define BCMDB_TRACE_DEBUG(fmt, args...)
73
74#endif
75
76
77
78/** Data base entry
79 * \ingroup bcmdb
80 */
81struct bcmdb_entry
82{
83 void *data; /* Set or record */
84 uint8_t flags;
85#define BCMDB_FLAG_VALID 0x01 /**< Entry is valid */
86#define BCMDB_FLAG_RECORD 0x02 /**< Record */
87#define BCMDB_FLAG_SOS 0x10 /**< Set of sets */
88 uint8_t read_count;
89 uint8_t write_pending;
90 uint8_t ffu;
91};
92
93/** Set/Record change notification
94 * \ingroup bcmdb
95 */
96typedef struct bcmdb_notify
97{
98 struct bcmdb_notify *next;
99 bcmdb_notify_cb cb;
100 long cb_priv;
101} bcmdb_notify;
102
103/** Data Base Set control block
104 * \ingroup bcmdb
105 */
106struct bcmdb_set
107{
108 bcmdb_entry entry; /**< Common fields for set and record */
109 char *name; /**< Set name */
110 bcmdb_set *parent; /**< Set parent */
111 bcmdb_key my_key; /**< Key in the parent set */
112 int max_entries; /**< Max number of elements in the set. -1=inlimited */
113 int num_entries; /**< Current number of elements in the set */
114 int entry_size; /**< Set entry size. */
115 int magic; /**< Magic number */
116#define BCMDB_MAGIC_ACTIVE_SET (('a'<<24) | ('s'<<16) | ('e'<<8) | 't')
117#define BCMDB_MAGIC_FREE_SET (('f'<<24) | ('s'<<16) | ('e'<<8) | 't')
118
119 /** Get next element */
120 bcmdb_key (*entry_get_next)(const bcmdb_set *this, bcmdb_key cur);
121
122 /** Add new entry. returns 0 if ok */
123 int (*entry_new)(bcmdb_set *this, bcmdb_key key, const void *data);
124
125 /** Delete entry */
126 int (*entry_delete)(bcmdb_set *this, bcmdb_entry *entry);
127
128 /*
129 * Handle – key mapping
130 */
131
132 /** Convert entry handle to entry key */
133 bcmdb_key (*handle_to_key)(const bcmdb_set *this, const bcmdb_entry *entry);
134
135 /** Convert entry key to entry handle */
136 bcmdb_entry *(*key_to_handle)(const bcmdb_set *this, bcmdb_key key);
137
138 /*
139 * Set/Record locking
140 * entry is handle of the set or record to be locked/unlocked
141 */
142
143 /** Lock the whole set for reading */
144 void (*lock_set_read)(bcmdb_set *set);
145
146 /** Unlock set locked for reading */
147 void (*unlock_set_read)(bcmdb_set *set);
148
149 /** Lock the whole set for update */
150 long (*lock_set_modify)(bcmdb_set *set);
151
152 /** Unlock set locked for update */
153 void (*unlock_set_modify)(bcmdb_set *set, long fastlock_flags);
154
155 /** Lock the set recursively for update (SoS only) */
156 void (*lock_set_recursively_modify)(bcmdb_set *set);
157
158 /** Unlock recursively set locked for update (SoS only) */
159 void (*unlock_set_recursively_modify)(bcmdb_set *set);
160
161 /** Lock record for reading */
162 void *(*lock_record_read)(bcmdb_set *set, bcmdb_key key);
163
164 /** Release read lock */
165 void (*unlock_record_read)(bcmdb_set *set, bcmdb_key key);
166
167 /** Lock record for modification. */
168 void *(*lock_record_write)(bcmdb_set *set, bcmdb_key key, int is_deletion);
169
170 /** Release modify lock */
171 void (*unlock_record_write)(bcmdb_set *set, int is_deletion, int is_cancellation);
172
173 /** Format function that converts record data to human-readable form */
174 bcmdb_format_cb format;
175
176 /** Update notification mechanism.\n
177 * Note that notification functions are called before the actual update of the data base, so that
178 * there is an option to abort the update if needed.
179 */
180 bcmdb_notify *notify_list_head;
181
182 /** Shadow data record */
183 void *shadow_data;
184
185 /** holds the pointer to a write-locked entry */
186 bcmdb_entry *write_locked_entry ;
187
188 /** mutex that prevents multiple simultaneous updates */
189 bcmos_mutex mutex_update;
190
191 /** semaphore that holds update while there are unfinished reads */
192 bcmos_sem sem_wait_read_to_finish;
193
194 /** fastlock */
195 bcmos_fastlock fastlock;
196};
197
198
199/**< Data base record
200 * \ingroup bcmdb
201 */
202struct bcmdb_record
203{
204 struct bcmdb_entry e; /**< Entry - common part for set and record */
205};
206
207/*
208 * DB backend callbacks
209 */
210
211/*
212 * Array-based backend
213 */
214
215/** Get next element */
216static bcmdb_key _bcmdb_array_entry_get_next(const bcmdb_set *this, bcmdb_key key)
217{
218 BUG_ON(!this->entry.data);
219
220 if (key < 0)
221 key = 0;
222 else
223 ++key;
224
225 while((unsigned)key<this->max_entries)
226 {
227 bcmdb_entry *entry = (bcmdb_entry *)this->entry.data + key;
228 if ((entry->flags & BCMDB_FLAG_VALID))
229 break;
230 ++key;
231 }
232
233 if ((unsigned)key >= this->max_entries)
234 return BCMDB_KEY_NO_MORE; /* no more */
235
236 return key;
237}
238
239/*
240 * Handle – key mapping
241 */
242
243/** Convert entry handle to entry key */
244static inline bcmdb_key _bcmdb_array_handle_to_key(const bcmdb_set *this, const bcmdb_entry *entry)
245{
246 bcmdb_key key;
247
248 BUG_ON(!this);
249 BUG_ON(!entry);
250 BUG_ON(!this->magic == BCMDB_MAGIC_ACTIVE_SET);
251 BUG_ON(!this->entry.data);
252
253 key = entry - (bcmdb_entry *)this->entry.data;
254 if ((unsigned)key >= this->max_entries)
255 return BCMDB_KEY_INVAL;
256
257 return key;
258}
259
260
261/** Convert entry key to entry handle */
262static inline bcmdb_entry *_bcmdb_array_key_to_handle(const bcmdb_set *this, bcmdb_key key)
263{
264 BUG_ON(!this);
265 BUG_ON(!this->magic == BCMDB_MAGIC_ACTIVE_SET);
266 BUG_ON(!this->entry.data);
267
268 if ((unsigned long)key >= this->max_entries)
269 return NULL;
270
271 return (bcmdb_entry *)this->entry.data + key;
272}
273
274
275/** sem-based set read-lock */
276static void bcmdb_set_lock_read_sem(bcmdb_set *set)
277{
278 bcmos_mutex_lock(&set->mutex_update, BCMOS_WAIT_FOREVER);
279}
280
281
282/** sem-based set read-unlock */
283static void bcmdb_set_unlock_read_sem(bcmdb_set *set)
284{
285 bcmos_mutex_unlock(&set->mutex_update);
286}
287
288
289/** sem-based set modify-lock */
290static long bcmdb_set_lock_modify_sem(bcmdb_set *set)
291{
292 bcmos_mutex_lock(&set->mutex_update, BCMOS_WAIT_FOREVER);
293 return 0;
294}
295
296
297/** sem-based set modify-unlock */
298static void bcmdb_set_unlock_modify_sem(bcmdb_set *set, long fastlock_flags)
299{
300 bcmos_mutex_unlock(&set->mutex_update);
301}
302
303
304/** helper function which recursively locks all subsets of SoS
305 * for modify */
306static void bcmdb_recursive_subsets_lock_modify(bcmdb_set *sos)
307{
308 int key;
309 int left_entries = sos->num_entries;
310 bcmdb_entry *entry;
311 bcmdb_set *subset;
312
313 BUG_ON(!(sos->entry.flags & BCMDB_FLAG_SOS));
314
315 for (key = 0; key < sos->max_entries; ++key)
316 {
317 entry = sos->key_to_handle(sos, key);
318
319 if ((entry->flags & BCMDB_FLAG_VALID))
320 {
321 subset = (bcmdb_set *)entry->data;
322 subset->lock_set_recursively_modify(subset);
323
324 --left_entries;
325 /* if we handled all subsets we can break the "for" */
326 if (left_entries==0)
327 {
328 break;
329 }
330 }
331 }
332}
333
334
335/** helper function which recursively unlocks all subsets of SoS
336 * for modify */
337static void bcmdb_recursive_subsets_unlock_modify(bcmdb_set *sos)
338{
339 int key;
340 int left_entries = sos->num_entries;
341 bcmdb_entry *entry;
342 bcmdb_set *subset;
343
344 BUG_ON(!(sos->entry.flags & BCMDB_FLAG_SOS));
345
346 for (key = 0; key < sos->max_entries; ++key)
347 {
348 entry = sos->key_to_handle(sos, key);
349
350 if ((entry->flags & BCMDB_FLAG_VALID))
351 {
352 subset = (bcmdb_set *)entry->data;
353 subset->unlock_set_recursively_modify(subset);
354
355 --left_entries;
356 /* if we handled all subsets we can break the "for" */
357 if (left_entries==0)
358 {
359 break;
360 }
361 }
362 }
363}
364
365
366/** sem-based set modify-lock recursively */
367static void bcmdb_set_lock_recursively_modify_sem(bcmdb_set *set)
368{
369 BCMDB_TRACE_DEBUG("lock set modify recursively: %s\n", set->name);
370 bcmos_mutex_lock(&set->mutex_update, BCMOS_WAIT_FOREVER);
371 BCMDB_TRACE_DEBUG("mutex was locked\n");
372
373 if ((set->entry.flags & BCMDB_FLAG_SOS))
374 {
375 BCMDB_TRACE_DEBUG("going to lock the subsets\n");
376 bcmdb_recursive_subsets_lock_modify(set);
377 }
378}
379
380
381/** sem-based set modify-unlock recursively */
382static void bcmdb_set_unlock_recursively_modify_sem(bcmdb_set *set)
383{
384 BCMDB_TRACE_DEBUG("unlock set modify recursively: %s\n", set->name);
385
386 if ((set->entry.flags & BCMDB_FLAG_SOS))
387 {
388 BCMDB_TRACE_DEBUG("going to unlock the subsets\n");
389 bcmdb_recursive_subsets_unlock_modify(set);
390 }
391
392 bcmos_mutex_unlock(&set->mutex_update);
393 BCMDB_TRACE_DEBUG("mutex was unlocked\n");
394}
395
396
397/** NB-read-sem-write policy: set read lock */
398static void bcmdb_set_lock_read__nb_read_sem_write(bcmdb_set *set)
399{
400 long flags;
401
402 BCMDB_TRACE_DEBUG("lock set read: %s\n", set->name);
403 flags = bcmos_fastlock_lock(&set->fastlock);
404 ++set->entry.read_count;
405 BCMDB_TRACE_DEBUG("read_count is now: %u\n", set->entry.read_count);
406 bcmos_fastlock_unlock(&set->fastlock, flags);
407}
408
409
410/** NB-read-sem-write policy: set read unlock */
411static void bcmdb_set_unlock_read__nb_read_sem_write(bcmdb_set *set)
412{
413 long flags;
414
415 BCMDB_TRACE_DEBUG("unlock set read: %s\n", set->name);
416
417 flags = bcmos_fastlock_lock(&set->fastlock);
418 BUG_ON(!set->entry.read_count);
419 if (!(--set->entry.read_count) &&
420 set->entry.write_pending)
421 {
422 BCMDB_TRACE_DEBUG("going to wake pending writer\n");
423
424 set->entry.write_pending = 0;
425 bcmos_fastlock_unlock(&set->fastlock, flags);
426 bcmos_sem_post(&set->sem_wait_read_to_finish);
427 }
428 else
429 {
430 bcmos_fastlock_unlock(&set->fastlock, flags);
431 }
432}
433
434
435/** NB-read-sem-write policy: set modify lock */
436static long bcmdb_set_lock_modify__nb_read_sem_write(bcmdb_set *set)
437{
438 long flags;
439
440 BCMDB_TRACE_DEBUG("lock set modify: %s\n", set->name);
441 bcmos_mutex_lock(&set->mutex_update, BCMOS_WAIT_FOREVER);
442 BCMDB_TRACE_DEBUG("mutex was locked\n");
443
444 while(1)
445 {
446 flags = bcmos_fastlock_lock(&set->fastlock);
447 if (!set->entry.read_count)
448 break;
449 /* Wait until read is completed */
450 set->entry.write_pending = 1;
451 bcmos_fastlock_unlock(&set->fastlock, flags);
452 bcmos_sem_wait(&set->sem_wait_read_to_finish, BCMOS_WAIT_FOREVER);
453 }
454 /* At this point fastlock is taken and there are no pending reads */
455
456 BCMDB_TRACE_DEBUG("fastlock is taken, no active reads\n");
457
458 return flags;
459}
460
461
462/** NB-read-sem-write policy: set modify unlock */
463static void bcmdb_set_unlock_modify__nb_read_sem_write(bcmdb_set *set, long fastlock_flags)
464{
465 BCMDB_TRACE_DEBUG("unlock set modify: %s\n", set->name);
466 bcmos_fastlock_unlock(&set->fastlock, fastlock_flags);
467 bcmos_mutex_unlock(&set->mutex_update);
468 BCMDB_TRACE_DEBUG("mutex was unlocked\n");
469}
470
471
472/** sem-read/sem-write policy: lock entry */
473static void *bcmdb_sem_read_sem_write_lock(bcmdb_set *set, bcmdb_key key, int is_deletion)
474{
475 bcmdb_entry *entry;
476 bcmos_mutex_lock(&set->mutex_update, BCMOS_WAIT_FOREVER);
477
478 if (is_deletion)
479 {
480 /* there is nothing to return in deletion case */
481 return NULL;
482 }
483
484 entry = set->key_to_handle(set, key);
485 if (!entry || !(entry->flags & BCMDB_FLAG_VALID))
486 {
487 bcmos_mutex_unlock(&set->mutex_update);
488 return NULL;
489 }
490 return entry->data;
491}
492
493/** sem-read/sem-write policy: unlock entry */
494static void bcmdb_sem_read_sem_write_unlock(bcmdb_set *set)
495{
496 bcmos_mutex_unlock(&set->mutex_update);
497}
498
499/** sem-read/sem-write policy: lock entry for reading */
500static void *bcmdb_sem_read_sem_write_lock_read(bcmdb_set *set, bcmdb_key key)
501{
502 return bcmdb_sem_read_sem_write_lock(set, key, 0) ;
503}
504
505/** sem-read/sem-write policy: unlock entry for reading */
506static void bcmdb_sem_read_sem_write_unlock_read(bcmdb_set *set, bcmdb_key key)
507{
508 bcmdb_sem_read_sem_write_unlock(set);
509}
510
511/** sem-read/sem-write policy: lock entry for writing */
512static void *bcmdb_sem_read_sem_write_lock_write(bcmdb_set *set, bcmdb_key key, int is_deletion)
513{
514 return bcmdb_sem_read_sem_write_lock(set, key, is_deletion) ;
515}
516
517/** sem-read/sem-write policy: unlock entry for writing */
518static void bcmdb_sem_read_sem_write_unlock_write(bcmdb_set *set, int is_deletion, int is_cancellation)
519{
520 bcmdb_sem_read_sem_write_unlock(set);
521}
522
523/** non-blocking-read/shadow write policy: Lock entry for reading */
524static void *bcmdb_nb_read_shadow_write_lock_read(bcmdb_set *set, bcmdb_key key)
525{
526 bcmdb_entry *entry;
527 long flags;
528
529 flags = bcmos_fastlock_lock(&set->fastlock);
530 entry = set->key_to_handle(set, key);
531 if (!entry || !(entry->flags & BCMDB_FLAG_VALID))
532 {
533 bcmos_fastlock_unlock(&set->fastlock, flags);
534 return NULL;
535 }
536 ++entry->read_count;
537
538 BCMDB_TRACE_DEBUG("lock record read: %s, key=%d new_read_count=%d\n", set->name, key, entry->read_count);
539
540 bcmos_fastlock_unlock(&set->fastlock, flags);
541 return entry->data;
542}
543
544
545/** non-blocking-read/shadow write policy: Unlock entry for reading */
546static void bcmdb_nb_read_shadow_write_unlock_read(bcmdb_set *set, bcmdb_key key)
547{
548 bcmdb_entry *entry=set->key_to_handle(set, key);
549 long flags;
550 BUG_ON(!entry);
551
552 BCMDB_TRACE_DEBUG("unlock record read: %s, key=%d\n", set->name, key);
553
554 flags = bcmos_fastlock_lock(&set->fastlock);
555 /* If write is pending - finish it and release write lock */
556 BUG_ON(!entry->read_count);
557 if (!(--entry->read_count) && set->entry.write_pending)
558 {
559 BCMDB_TRACE_DEBUG("going to wake pending writer\n");
560
561 /* Write was pending. Release write task */
562 set->entry.write_pending = 0;
563 bcmos_fastlock_unlock(&set->fastlock, flags);
564 bcmos_sem_post(&set->sem_wait_read_to_finish);
565 }
566 else
567 {
568 BCMDB_TRACE_DEBUG("read_count is now: %u\n", entry->read_count);
569 bcmos_fastlock_unlock(&set->fastlock, flags);
570 }
571}
572
573/** non-blocking-read/shadow write policy: Lock entry for
574 * writing/deletion.
575 * returned value of NULL means error only in case that
576 * is_deletion is 0 */
577static void *bcmdb_nb_read_shadow_write_lock_write(bcmdb_set *set, bcmdb_key key, int is_deletion)
578{
579 bcmdb_entry *entry;
580
581 BCMDB_TRACE_DEBUG("lock record write: %s, key=%d\n", set->name, key);
582
583 bcmos_mutex_lock(&set->mutex_update, BCMOS_WAIT_FOREVER);
584 BCMDB_TRACE_DEBUG("mutex was locked\n");
585
586 if (is_deletion)
587 {
588 /* there is nothing to return in deletion case */
589 return NULL;
590 }
591
592 /* this check is needed since mutex_update is task-aware.
593 it is not allowed for a task to lock for writing a 2nd record before unlocking the first one. */
594 if (set->write_locked_entry)
595 {
596 BCMDB_TRACE_ERROR("there is already an entry locked for writing\n");
597 bcmos_mutex_unlock(&set->mutex_update);
598 return NULL;
599 }
600
601 entry = set->key_to_handle(set, key);
602 if (!entry || !(entry->flags & BCMDB_FLAG_VALID))
603 {
604 bcmos_mutex_unlock(&set->mutex_update);
605 return NULL;
606 }
607 /* Copy data to shadow entry */
608 memcpy(set->shadow_data, entry->data, set->entry_size);
609 set->write_locked_entry = entry;
610 return set->shadow_data;
611}
612
613/** non-blocking-read/shadow write policy: Unlock entry for
614 * writing/deletion */
615static void bcmdb_nb_read_shadow_write_unlock_write(bcmdb_set *set, int is_deletion, int is_cancellation)
616{
617 bcmdb_entry *entry = set->write_locked_entry;
618 long flags;
619 void *old_data;
620
621 /* no entry is locked */
622 BUG_ON(!entry);
623
624 BCMDB_TRACE_DEBUG("unlock record write: %s\n", set->name);
625
626 /* cancellation: no need to update the entry from the shadow (or to delete the entry in case of deletion). */
627 if (is_cancellation)
628 {
629 set->write_locked_entry = NULL;
630 bcmos_mutex_unlock(&set->mutex_update);
631 return;
632 }
633
634 while(1)
635 {
636 flags = bcmos_fastlock_lock(&set->fastlock);
637 /* Wait until neither record nor set are locked for reading */
638 if (!entry->read_count && !set->entry.read_count)
639 break;
640
641 /* Read lock is active. wait */
642
643 BCMDB_TRACE_DEBUG("read lock is active. going to sleep.\n");
644
645 set->entry.write_pending = 1;
646 bcmos_fastlock_unlock(&set->fastlock, flags);
647 bcmos_sem_wait(&set->sem_wait_read_to_finish, BCMOS_WAIT_FOREVER);
648 }
649
650 /* At this point there is no read lock and fastlock is taken. */
651
652 BCMDB_TRACE_DEBUG("fastlock is taken, no active reads\n");
653
654 if (is_deletion)
655 {
656 /* delete the entry */
657 set->entry_delete(set, entry);
658 }
659 else
660 {
661 /* Exchange record data with shadow and release all locks. */
662 old_data = entry->data;
663 entry->data = set->shadow_data;
664 set->shadow_data = old_data;
665 set->write_locked_entry = NULL;
666 }
667
668 bcmos_fastlock_unlock(&set->fastlock, flags);
669 bcmos_mutex_unlock(&set->mutex_update);
670 BCMDB_TRACE_DEBUG("mutex was unlocked\n");
671}
672
673/** none policy: set read-lock */
674static inline void bcmdb_set_lock_read_dummy(bcmdb_set *set)
675{
676}
677
678/** none policy: set read-unlock */
679static inline void bcmdb_set_unlock_read_dummy(bcmdb_set *set)
680{
681}
682
683/** none policy: set modify-lock */
684static inline long bcmdb_set_lock_modify_dummy(bcmdb_set *set)
685{
686 return 0;
687}
688
689/** none policy: set modify-unlock */
690static inline void bcmdb_set_unlock_modify_dummy(bcmdb_set *set, long fastlock_flags)
691{
692}
693
694/** none policy: set modify-lock recursively */
695static void bcmdb_set_lock_recursively_modify_dummy(bcmdb_set *set)
696{
697}
698
699/** none policy: set modify-unlock recursively */
700static void bcmdb_set_unlock_recursively_modify_dummy(bcmdb_set *set)
701{
702}
703
704/** none policy: record lock */
705static inline void *bcmdb_dummy_lock(bcmdb_set *set, bcmdb_key key, int is_deletion)
706{
707 bcmdb_entry *entry;
708
709 /* there is nothing to return in deletion case */
710 if (is_deletion)
711 return NULL;
712
713 entry = set->key_to_handle(set, key);
714 if (!entry || !(entry->flags & BCMDB_FLAG_VALID))
715 return NULL;
716 return entry->data;
717}
718
719/** none policy: record unlock */
720static inline void bcmdb_dummy_unlock(bcmdb_set *set)
721{
722}
723
724/** none policy: record lock for reading */
725static inline void *bcmdb_dummy_lock_read(bcmdb_set *set, bcmdb_key key)
726{
727 return bcmdb_dummy_lock(set, key, 0);
728}
729
730/** none policy: record unlock for reading */
731static inline void bcmdb_dummy_unlock_read(bcmdb_set *set, bcmdb_key key)
732{
733 bcmdb_dummy_unlock(set);
734}
735
736/** none policy: record lock for writing */
737static inline void *bcmdb_dummy_lock_write(bcmdb_set *set, bcmdb_key key, int is_deletion)
738{
739 return bcmdb_dummy_lock(set, key, is_deletion);
740}
741
742/** none policy: record unlock for writing */
743static inline void bcmdb_dummy_unlock_write(bcmdb_set *set, int is_deletion, int is_cancellation)
744{
745 bcmdb_dummy_unlock(set);
746}
747
748
749
750/** Add new sub-set. returns 0 if ok
751 * data contains new set handle
752 */
753static int bcmdb_set_new(bcmdb_set *this, bcmdb_key key, const void *data)
754{
755 /* Although this callback takes "const void *" parameter,
756 * it is just for compatibility fith SoR->new_entry interface.
757 * For SoS this parameter is not constant on application level
758 * (see bcmdb_set_add())
759 */
760 bcmdb_entry *entry = this->key_to_handle(this, key);
761 bcmdb_set *new_set = (bcmdb_set *)(long)data;
762
763 if (!entry)
764 return BCM_ERR_PARM;
765 if ((entry->flags & BCMDB_FLAG_VALID))
766 return BCM_ERR_ALREADY;
767 ++this->num_entries;
768 entry->data = (void *)(long)data;
769 entry->flags |= BCMDB_FLAG_VALID;
770 new_set->my_key = key;
771 new_set->parent = this;
772 return 0;
773}
774
775/** Add new record. returns 0 if ok
776 * data contains record data pointer
777 */
778static int bcmdb_record_new(bcmdb_set *this, bcmdb_key key, const void *data)
779{
780 bcmdb_record *record = (bcmdb_record *)this->key_to_handle(this, key);
781 if (!record || !record->e.data)
782 return BCM_ERR_PARM;
783 if ((record->e.flags & BCMDB_FLAG_VALID))
784 return BCM_ERR_ALREADY;
785 ++this->num_entries;
786 memcpy(record->e.data, data, this->entry_size);
787 record->e.flags |= BCMDB_FLAG_VALID;
788 return 0;
789}
790
791/** Delete entry */
792static int bcmdb_entry_delete(bcmdb_set *this, bcmdb_entry *entry)
793{
794 if (!entry)
795 return BCM_ERR_PARM;
796 if (!(entry->flags & BCMDB_FLAG_VALID))
797 return BCM_ERR_ALREADY;
798 entry->flags &= ~BCMDB_FLAG_VALID;
799 --this->num_entries;
800 return 0;
801}
802
803
804/*
805 * External APIs
806 */
807
808
809/** Initialize data base engine
810 *
811 * \return
812 * 0 - OK\n
813 * <0 - error code
814 * \ingroup bcmdb
815 */
816int bcmdb_module_init(void)
817{
818 return 0;
819}
820
821
822/** Make set-of-sets control block.
823 *
824 * Helper function that creates a set of sets with reasonable defaults for all callbacks and fields.
825 * Once created, the set control block can be tuned before adding the new set to its parent set.
826 * \param[in] init set parameters
827 * \param[out] new_set set control block
828 * \return
829 * 0 - OK\n
830 * <0 - error code
831 */
832int bcmdb_make_set_of_sets(const bcmdb_sos_init *init, bcmdb_set **new_set)
833{
834 bcmdb_set *sos;
835 bcmdb_entry *entries;
836 int rc;
837
838 /* Parameter check */
839 if (!init || !init->name || !new_set)
840 return BCM_ERR_PARM;
841 if ((init->backend_type == BCMDB_BACKEND_ARRAY) && !init->max_entries)
842 return BCM_ERR_PARM;
843
844 /* Allocate set control block and set records */
845 sos = bcmos_calloc(sizeof(bcmdb_set) + strlen(init->name) + 1);
846 if (!sos)
847 return BCM_ERR_NOMEM;
848 sos->name = (char *)(sos + 1);
849 strcpy(sos->name, init->name);
850 sos->entry_size = sizeof(bcmdb_set);
851 sos->max_entries = init->max_entries;
852 sos->my_key = BCMDB_KEY_INVAL;
853 sos->entry.flags = BCMDB_FLAG_SOS;
854 sos->magic = BCMDB_MAGIC_ACTIVE_SET;
855
856 /* Set backend callbacks */
857 switch(init->backend_type)
858 {
859 case BCMDB_BACKEND_ARRAY:
860 entries = bcmos_calloc(sizeof(bcmdb_set)*init->max_entries);
861 if (!entries)
862 {
863 bcmos_free(sos);
864 return BCM_ERR_NOMEM;
865 }
866 sos->entry.data = entries;
867 sos->entry_get_next = _bcmdb_array_entry_get_next;
868 sos->handle_to_key = _bcmdb_array_handle_to_key;
869 sos->key_to_handle = _bcmdb_array_key_to_handle;
870 sos->entry_new = bcmdb_set_new;
871 sos->entry_delete = bcmdb_entry_delete;
872 break;
873
874 default:
875 printf("Only array-based DB backend is supported\n");
876 bcmos_free(sos);
877 return BCM_ERR_NOT_SUPPORTED;
878 }
879
880 /* Set locking callbacks. SoS locking policy is always SEMAPHORE */
881
882 /* in SoS, locking for read is same as for write (and is done recursively). */
883 sos->lock_set_read = bcmdb_set_lock_recursively_modify_sem;
884 sos->unlock_set_read = bcmdb_set_unlock_recursively_modify_sem;
885 sos->lock_set_modify = bcmdb_set_lock_modify_sem;
886 sos->unlock_set_modify = bcmdb_set_unlock_modify_sem;
887 sos->lock_set_recursively_modify = bcmdb_set_lock_recursively_modify_sem ;
888 sos->unlock_set_recursively_modify = bcmdb_set_unlock_recursively_modify_sem ;
889
890 /* create mutex_update */
891 rc = bcmos_mutex_create(&sos->mutex_update, init->os_flags);
892 if (rc)
893 {
894 bcmos_free(entries);
895 bcmos_free(sos);
896 return BCM_ERR_NOMEM;
897 }
898
899 bcmos_fastlock_init(&sos->fastlock, init->os_flags);
900
901 *new_set = sos;
902
903 return 0;
904}
905
906
907
908
909/** Make set-of-records control block.
910 *
911 * Helper function that creates a set of records with reasonable defaults for all callbacks and fields.
912 * Once created, the set control block can be tuned before adding the new set to its parent set.
913 * \param[in] init set parameters
914 * \param[in] alloc_records true (1) - allocate memory for all records.
915 * \param[out] new_set set control block
916 * \return
917 * 0 - OK\n
918 * <0 - error code
919 */
920int bcmdb_make_set_of_records(const bcmdb_sor_init *init, int alloc_records, bcmdb_set **new_set)
921{
922 bcmdb_set *sor;
923 bcmdb_entry *entries = NULL;
924 void *data = NULL;
925 int i;
926 int rc ;
927
928 /* Parameter check */
929 if (!init || !init->name)
930 return BCM_ERR_PARM;
931 if ((init->backend_type == BCMDB_BACKEND_ARRAY) && !init->max_entries)
932 return BCM_ERR_PARM;
933 if (!init->record_size)
934 return BCM_ERR_PARM;
935
936 /* Allocate set control block and set records */
937 sor = bcmos_calloc(sizeof(bcmdb_set) + strlen(init->name) + 1);
938 if (!sor)
939 return BCM_ERR_NOMEM;
940 sor->name = (char *)(sor + 1);
941 strcpy(sor->name, init->name);
942 sor->entry_size = init->record_size;
943 sor->max_entries = init->max_entries;
944 sor->my_key = BCMDB_KEY_INVAL;
945 sor->magic = BCMDB_MAGIC_ACTIVE_SET;
946 sor->format = init->format;
947
948 /* Set backend callbacks */
949 switch(init->backend_type)
950 {
951 case BCMDB_BACKEND_ARRAY:
952 entries = bcmos_calloc(sizeof(bcmdb_entry)*init->max_entries);
953 if (!entries)
954 {
955 bcmos_free(sor);
956 return BCM_ERR_NOMEM;
957 }
958 sor->entry.data = entries;
959 sor->entry_get_next = _bcmdb_array_entry_get_next;
960 sor->handle_to_key = _bcmdb_array_handle_to_key;
961 sor->key_to_handle = _bcmdb_array_key_to_handle;
962 sor->entry_new = bcmdb_record_new;
963 sor->entry_delete = bcmdb_entry_delete;
964
965 /* Preallocate data */
966 if (alloc_records)
967 {
968 int size = init->max_entries * init->record_size;
969 if (init->lock_policy == BCMDB_LOCK_NB_READ_SHADOW_WRITE)
970 size += init->record_size; /* room for shadow entry */
971 /* Allocate data + 1 extra for shadow area */
972 data = bcmos_calloc(size);
973 if (!data)
974 {
975 bcmos_free(entries);
976 bcmos_free(sor);
977 return BCM_ERR_NOMEM;
978 }
979 for(i=0; i<init->max_entries; i++)
980 {
981 bcmdb_entry *entry = (bcmdb_entry *)sor->entry.data + i;
982 entry->data = (void *)((long)data + i * init->record_size);
983 }
984 if (init->lock_policy == BCMDB_LOCK_NB_READ_SHADOW_WRITE)
985 {
986 sor->shadow_data = (void *)((long)data + i * init->record_size);
987 }
988 }
989
990 /* Initialize records */
991 for(i=0; i<init->max_entries; i++)
992 {
993 bcmdb_entry *entry = (bcmdb_entry *)sor->entry.data + i;
994 entry->flags = BCMDB_FLAG_RECORD;
995 }
996 break;
997
998 default:
999 printf("Only array-based DB backend is supported\n");
1000 bcmos_free(sor);
1001 return BCM_ERR_NOT_SUPPORTED;
1002 }
1003
1004 /* Set locking callbacks based on locking policy */
1005 switch(init->lock_policy)
1006 {
1007 case BCMDB_LOCK_SEM_READ_SEM_WRITE:
1008 sor->lock_record_write = bcmdb_sem_read_sem_write_lock_write;
1009 sor->lock_record_read = bcmdb_sem_read_sem_write_lock_read;
1010 sor->unlock_record_write = bcmdb_sem_read_sem_write_unlock_write;
1011 sor->unlock_record_read = bcmdb_sem_read_sem_write_unlock_read;
1012 sor->lock_set_read = bcmdb_set_lock_read_sem;
1013 sor->unlock_set_read = bcmdb_set_unlock_read_sem;
1014 sor->lock_set_modify = bcmdb_set_lock_modify_sem;
1015 sor->unlock_set_modify = bcmdb_set_unlock_modify_sem;
1016 sor->lock_set_recursively_modify = bcmdb_set_lock_recursively_modify_sem ;
1017 sor->unlock_set_recursively_modify = bcmdb_set_unlock_recursively_modify_sem ;
1018 break;
1019
1020 case BCMDB_LOCK_NONE:
1021 case BCMDB_LOCK_OTHER:
1022 sor->lock_record_write = bcmdb_dummy_lock_write;
1023 sor->lock_record_read = bcmdb_dummy_lock_read;
1024 sor->unlock_record_write = bcmdb_dummy_unlock_write;
1025 sor->unlock_record_read = bcmdb_dummy_unlock_read;
1026 sor->lock_set_read = bcmdb_set_lock_read_dummy;
1027 sor->unlock_set_read = bcmdb_set_unlock_read_dummy;
1028 sor->lock_set_modify = bcmdb_set_lock_modify_dummy;
1029 sor->unlock_set_modify = bcmdb_set_unlock_modify_dummy;
1030 sor->lock_set_recursively_modify = bcmdb_set_lock_recursively_modify_dummy ;
1031 sor->unlock_set_recursively_modify = bcmdb_set_unlock_recursively_modify_dummy ;
1032 break;
1033
1034 case BCMDB_LOCK_NB_READ_SHADOW_WRITE:
1035 sor->lock_record_write = bcmdb_nb_read_shadow_write_lock_write;
1036 sor->lock_record_read = bcmdb_nb_read_shadow_write_lock_read;
1037 sor->unlock_record_write = bcmdb_nb_read_shadow_write_unlock_write;
1038 sor->unlock_record_read = bcmdb_nb_read_shadow_write_unlock_read;
1039 sor->lock_set_read = bcmdb_set_lock_read__nb_read_sem_write;
1040 sor->unlock_set_read = bcmdb_set_unlock_read__nb_read_sem_write;
1041 sor->lock_set_modify = bcmdb_set_lock_modify__nb_read_sem_write;
1042 sor->unlock_set_modify = bcmdb_set_unlock_modify__nb_read_sem_write;
1043 sor->lock_set_recursively_modify = bcmdb_set_lock_recursively_modify_sem ;
1044 sor->unlock_set_recursively_modify = bcmdb_set_unlock_recursively_modify_sem ;
1045 break;
1046
1047 default:
1048 printf("Lock policy %d is not supported\n", init->lock_policy);
1049 if (data)
1050 bcmos_free(data);
1051 if (entries)
1052 bcmos_free(entries);
1053 bcmos_free(sor);
1054 return BCM_ERR_NOT_SUPPORTED;
1055 }
1056
1057 /* create mutex_update */
1058 rc = bcmos_mutex_create(&sor->mutex_update, init->os_flags);
1059 if (rc)
1060 {
1061 if (data)
1062 bcmos_free(data);
1063 if (entries)
1064 bcmos_free(entries);
1065 bcmos_free(sor);
1066 return BCM_ERR_NOMEM;
1067 }
1068
1069 /* create sem_wait_read_to_finish. it is initialized to be taken */
1070 rc = bcmos_sem_create(&sor->sem_wait_read_to_finish, 0, init->os_flags);
1071 if (rc)
1072 {
1073 /* no point to check here the error code of bcmos_mutex_destroy */
1074 bcmos_mutex_destroy(&sor->mutex_update);
1075 if (data)
1076 bcmos_free(data);
1077 if (entries)
1078 bcmos_free(entries);
1079 bcmos_free(sor);
1080 return BCM_ERR_NOMEM;
1081 }
1082
1083 bcmos_fastlock_init(&sor->fastlock, init->os_flags);
1084
1085 *new_set = sor;
1086
1087 return 0;
1088}
1089
1090
1091/** Lock data set for reading. When set is locked - it can't be
1092 * modified.
1093 *
1094 * \param[in] set data base set to be locked
1095 *
1096 * \ingroup bcmdb
1097 */
1098void bcmdb_set_lock_read(bcmdb_set *set)
1099{
1100 BUG_ON(!set);
1101 BUG_ON(!set->magic == BCMDB_MAGIC_ACTIVE_SET);
1102 BUG_ON(!set->lock_set_read);
1103 set->lock_set_read(set);
1104}
1105
1106
1107/** Release data set lock
1108 *
1109 * Unlock set locked by \ref bcmdb_set_lock_read
1110 *
1111 * \param[in] set data base set to be unlocked
1112 *
1113 * \ingroup bcmdb
1114 */
1115void bcmdb_set_unlock_read(bcmdb_set *set)
1116{
1117 BUG_ON(!set);
1118 BUG_ON(!set->magic == BCMDB_MAGIC_ACTIVE_SET);
1119 BUG_ON(!set->unlock_set_read);
1120 set->unlock_set_read(set);
1121}
1122
1123
1124/** Lock data set for modify. If the set is SoS, the locking
1125 * will be recursive.
1126 *
1127 * \param[in] set data base set to be locked
1128 *
1129 * \ingroup bcmdb
1130 */
1131void bcmdb_set_lock_modify(bcmdb_set *set)
1132{
1133 BUG_ON(!set);
1134 BUG_ON(!set->magic == BCMDB_MAGIC_ACTIVE_SET);
1135 BUG_ON(!set->lock_set_recursively_modify);
1136 set->lock_set_recursively_modify(set);
1137}
1138
1139
1140/** Release data set lock
1141 *
1142 * Unlock set locked by \ref bcmdb_set_lock_modify
1143 *
1144 * \param[in] set data base set to be unlocked
1145 *
1146 * \ingroup bcmdb
1147 */
1148void bcmdb_set_unlock_modify(bcmdb_set *set)
1149{
1150 BUG_ON(!set);
1151 BUG_ON(!set->magic == BCMDB_MAGIC_ACTIVE_SET);
1152 BUG_ON(!set->unlock_set_recursively_modify);
1153 set->unlock_set_recursively_modify(set);
1154}
1155
1156
1157/** Add set to the parent set with specific key.
1158 *
1159 * The function adds set to the parent set creating data base hierarchy.
1160 * The function automatically acquires modify lock and releases it
1161 * in the end of operation.
1162 * \param[in] sos parent set of sets
1163 * \param[in] key key to add new set at
1164 * \param[in] new_set set control block
1165 * \return
1166 * =0 - OK\n
1167 * <0 - error code
1168 * \ingroup bcmdb
1169 */
1170int bcmdb_set_add(bcmdb_set *sos, bcmdb_key key, bcmdb_set *new_set)
1171{
1172 int rc;
1173 long fastlock_flags;
1174 BUG_ON(!sos);
1175 BUG_ON(!sos->magic == BCMDB_MAGIC_ACTIVE_SET);
1176 BUG_ON(!(sos->entry.flags & BCMDB_FLAG_SOS));
1177 BUG_ON(!new_set);
1178 BUG_ON(!new_set->magic == BCMDB_MAGIC_ACTIVE_SET);
1179 BUG_ON(!new_set->my_key == BCMDB_KEY_INVAL);
1180 fastlock_flags = sos->lock_set_modify(sos);
1181 rc = sos->entry_new(sos, key, new_set);
1182 sos->unlock_set_modify(sos, fastlock_flags);
1183 return rc;
1184}
1185
1186
1187/** Get set handle given its key.
1188 *
1189 * \param[in] sos parent set of sets
1190 * \param[in] key set key.
1191 * \return
1192 * !=0 - set handle
1193 * NULL- doesn't exist
1194 * \ingroup bcmdb
1195 */
1196bcmdb_set *bcmdb_set_handle(const bcmdb_set *sos, bcmdb_key key)
1197{
1198 bcmdb_entry *entry;
1199 BUG_ON(!sos);
1200 BUG_ON(!sos->magic == BCMDB_MAGIC_ACTIVE_SET);
1201 BUG_ON(!(sos->entry.flags & BCMDB_FLAG_SOS));
1202 entry = sos->key_to_handle(sos, key);
1203 if (!entry || !(entry->flags & BCMDB_FLAG_VALID))
1204 return NULL;
1205 return (bcmdb_set *)entry->data;
1206}
1207
1208
1209/** Get set key given its handle.
1210 *
1211 * \param[in] set set handle
1212 * \param[in] key set key.
1213 * \return
1214 * !=BCMDB_KEY_INVAL - set key
1215 * BCMDB_KEY_INVAL - error
1216 * \ingroup bcmdb
1217 */
1218bcmdb_key bcmdb_set_key(const bcmdb_set *set)
1219{
1220 BUG_ON(!set);
1221 BUG_ON(!set->magic == BCMDB_MAGIC_ACTIVE_SET);
1222 return set->my_key;
1223}
1224
1225
1226/** Get set name
1227 *
1228 * \param[in] set set handle
1229 * \return set name
1230 * \ingroup bcmdb
1231 */
1232const char *bcmdb_set_name(const bcmdb_set *set)
1233{
1234 BUG_ON(!set);
1235 BUG_ON(!set->magic == BCMDB_MAGIC_ACTIVE_SET);
1236 return set->name;
1237}
1238
1239
1240/** Get number of records in the set.
1241 *
1242 * \param[in] set set handle
1243 * \return number of active records in the set
1244 * \ingroup bcmdb
1245 */
1246int bcmdb_set_num_records(const bcmdb_set *set)
1247{
1248 BUG_ON(!set);
1249 BUG_ON(!set->magic == BCMDB_MAGIC_ACTIVE_SET);
1250 return set->num_entries;
1251}
1252
1253
1254/** Get entry size
1255 *
1256 * \param[in] set set handle
1257 * \return set entry size
1258 * \ingroup bcmdb
1259 */
1260int bcmdb_set_entry_size(const bcmdb_set *set)
1261{
1262 BUG_ON(!set);
1263 BUG_ON(!set->magic == BCMDB_MAGIC_ACTIVE_SET);
1264 return set->entry_size;
1265}
1266
1267
1268/** Add record to the parent set with specific key.
1269 *
1270 * The function creates a new record and adds it to the parent set with specific key.
1271 * The function automatically acquires modify lock and releases it
1272 * in the end of operation.
1273 * \param[in] sor parent set of records
1274 * \param[in] key key to add new set at
1275 * \param[in] data record data. Data size is defined at parent SOR registration time.
1276 * \param[out] p_record new record handle
1277 * \return
1278 * =0 - OK\n
1279 * <0 - error code
1280 * \ingroup bcmdb
1281 */
1282int bcmdb_record_add(bcmdb_set *sor, bcmdb_key key, const void *data)
1283{
1284 int rc;
1285 long fastlock_flags;
1286
1287 BUG_ON(!sor);
1288 BUG_ON(!data);
1289 BUG_ON(!sor->magic == BCMDB_MAGIC_ACTIVE_SET);
1290 BUG_ON(!(sor->entry.flags & BCMDB_FLAG_SOS)==0);
1291
1292 fastlock_flags = sor->lock_set_modify(sor);
1293 rc=sor->entry_new(sor, key, data);
1294 sor->unlock_set_modify(sor, fastlock_flags);
1295 return rc;
1296}
1297
1298
1299/** Delete record from the parent SoR given the record key.
1300 *
1301 * The function automatically acquires modify lock and releases it
1302 * in the end of operation.
1303 *
1304 * \param[in] sor parent set of records
1305 * \param[in] key record key.
1306 */
1307void bcmdb_record_delete(bcmdb_set *sor, bcmdb_key key)
1308{
1309 BUG_ON(!sor);
1310 BUG_ON(!sor->magic == BCMDB_MAGIC_ACTIVE_SET);
1311 BUG_ON(!(sor->entry.flags & BCMDB_FLAG_SOS)==0);
1312
1313 sor->lock_record_write(sor, key, 1);
1314 sor->unlock_record_write(sor, 1, 0);
1315}
1316
1317
1318/** Get record data pointer without locking.
1319 *
1320 * The function returns pointer to data structure stored in data base record.\n
1321 * Attention! The caller is required to aquire read or write lock - as appropriate
1322 * before calling this function and release the lock when processing is finished.
1323 *
1324 * \param[in] sor parent set of records
1325 * \param[in] key record key
1326 * \return
1327 * data pointer. NULL if there is no record matching the key.
1328 * \ingroup bcmdb
1329 */
1330void *bcmdb_record_getraw_nolock(bcmdb_set *sor, bcmdb_key key)
1331{
1332 bcmdb_entry *entry;
1333 BUG_ON(!sor);
1334 BUG_ON(!sor->magic == BCMDB_MAGIC_ACTIVE_SET);
1335 BUG_ON(!(sor->entry.flags & BCMDB_FLAG_SOS)==0);
1336 entry = sor->key_to_handle(sor, key);
1337 if (!entry || !(entry->flags & BCMDB_FLAG_VALID))
1338 return NULL;
1339 return entry->data;
1340}
1341
1342
1343/** Lock record for reading and return record data pointer.
1344 *
1345 * The function aquires read-lock and returns pointer to data structure stored in data base record.\n
1346 * read-lock must be released separately when the pointer is no longer in use.
1347 * Note that the default record-read lock is non-blocking and counting.
1348 * That means that multiple processes cam read-lock the same record without blocking.
1349 * The function is low-level. It is recommended to use macro \ref bcmdb_record_get_read instead.
1350 *
1351 * \param[in] sor parent set of records
1352 * \param[in] key record key
1353 * \return
1354 * data pointer. NULL if there is no record matching the key.
1355 * \ingroup bcmdb
1356 */
1357const void *bcmdb_record_getraw_read(bcmdb_set *sor, bcmdb_key key)
1358{
1359 BUG_ON(!sor);
1360 BUG_ON(!sor->magic == BCMDB_MAGIC_ACTIVE_SET);
1361 BUG_ON(!(sor->entry.flags & BCMDB_FLAG_SOS)==0);
1362 return sor->lock_record_read(sor, key);
1363}
1364
1365
1366/** Unlock record locked for reading.
1367 *
1368 * \param[in] sor parent set of records
1369 * \param[in] key record key
1370 *
1371 * \ingroup bcmdb
1372 */
1373void bcmdb_record_unlock_read(bcmdb_set *sor, bcmdb_key key)
1374{
1375 BUG_ON(!sor);
1376 BUG_ON(!sor->magic == BCMDB_MAGIC_ACTIVE_SET);
1377 BUG_ON(!(sor->entry.flags & BCMDB_FLAG_SOS)==0);
1378 sor->unlock_record_read(sor, key);
1379}
1380
1381
1382/** Read record data into user area.
1383 *
1384 * The function aquires read-lock, reads data into user area and releases read-lock.
1385 *
1386 * \param[in] sor parent set of records
1387 * \param[in] key record key
1388 * \param[in] offset offset in data record
1389 * \param[in] size data size. Note that offset+size must be <= record_size
1390 * \param[in] data data pointer.
1391 * \return
1392 * =0-OK\n
1393 * <0-error code
1394 * \ingroup bcmdb
1395 */
1396int bcmdb_record_read(bcmdb_set *sor, bcmdb_key key, int offset, int size, void *data)
1397{
1398 const void *d = bcmdb_record_getraw_read(sor, key);
1399 if (!d)
1400 return BCM_ERR_PARM;
1401 if ((unsigned)offset + (unsigned)size > sor->entry_size)
1402 {
1403 bcmdb_record_unlock_read(sor, key);
1404 return BCM_ERR_PARM;
1405 }
1406 memcpy(data, (const char *)d+(unsigned)offset, (unsigned)size);
1407 bcmdb_record_unlock_read(sor, key);
1408 return 0;
1409}
1410
1411
1412/** Lock record for writing and return record data pointer.
1413 *
1414 * The function aquires write-lock and returns pointer to data structure stored in data base record.\n
1415 * write-lock must be released separately when the pointer is no longer in use.
1416 * The function is low-level. It is recommended to use macro \ref bcmdb_record_get_write instead.
1417 *
1418 * \param[in] sor parent set of records
1419 * \param[in] key record key
1420 * \return
1421 * data pointer. NULL if there is no record matching the key.
1422 * \ingroup bcmdb
1423 */
1424void *bcmdb_record_getraw_write(bcmdb_set *sor, bcmdb_key key)
1425{
1426 BUG_ON(!sor);
1427 BUG_ON(!sor->magic == BCMDB_MAGIC_ACTIVE_SET);
1428 BUG_ON(!(sor->entry.flags & BCMDB_FLAG_SOS)==0);
1429 return sor->lock_record_write(sor, key, 0);
1430}
1431
1432
1433/** Unlock record locked for writing.
1434 *
1435 * \param[in] sor parent set of records
1436 * \param[in] is_cancellation TRUE=cancel transaction
1437 *
1438 * \ingroup bcmdb
1439 */
1440void bcmdb_record_unlock_write(bcmdb_set *sor, int is_cancellation)
1441{
1442 BUG_ON(!sor);
1443 BUG_ON(!sor->magic == BCMDB_MAGIC_ACTIVE_SET);
1444 BUG_ON(!(sor->entry.flags & BCMDB_FLAG_SOS)==0);
1445 sor->unlock_record_write(sor, 0, is_cancellation);
1446}
1447
1448
1449/** Write record data.
1450 *
1451 * The function aquires modify-lock, replaces data stored in data base record
1452 * and releses the lock.
1453 *
1454 * \param[in] sor parent set of records
1455 * \param[in] key record key
1456 * \param[in] offset offset in data record
1457 * \param[in] size data size. Note that offset+size must be <= record_size
1458 * \param[in] data data pointer.
1459 * \return
1460 * =0-OK\n
1461 * <0-error code
1462 * \ingroup bcmdb
1463 */
1464int bcmdb_record_write(bcmdb_set *sor, bcmdb_key key, int offset, int size, const void *data)
1465{
1466 void *d=bcmdb_record_getraw_write(sor, key);
1467 if (!d)
1468 return BCM_ERR_PARM;
1469 if ((unsigned)offset + (unsigned)size > sor->entry_size)
1470 {
1471 bcmdb_record_unlock_write(sor, 0);
1472 return BCM_ERR_PARM;
1473 }
1474 memcpy((char *)d+(unsigned)offset, data, (unsigned)size);
1475 bcmdb_record_unlock_write(sor, 0);
1476 return 0;
1477}
1478
1479
1480/** Register notification function to get informed
1481 * when data base set is modified.
1482 *
1483 * \param[in] sor parent set of records
1484 * \param[in] cb callback function pointer
1485 * \param[in] cb_priv private data that should be passed to the callback
1486 * \return
1487 * =0 - OK\n
1488 * <0 - error code
1489 * \ingroup bcmdb
1490 */
1491int bcmdb_set_notify_register(bcmdb_set *sor, bcmdb_notify_cb cb, long cb_priv)
1492{
1493 bcmdb_notify *nf_new, *nf, *nf_prev = NULL;
1494
1495 BUG_ON(!sor);
1496 BUG_ON(!sor->magic == BCMDB_MAGIC_ACTIVE_SET);
1497 BUG_ON(!cb);
1498
1499 nf_new = bcmos_calloc(sizeof(bcmdb_notify));
1500 if (!nf_new)
1501 return BCM_ERR_NOMEM;
1502 nf_new->cb = cb;
1503 nf_new->cb_priv = cb_priv;
1504
1505 /* Add to set's notification list */
1506 nf = sor->notify_list_head;
1507 while(nf)
1508 {
1509 nf_prev = nf;
1510 nf = nf->next;
1511 }
1512 if (nf_prev)
1513 nf_prev->next = nf_new;
1514 else
1515 sor->notify_list_head = nf_new;
1516
1517 return 0;
1518}
1519
1520
1521/** Data base iterator
1522 *
1523 * \param[in] set data base set
1524 * \param[in] prev last entry. BCMDB_KEY_ANY=start from the beginning
1525 * \return data base entry key following prev or BCMDB_KEY_NO_MORE if end is reached.\n
1526 * BCMDB_KEY_INVAL is reqturned if prev key is invalid
1527 * \ingroup bcmdb
1528 */
1529bcmdb_key bcmdb_set_iterate(const bcmdb_set *set, bcmdb_key prev)
1530{
1531 BUG_ON(!set);
1532 BUG_ON(!set->magic == BCMDB_MAGIC_ACTIVE_SET);
1533 return set->entry_get_next(set, prev);
1534}
1535
1536
1537/* Print database structure */
1538static void _bcmdb_print_structure(const bcmdb_set *set, int level)
1539{
1540 int i;
1541
1542 if (!set)
1543 return;
1544
1545 /* Indentation */
1546 for(i=0; i<level; i++)
1547 printf("\t");
1548
1549 if ((set->entry.flags & BCMDB_FLAG_SOS))
1550 {
1551 bcmdb_key key = bcmdb_set_iterate(set, BCMDB_KEY_ANY);
1552 printf("%-16s SoS max_entries=%d entries=%d\n", set->name, set->max_entries, set->num_entries);
1553 while(key >= 0)
1554 {
1555 _bcmdb_print_structure(bcmdb_set_handle(set, key), level+1);
1556 key = bcmdb_set_iterate(set, key);
1557 }
1558 }
1559 else
1560 {
1561 printf("%-16s SoR max_entries=%d entries=%d record_size=%d total_size=%d\n",
1562 set->name, set->max_entries, set->num_entries, set->entry_size,
1563 set->entry_size*set->max_entries);
1564 }
1565}
1566
1567
1568/** Print database structure.
1569 *
1570 * \param[in] set root set
1571 * \ingroup bcmdb
1572 */
1573void bcmdb_set_print_structure(const bcmdb_set *set)
1574{
1575 _bcmdb_print_structure(set, 0);
1576}
1577
1578
1579/** Format record for printing.
1580 *
1581 * The function converts record data to human-readible format.
1582 *
1583 * \param[in] sor parent set of records
1584 * \param[in] key record key
1585 * \param[out] buffer output buffer
1586 * \param[in] size buffer size
1587 * \return
1588 * >=0-amount of data placed in the buffer\n
1589 * <0-error code
1590 */
1591int bcmdb_record_read_formatted(bcmdb_set *sor, bcmdb_key key, char *buffer, int size)
1592{
1593 const void *data;
1594 int len;
1595 if (!buffer || !size)
1596 return BCM_ERR_PARM;
1597 if (!sor->format)
1598 return BCM_ERR_NOT_SUPPORTED;
1599 *buffer=0;
1600 data = bcmdb_record_getraw_read(sor, key);
1601 if (!data)
1602 return 0;
1603 len = sor->format(data, buffer, size);
1604 bcmdb_record_unlock_read(sor, key);
1605 return len;
1606}