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.
8 //! BTree implementation
16 # define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
18 # define TRACE(x...) ;
20 # define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
23 BTree::Node::Node(Volume
* volume
)
34 BTree::Node::Node(Volume
* volume
, off_t block
)
62 block_cache_put(fVolume
->BlockCache(), fBlockNumber
);
69 BTree::Node::SetTo(off_t block
)
73 fNode
= (btrfs_stream
*)block_cache_get(fVolume
->BlockCache(), block
);
78 BTree::Node::SetToWritable(off_t block
, int32 transactionId
, bool empty
)
84 fNode
= (btrfs_stream
*)block_cache_get_empty(fVolume
->BlockCache(),
85 block
, transactionId
);
87 fNode
= (btrfs_stream
*)block_cache_get_writable(fVolume
->BlockCache(),
88 block
, transactionId
);
94 BTree::Node::SearchSlot(const btrfs_key
& key
, int* slot
, btree_traversing type
)
97 //binary search for item slot in a node
98 int entrySize
= sizeof(btrfs_entry
);
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
;
109 mid
= (low
+ high
) / 2;
110 other
= (const btrfs_key
*)(base
+ mid
* entrySize
);
111 comp
= key
.Compare(*other
);
118 return B_OK
; //if key is in node
122 // |--item1--|--item2--|--item3--|--etc--|
126 if (type
== BTREE_BACKWARD
) {
130 } else if (type
== BTREE_FORWARD
) {
136 if (type
== BTREE_EXACT
|| *slot
< 0)
137 return B_ENTRY_NOT_FOUND
;
139 TRACE("SearchSlot() found slot %" B_PRId32
" comp %" B_PRId32
"\n",
148 BTree::BTree(Volume
* volume
)
153 mutex_init(&fIteratorLock
, "btrfs b+tree iterator");
157 BTree::BTree(Volume
* volume
, btrfs_stream
* stream
)
162 mutex_init(&fIteratorLock
, "btrfs b+tree iterator");
166 BTree::BTree(Volume
* volume
, fsblock_t rootBlock
)
168 fRootBlock(rootBlock
),
171 mutex_init(&fIteratorLock
, "btrfs b+tree iterator");
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
);
191 btrfs_key::Compare(const btrfs_key
& key
) const
193 if (ObjectID() > key
.ObjectID())
195 if (ObjectID() < key
.ObjectID())
197 if (Type() > key
.Type())
199 if (Type() < key
.Type())
201 if (Offset() > key
.Offset())
203 if (Offset() < key
.Offset())
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.
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
);
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
);
229 TRACE("Find() getting index %" B_PRIu32
"\n", slot
);
231 if (fVolume
->FindBlock(node
.Index(slot
)->LogicalAddress(), physicalBlock
)
233 ERROR("Find() unmapped block %" B_PRId64
"\n",
234 node
.Index(slot
)->LogicalAddress());
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())
245 TRACE("Find() not found %" B_PRId64
" %" B_PRId64
"\n", key
.Offset(),
247 return B_ENTRY_NOT_FOUND
;
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());
261 *_size
= node
.Item(slot
)->Size();
264 *_value
= (void*)&slot
;
271 BTree::FindNext(btrfs_key
& key
, void** _value
, uint32
* _size
, bool read
)
273 return _Find(key
, _value
, _size
, read
, BTREE_FORWARD
);
278 BTree::FindPrevious(btrfs_key
& key
, void** _value
, uint32
* _size
, bool read
)
280 return _Find(key
, _value
, _size
, read
, BTREE_BACKWARD
);
285 BTree::FindExact(btrfs_key
& key
, void** _value
, uint32
* _size
, bool read
)
287 return _Find(key
, _value
, _size
, read
, BTREE_EXACT
);
292 BTree::SetRoot(off_t logical
, fsblock_t
* block
)
296 //TODO: mapping physical block -> logical address
298 fLogicalRoot
= logical
;
299 if (fVolume
->FindBlock(logical
, fRootBlock
) != B_OK
) {
300 ERROR("Find() unmapped block %" B_PRId64
"\n", fRootBlock
);
309 BTree::_AddIterator(TreeIterator
* iterator
)
311 MutexLocker
_(fIteratorLock
);
312 fIterators
.Add(iterator
);
317 BTree::_RemoveIterator(TreeIterator
* iterator
)
319 MutexLocker
_(fIteratorLock
);
320 fIterators
.Remove(iterator
);
327 TreeIterator::TreeIterator(BTree
* tree
, btrfs_key
& key
)
333 tree
->_AddIterator(this);
337 TreeIterator::~TreeIterator()
340 fTree
->_RemoveIterator(this);
344 /*! Iterates through the tree in the specified direction.
347 TreeIterator::Traverse(btree_traversing direction
, btrfs_key
& key
,
348 void** value
, uint32
* size
)
351 return B_INTERRUPTED
;
353 fCurrentKey
.SetOffset(fCurrentKey
.Offset() + direction
);
354 status_t status
= fTree
->_Find(fCurrentKey
, value
, size
,
356 if (status
!= B_OK
) {
357 TRACE("TreeIterator::Traverse() Find failed\n");
358 return B_ENTRY_NOT_FOUND
;
365 /*! just sets the current key in the iterator.
368 TreeIterator::Find(btrfs_key
& key
)
371 return B_INTERRUPTED
;