16513c29fSJoe Thornber /* 26513c29fSJoe Thornber * Copyright (C) 2012 Red Hat, Inc. 36513c29fSJoe Thornber * 46513c29fSJoe Thornber * This file is released under the GPL. 56513c29fSJoe Thornber */ 66513c29fSJoe Thornber #ifndef _LINUX_DM_ARRAY_H 76513c29fSJoe Thornber #define _LINUX_DM_ARRAY_H 86513c29fSJoe Thornber 96513c29fSJoe Thornber #include "dm-btree.h" 106513c29fSJoe Thornber 116513c29fSJoe Thornber /*----------------------------------------------------------------*/ 126513c29fSJoe Thornber 136513c29fSJoe Thornber /* 146513c29fSJoe Thornber * The dm-array is a persistent version of an array. It packs the data 156513c29fSJoe Thornber * more efficiently than a btree which will result in less disk space use, 166513c29fSJoe Thornber * and a performance boost. The element get and set operations are still 176513c29fSJoe Thornber * O(ln(n)), but with a much smaller constant. 186513c29fSJoe Thornber * 196513c29fSJoe Thornber * The value type structure is reused from the btree type to support proper 206513c29fSJoe Thornber * reference counting of values. 216513c29fSJoe Thornber * 226513c29fSJoe Thornber * The arrays implicitly know their length, and bounds are checked for 236513c29fSJoe Thornber * lookups and updated. It doesn't store this in an accessible place 246513c29fSJoe Thornber * because it would waste a whole metadata block. Make sure you store the 256513c29fSJoe Thornber * size along with the array root in your encompassing data. 266513c29fSJoe Thornber * 276513c29fSJoe Thornber * Array entries are indexed via an unsigned integer starting from zero. 286513c29fSJoe Thornber * Arrays are not sparse; if you resize an array to have 'n' entries then 296513c29fSJoe Thornber * 'n - 1' will be the last valid index. 306513c29fSJoe Thornber * 316513c29fSJoe Thornber * Typical use: 326513c29fSJoe Thornber * 336513c29fSJoe Thornber * a) initialise a dm_array_info structure. This describes the array 346513c29fSJoe Thornber * values and ties it into a specific transaction manager. It holds no 356513c29fSJoe Thornber * instance data; the same info can be used for many similar arrays if 366513c29fSJoe Thornber * you wish. 376513c29fSJoe Thornber * 386513c29fSJoe Thornber * b) Get yourself a root. The root is the index of a block of data on the 396513c29fSJoe Thornber * disk that holds a particular instance of an array. You may have a 406513c29fSJoe Thornber * pre existing root in your metadata that you wish to use, or you may 416513c29fSJoe Thornber * want to create a brand new, empty array with dm_array_empty(). 426513c29fSJoe Thornber * 436513c29fSJoe Thornber * Like the other data structures in this library, dm_array objects are 446513c29fSJoe Thornber * immutable between transactions. Update functions will return you the 456513c29fSJoe Thornber * root for a _new_ array. If you've incremented the old root, via 466513c29fSJoe Thornber * dm_tm_inc(), before calling the update function you may continue to use 476513c29fSJoe Thornber * it in parallel with the new root. 486513c29fSJoe Thornber * 496513c29fSJoe Thornber * c) resize an array with dm_array_resize(). 506513c29fSJoe Thornber * 516513c29fSJoe Thornber * d) Get a value from the array with dm_array_get_value(). 526513c29fSJoe Thornber * 536513c29fSJoe Thornber * e) Set a value in the array with dm_array_set_value(). 546513c29fSJoe Thornber * 556513c29fSJoe Thornber * f) Walk an array of values in index order with dm_array_walk(). More 566513c29fSJoe Thornber * efficient than making many calls to dm_array_get_value(). 576513c29fSJoe Thornber * 586513c29fSJoe Thornber * g) Destroy the array with dm_array_del(). This tells the transaction 596513c29fSJoe Thornber * manager that you're no longer using this data structure so it can 606513c29fSJoe Thornber * recycle it's blocks. (dm_array_dec() would be a better name for it, 616513c29fSJoe Thornber * but del is in keeping with dm_btree_del()). 626513c29fSJoe Thornber */ 636513c29fSJoe Thornber 646513c29fSJoe Thornber /* 656513c29fSJoe Thornber * Describes an array. Don't initialise this structure yourself, use the 666513c29fSJoe Thornber * init function below. 676513c29fSJoe Thornber */ 686513c29fSJoe Thornber struct dm_array_info { 696513c29fSJoe Thornber struct dm_transaction_manager *tm; 706513c29fSJoe Thornber struct dm_btree_value_type value_type; 716513c29fSJoe Thornber struct dm_btree_info btree_info; 726513c29fSJoe Thornber }; 736513c29fSJoe Thornber 746513c29fSJoe Thornber /* 756513c29fSJoe Thornber * Sets up a dm_array_info structure. You don't need to do anything with 766513c29fSJoe Thornber * this structure when you finish using it. 776513c29fSJoe Thornber * 786513c29fSJoe Thornber * info - the structure being filled in. 796513c29fSJoe Thornber * tm - the transaction manager that should supervise this structure. 806513c29fSJoe Thornber * vt - describes the leaf values. 816513c29fSJoe Thornber */ 826513c29fSJoe Thornber void dm_array_info_init(struct dm_array_info *info, 836513c29fSJoe Thornber struct dm_transaction_manager *tm, 846513c29fSJoe Thornber struct dm_btree_value_type *vt); 856513c29fSJoe Thornber 866513c29fSJoe Thornber /* 876513c29fSJoe Thornber * Create an empty, zero length array. 886513c29fSJoe Thornber * 896513c29fSJoe Thornber * info - describes the array 906513c29fSJoe Thornber * root - on success this will be filled out with the root block 916513c29fSJoe Thornber */ 926513c29fSJoe Thornber int dm_array_empty(struct dm_array_info *info, dm_block_t *root); 936513c29fSJoe Thornber 946513c29fSJoe Thornber /* 956513c29fSJoe Thornber * Resizes the array. 966513c29fSJoe Thornber * 976513c29fSJoe Thornber * info - describes the array 986513c29fSJoe Thornber * root - the root block of the array on disk 996513c29fSJoe Thornber * old_size - the caller is responsible for remembering the size of 1006513c29fSJoe Thornber * the array 1016513c29fSJoe Thornber * new_size - can be bigger or smaller than old_size 1026513c29fSJoe Thornber * value - if we're growing the array the new entries will have this value 1036513c29fSJoe Thornber * new_root - on success, points to the new root block 1046513c29fSJoe Thornber * 1056513c29fSJoe Thornber * If growing the inc function for 'value' will be called the appropriate 1066513c29fSJoe Thornber * number of times. So if the caller is holding a reference they may want 1076513c29fSJoe Thornber * to drop it. 1086513c29fSJoe Thornber */ 1096513c29fSJoe Thornber int dm_array_resize(struct dm_array_info *info, dm_block_t root, 1106513c29fSJoe Thornber uint32_t old_size, uint32_t new_size, 1116513c29fSJoe Thornber const void *value, dm_block_t *new_root) 1126513c29fSJoe Thornber __dm_written_to_disk(value); 1136513c29fSJoe Thornber 1146513c29fSJoe Thornber /* 115dd6a77d9SJoe Thornber * Creates a new array populated with values provided by a callback 116dd6a77d9SJoe Thornber * function. This is more efficient than creating an empty array, 117dd6a77d9SJoe Thornber * resizing, and then setting values since that process incurs a lot of 118dd6a77d9SJoe Thornber * copying. 119dd6a77d9SJoe Thornber * 120dd6a77d9SJoe Thornber * Assumes 32bit values for now since it's only used by the cache hint 121dd6a77d9SJoe Thornber * array. 122dd6a77d9SJoe Thornber * 123dd6a77d9SJoe Thornber * info - describes the array 124dd6a77d9SJoe Thornber * root - the root block of the array on disk 125dd6a77d9SJoe Thornber * size - the number of entries in the array 126dd6a77d9SJoe Thornber * fn - the callback 127dd6a77d9SJoe Thornber * context - passed to the callback 128dd6a77d9SJoe Thornber */ 129dd6a77d9SJoe Thornber typedef int (*value_fn)(uint32_t index, void *value_le, void *context); 130dd6a77d9SJoe Thornber int dm_array_new(struct dm_array_info *info, dm_block_t *root, 131dd6a77d9SJoe Thornber uint32_t size, value_fn fn, void *context); 132dd6a77d9SJoe Thornber 133dd6a77d9SJoe Thornber /* 1346513c29fSJoe Thornber * Frees a whole array. The value_type's decrement operation will be called 1356513c29fSJoe Thornber * for all values in the array 1366513c29fSJoe Thornber */ 1376513c29fSJoe Thornber int dm_array_del(struct dm_array_info *info, dm_block_t root); 1386513c29fSJoe Thornber 1396513c29fSJoe Thornber /* 1406513c29fSJoe Thornber * Lookup a value in the array 1416513c29fSJoe Thornber * 1426513c29fSJoe Thornber * info - describes the array 1436513c29fSJoe Thornber * root - root block of the array 1446513c29fSJoe Thornber * index - array index 1456513c29fSJoe Thornber * value - the value to be read. Will be in on-disk format of course. 1466513c29fSJoe Thornber * 1476513c29fSJoe Thornber * -ENODATA will be returned if the index is out of bounds. 1486513c29fSJoe Thornber */ 1496513c29fSJoe Thornber int dm_array_get_value(struct dm_array_info *info, dm_block_t root, 1506513c29fSJoe Thornber uint32_t index, void *value); 1516513c29fSJoe Thornber 1526513c29fSJoe Thornber /* 1536513c29fSJoe Thornber * Set an entry in the array. 1546513c29fSJoe Thornber * 1556513c29fSJoe Thornber * info - describes the array 1566513c29fSJoe Thornber * root - root block of the array 1576513c29fSJoe Thornber * index - array index 1586513c29fSJoe Thornber * value - value to be written to disk. Make sure you confirm the value is 1596513c29fSJoe Thornber * in on-disk format with__dm_bless_for_disk() before calling. 1606513c29fSJoe Thornber * new_root - the new root block 1616513c29fSJoe Thornber * 1626513c29fSJoe Thornber * The old value being overwritten will be decremented, the new value 1636513c29fSJoe Thornber * incremented. 1646513c29fSJoe Thornber * 1656513c29fSJoe Thornber * -ENODATA will be returned if the index is out of bounds. 1666513c29fSJoe Thornber */ 1676513c29fSJoe Thornber int dm_array_set_value(struct dm_array_info *info, dm_block_t root, 1686513c29fSJoe Thornber uint32_t index, const void *value, dm_block_t *new_root) 1696513c29fSJoe Thornber __dm_written_to_disk(value); 1706513c29fSJoe Thornber 1716513c29fSJoe Thornber /* 1726513c29fSJoe Thornber * Walk through all the entries in an array. 1736513c29fSJoe Thornber * 1746513c29fSJoe Thornber * info - describes the array 1756513c29fSJoe Thornber * root - root block of the array 1766513c29fSJoe Thornber * fn - called back for every element 1776513c29fSJoe Thornber * context - passed to the callback 1786513c29fSJoe Thornber */ 1796513c29fSJoe Thornber int dm_array_walk(struct dm_array_info *info, dm_block_t root, 1806513c29fSJoe Thornber int (*fn)(void *context, uint64_t key, void *leaf), 1816513c29fSJoe Thornber void *context); 1826513c29fSJoe Thornber 1836513c29fSJoe Thornber /*----------------------------------------------------------------*/ 1846513c29fSJoe Thornber 185fdd1315aSJoe Thornber /* 186fdd1315aSJoe Thornber * Cursor api. 187fdd1315aSJoe Thornber * 188fdd1315aSJoe Thornber * This lets you iterate through all the entries in an array efficiently 189fdd1315aSJoe Thornber * (it will preload metadata). 190fdd1315aSJoe Thornber * 191fdd1315aSJoe Thornber * I'm using a cursor, rather than a walk function with a callback because 192fdd1315aSJoe Thornber * the cache target needs to iterate both the mapping and hint arrays in 193fdd1315aSJoe Thornber * unison. 194fdd1315aSJoe Thornber */ 195fdd1315aSJoe Thornber struct dm_array_cursor { 196fdd1315aSJoe Thornber struct dm_array_info *info; 197fdd1315aSJoe Thornber struct dm_btree_cursor cursor; 198fdd1315aSJoe Thornber 199fdd1315aSJoe Thornber struct dm_block *block; 200fdd1315aSJoe Thornber struct array_block *ab; 201fdd1315aSJoe Thornber unsigned index; 202fdd1315aSJoe Thornber }; 203fdd1315aSJoe Thornber 204fdd1315aSJoe Thornber int dm_array_cursor_begin(struct dm_array_info *info, 205fdd1315aSJoe Thornber dm_block_t root, struct dm_array_cursor *c); 206fdd1315aSJoe Thornber void dm_array_cursor_end(struct dm_array_cursor *c); 207fdd1315aSJoe Thornber 208fdd1315aSJoe Thornber uint32_t dm_array_cursor_index(struct dm_array_cursor *c); 209fdd1315aSJoe Thornber int dm_array_cursor_next(struct dm_array_cursor *c); 210*9b696229SJoe Thornber int dm_array_cursor_skip(struct dm_array_cursor *c, uint32_t count); 211fdd1315aSJoe Thornber 212fdd1315aSJoe Thornber /* 213fdd1315aSJoe Thornber * value_le is only valid while the cursor points at the current value. 214fdd1315aSJoe Thornber */ 215fdd1315aSJoe Thornber void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le); 216fdd1315aSJoe Thornber 217fdd1315aSJoe Thornber /*----------------------------------------------------------------*/ 218fdd1315aSJoe Thornber 2196513c29fSJoe Thornber #endif /* _LINUX_DM_ARRAY_H */ 220