summaryrefslogtreecommitdiffstats
path: root/drivers/md/persistent-data/dm-btree.h
blob: dacfc34180b4373ce1abbe8fd5f97cc91391a2d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 * Copyright (C) 2011 Red Hat, Inc.
 *
 * This file is released under the GPL.
 */
#ifndef _LINUX_DM_BTREE_H
#define _LINUX_DM_BTREE_H

#include "dm-block-manager.h"

struct dm_transaction_manager;

/*----------------------------------------------------------------*/

/*
 * Annotations used to check on-disk metadata is handled as little-endian.
 */
#ifdef __CHECKER__
#  define __dm_written_to_disk(x) __releases(x)
#  define __dm_reads_from_disk(x) __acquires(x)
#  define __dm_bless_for_disk(x) __acquire(x)
#  define __dm_unbless_for_disk(x) __release(x)
#else
#  define __dm_written_to_disk(x)
#  define __dm_reads_from_disk(x)
#  define __dm_bless_for_disk(x)
#  define __dm_unbless_for_disk(x)
#endif

/*----------------------------------------------------------------*/

/*
 * Manipulates hierarchical B+ trees with 64-bit keys and arbitrary-sized
 * values.
 */

/*
 * Information about the values stored within the btree.
 */
struct dm_btree_value_type {
	void *context;

	/*
	 * The size in bytes of each value.
	 */
	uint32_t size;

	/*
	 * Any of these methods can be safely set to NULL if you do not
	 * need the corresponding feature.
	 */

	/*
	 * The btree is making a duplicate of the value, for instance
	 * because previously-shared btree nodes have now diverged.
	 * @value argument is the new copy that the copy function may modify.
	 * (Probably it just wants to increment a reference count
	 * somewhere.) This method is _not_ called for insertion of a new
	 * value: It is assumed the ref count is already 1.
	 */
	void (*inc)(void *context, const void *value);

	/*
	 * This value is being deleted.  The btree takes care of freeing
	 * the memory pointed to by @value.  Often the del function just
	 * needs to decrement a reference count somewhere.
	 */
	void (*dec)(void *context, const void *value);

	/*
	 * A test for equality between two values.  When a value is
	 * overwritten with a new one, the old one has the dec method
	 * called _unless_ the new and old value are deemed equal.
	 */
	int (*equal)(void *context, const void *value1, const void *value2);
};

/*
 * The shape and contents of a btree.
 */
struct dm_btree_info {
	struct dm_transaction_manager *tm;

	/*
	 * Number of nested btrees. (Not the depth of a single tree.)
	 */
	unsigned levels;
	struct dm_btree_value_type value_type;
};

/*
 * Set up an empty tree.  O(1).
 */
int dm_btree_empty(struct dm_btree_info *info, dm_block_t *root);

/*
 * Delete a tree.  O(n) - this is the slow one!  It can also block, so
 * please don't call it on an IO path.
 */
int dm_btree_del(struct dm_btree_info *info, dm_block_t root);

/*
 * All the lookup functions return -ENODATA if the key cannot be found.
 */

/*
 * Tries to find a key that matches exactly.  O(ln(n))
 */
int dm_btree_lookup(struct dm_btree_info *info, dm_block_t root,
		    uint64_t *keys, void *value_le);

/*
 * Insertion (or overwrite an existing value).  O(ln(n))
 */
int dm_btree_insert(struct dm_btree_info *info, dm_block_t root,
		    uint64_t *keys, void *value, dm_block_t *new_root)
		    __dm_written_to_disk(value);

/*
 * A variant of insert that indicates whether it actually inserted or just
 * overwrote.  Useful if you're keeping track of the number of entries in a
 * tree.
 */
int dm_btree_insert_notify(struct dm_btree_info *info, dm_block_t root,
			   uint64_t *keys, void *value, dm_block_t *new_root,
			   int *inserted)
			   __dm_written_to_disk(value);

/*
 * Remove a key if present.  This doesn't remove empty sub trees.  Normally
 * subtrees represent a separate entity, like a snapshot map, so this is
 * correct behaviour.  O(ln(n)).
 */
int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
		    uint64_t *keys, dm_block_t *new_root);

/*
 * Returns < 0 on failure.  Otherwise the number of key entries that have
 * been filled out.  Remember trees can have zero entries, and as such have
 * no lowest key.
 */
int dm_btree_find_lowest_key(struct dm_btree_info *info, dm_block_t root,
			     uint64_t *result_keys);

/*
 * Returns < 0 on failure.  Otherwise the number of key entries that have
 * been filled out.  Remember trees can have zero entries, and as such have
 * no highest key.
 */
int dm_btree_find_highest_key(struct dm_btree_info *info, dm_block_t root,
			      uint64_t *result_keys);

/*
 * Iterate through the a btree, calling fn() on each entry.
 * It only works for single level trees and is internally recursive, so
 * monitor stack usage carefully.
 */
int dm_btree_walk(struct dm_btree_info *info, dm_block_t root,
		  int (*fn)(void *context, uint64_t *keys, void *leaf),
		  void *context);

#endif	/* _LINUX_DM_BTREE_H */