dm-array.h (7448B)
1/* 2 * Copyright (C) 2012 Red Hat, Inc. 3 * 4 * This file is released under the GPL. 5 */ 6#ifndef _LINUX_DM_ARRAY_H 7#define _LINUX_DM_ARRAY_H 8 9#include "dm-btree.h" 10 11/*----------------------------------------------------------------*/ 12 13/* 14 * The dm-array is a persistent version of an array. It packs the data 15 * more efficiently than a btree which will result in less disk space use, 16 * and a performance boost. The element get and set operations are still 17 * O(ln(n)), but with a much smaller constant. 18 * 19 * The value type structure is reused from the btree type to support proper 20 * reference counting of values. 21 * 22 * The arrays implicitly know their length, and bounds are checked for 23 * lookups and updated. It doesn't store this in an accessible place 24 * because it would waste a whole metadata block. Make sure you store the 25 * size along with the array root in your encompassing data. 26 * 27 * Array entries are indexed via an unsigned integer starting from zero. 28 * Arrays are not sparse; if you resize an array to have 'n' entries then 29 * 'n - 1' will be the last valid index. 30 * 31 * Typical use: 32 * 33 * a) initialise a dm_array_info structure. This describes the array 34 * values and ties it into a specific transaction manager. It holds no 35 * instance data; the same info can be used for many similar arrays if 36 * you wish. 37 * 38 * b) Get yourself a root. The root is the index of a block of data on the 39 * disk that holds a particular instance of an array. You may have a 40 * pre existing root in your metadata that you wish to use, or you may 41 * want to create a brand new, empty array with dm_array_empty(). 42 * 43 * Like the other data structures in this library, dm_array objects are 44 * immutable between transactions. Update functions will return you the 45 * root for a _new_ array. If you've incremented the old root, via 46 * dm_tm_inc(), before calling the update function you may continue to use 47 * it in parallel with the new root. 48 * 49 * c) resize an array with dm_array_resize(). 50 * 51 * d) Get a value from the array with dm_array_get_value(). 52 * 53 * e) Set a value in the array with dm_array_set_value(). 54 * 55 * f) Walk an array of values in index order with dm_array_walk(). More 56 * efficient than making many calls to dm_array_get_value(). 57 * 58 * g) Destroy the array with dm_array_del(). This tells the transaction 59 * manager that you're no longer using this data structure so it can 60 * recycle it's blocks. (dm_array_dec() would be a better name for it, 61 * but del is in keeping with dm_btree_del()). 62 */ 63 64/* 65 * Describes an array. Don't initialise this structure yourself, use the 66 * init function below. 67 */ 68struct dm_array_info { 69 struct dm_transaction_manager *tm; 70 struct dm_btree_value_type value_type; 71 struct dm_btree_info btree_info; 72}; 73 74/* 75 * Sets up a dm_array_info structure. You don't need to do anything with 76 * this structure when you finish using it. 77 * 78 * info - the structure being filled in. 79 * tm - the transaction manager that should supervise this structure. 80 * vt - describes the leaf values. 81 */ 82void dm_array_info_init(struct dm_array_info *info, 83 struct dm_transaction_manager *tm, 84 struct dm_btree_value_type *vt); 85 86/* 87 * Create an empty, zero length array. 88 * 89 * info - describes the array 90 * root - on success this will be filled out with the root block 91 */ 92int dm_array_empty(struct dm_array_info *info, dm_block_t *root); 93 94/* 95 * Resizes the array. 96 * 97 * info - describes the array 98 * root - the root block of the array on disk 99 * old_size - the caller is responsible for remembering the size of 100 * the array 101 * new_size - can be bigger or smaller than old_size 102 * value - if we're growing the array the new entries will have this value 103 * new_root - on success, points to the new root block 104 * 105 * If growing the inc function for 'value' will be called the appropriate 106 * number of times. So if the caller is holding a reference they may want 107 * to drop it. 108 */ 109int dm_array_resize(struct dm_array_info *info, dm_block_t root, 110 uint32_t old_size, uint32_t new_size, 111 const void *value, dm_block_t *new_root) 112 __dm_written_to_disk(value); 113 114/* 115 * Creates a new array populated with values provided by a callback 116 * function. This is more efficient than creating an empty array, 117 * resizing, and then setting values since that process incurs a lot of 118 * copying. 119 * 120 * Assumes 32bit values for now since it's only used by the cache hint 121 * array. 122 * 123 * info - describes the array 124 * root - the root block of the array on disk 125 * size - the number of entries in the array 126 * fn - the callback 127 * context - passed to the callback 128 */ 129typedef int (*value_fn)(uint32_t index, void *value_le, void *context); 130int dm_array_new(struct dm_array_info *info, dm_block_t *root, 131 uint32_t size, value_fn fn, void *context); 132 133/* 134 * Frees a whole array. The value_type's decrement operation will be called 135 * for all values in the array 136 */ 137int dm_array_del(struct dm_array_info *info, dm_block_t root); 138 139/* 140 * Lookup a value in the array 141 * 142 * info - describes the array 143 * root - root block of the array 144 * index - array index 145 * value - the value to be read. Will be in on-disk format of course. 146 * 147 * -ENODATA will be returned if the index is out of bounds. 148 */ 149int dm_array_get_value(struct dm_array_info *info, dm_block_t root, 150 uint32_t index, void *value); 151 152/* 153 * Set an entry in the array. 154 * 155 * info - describes the array 156 * root - root block of the array 157 * index - array index 158 * value - value to be written to disk. Make sure you confirm the value is 159 * in on-disk format with__dm_bless_for_disk() before calling. 160 * new_root - the new root block 161 * 162 * The old value being overwritten will be decremented, the new value 163 * incremented. 164 * 165 * -ENODATA will be returned if the index is out of bounds. 166 */ 167int dm_array_set_value(struct dm_array_info *info, dm_block_t root, 168 uint32_t index, const void *value, dm_block_t *new_root) 169 __dm_written_to_disk(value); 170 171/* 172 * Walk through all the entries in an array. 173 * 174 * info - describes the array 175 * root - root block of the array 176 * fn - called back for every element 177 * context - passed to the callback 178 */ 179int dm_array_walk(struct dm_array_info *info, dm_block_t root, 180 int (*fn)(void *context, uint64_t key, void *leaf), 181 void *context); 182 183/*----------------------------------------------------------------*/ 184 185/* 186 * Cursor api. 187 * 188 * This lets you iterate through all the entries in an array efficiently 189 * (it will preload metadata). 190 * 191 * I'm using a cursor, rather than a walk function with a callback because 192 * the cache target needs to iterate both the mapping and hint arrays in 193 * unison. 194 */ 195struct dm_array_cursor { 196 struct dm_array_info *info; 197 struct dm_btree_cursor cursor; 198 199 struct dm_block *block; 200 struct array_block *ab; 201 unsigned index; 202}; 203 204int dm_array_cursor_begin(struct dm_array_info *info, 205 dm_block_t root, struct dm_array_cursor *c); 206void dm_array_cursor_end(struct dm_array_cursor *c); 207 208uint32_t dm_array_cursor_index(struct dm_array_cursor *c); 209int dm_array_cursor_next(struct dm_array_cursor *c); 210int dm_array_cursor_skip(struct dm_array_cursor *c, uint32_t count); 211 212/* 213 * value_le is only valid while the cursor points at the current value. 214 */ 215void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le); 216 217/*----------------------------------------------------------------*/ 218 219#endif /* _LINUX_DM_ARRAY_H */