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