1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * Copyright 2023 Red Hat
6 #ifndef UDS_DELTA_INDEX_H
7 #define UDS_DELTA_INDEX_H
9 #include <linux/cache.h>
12 #include "time-utils.h"
15 #include "io-factory.h"
18 * A delta index is a key-value store, where each entry maps an address (the key) to a payload (the
19 * value). The entries are sorted by address, and only the delta between successive addresses is
20 * stored in the entry. The addresses are assumed to be uniformly distributed, and the deltas are
21 * therefore exponentially distributed.
23 * A delta_index can either be mutable or immutable depending on its expected use. The immutable
24 * form of a delta index is used for the indexes of closed chapters committed to the volume. The
25 * mutable form of a delta index is used by the volume index, and also by the chapter index in an
26 * open chapter. Like the index as a whole, each mutable delta index is divided into a number of
31 /* The offset of the delta list start, in bits */
33 /* The number of bits in the delta list */
35 /* Where the last search "found" the key, in bits */
37 /* The key for the record just before save_offset */
42 /* The delta list memory */
44 /* The delta list headers */
45 struct delta_list
*delta_lists
;
46 /* Temporary starts of delta lists */
48 /* Buffered writer for saving an index */
49 struct buffered_writer
*buffered_writer
;
50 /* The size of delta list memory */
52 /* Nanoseconds spent rebalancing */
53 ktime_t rebalance_time
;
54 /* Number of memory rebalances */
56 /* The number of bits in a stored value */
58 /* The number of bits in the minimal key code */
60 /* The number of keys used in a minimal code */
62 /* The number of keys used for another code bit */
64 /* The number of records in the index */
66 /* The number of collision records */
68 /* The number of records removed */
70 /* The number of UDS_OVERFLOW errors detected */
72 /* The index of the first delta list */
74 /* The number of delta lists */
76 /* Tag belonging to this delta index */
78 } __aligned(L1_CACHE_BYTES
);
80 struct delta_list_save_info
{
81 /* Tag identifying which delta index this list is in */
83 /* Bit offset of the start of the list data */
85 /* Number of bytes of list data */
87 /* The delta list number within the delta index */
93 struct delta_zone
*delta_zones
;
94 /* The number of zones */
95 unsigned int zone_count
;
96 /* The number of delta lists */
98 /* Maximum lists per zone */
100 /* Total memory allocated to this index */
102 /* The number of non-empty lists at load time per zone */
103 u32 load_lists
[MAX_ZONES
];
104 /* True if this index is mutable */
106 /* Tag belonging to this delta index */
111 * A delta_index_page describes a single page of a chapter index. The delta_index field allows the
112 * page to be treated as an immutable delta_index. We use the delta_zone field to treat the chapter
113 * index page as a single zone index, and without the need to do an additional memory allocation.
115 struct delta_index_page
{
116 struct delta_index delta_index
;
117 /* These values are loaded from the delta_page_header */
118 u32 lowest_list_number
;
119 u32 highest_list_number
;
120 u64 virtual_chapter_number
;
121 /* This structure describes the single zone of a delta index page. */
122 struct delta_zone delta_zone
;
126 * Notes on the delta_index_entries:
128 * The fields documented as "public" can be read by any code that uses a delta_index. The fields
129 * documented as "private" carry information between delta_index method calls and should not be
130 * used outside the delta_index module.
132 * (1) The delta_index_entry is used like an iterator when searching a delta list.
134 * (2) It is also the result of a successful search and can be used to refer to the element found
137 * (3) It is also the result of an unsuccessful search and can be used to refer to the insertion
138 * point for a new record.
140 * (4) If at_end is true, the delta_list entry can only be used as the insertion point for a new
141 * record at the end of the list.
143 * (5) If at_end is false and is_collision is true, the delta_list entry fields refer to a
144 * collision entry in the list, and the delta_list entry can be used as a reference to this
147 * (6) If at_end is false and is_collision is false, the delta_list entry fields refer to a
148 * non-collision entry in the list. Such delta_list entries can be used as a reference to a
149 * found entry, or an insertion point for a non-collision entry before this entry, or an
150 * insertion point for a collision entry that collides with this entry.
152 struct delta_index_entry
{
154 /* The key for this entry */
156 /* We are after the last list entry */
158 /* This record is a collision */
162 /* This delta list overflowed */
164 /* The number of bits used for the value */
166 /* The number of bits used for the entire entry */
168 /* The delta index zone */
169 struct delta_zone
*delta_zone
;
170 /* The delta list containing the entry */
171 struct delta_list
*delta_list
;
172 /* The delta list number */
174 /* Bit offset of this entry within the list */
176 /* The delta between this and previous entry */
178 /* Temporary delta list for immutable indices */
179 struct delta_list temp_delta_list
;
182 struct delta_index_stats
{
183 /* Number of bytes allocated */
184 size_t memory_allocated
;
185 /* Nanoseconds spent rebalancing */
186 ktime_t rebalance_time
;
187 /* Number of memory rebalances */
189 /* The number of records in the index */
191 /* The number of collision records */
193 /* The number of records removed */
195 /* The number of UDS_OVERFLOW errors detected */
197 /* The number of delta lists */
201 int __must_check
uds_initialize_delta_index(struct delta_index
*delta_index
,
202 unsigned int zone_count
, u32 list_count
,
203 u32 mean_delta
, u32 payload_bits
,
204 size_t memory_size
, u8 tag
);
206 int __must_check
uds_initialize_delta_index_page(struct delta_index_page
*delta_index_page
,
207 u64 expected_nonce
, u32 mean_delta
,
208 u32 payload_bits
, u8
*memory
,
211 void uds_uninitialize_delta_index(struct delta_index
*delta_index
);
213 void uds_reset_delta_index(const struct delta_index
*delta_index
);
215 int __must_check
uds_pack_delta_index_page(const struct delta_index
*delta_index
,
216 u64 header_nonce
, u8
*memory
,
218 u64 virtual_chapter_number
, u32 first_list
,
221 int __must_check
uds_start_restoring_delta_index(struct delta_index
*delta_index
,
222 struct buffered_reader
**buffered_readers
,
223 unsigned int reader_count
);
225 int __must_check
uds_finish_restoring_delta_index(struct delta_index
*delta_index
,
226 struct buffered_reader
**buffered_readers
,
227 unsigned int reader_count
);
229 int __must_check
uds_check_guard_delta_lists(struct buffered_reader
**buffered_readers
,
230 unsigned int reader_count
);
232 int __must_check
uds_start_saving_delta_index(const struct delta_index
*delta_index
,
233 unsigned int zone_number
,
234 struct buffered_writer
*buffered_writer
);
236 int __must_check
uds_finish_saving_delta_index(const struct delta_index
*delta_index
,
237 unsigned int zone_number
);
239 int __must_check
uds_write_guard_delta_list(struct buffered_writer
*buffered_writer
);
241 size_t __must_check
uds_compute_delta_index_save_bytes(u32 list_count
,
244 int __must_check
uds_start_delta_index_search(const struct delta_index
*delta_index
,
245 u32 list_number
, u32 key
,
246 struct delta_index_entry
*iterator
);
248 int __must_check
uds_next_delta_index_entry(struct delta_index_entry
*delta_entry
);
250 int __must_check
uds_remember_delta_index_offset(const struct delta_index_entry
*delta_entry
);
252 int __must_check
uds_get_delta_index_entry(const struct delta_index
*delta_index
,
253 u32 list_number
, u32 key
, const u8
*name
,
254 struct delta_index_entry
*delta_entry
);
256 int __must_check
uds_get_delta_entry_collision(const struct delta_index_entry
*delta_entry
,
259 u32 __must_check
uds_get_delta_entry_value(const struct delta_index_entry
*delta_entry
);
261 int __must_check
uds_set_delta_entry_value(const struct delta_index_entry
*delta_entry
, u32 value
);
263 int __must_check
uds_put_delta_index_entry(struct delta_index_entry
*delta_entry
, u32 key
,
264 u32 value
, const u8
*name
);
266 int __must_check
uds_remove_delta_index_entry(struct delta_index_entry
*delta_entry
);
268 void uds_get_delta_index_stats(const struct delta_index
*delta_index
,
269 struct delta_index_stats
*stats
);
271 size_t __must_check
uds_compute_delta_index_size(u32 entry_count
, u32 mean_delta
,
274 u32
uds_get_delta_index_page_count(u32 entry_count
, u32 list_count
, u32 mean_delta
,
275 u32 payload_bits
, size_t bytes_per_page
);
277 void uds_log_delta_index_entry(struct delta_index_entry
*delta_entry
);
279 #endif /* UDS_DELTA_INDEX_H */