blob: 8d7702290e36a8ceba88cae2cb1fa3253fbb1498 [file] [log] [blame]
/******************************************************************************
*
* <:copyright-BRCM:2016:DUAL/GPL:standard
*
* Copyright (c) 2016 Broadcom
* All Rights Reserved
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed
* to you under the terms of the GNU General Public License version 2
* (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
* with the following added to such license:
*
* As a special exception, the copyright holders of this software give
* you permission to link this software with independent modules, and
* to copy and distribute the resulting executable under terms of your
* choice, provided that you also meet, for each linked independent
* module, the terms and conditions of the license of that module.
* An independent module is a module which is not derived from this
* software. The special exception does not apply to any modifications
* of the software.
*
* Not withstanding the above, under no circumstances may you combine
* this software in any way with any other Broadcom software provided
* under a license other than the GPL, without Broadcom's express prior
* written consent.
*
* :>
*
*****************************************************************************/
/*
* bcm_db_engine.c
*
* Data base engine
*/
#ifndef BCMDB_ENGINE_H
#define BCMDB_ENGINE_H
/** \defgroup bcmdb_e Data Base Engine Module
Hierarchical data base is built from 3 types of objects:
- set: consists of control info and dynamic array of other sets OR of records of the same kind.
- Mixing subsets and records in the same set is not supported.
- Sets are objects that perform operations like access, locking, adding or removing elements,
etc., via methods that can differ for every set.
- Set elements are addressed using a single key.
- Most sets are internally organized as arrays. However, other organizations (e.g., lists, hash tables)
are also possible because each set can have different set of methods for element access.
- record: is a container for storing information.
- Record consists of control info and a structure containing fields.
- Record is the smallest DB element that has a handle and can be individually locked.
- Record size is fixed at time when the set containing records is created.
- field: is a convenience element.
- DB API includes field access macros for convenience and traceability.
Apart from that, record layout is transparent to the DB engine.
- DB user has an option of accessing record fields directly (as C structure fields), without using DB API
@{
*/
#define bcmdb_error_print(rc,format,args...) BCMOS_TRACE_ERR("status:%s :" format, bcmos_strerror(rc), ##args)
/** Data base backend type
*/
typedef enum
{
BCMDB_BACKEND_ARRAY, /**< Array-based backend */
BCMDB_BACKEND_HASH, /**< Hash-based backend */
BCMDB_BACKEND_OTHER /**< User-defined backend */
} bcmdb_backend_type;
/** Data locking policy
*/
typedef enum
{
BCMDB_LOCK_NONE, /**< No record-level locking. Can be used for records containing independent fields */
BCMDB_LOCK_NB_READ_SHADOW_WRITE,/**< Non-blocking read, write using shadow area (default) */
BCMDB_LOCK_SEM_READ_SEM_WRITE, /**< Strong locking. Both read and write locks use semaphores */
BCMDB_LOCK_OTHER /**< User-defined locking policy */
} bcmdb_lock_policy;
/** Data base key
* Valid values >= 0
*/
typedef int bcmdb_key;
/** Any key
*/
#define BCMDB_KEY_ANY (-1)
/** Invalid key
*/
#define BCMDB_KEY_INVAL (-2)
/** No more records
*/
#define BCMDB_KEY_NO_MORE (-3)
/** Data Base Set control block */
typedef struct bcmdb_set bcmdb_set;
/** Data Base Record control block */
typedef struct bcmdb_record bcmdb_record;
/** Data Base Set or Record */
typedef struct bcmdb_entry bcmdb_entry;
/** Data base operations for notifications.
*/
typedef enum
{
BCMDB_OPER_ADD, /**< Entry has been added */
BCMDB_OPER_DELETE, /**< Entry has been deleted */
BCMDB_OPER_UPDATE /**< Entry has been modified */
} bcmdb_oper_t;
/** Data base update notification callback.
*/
typedef void (*bcmdb_notify_cb)(bcmdb_set *set, bcmdb_key key, bcmdb_oper_t oper, void *new_data);
/** Format callback. Used by bcmdb_record_read_formatted to convert record data to human-readible format */
typedef int (*bcmdb_format_cb)(const void *data, char *buffer, int buffer_size);
/** Set-of-Sets init structure.
*/
typedef struct bcmdb_sos_init
{
const char *name; /**< Set name */
bcmdb_backend_type backend_type; /**< Backend type */
uint32_t max_entries; /**< Max number of entries. 0=unlimited (not supported for array backend) */
uint32_t os_flags; /**< OS flags. Control whether set can be accessed by multiple cores. See bcmos_mutex_create() */
} bcmdb_sos_init;
/** Set-of-Records init structure.
*/
typedef struct bcmdb_sor_init
{
const char *name; /**< Set name */
bcmdb_backend_type backend_type; /**< Backend type */
bcmdb_lock_policy lock_policy; /**< Set locking policy */
uint32_t max_entries; /**< Max number of entries. 0=unlimited (not supported for array backend) */
uint32_t record_size; /**< Record size > 0 */
bcmdb_format_cb format; /**< callback that converts record data to human-readable form */
uint32_t os_flags; /**< OS flags. Control whether set can be accessed by multiple cores. See bcmos_mutex_create() */
} bcmdb_sor_init;
/** Initialize data base engine
*
* \return
* 0 - OK\n
* <0 - error code
*/
int bcmdb_module_init(void);
/** Make set-of-sets control block.
*
* Helper function that creates a set of sets with reasonable defaults for all callbacks and fields.
* Once created, the set control block can be tuned before adding the new set to its parent set.
* \param[in] init set parameters
* \param[out] new_set set control block
* \return
* 0 - OK\n
* <0 - error code
*/
int bcmdb_make_set_of_sets(const bcmdb_sos_init *init, bcmdb_set **new_set);
/** Make set-of-sets control block macro.
*
* Calls \ref bcmdb_make_set_of_sets.
* Prints error message and jumps to error_label in case of failure.
* For parameter description see \ref bcmdb_make_set_of_sets
*/
#define BCMDB_MAKE_SOS(_name,_backend,_max_entries,_p_handle,_rc,_error_label) \
({\
bcmdb_sos_init _init = { .name=_name, .max_entries=_max_entries, .backend_type=_backend};\
_rc = bcmdb_make_set_of_sets(&_init, _p_handle);\
if (_rc)\
{\
bcmdb_error_print(_rc, "failed to create set %s.\n", _name);\
goto _error_label;\
}\
})
/** Make set-of-records control block.
*
* Helper function that creates a set of records with reasonable defaults for all callbacks and fields.
* Once created, the set control block can be tuned before adding the new set to its parent set.
* \param[in] init set parameters
* \param[in] alloc_records true (1) - allocate memory for all records.
* \param[out] new_set set control block
* \return
* 0 - OK\n
* <0 - error code
*/
int bcmdb_make_set_of_records(const bcmdb_sor_init *init, int alloc_records, bcmdb_set **new_set);
/** Make set-of-records control block macro.
*
* Calls \ref bcmdb_make_set_of_records.
* Prints error message and jumps to error_label in case of failure.
* For parameter description see \ref bcmdb_make_set_of_records
*/
#define BCMDB_MAKE_SOR(_name,_backend,_lock,_max_entries,_rec_size,_is_alloc,_format,_p_handle,_rc,_error_label) \
({\
bcmdb_sor_init _init = { .name=_name, .max_entries=_max_entries, .backend_type=_backend,\
.lock_policy=_lock, .record_size=_rec_size,.format=_format};\
_rc = bcmdb_make_set_of_records(&_init,_is_alloc,_p_handle);\
if (_rc)\
{\
bcmdb_error_print(_rc, "failed to create record set %s.\n", _name);\
goto _error_label;\
}\
})
/** Lock data set. When set is locked - it can't be modified.
*
* \param[in] set data base set to be locked
*
*/
void bcmdb_set_lock_read(bcmdb_set *set);
/** Release data set lock
*
* Unlock set locked by \ref bcmdb_set_lock_read
*
* \param[in] set data base set to be unlocked
*/
void bcmdb_set_unlock_read(bcmdb_set *set);
/** Lock data set for modify. If the set is SoS, the locking
* will be recursive.
*
* \param[in] set data base set to be locked
*
* \ingroup bcmdb
*/
void bcmdb_set_lock_modify(bcmdb_set *set);
/** Release data set lock
*
* Unlock set locked by \ref bcmdb_set_lock_modify
*
* \param[in] set data base set to be unlocked
*
* \ingroup bcmdb
*/
void bcmdb_set_unlock_modify(bcmdb_set *set);
/** Add set to the parent set.
*
* The function adds set to the parent set creating data base hierarchy.
* The function automatically acquires modify lock and releases it
* in the end of operation.
* \param[in] sos parent set of sets
* \param[in] key key to add new set at
* \param[in] new_set set control block
* \return
* =0 - OK\n
* <0 - error code
*/
int bcmdb_set_add(bcmdb_set *sos, bcmdb_key key, bcmdb_set *new_set);
/** Add set to the parent set with specific key macro.
*
* Calls \ref bcmdb_set_add.
* Prints error message and jumps to error_label in case of failure.
* For parameter description see \ref bcmdb_set_add
*/
#define BCMDB_SET_ADD(_parent,_key,_set,_rc,_error_label) \
({\
_rc = bcmdb_set_add(_parent,_key,_set);\
if (_rc)\
{\
bcmdb_error_print(_rc, "failed to add set %s to %s.\n", bcmdb_set_name(_set), bcmdb_set_name(_parent));\
goto _error_label;\
}\
})
/** Get set handle given its key.
*
* \param[in] sos parent set of sets
* \param[in] key set key.
* \return
* !=0 - set handle
* NULL- doesn't exist
*/
bcmdb_set *bcmdb_set_handle(const bcmdb_set *sos, bcmdb_key key);
/** Get set key given its handle.
*
* \param[in] set set handle
* \return
* !=BCMDB_KEY_INVAL - set key\n
* BCMDB_KEY_INVAL - error
*/
bcmdb_key bcmdb_set_key(const bcmdb_set *set);
/** Get set name
*
* \param[in] set set handle
* \return set name
*/
const char *bcmdb_set_name(const bcmdb_set *set);
/** Get number of records in the set.
*
* \param[in] set set handle
* \return number of active records in the set
*/
int bcmdb_set_num_records(const bcmdb_set *set);
/** Get entry size
*
* \param[in] set set handle
* \return set entry size
*/
int bcmdb_set_entry_size(const bcmdb_set *set);
/** Add record to the parent set.
*
* The function creates a new record and adds it to the parent set with specific key.
* The function automatically acquires modify lock and releases it
* in the end of operation.
* \param[in] sor parent set of records
* \param[in] key record key
* \param[in] data record data. Data size is defined at parent SOR registration time.
* \return
* =0 - OK\n
* <0 - error code
*/
int bcmdb_record_add(bcmdb_set *sor, bcmdb_key key, const void *data);
/** Delete record from the parent SoR given the record key.
*
* The function automatically acquires modify lock and releases it
* in the end of operation.
*
* \param[in] sor parent set of records
* \param[in] key record key.
*/
void bcmdb_record_delete(bcmdb_set *sor, bcmdb_key key);
/** Get record data pointer without locking.
*
* The function returns pointer to data structure stored in data base record.\n
* Attention! The caller is required to aquire read or write lock - as appropriate
* before calling this function and release the lock when processing is finished.
* The function is low-level. It is recommended to use \ref bcmdb_record_get_nolock instead.
*
* \param[in] sor parent set of records
* \param[in] key record key
* \return
* data pointer. NULL if there is no record matching the key.
*/
void *bcmdb_record_getraw_nolock(bcmdb_set *sor, bcmdb_key key);
/** Get record data pointer without locking.
*
* The function returns pointer to data structure stored in data base record.\n
* Attention! The caller is required to aquire read or write lock - as appropriate
* before calling this function and release the lock when processing is finished.
*
* \param[in] _sor parent set of records
* \param[in] _key record key
* \param[in] _record_type underlying data type.
* \return
* data pointer casted to the underlying data type\n
* NULL if there is no record matching the key.
*/
#define bcmdb_record_get_nolock(_sor, _key, _record_type) \
({ \
assert(sizeof(_record_type)==bcmdb_set_entry_size(_sor)); \
(_record_type *)bcmdb_record_getraw_nolock(_sor, _key); \
})
/** Lock record for reading and return record data pointer.
*
* The function aquires read-lock and returns pointer to data structure stored in data base record.\n
* read-lock must be released separately when the pointer is no longer in use.
* Note that the default record-read lock is non-blocking and counting.
* That means that multiple processes can read-lock the same record without blocking.
* The function is low-level. It is recommended to use macro \ref bcmdb_record_get_read instead.
*
* \param[in] sor parent set of records
* \param[in] key record key
* \return
* data pointer. NULL if there is no record matching the key.
*/
const void *bcmdb_record_getraw_read(bcmdb_set *sor, bcmdb_key key);
/** Lock record for reading and return record data pointer.
*
* The macro returns pointer to data structure stored in data base record.\n
* The read-lock must be released separately when the pointer is no longer in use.
* Note that the default record-read lock is non-blocking and counting.
* That means that multiple processes can read-lock the same record without blocking.
*
* \param[in] _sor parent set of records
* \param[in] _key record key
* \param[in] _record_type underlying data type.
* \return
* data pointer casted to the underlying data type
*/
#define bcmdb_record_get_read(_sor, _key, _record_type) \
({ \
assert(sizeof(_record_type)==bcmdb_set_entry_size(_sor)); \
(const _record_type *)bcmdb_record_getraw_read(_sor, _key);\
})
/** Unlock record locked for reading.
*
* This function must be called after \ref bcmdb_record_get_read or
* \ref bcmdb_record_getraw_read. Following bcmdb_record_read_unlock
* call pointer returned by \ref bcmdb_record_get_read becomes invalid.
*
* \param[in] sor parent set of records
* \param[in] key record key
*
*/
void bcmdb_record_unlock_read(bcmdb_set *sor, bcmdb_key key);
/** Read record data into user area.
*
* The function aquires read-lock, reads data into user area and releases read-lock.
*
* \param[in] sor parent set of records
* \param[in] key record key
* \param[in] offset offset in data record
* \param[in] size data size. Note that offset+size must be <= record_size
* \param[in] data data pointer.
* \return
* =0-OK\n
* <0-error code
*/
int bcmdb_record_read(bcmdb_set *sor, bcmdb_key key, int offset, int size, void *data);
/** Get record field.
*
* The macro returns record field value.
*
* \param[in] _sor parent set of records
* \param[in] _key record key
* \param[in] _record_type type of the underlying data structure.
* \param[in] _field_name data structure field name
* \param[out] _p_field_value pointer of variable where data structure field value should be returned
* \return
* =0-OK\n
* <0-error code
*/
#define bcmdb_record_read_field(_sor, _key, _record_type, _field_name, _p_field_value) \
bcmdb_record_read(_sor, _key, offsetof(_record_type, _field_name), \
sizeof(*(_p_field_value)), _p_field_value);
/** Lock record for writing and return record data pointer.
*
* The function aquires write-lock and returns pointer to data structure stored in data base record.\n
* write-lock must be released separately when the pointer is no longer in use.
* The function is low-level. It is recommended to use macro \ref bcmdb_record_get_write instead.
*
* \param[in] sor parent set of records
* \param[in] key record key
* \return
* data pointer. NULL if there is no record matching the key.
*/
void *bcmdb_record_getraw_write(bcmdb_set *sor, bcmdb_key key);
/** Lock record for writing and return record data pointer.
*
* The function aquires write-lock and returns pointer to data structure stored in data base record.\n
* write-lock must be released separately when the pointer is no longer in use.
*
* \param[in] _sor parent set of records
* \param[in] _key record key
* \param[in] _record_type underlying data type.
* \return
* data pointer casted to the underlying data type
*/
#define bcmdb_record_get_write(_sor, _key, _record_type) \
({ \
assert(sizeof(_record_type)==bcmdb_set_entry_size(_sor)); \
(_record_type *)bcmdb_record_getraw_write(_sor, _key);\
})
/** Unlock record locked for writing.
*
* This function must be called after \ref bcmdb_record_get_write or
* \ref bcmdb_record_getraw_write. Following bcmdb_record_unlock_write
* call pointer returned by \ref bcmdb_record_get_write becomes invalid.
*
* \param[in] sor parent set of records
* \param[in] is_cancellation TRUE=cancel transaction
*
*/
void bcmdb_record_unlock_write(bcmdb_set *sor, int is_cancellation);
/** Write record data.
*
* The function aquires modify-lock, replaces data stored in data base record
* and releses the lock.
*
* \param[in] sor parent set of records
* \param[in] key record key
* \param[in] offset offset in data record
* \param[in] size data size. Note that offset+size must be <= record_size
* \param[in] data data pointer.
* \return
* =0-OK\n
* <0-error code
*/
int bcmdb_record_write(bcmdb_set *sor, bcmdb_key key, int offset, int size, const void *data);
/** Write record field.
*
* The macro updates record field value.\n
* The macro aquires and releases record-modify lock.
*
* \param[in] _sor parent set of records
* \param[in] _key record key
* \param[in] _record_type type of the underlying data structure.
* \param[in] _field_name data structure field name
* \param[in] _field_value field value
* \return
* =0-OK\n
* <0-error code
*/
#define bcmdb_record_write_field(_sor, _key, _record_type, _field_name, _field_value) \
({ \
typeof(((_record_type *)0)->_field_name) _f = _field_value;\
bcmdb_record_write(_sor, _key, offsetof(_record_type, _field_name), sizeof(_f), &_f);\
});
/** Register notification function to get informed
* when data base set is modified.
*
* \param[in] sor parent set of records
* \param[in] cb callback function pointer
* \param[in] cb_priv private data that should be passed to the callback
* \return
* =0 - OK\n
* <0 - error code
*/
int bcmdb_set_notify_register(bcmdb_set *sor, bcmdb_notify_cb cb, long cb_priv);
/** Data base iterator
*
* \param[in] set data base set
* \param[in] prev last entry. BCMDB_KEY_ANY=start from the beginning
* \return data base entry key following prev or BCMDB_KEY_NO_MORE if end is reached.\n
* BCMDB_KEY_INVAL is reqturned if prev key is invalid
*/
bcmdb_key bcmdb_set_iterate(const bcmdb_set *set, bcmdb_key prev);
/** Print database structure.
*
* \param[in] set root set
*/
void bcmdb_set_print_structure(const bcmdb_set *set);
/** Format record for printing.
*
* The function converts record data to human-readable format.
*
* \param[in] sor parent set of records
* \param[in] key record key
* \param[out] buffer output buffer
* \param[in] size buffer size
* \return
* >=0-amount of data placed in the buffer\n
* <0-error code
*/
int bcmdb_record_read_formatted(bcmdb_set *sor, bcmdb_key key, char *buffer, int size);
/** @} end of bcmdb_e group */
#endif /* #ifndef BCMDB_ENGINE_H */