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