xref: /linux/drivers/md/persistent-data/dm-array.h (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
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