/* * Copyright (C) 2007-2009 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ /** \file osl.h User interface for the object storage layer. */ #include #include /** Export all declarations in this file. */ #pragma GCC visibility push(default) /** Describes an object of the object storage layer (osl) */ struct osl_object { /** Pointer to the data of the object. */ void *data; /** The object's size. */ size_t size; }; /** Flags that change the internal handling of osl tables. */ enum osl_table_flags { /** This table will have many rows. */ OSL_LARGE_TABLE = 1 }; /** The three different types of storage for an osl column */ enum osl_storage_type { /** * All data for this column is stored in one file which gets mmapped by * osl_open_table(). This is suitable for columns that do not hold much * data. */ OSL_MAPPED_STORAGE, /** * Each entry is stored on disk and is loaded on demand by * open_disk_object(). This is the preferable storage type for large * objects that need not be in memory all the time. */ OSL_DISK_STORAGE, /** * Objects for columns of this type are volatile: They are only stored * in memory and are discarded once the table gets closed. */ OSL_NO_STORAGE }; /** * Additional per-column flags */ enum osl_storage_flags { /** * Build an rbtree for this column. This is only possible if the * storage type of the column is either \a OSL_MAPPED_STORAGE or \a * OSL_NO_STORAGE. In order to lookup objects in the table by using \a * osl_get_row(), the lookup column must have an associated rbtree. * * \sa osl_storage_type, osl_get_row() */ OSL_RBTREE = 1, /** The data for this column will have constant size. */ OSL_FIXED_SIZE = 2, /** All values of this column will be different. */ OSL_UNIQUE = 4, /** Do not free the data for this column (\p OSL_NO_STORAGE). */ OSL_DONT_FREE = 8 }; /** Opaque osl table structure. */ struct osl_table; /** Opaque osl row structure. */ struct osl_row; /** * In order to build up an rbtree a compare function for the objects must be * specified. Such a function always takes pointers to the two objects to be * compared. It must return -1, zero, or 1, if the first argument is considered * to be respectively less than, equal to, or greater than the second. If two * members compare as equal, their order in the rbtree is undefined. */ typedef int osl_compare_func(const struct osl_object *obj1, const struct osl_object *obj2); /** * The osl_rbreee_loop functions take a function pointer of this type. For each * node in the rbtree, the given function is called. * * \sa osl_rbtree_loop(), osl_rbtree_loop_reverse(). */ typedef int osl_rbtree_loop_func(struct osl_row *row, void *data); /** * Describes one column of a osl table. */ struct osl_column_description { /** One of the tree possible types of storage, \sa osl_storage_type. */ uint16_t storage_type; /** Specifies further properties of the column, \sa osl_storage_flags. */ uint16_t storage_flags; /** * The column name determines the name of the directory where all data * for this column will be stored. Its hash is stored in the table * header. This field is ignored if the storage type is \a NO_STORAGE */ char *name; /** * For columns with an associated rbtree, this must point to a function * that compares the values of two objects, either a built-in function * or a function defined by the application may be supplied. This * field is ignored if the column does not have an associated rbtree. * * \sa osl_storage_flags, osl_compare_func */ osl_compare_func *compare_function; /** * If the \a OSL_FIXED_SIZE flag is set for this column, this value * determines the fixed size of all objects of this column. It is * ignored, if \a OSL_FIXED_SIZE is not set. */ uint32_t data_size; }; /** * Describes one osl table. */ struct osl_table_description { /** The directory which contains all files of this table. */ const char *dir; /** * The table name. A subdirectory of \a dir called \a name is created * at table creation time. It must be a valid name for a subdirectory. * In particular, no slashes are allowed for \a name. */ const char *name; /** The number of columns of this table. */ uint16_t num_columns; /** Further table-wide information, \sa osl_table_flags. */ uint8_t flags; /** The array describing the individual columns of the table. */ struct osl_column_description *column_descriptions; }; /** Flags to be passed to \a osl_close_table(). */ enum osl_close_flags { /** * The table header contains a "dirty" flag which specifies whether * the table is currently open by another process. This flag specifies * that the dirty flag should be cleared before closing the table. */ OSL_MARK_CLEAN = 1, /** * If the table contains columns of type \a OSL_NO_STORAGE and this * flag is passed to osl_close_table(), free(3) is called for each * object of each column of type \a OSL_NO_STORAGE. */ OSL_FREE_VOLATILE = 2 }; /** * Create a new osl table. * * \param desc Pointer to the table description. * * \return Standard. */ int osl_create_table(const struct osl_table_description *desc); /** * Open an osl table. * * Each osl table must be opened before its data can be accessed. * * \param desc Describes the table to be opened. * \param result Contains a pointer to the open table on success. * * The table description given by \a desc should coincide with the * description used at creation time. * * \return Standard. */ int osl_open_table(const struct osl_table_description *desc, struct osl_table **result); /** * Close an osl table. * * \param t Pointer to the table to be closed. * \param flags Options for what should be cleaned up. * * If osl_open_table() succeeds, the resulting table pointer must later be * passed to this function in order to flush all changes to the file system and * to free the resources that were allocated by osl_open_table(). * * \return Standard. * * \sa osl_open_table(), unmap_table(). */ int osl_close_table(struct osl_table *t, enum osl_close_flags flags); /** * Get the row that contains the given object. * * \param t Pointer to an open osl table. * \param col_num The number of the column to be searched. * \param obj The object to be looked up. * \param result Points to the row containing \a obj. * * Lookup \a obj in \a t and return the row containing \a obj. The column * specified by \a col_num must have an associated rbtree. * * \return Standard. * * \sa osl_storage_flags */ int osl_get_row(const struct osl_table *t, unsigned col_num, const struct osl_object *obj, struct osl_row **result); /** * Retrieve an object identified by row and column * * \param t Pointer to an open osl table. * \param row Pointer to the row. * \param col_num The column number. * \param object The result pointer. * * The column determined by \a col_num must be of type \p OSL_MAPPED_STORAGE * or \p OSL_NO_STORAGE, i.e. no disk storage objects may be retrieved by this * function. * * \return Standard. * * \sa osl_storage_type, osl_open_disk_object(). */ int osl_get_object(const struct osl_table *t, const struct osl_row *row, unsigned col_num, struct osl_object *object); /** * Retrieve an object of type \p OSL_DISK_STORAGE by row and column. * * \param t Pointer to an open osl table. * \param r Pointer to the row containing the object. * \param col_num The column number. * \param obj Points to the result upon successful return. * * For columns of type \p OSL_DISK_STORAGE, this function must be used to * retrieve one of its containing objects. Afterwards, osl_close_disk_object() * must be called in order to deallocate the resources. * * \return Standard. * * \sa osl_get_object(), osl_storage_type, osl_close_disk_object(). */ int osl_open_disk_object(const struct osl_table *t, const struct osl_row *r, unsigned col_num, struct osl_object *obj); /** * Free resources that were allocated during osl_open_disk_object(). * * \param obj Pointer to the object previously returned by open_disk_object(). * * \return The return value of the underlying call to munmap(). * * \sa munmap(2). */ int osl_close_disk_object(struct osl_object *obj); /** * Add a new row to an osl table and retrieve this row. * * \param t Pointer to an open osl table. * \param objects Array of objects to be added. * \param row Result pointer. * * The \a objects parameter must point to an array containing one object per * column. The order of the objects in the array is given by the table * description of \a table. Several sanity checks are performed during object * insertion and the function returns without modifying the table if any of * these tests fail. In fact, it is atomic in the sense that it either * succeeds or leaves the table unchanged (i.e. either all or none of the * objects are added to the table). * * It is considered an error if an object is added to a column with associated * rbtree if this object is equal to an object already contained in that column * (i.e. the compare function for the column's rbtree returns zero). * * \return Standard. * * \sa struct osl_table_description, osl_compare_func, osl_add_row(). */ int osl_add_and_get_row(struct osl_table *t, struct osl_object *objects, struct osl_row **row); /** * Add a new row to an osl table. * * \param t Same meaning as osl_add_and_get_row(). * \param objects Same meaning as osl_add_and_get_row(). * * \return The return value of the underlying call to osl_add_and_get_row(). * * This is equivalent to osl_add_and_get_row(t, objects, NULL). */ int osl_add_row(struct osl_table *t, struct osl_object *objects); /** * Delete a row from an osl table. * * \param t Pointer to an open osl table. * \param row Pointer to the row to delete. * * This removes all disk storage objects, removes all rbtree nodes, and frees * all volatile objects belonging to the given row. For mapped columns, the * data is merely marked invalid and may be pruned from time to time by * osl_fsck. * * \return Standard. */ int osl_del_row(struct osl_table *t, struct osl_row *row); /** * Loop over all nodes in an rbtree. * * \param t Pointer to an open osl table. * \param col_num The column to use for iterating over the elements. * \param private_data Pointer that gets passed to \a func. * \param func The function to be called for each node in the rbtree. * * This function does an in-order walk of the rbtree associated with \a * col_num. It is an error if the \p OSL_RBTREE flag is not set for this * column. For each node in the rbtree, the given function \a func is called * with two pointers as arguments: The first osl_row* argument points to the * row that contains the object corresponding to the rbtree node currently * traversed, and the \a private_data pointer is passed verbatim to \a func as the * second argument. The loop terminates either if \a func returns a negative * value, or if all nodes of the tree have been visited. * * * \return Standard. If the termination of the loop was caused by \a func * returning a negative value, \p -E_OSL_LOOP is returned. * * \sa osl_storage_flags, osl_rbtree_loop_reverse(), osl_compare_func. */ int osl_rbtree_loop(const struct osl_table *t, unsigned col_num, void *private_data, osl_rbtree_loop_func *func); /** * Loop over all nodes in an rbtree in reverse order. * * \param t Identical meaning as in \p osl_rbtree_loop(). * \param col_num Identical meaning as in \p osl_rbtree_loop(). * \param private_data Identical meaning as in \p osl_rbtree_loop(). * \param func Identical meaning as in \p osl_rbtree_loop(). * * This function is identical to \p osl_rbtree_loop(), the only difference * is that the tree is walked in reverse order. * * \return The same return value as \p osl_rbtree_loop(). * * \sa osl_rbtree_loop(). */ int osl_rbtree_loop_reverse(const struct osl_table *t, unsigned col_num, void *private_data, osl_rbtree_loop_func *func); /** * Change an object in an osl table. * * \param t Pointer to an open osl table. * \param r Pointer to the row containing the object to be updated. * \param col_num Number of the column containing the object to be updated. * \param obj Pointer to the replacement object. * * This function gets rid of all references to the old object. This includes * removal of the rbtree node in case there is an rbtree associated with \a * col_num. It then inserts \a obj into the table and the rbtree if necessary. * * If the \p OSL_RBTREE flag is set for \a col_num, you \b MUST call this * function in order to change the contents of an object, even for volatile or * mapped columns of constant size (which may be updated directly if \p * OSL_RBTREE is not set). Otherwise the rbtree might become corrupted. * * \return Standard */ int osl_update_object(struct osl_table *t, const struct osl_row *r, unsigned col_num, struct osl_object *obj); /** * Get the number of rows of the given table. * * \param t Pointer to an open osl table. * \param num_rows Result is returned here. * * The number of rows returned via \a num_rows excluding any invalid rows. * * \return Positive on success, \p -E_OSL_BAD_TABLE if \a t is \p NULL. */ int osl_get_num_rows(const struct osl_table *t, unsigned *num_rows); /** * Get the row corresponding to the smallest rbtree node of a column. * * \param t An open rbtree table. * \param col_num The number of the rbtree column. * \param result A pointer to the first row is returned here. * * The rbtree node of the smallest object (with respect to the corresponding * compare function) is selected and the row containing this object is * returned. It is an error if \a col_num refers to a column without an * associated rbtree. * * \return Standard. * * \sa osl_get_nth_row(), osl_rbtree_last_row(). */ int osl_rbtree_first_row(const struct osl_table *t, unsigned col_num, struct osl_row **result); /** * Get the row corresponding to the greatest rbtree node of a column. * * \param t The same meaning as in \p osl_rbtree_first_row(). * \param col_num The same meaning as in \p osl_rbtree_first_row(). * \param result The same meaning as in \p osl_rbtree_first_row(). * * This function works just like osl_rbtree_first_row(), the only difference * is that the row containing the greatest rather than the smallest object is * returned. * * \return Standard. * * \sa osl_get_nth_row(), osl_rbtree_first_row(). */ int osl_rbtree_last_row(const struct osl_table *t, unsigned col_num, struct osl_row **result); /** * Get the row with n-th greatest value. * * \param t Pointer to an open osl table. * \param col_num The column number. * \param n The rank of the desired row. * \param result Row is returned here. * * Retrieve the n-th order statistic with respect to the compare function * of the rbtree column \a col_num. In other words, get the row with * \a n th greatest value in column \a col_num. It is an error if * \a col_num is not a rbtree column, or if \a n is larger than the * number of rows in the table. * * \return Standard. * * \sa osl_storage_flags, osl_compare_func, osl_get_row(), * osl_rbtree_last_row(), osl_rbtree_first_row(), osl_get_rank(). */ int osl_get_nth_row(const struct osl_table *t, unsigned col_num, unsigned n, struct osl_row **result); /** * Get the rank of a row. * * \param t An open osl table. * \param r The row to get the rank of. * \param col_num The number of an rbtree column. * \param rank Result pointer. * * The rank is, by definition, the position of the row in the linear order * determined by an in-order tree walk of the rbtree associated with column * number \a col_num of \a table. * * \return Standard. * * \sa osl_get_nth_row(). */ int osl_get_rank(const struct osl_table *t, struct osl_row *r, unsigned col_num, unsigned *rank); /** * Get a string describing the error code passed in the argument. * * \param num The error code. * * This works just like strerror(3). The given number must be an osl error * code. The result must not be freed by the caller. * * \return The error text corresponding to an osl error code. */ const char *osl_strerror(int num); #pragma GCC visibility pop