BTRFS: Node now holding Volume instead of cache to retrieve more values
[haiku.git] / src / add-ons / kernel / file_systems / btrfs / BTree.cpp
blob4ca1ef195270525d8b4b333afddf2196e3b16100
1 /*
2 * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
3 * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
4 * This file may be used under the terms of the MIT License.
5 */
8 //! BTree implementation
11 #include "BTree.h"
14 //#define TRACE_BTRFS
15 #ifdef TRACE_BTRFS
16 # define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
17 #else
18 # define TRACE(x...) ;
19 #endif
20 # define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
23 BTree::Node::Node(Volume* volume)
25 fNode(NULL),
26 fVolume(volume),
27 fBlockNumber(0),
28 fCurrentSlot(0),
29 fWritable(false)
34 BTree::Node::Node(Volume* volume, off_t block)
36 fNode(NULL),
37 fVolume(volume),
38 fBlockNumber(0),
39 fCurrentSlot(0),
40 fWritable(false)
42 SetTo(block);
46 BTree::Node::~Node()
48 Unset();
52 void
53 BTree::Node::Keep()
55 fNode = NULL;
58 void
59 BTree::Node::Unset()
61 if (fNode != NULL) {
62 block_cache_put(fVolume->BlockCache(), fBlockNumber);
63 fNode = NULL;
68 void
69 BTree::Node::SetTo(off_t block)
71 Unset();
72 fBlockNumber = block;
73 fNode = (btrfs_stream*)block_cache_get(fVolume->BlockCache(), block);
77 void
78 BTree::Node::SetToWritable(off_t block, int32 transactionId, bool empty)
80 Unset();
81 fBlockNumber = block;
82 fWritable = true;
83 if (empty) {
84 fNode = (btrfs_stream*)block_cache_get_empty(fVolume->BlockCache(),
85 block, transactionId);
86 } else {
87 fNode = (btrfs_stream*)block_cache_get_writable(fVolume->BlockCache(),
88 block, transactionId);
93 status_t
94 BTree::Node::SearchSlot(const btrfs_key& key, int* slot, btree_traversing type)
95 const
97 //binary search for item slot in a node
98 int entrySize = sizeof(btrfs_entry);
99 if (Level() != 0) {
100 // internal node
101 entrySize = sizeof(btrfs_index);
104 int high = ItemCount();
105 int low = 0, mid = 0, comp = 0;
106 uint8* base = (uint8*)fNode + sizeof(btrfs_header);
107 const btrfs_key* other;
108 while (low < high) {
109 mid = (low + high) / 2;
110 other = (const btrfs_key*)(base + mid * entrySize);
111 comp = key.Compare(*other);
112 if (comp < 0)
113 high = mid;
114 else if (comp > 0)
115 low = mid + 1;
116 else {
117 *slot = mid;
118 return B_OK; //if key is in node
122 // |--item1--|--item2--|--item3--|--etc--|
123 // m-1 m m+1
124 // k : comp < 0
125 // k : comp > 0
126 if (type == BTREE_BACKWARD) {
127 *slot = mid - 1;
128 if (comp > 0)
129 *slot = mid;
130 } else if (type == BTREE_FORWARD) {
131 *slot = mid;
132 if (comp > 0)
133 *slot = mid + 1;
136 if (type == BTREE_EXACT || *slot < 0)
137 return B_ENTRY_NOT_FOUND;
139 TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n",
140 *slot, comp);
141 return B_OK;
145 //-pragma mark
148 BTree::BTree(Volume* volume)
150 fRootBlock(0),
151 fVolume(volume)
153 mutex_init(&fIteratorLock, "btrfs b+tree iterator");
157 BTree::BTree(Volume* volume, btrfs_stream* stream)
159 fRootBlock(0),
160 fVolume(volume)
162 mutex_init(&fIteratorLock, "btrfs b+tree iterator");
166 BTree::BTree(Volume* volume, fsblock_t rootBlock)
168 fRootBlock(rootBlock),
169 fVolume(volume)
171 mutex_init(&fIteratorLock, "btrfs b+tree iterator");
175 BTree::~BTree()
177 // if there are any TreeIterators left, we need to stop them
178 // (can happen when the tree's inode gets deleted while
179 // traversing the tree - a TreeIterator doesn't lock the inode)
180 mutex_lock(&fIteratorLock);
182 SinglyLinkedList<TreeIterator>::Iterator iterator
183 = fIterators.GetIterator();
184 while (iterator.HasNext())
185 iterator.Next()->Stop();
186 mutex_destroy(&fIteratorLock);
190 int32
191 btrfs_key::Compare(const btrfs_key& key) const
193 if (ObjectID() > key.ObjectID())
194 return 1;
195 if (ObjectID() < key.ObjectID())
196 return -1;
197 if (Type() > key.Type())
198 return 1;
199 if (Type() < key.Type())
200 return -1;
201 if (Offset() > key.Offset())
202 return 1;
203 if (Offset() < key.Offset())
204 return -1;
205 return 0;
209 /*! Searches the key in the tree, and stores the allocated found item in
210 _value, if successful.
211 Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not.
212 It can also return other errors to indicate that something went wrong.
214 status_t
215 BTree::_Find(btrfs_key& key, void** _value, uint32* _size,
216 bool read, btree_traversing type)
218 TRACE("Find() objectid %" B_PRId64 " type %d offset %" B_PRId64 " \n",
219 key.ObjectID(), key.Type(), key.Offset());
220 BTree::Node node(fVolume, fRootBlock);
221 int slot, ret;
222 fsblock_t physicalBlock;
224 while (node.Level() != 0) {
225 TRACE("Find() level %d\n", node.Level());
226 ret = node.SearchSlot(key, &slot, BTREE_BACKWARD);
227 if (ret != B_OK)
228 return ret;
229 TRACE("Find() getting index %" B_PRIu32 "\n", slot);
231 if (fVolume->FindBlock(node.Index(slot)->LogicalAddress(), physicalBlock)
232 != B_OK) {
233 ERROR("Find() unmapped block %" B_PRId64 "\n",
234 node.Index(slot)->LogicalAddress());
235 return B_ERROR;
237 node.SetTo(physicalBlock);
240 TRACE("Find() dump count %" B_PRId32 "\n", node.ItemCount());
241 ret = node.SearchSlot(key, &slot, type);
242 if ((slot >= node.ItemCount() || node.Item(slot)->key.Type() != key.Type())
243 && read == true
244 || ret != B_OK) {
245 TRACE("Find() not found %" B_PRId64 " %" B_PRId64 "\n", key.Offset(),
246 key.ObjectID());
247 return B_ENTRY_NOT_FOUND;
250 if (read == true) {
251 TRACE("Find() found %" B_PRIu32 " %" B_PRIu32 "\n",
252 node.Item(slot)->Offset(), node.Item(slot)->Size());
254 if (_value != NULL) {
255 *_value = malloc(node.Item(slot)->Size());
256 memcpy(*_value, node.ItemData(slot),
257 node.Item(slot)->Size());
258 key.SetOffset(node.Item(slot)->key.Offset());
259 key.SetObjectID(node.Item(slot)->key.ObjectID());
260 if (_size != NULL)
261 *_size = node.Item(slot)->Size();
263 } else {
264 *_value = (void*)&slot;
266 return B_OK;
270 status_t
271 BTree::FindNext(btrfs_key& key, void** _value, uint32* _size, bool read)
273 return _Find(key, _value, _size, read, BTREE_FORWARD);
277 status_t
278 BTree::FindPrevious(btrfs_key& key, void** _value, uint32* _size, bool read)
280 return _Find(key, _value, _size, read, BTREE_BACKWARD);
284 status_t
285 BTree::FindExact(btrfs_key& key, void** _value, uint32* _size, bool read)
287 return _Find(key, _value, _size, read, BTREE_EXACT);
291 status_t
292 BTree::SetRoot(off_t logical, fsblock_t* block)
294 if (block != NULL) {
295 fRootBlock = *block;
296 //TODO: mapping physical block -> logical address
297 } else {
298 fLogicalRoot = logical;
299 if (fVolume->FindBlock(logical, fRootBlock) != B_OK) {
300 ERROR("Find() unmapped block %" B_PRId64 "\n", fRootBlock);
301 return B_ERROR;
304 return B_OK;
308 void
309 BTree::_AddIterator(TreeIterator* iterator)
311 MutexLocker _(fIteratorLock);
312 fIterators.Add(iterator);
316 void
317 BTree::_RemoveIterator(TreeIterator* iterator)
319 MutexLocker _(fIteratorLock);
320 fIterators.Remove(iterator);
324 // #pragma mark -
327 TreeIterator::TreeIterator(BTree* tree, btrfs_key& key)
329 fTree(tree),
330 fCurrentKey(key)
332 Rewind();
333 tree->_AddIterator(this);
337 TreeIterator::~TreeIterator()
339 if (fTree)
340 fTree->_RemoveIterator(this);
344 /*! Iterates through the tree in the specified direction.
346 status_t
347 TreeIterator::Traverse(btree_traversing direction, btrfs_key& key,
348 void** value, uint32* size)
350 if (fTree == NULL)
351 return B_INTERRUPTED;
353 fCurrentKey.SetOffset(fCurrentKey.Offset() + direction);
354 status_t status = fTree->_Find(fCurrentKey, value, size,
355 true, direction);
356 if (status != B_OK) {
357 TRACE("TreeIterator::Traverse() Find failed\n");
358 return B_ENTRY_NOT_FOUND;
361 return B_OK;
365 /*! just sets the current key in the iterator.
367 status_t
368 TreeIterator::Find(btrfs_key& key)
370 if (fTree == NULL)
371 return B_INTERRUPTED;
372 fCurrentKey = key;
373 return B_OK;
377 void
378 TreeIterator::Stop()
380 fTree = NULL;