| /* | |
| * Copyright (C) 2012 Red Hat, Inc. | |
| * | |
| * This file is released under the GPL. | |
| */ | |
| #ifndef _LINUX_DM_ARRAY_H | |
| #define _LINUX_DM_ARRAY_H | |
| #include "dm-btree.h" | |
| /*----------------------------------------------------------------*/ | |
| /* | |
| * The dm-array is a persistent version of an array. It packs the data | |
| * more efficiently than a btree which will result in less disk space use, | |
| * and a performance boost. The element get and set operations are still | |
| * O(ln(n)), but with a much smaller constant. | |
| * | |
| * The value type structure is reused from the btree type to support proper | |
| * reference counting of values. | |
| * | |
| * The arrays implicitly know their length, and bounds are checked for | |
| * lookups and updated. It doesn't store this in an accessible place | |
| * because it would waste a whole metadata block. Make sure you store the | |
| * size along with the array root in your encompassing data. | |
| * | |
| * Array entries are indexed via an unsigned integer starting from zero. | |
| * Arrays are not sparse; if you resize an array to have 'n' entries then | |
| * 'n - 1' will be the last valid index. | |
| * | |
| * Typical use: | |
| * | |
| * a) initialise a dm_array_info structure. This describes the array | |
| * values and ties it into a specific transaction manager. It holds no | |
| * instance data; the same info can be used for many similar arrays if | |
| * you wish. | |
| * | |
| * b) Get yourself a root. The root is the index of a block of data on the | |
| * disk that holds a particular instance of an array. You may have a | |
| * pre existing root in your metadata that you wish to use, or you may | |
| * want to create a brand new, empty array with dm_array_empty(). | |
| * | |
| * Like the other data structures in this library, dm_array objects are | |
| * immutable between transactions. Update functions will return you the | |
| * root for a _new_ array. If you've incremented the old root, via | |
| * dm_tm_inc(), before calling the update function you may continue to use | |
| * it in parallel with the new root. | |
| * | |
| * c) resize an array with dm_array_resize(). | |
| * | |
| * d) Get a value from the array with dm_array_get_value(). | |
| * | |
| * e) Set a value in the array with dm_array_set_value(). | |
| * | |
| * f) Walk an array of values in index order with dm_array_walk(). More | |
| * efficient than making many calls to dm_array_get_value(). | |
| * | |
| * g) Destroy the array with dm_array_del(). This tells the transaction | |
| * manager that you're no longer using this data structure so it can | |
| * recycle it's blocks. (dm_array_dec() would be a better name for it, | |
| * but del is in keeping with dm_btree_del()). | |
| */ | |
| /* | |
| * Describes an array. Don't initialise this structure yourself, use the | |
| * init function below. | |
| */ | |
| struct dm_array_info { | |
| struct dm_transaction_manager *tm; | |
| struct dm_btree_value_type value_type; | |
| struct dm_btree_info btree_info; | |
| }; | |
| /* | |
| * Sets up a dm_array_info structure. You don't need to do anything with | |
| * this structure when you finish using it. | |
| * | |
| * info - the structure being filled in. | |
| * tm - the transaction manager that should supervise this structure. | |
| * vt - describes the leaf values. | |
| */ | |
| void dm_array_info_init(struct dm_array_info *info, | |
| struct dm_transaction_manager *tm, | |
| struct dm_btree_value_type *vt); | |
| /* | |
| * Create an empty, zero length array. | |
| * | |
| * info - describes the array | |
| * root - on success this will be filled out with the root block | |
| */ | |
| int dm_array_empty(struct dm_array_info *info, dm_block_t *root); | |
| /* | |
| * Resizes the array. | |
| * | |
| * info - describes the array | |
| * root - the root block of the array on disk | |
| * old_size - the caller is responsible for remembering the size of | |
| * the array | |
| * new_size - can be bigger or smaller than old_size | |
| * value - if we're growing the array the new entries will have this value | |
| * new_root - on success, points to the new root block | |
| * | |
| * If growing the inc function for 'value' will be called the appropriate | |
| * number of times. So if the caller is holding a reference they may want | |
| * to drop it. | |
| */ | |
| int dm_array_resize(struct dm_array_info *info, dm_block_t root, | |
| uint32_t old_size, uint32_t new_size, | |
| const void *value, dm_block_t *new_root) | |
| __dm_written_to_disk(value); | |
| /* | |
| * Creates a new array populated with values provided by a callback | |
| * function. This is more efficient than creating an empty array, | |
| * resizing, and then setting values since that process incurs a lot of | |
| * copying. | |
| * | |
| * Assumes 32bit values for now since it's only used by the cache hint | |
| * array. | |
| * | |
| * info - describes the array | |
| * root - the root block of the array on disk | |
| * size - the number of entries in the array | |
| * fn - the callback | |
| * context - passed to the callback | |
| */ | |
| typedef int (*value_fn)(uint32_t index, void *value_le, void *context); | |
| int dm_array_new(struct dm_array_info *info, dm_block_t *root, | |
| uint32_t size, value_fn fn, void *context); | |
| /* | |
| * Frees a whole array. The value_type's decrement operation will be called | |
| * for all values in the array | |
| */ | |
| int dm_array_del(struct dm_array_info *info, dm_block_t root); | |
| /* | |
| * Lookup a value in the array | |
| * | |
| * info - describes the array | |
| * root - root block of the array | |
| * index - array index | |
| * value - the value to be read. Will be in on-disk format of course. | |
| * | |
| * -ENODATA will be returned if the index is out of bounds. | |
| */ | |
| int dm_array_get_value(struct dm_array_info *info, dm_block_t root, | |
| uint32_t index, void *value); | |
| /* | |
| * Set an entry in the array. | |
| * | |
| * info - describes the array | |
| * root - root block of the array | |
| * index - array index | |
| * value - value to be written to disk. Make sure you confirm the value is | |
| * in on-disk format with__dm_bless_for_disk() before calling. | |
| * new_root - the new root block | |
| * | |
| * The old value being overwritten will be decremented, the new value | |
| * incremented. | |
| * | |
| * -ENODATA will be returned if the index is out of bounds. | |
| */ | |
| int dm_array_set_value(struct dm_array_info *info, dm_block_t root, | |
| uint32_t index, const void *value, dm_block_t *new_root) | |
| __dm_written_to_disk(value); | |
| /* | |
| * Walk through all the entries in an array. | |
| * | |
| * info - describes the array | |
| * root - root block of the array | |
| * fn - called back for every element | |
| * context - passed to the callback | |
| */ | |
| int dm_array_walk(struct dm_array_info *info, dm_block_t root, | |
| int (*fn)(void *context, uint64_t key, void *leaf), | |
| void *context); | |
| /*----------------------------------------------------------------*/ | |
| /* | |
| * Cursor api. | |
| * | |
| * This lets you iterate through all the entries in an array efficiently | |
| * (it will preload metadata). | |
| * | |
| * I'm using a cursor, rather than a walk function with a callback because | |
| * the cache target needs to iterate both the mapping and hint arrays in | |
| * unison. | |
| */ | |
| struct dm_array_cursor { | |
| struct dm_array_info *info; | |
| struct dm_btree_cursor cursor; | |
| struct dm_block *block; | |
| struct array_block *ab; | |
| unsigned index; | |
| }; | |
| int dm_array_cursor_begin(struct dm_array_info *info, | |
| dm_block_t root, struct dm_array_cursor *c); | |
| void dm_array_cursor_end(struct dm_array_cursor *c); | |
| uint32_t dm_array_cursor_index(struct dm_array_cursor *c); | |
| int dm_array_cursor_next(struct dm_array_cursor *c); | |
| int dm_array_cursor_skip(struct dm_array_cursor *c, uint32_t count); | |
| /* | |
| * value_le is only valid while the cursor points at the current value. | |
| */ | |
| void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le); | |
| /*----------------------------------------------------------------*/ | |
| #endif /* _LINUX_DM_ARRAY_H */ |