xref: /haiku/src/add-ons/kernel/file_systems/btrfs/BTree.cpp (revision 3216460dec5447c463e617b5dd537ac496dc0370)
1299aba38Shyche /*
2299aba38Shyche  * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
3299aba38Shyche  * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
4299aba38Shyche  * This file may be used under the terms of the MIT License.
5299aba38Shyche  */
6299aba38Shyche 
7299aba38Shyche 
8299aba38Shyche //! BTree implementation
9299aba38Shyche 
10299aba38Shyche 
11299aba38Shyche #include "BTree.h"
12299aba38Shyche 
13299aba38Shyche 
14299aba38Shyche //#define TRACE_BTRFS
15299aba38Shyche #ifdef TRACE_BTRFS
16299aba38Shyche #	define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
17299aba38Shyche #else
18299aba38Shyche #	define TRACE(x...) ;
19299aba38Shyche #endif
20299aba38Shyche #	define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
21299aba38Shyche 
22299aba38Shyche 
238160f31fShyche BTree::Node::Node(Volume* volume)
241481c49cShyche 	:
251481c49cShyche 	fNode(NULL),
268160f31fShyche 	fVolume(volume),
271481c49cShyche 	fBlockNumber(0),
281481c49cShyche 	fWritable(false)
291481c49cShyche {
301481c49cShyche }
311481c49cShyche 
321481c49cShyche 
338160f31fShyche BTree::Node::Node(Volume* volume, off_t block)
341481c49cShyche 	:
351481c49cShyche 	fNode(NULL),
368160f31fShyche 	fVolume(volume),
371481c49cShyche 	fBlockNumber(0),
381481c49cShyche 	fWritable(false)
391481c49cShyche {
401481c49cShyche 	SetTo(block);
411481c49cShyche }
421481c49cShyche 
431481c49cShyche 
44548a0d80Shyche BTree::Node::~Node()
451481c49cShyche {
461481c49cShyche 	Unset();
471481c49cShyche }
481481c49cShyche 
491481c49cShyche 
501481c49cShyche void
51548a0d80Shyche BTree::Node::Keep()
521481c49cShyche {
531481c49cShyche 	fNode = NULL;
541481c49cShyche }
551481c49cShyche 
561481c49cShyche void
57548a0d80Shyche BTree::Node::Unset()
581481c49cShyche {
591481c49cShyche 	if (fNode != NULL) {
608160f31fShyche 		block_cache_put(fVolume->BlockCache(), fBlockNumber);
611481c49cShyche 		fNode = NULL;
621481c49cShyche 	}
631481c49cShyche }
641481c49cShyche 
651481c49cShyche 
661481c49cShyche void
67548a0d80Shyche BTree::Node::SetTo(off_t block)
681481c49cShyche {
691481c49cShyche 	Unset();
701481c49cShyche 	fBlockNumber = block;
718160f31fShyche 	fNode = (btrfs_stream*)block_cache_get(fVolume->BlockCache(), block);
721481c49cShyche }
731481c49cShyche 
741481c49cShyche 
751481c49cShyche void
76548a0d80Shyche BTree::Node::SetToWritable(off_t block, int32 transactionId, bool empty)
771481c49cShyche {
781481c49cShyche 	Unset();
791481c49cShyche 	fBlockNumber = block;
801481c49cShyche 	fWritable = true;
811481c49cShyche 	if (empty) {
828160f31fShyche 		fNode = (btrfs_stream*)block_cache_get_empty(fVolume->BlockCache(),
838160f31fShyche 			block, transactionId);
841481c49cShyche 	} else {
858160f31fShyche 		fNode = (btrfs_stream*)block_cache_get_writable(fVolume->BlockCache(),
868160f31fShyche 			block, transactionId);
871481c49cShyche 	}
881481c49cShyche }
891481c49cShyche 
901481c49cShyche 
912ed88a48Shyche status_t
922ed88a48Shyche BTree::Node::SearchSlot(const btrfs_key& key, int* slot, btree_traversing type)
932ed88a48Shyche 	const
9491d7f850Shyche {
9591d7f850Shyche 	//binary search for item slot in a node
9691d7f850Shyche 	int entrySize = sizeof(btrfs_entry);
9791d7f850Shyche 	if (Level() != 0) {
9891d7f850Shyche 		// internal node
9991d7f850Shyche 		entrySize = sizeof(btrfs_index);
10091d7f850Shyche 	}
10191d7f850Shyche 
10291d7f850Shyche 	int high = ItemCount();
1032ed88a48Shyche 	int low = 0, mid = 0, comp = 0;
1042ed88a48Shyche 	uint8* base = (uint8*)fNode + sizeof(btrfs_header);
10591d7f850Shyche 	const btrfs_key* other;
10691d7f850Shyche 	while (low < high) {
10791d7f850Shyche 		mid = (low + high) / 2;
1082ed88a48Shyche 		other = (const btrfs_key*)(base + mid * entrySize);
1090d726c5cShyche 		comp = key.Compare(*other);
11091d7f850Shyche 		if (comp < 0)
11191d7f850Shyche 			high = mid;
11291d7f850Shyche 		else if (comp > 0)
11391d7f850Shyche 			low = mid + 1;
11491d7f850Shyche 		else {
11591d7f850Shyche 			*slot = mid;
1160d726c5cShyche 			return B_OK; 		//if key is in node
11791d7f850Shyche 		}
11891d7f850Shyche 	}
1190d726c5cShyche 
1202ed88a48Shyche 	// |--item1--|--item2--|--item3--|--etc--|
1212ed88a48Shyche 	//     m-1        m        m+1
1222ed88a48Shyche 	//           k          		: comp < 0
1232ed88a48Shyche 	//                     k		: comp > 0
1242ed88a48Shyche 	if (type == BTREE_BACKWARD) {
1252ed88a48Shyche 		*slot = mid - 1;
1262ed88a48Shyche 		if (comp > 0)
1272ed88a48Shyche 			*slot = mid;
1282ed88a48Shyche 	} else if (type == BTREE_FORWARD) {
1292ed88a48Shyche 		*slot = mid;
1302ed88a48Shyche 		if (comp > 0)
1312ed88a48Shyche 			*slot = mid + 1;
1322ed88a48Shyche 	}
1332ed88a48Shyche 
1342ed88a48Shyche 	if (type == BTREE_EXACT || *slot < 0)
1352ed88a48Shyche 		return B_ENTRY_NOT_FOUND;
1362ed88a48Shyche 
1370d726c5cShyche 	TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n",
1380d726c5cShyche 		*slot, comp);
1390d726c5cShyche 	return B_OK;
14091d7f850Shyche }
14191d7f850Shyche 
14291d7f850Shyche 
143*3216460dShyche //	#pragma mark - BTree::Path implementation
144*3216460dShyche 
145*3216460dShyche 
146*3216460dShyche BTree::Path::Path(BTree* tree)
147*3216460dShyche 	:
148*3216460dShyche 	fTree(tree)
149*3216460dShyche {
150*3216460dShyche 	for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) {
151*3216460dShyche 		fNodes[i] = NULL;
152*3216460dShyche 		fSlots[i] = 0;
153*3216460dShyche 	}
154*3216460dShyche }
155*3216460dShyche 
156*3216460dShyche 
157*3216460dShyche BTree::Path::~Path()
158*3216460dShyche {
159*3216460dShyche 	for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) {
160*3216460dShyche 		delete fNodes[i];
161*3216460dShyche 		fNodes[i] = NULL;
162*3216460dShyche 		fSlots[i] = 0;
163*3216460dShyche 	}
164*3216460dShyche }
165*3216460dShyche 
166*3216460dShyche 
167*3216460dShyche BTree::Node*
168*3216460dShyche BTree::Path::GetNode(int level, int* _slot) const
169*3216460dShyche {
170*3216460dShyche 	if (_slot != NULL)
171*3216460dShyche 		*_slot = fSlots[level];
172*3216460dShyche 	return fNodes[level];
173*3216460dShyche }
174*3216460dShyche 
175*3216460dShyche 
176*3216460dShyche BTree::Node*
177*3216460dShyche BTree::Path::SetNode(off_t block, int slot)
178*3216460dShyche {
179*3216460dShyche 	Node node(fTree->SystemVolume(), block);
180*3216460dShyche 	return SetNode(&node, slot);
181*3216460dShyche }
182*3216460dShyche 
183*3216460dShyche 
184*3216460dShyche BTree::Node*
185*3216460dShyche BTree::Path::SetNode(const Node* node, int slot)
186*3216460dShyche {
187*3216460dShyche 	uint8 level = node->Level();
188*3216460dShyche 	if (fNodes[level] == NULL) {
189*3216460dShyche 		fNodes[level] = new Node(fTree->SystemVolume(), node->BlockNum());
190*3216460dShyche 		if (fNodes[level] == NULL)
191*3216460dShyche 			return NULL;
192*3216460dShyche 	} else
193*3216460dShyche 		fNodes[level]->SetTo(node->BlockNum());
194*3216460dShyche 
195*3216460dShyche 	if (slot == -1)
196*3216460dShyche 		fSlots[level] = fNodes[level]->ItemCount() - 1;
197*3216460dShyche 	else
198*3216460dShyche 		fSlots[level] = slot;
199*3216460dShyche 	return fNodes[level];
200*3216460dShyche }
201*3216460dShyche 
202*3216460dShyche 
203*3216460dShyche int
204*3216460dShyche BTree::Path::Move(int level, int step)
205*3216460dShyche {
206*3216460dShyche 	fSlots[level] += step;
207*3216460dShyche 	if (fSlots[level] < 0)
208*3216460dShyche 		return -1;
209*3216460dShyche 	if (fSlots[level] >= fNodes[level]->ItemCount())
210*3216460dShyche 		return 1;
211*3216460dShyche 	return 0;
212*3216460dShyche }
213*3216460dShyche 
214*3216460dShyche 
215*3216460dShyche status_t
216*3216460dShyche BTree::Path::GetEntry(int slot, btrfs_key* _key, void** _value, uint32* _size,
217*3216460dShyche 	uint32* _offset)
218*3216460dShyche {
219*3216460dShyche 	BTree::Node* leaf = fNodes[0];
220*3216460dShyche 	if (slot < 0 || slot >= leaf->ItemCount())
221*3216460dShyche 		return B_ENTRY_NOT_FOUND;
222*3216460dShyche 
223*3216460dShyche 	if (_key != NULL)
224*3216460dShyche 		*_key = leaf->Item(slot)->key;
225*3216460dShyche 
226*3216460dShyche 	uint32 itemSize = leaf->Item(slot)->Size();
227*3216460dShyche 	if (_value != NULL) {
228*3216460dShyche 		*_value = malloc(itemSize);
229*3216460dShyche 		if (*_value == NULL)
230*3216460dShyche 			return B_NO_MEMORY;
231*3216460dShyche 
232*3216460dShyche 		memcpy(*_value, leaf->ItemData(slot), itemSize);
233*3216460dShyche 	}
234*3216460dShyche 
235*3216460dShyche 	if (_size != NULL)
236*3216460dShyche 		*_size = itemSize;
237*3216460dShyche 
238*3216460dShyche 	if (_offset != NULL)
239*3216460dShyche 		*_offset = leaf->Item(slot)->Offset();
240*3216460dShyche 
241*3216460dShyche 	return B_OK;
242*3216460dShyche }
243*3216460dShyche 
244*3216460dShyche 
245*3216460dShyche //	#pragma mark - BTree implementation
2461481c49cShyche 
2471481c49cShyche 
248fc4a1e78Shyche BTree::BTree(Volume* volume)
249fc4a1e78Shyche 	:
250fc4a1e78Shyche 	fRootBlock(0),
251fc4a1e78Shyche 	fVolume(volume)
252fc4a1e78Shyche {
253fc4a1e78Shyche 	mutex_init(&fIteratorLock, "btrfs b+tree iterator");
254fc4a1e78Shyche }
255fc4a1e78Shyche 
256fc4a1e78Shyche 
257299aba38Shyche BTree::BTree(Volume* volume, btrfs_stream* stream)
258299aba38Shyche 	:
259299aba38Shyche 	fRootBlock(0),
260299aba38Shyche 	fVolume(volume)
261299aba38Shyche {
262299aba38Shyche 	mutex_init(&fIteratorLock, "btrfs b+tree iterator");
263299aba38Shyche }
264299aba38Shyche 
265299aba38Shyche 
266299aba38Shyche BTree::BTree(Volume* volume, fsblock_t rootBlock)
267299aba38Shyche 	:
268299aba38Shyche 	fRootBlock(rootBlock),
269299aba38Shyche 	fVolume(volume)
270299aba38Shyche {
271299aba38Shyche 	mutex_init(&fIteratorLock, "btrfs b+tree iterator");
272299aba38Shyche }
273299aba38Shyche 
274299aba38Shyche 
275299aba38Shyche BTree::~BTree()
276299aba38Shyche {
277299aba38Shyche 	// if there are any TreeIterators left, we need to stop them
278299aba38Shyche 	// (can happen when the tree's inode gets deleted while
279299aba38Shyche 	// traversing the tree - a TreeIterator doesn't lock the inode)
280299aba38Shyche 	mutex_lock(&fIteratorLock);
281299aba38Shyche 
282299aba38Shyche 	SinglyLinkedList<TreeIterator>::Iterator iterator
283299aba38Shyche 		= fIterators.GetIterator();
284299aba38Shyche 	while (iterator.HasNext())
285299aba38Shyche 		iterator.Next()->Stop();
286299aba38Shyche 	mutex_destroy(&fIteratorLock);
287299aba38Shyche }
288299aba38Shyche 
289299aba38Shyche 
290299aba38Shyche int32
291875a0552Shyche btrfs_key::Compare(const btrfs_key& key) const
292299aba38Shyche {
293875a0552Shyche 	if (ObjectID() > key.ObjectID())
294299aba38Shyche 		return 1;
295875a0552Shyche 	if (ObjectID() < key.ObjectID())
296299aba38Shyche 		return -1;
297875a0552Shyche 	if (Type() > key.Type())
298299aba38Shyche 		return 1;
299875a0552Shyche 	if (Type() < key.Type())
300299aba38Shyche 		return -1;
301875a0552Shyche 	if (Offset() > key.Offset())
302299aba38Shyche 		return 1;
303875a0552Shyche 	if (Offset() < key.Offset())
304299aba38Shyche 		return -1;
305299aba38Shyche 	return 0;
306299aba38Shyche }
307299aba38Shyche 
308299aba38Shyche 
309*3216460dShyche /* Traverse from root to fill in the path along way its finding.
310*3216460dShyche  * Return current slot at leaf if successful.
311*3216460dShyche  */
312*3216460dShyche status_t
313*3216460dShyche BTree::Traverse(btree_traversing type, Path* path, const btrfs_key& key)
314*3216460dShyche 	const
315*3216460dShyche {
316*3216460dShyche 	TRACE("BTree::Traverse() objectid %" B_PRId64 " type %d offset %"
317*3216460dShyche 		B_PRId64 " \n", key.ObjectID(),	key.Type(), key.Offset());
318*3216460dShyche 	fsblock_t physicalBlock = fRootBlock;
319*3216460dShyche 	Node node(fVolume, physicalBlock);
320*3216460dShyche 	int slot;
321*3216460dShyche 	status_t status = B_OK;
322*3216460dShyche 
323*3216460dShyche 	while (node.Level() != 0) {
324*3216460dShyche 		TRACE("BTree::Traverse() level %d count %d\n", node.Level(),
325*3216460dShyche 			node.ItemCount());
326*3216460dShyche 		status = node.SearchSlot(key, &slot, BTREE_BACKWARD);
327*3216460dShyche 		if (status != B_OK)
328*3216460dShyche 			return status;
329*3216460dShyche 		if (path->SetNode(&node, slot) == NULL)
330*3216460dShyche 			return B_NO_MEMORY;
331*3216460dShyche 
332*3216460dShyche 		TRACE("BTree::Traverse() getting index %" B_PRIu32 "\n", slot);
333*3216460dShyche 
334*3216460dShyche 		status = fVolume->FindBlock(node.Index(slot)->LogicalAddress(),
335*3216460dShyche 				physicalBlock);
336*3216460dShyche 		if (status != B_OK) {
337*3216460dShyche 			ERROR("BTree::Traverse() unmapped block %" B_PRId64 "\n",
338*3216460dShyche 				node.Index(slot)->LogicalAddress());
339*3216460dShyche 			return status;
340*3216460dShyche 		}
341*3216460dShyche 		node.SetTo(physicalBlock);
342*3216460dShyche 	}
343*3216460dShyche 
344*3216460dShyche 	TRACE("BTree::Traverse() dump count %" B_PRId32 "\n", node.ItemCount());
345*3216460dShyche 	status = node.SearchSlot(key, &slot, type);
346*3216460dShyche 	if (status != B_OK)
347*3216460dShyche 		return status;
348*3216460dShyche 	if (path->SetNode(&node, slot) == NULL)
349*3216460dShyche 		return B_NO_MEMORY;
350*3216460dShyche 
351*3216460dShyche 	TRACE("BTree::Traverse() found %" B_PRIu32 " %" B_PRIu32 "\n",
352*3216460dShyche 		node.Item(slot)->Offset(), node.Item(slot)->Size());
353*3216460dShyche 	return slot;
354*3216460dShyche }
355*3216460dShyche 
356*3216460dShyche 
357299aba38Shyche /*!	Searches the key in the tree, and stores the allocated found item in
358299aba38Shyche 	_value, if successful.
359299aba38Shyche 	Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not.
360299aba38Shyche 	It can also return other errors to indicate that something went wrong.
361299aba38Shyche */
362299aba38Shyche status_t
363*3216460dShyche BTree::_Find(Path* path, btrfs_key& wanted, void** _value, uint32* _size,
364*3216460dShyche 	uint32* _offset, btree_traversing type) const
365299aba38Shyche {
366*3216460dShyche 	status_t status = Traverse(type, path, wanted);
367*3216460dShyche 	if (status < B_OK)
368*3216460dShyche 		return status;
369299aba38Shyche 
370*3216460dShyche 	btrfs_key found;
371*3216460dShyche 	status = path->GetCurrentEntry(&found, _value, _size, _offset);
372*3216460dShyche 	if (status != B_OK)
373*3216460dShyche 		return status;
374299aba38Shyche 
375*3216460dShyche 	if (found.Type() != wanted.Type() && wanted.Type() != BTRFS_KEY_TYPE_ANY)
37646eba5c0Shyche 		return B_ENTRY_NOT_FOUND;
377299aba38Shyche 
378*3216460dShyche 	wanted = found;
379299aba38Shyche 	return B_OK;
380299aba38Shyche }
381299aba38Shyche 
382299aba38Shyche 
38346eba5c0Shyche status_t
384*3216460dShyche BTree::FindNext(Path* path, btrfs_key& key, void** _value, uint32* _size,
385*3216460dShyche 	uint32* _offset) const
38646eba5c0Shyche {
387*3216460dShyche 	return _Find(path, key, _value, _size, _offset, BTREE_FORWARD);
388299aba38Shyche }
389299aba38Shyche 
390299aba38Shyche 
391299aba38Shyche status_t
392*3216460dShyche BTree::FindPrevious(Path* path, btrfs_key& key, void** _value, uint32* _size,
393*3216460dShyche 	uint32* _offset) const
394299aba38Shyche {
395*3216460dShyche 	return _Find(path, key, _value, _size, _offset, BTREE_BACKWARD);
396299aba38Shyche }
397299aba38Shyche 
398299aba38Shyche 
399299aba38Shyche status_t
400*3216460dShyche BTree::FindExact(Path* path, btrfs_key& key, void** _value, uint32* _size,
401*3216460dShyche 	uint32* _offset) const
402299aba38Shyche {
403*3216460dShyche 	return _Find(path, key, _value, _size, _offset, BTREE_EXACT);
404*3216460dShyche }
405*3216460dShyche 
406*3216460dShyche 
407*3216460dShyche status_t
408*3216460dShyche BTree::PreviousLeaf(Path* path) const
409*3216460dShyche {
410*3216460dShyche 	// TODO: use Traverse() ???
411*3216460dShyche 	int level = 0;
412*3216460dShyche 	int slot;
413*3216460dShyche 	Node* node = NULL;
414*3216460dShyche 	// iterate to the root until satisfy the condition
415*3216460dShyche 	while (true) {
416*3216460dShyche 		node = path->GetNode(level, &slot);
417*3216460dShyche 		if (node == NULL || slot != 0)
418*3216460dShyche 			break;
419*3216460dShyche 		level++;
420*3216460dShyche 	}
421*3216460dShyche 
422*3216460dShyche 	// the current leaf is already the left most leaf or
423*3216460dShyche 	// path was not initialized
424*3216460dShyche 	if (node == NULL)
425*3216460dShyche 		return B_ENTRY_NOT_FOUND;
426*3216460dShyche 
427*3216460dShyche 	path->Move(level, BTREE_BACKWARD);
428*3216460dShyche 	fsblock_t physicalBlock;
429*3216460dShyche 	// change all nodes below this level and slot to the ending
430*3216460dShyche 	do {
431*3216460dShyche 		status_t status = fVolume->FindBlock(
432*3216460dShyche 			node->Index(slot)->LogicalAddress(), physicalBlock);
433*3216460dShyche 		if (status != B_OK)
434*3216460dShyche 			return status;
435*3216460dShyche 
436*3216460dShyche 		node = path->SetNode(physicalBlock, -1);
437*3216460dShyche 		if (node == NULL)
438*3216460dShyche 			return B_NO_MEMORY;
439*3216460dShyche 		slot = node->ItemCount() - 1;
440*3216460dShyche 		level--;
441*3216460dShyche 	} while(level != 0);
442*3216460dShyche 
443*3216460dShyche 	return B_OK;
444*3216460dShyche }
445*3216460dShyche 
446*3216460dShyche 
447*3216460dShyche status_t
448*3216460dShyche BTree::NextLeaf(Path* path) const
449*3216460dShyche {
450*3216460dShyche 	int level = 0;
451*3216460dShyche 	int slot;
452*3216460dShyche 	Node* node = NULL;
453*3216460dShyche 	// iterate to the root until satisfy the condition
454*3216460dShyche 	while (true) {
455*3216460dShyche 		node = path->GetNode(level, &slot);
456*3216460dShyche 		if (node == NULL || slot < node->ItemCount() - 1)
457*3216460dShyche 			break;
458*3216460dShyche 		level++;
459*3216460dShyche 	}
460*3216460dShyche 
461*3216460dShyche 	// the current leaf is already the right most leaf or
462*3216460dShyche 	// path was not initialized
463*3216460dShyche 	if (node == NULL)
464*3216460dShyche 		return B_ENTRY_NOT_FOUND;
465*3216460dShyche 
466*3216460dShyche 	path->Move(level, BTREE_FORWARD);
467*3216460dShyche 	fsblock_t physicalBlock;
468*3216460dShyche 	// change all nodes below this level and slot to the beginning
469*3216460dShyche 	do {
470*3216460dShyche 		status_t status = fVolume->FindBlock(
471*3216460dShyche 			node->Index(slot)->LogicalAddress(), physicalBlock);
472*3216460dShyche 		if (status != B_OK)
473*3216460dShyche 			return status;
474*3216460dShyche 
475*3216460dShyche 		node = path->SetNode(physicalBlock, 0);
476*3216460dShyche 		if (node == NULL)
477*3216460dShyche 			return B_NO_MEMORY;
478*3216460dShyche 		slot = 0;
479*3216460dShyche 		level--;
480*3216460dShyche 	} while(level != 0);
481*3216460dShyche 
482*3216460dShyche 	return B_OK;
483299aba38Shyche }
484299aba38Shyche 
485299aba38Shyche 
486fc4a1e78Shyche status_t
487fc4a1e78Shyche BTree::SetRoot(off_t logical, fsblock_t* block)
488fc4a1e78Shyche {
489fc4a1e78Shyche 	if (block != NULL) {
490fc4a1e78Shyche 		fRootBlock = *block;
491370ee09fShyche 		//TODO: mapping physical block -> logical address
492fc4a1e78Shyche 	} else {
493370ee09fShyche 		fLogicalRoot = logical;
494fc4a1e78Shyche 		if (fVolume->FindBlock(logical, fRootBlock) != B_OK) {
495fc4a1e78Shyche 			ERROR("Find() unmapped block %" B_PRId64 "\n", fRootBlock);
496fc4a1e78Shyche 			return B_ERROR;
497fc4a1e78Shyche 		}
498fc4a1e78Shyche 	}
499fc4a1e78Shyche 	return B_OK;
500fc4a1e78Shyche }
501fc4a1e78Shyche 
502fc4a1e78Shyche 
503299aba38Shyche void
504299aba38Shyche BTree::_AddIterator(TreeIterator* iterator)
505299aba38Shyche {
506299aba38Shyche 	MutexLocker _(fIteratorLock);
507299aba38Shyche 	fIterators.Add(iterator);
508299aba38Shyche }
509299aba38Shyche 
510299aba38Shyche 
511299aba38Shyche void
512299aba38Shyche BTree::_RemoveIterator(TreeIterator* iterator)
513299aba38Shyche {
514299aba38Shyche 	MutexLocker _(fIteratorLock);
515299aba38Shyche 	fIterators.Remove(iterator);
516299aba38Shyche }
517299aba38Shyche 
518299aba38Shyche 
519299aba38Shyche //	#pragma mark -
520299aba38Shyche 
521299aba38Shyche 
522299aba38Shyche TreeIterator::TreeIterator(BTree* tree, btrfs_key& key)
523299aba38Shyche 	:
524299aba38Shyche 	fTree(tree),
525299aba38Shyche 	fCurrentKey(key)
526299aba38Shyche {
527299aba38Shyche 	Rewind();
528299aba38Shyche 	tree->_AddIterator(this);
529299aba38Shyche }
530299aba38Shyche 
531299aba38Shyche 
532299aba38Shyche TreeIterator::~TreeIterator()
533299aba38Shyche {
534299aba38Shyche 	if (fTree)
535299aba38Shyche 		fTree->_RemoveIterator(this);
536299aba38Shyche }
537299aba38Shyche 
538299aba38Shyche 
539299aba38Shyche /*!	Iterates through the tree in the specified direction.
540299aba38Shyche */
541299aba38Shyche status_t
542299aba38Shyche TreeIterator::Traverse(btree_traversing direction, btrfs_key& key,
54316de9db5Shyche 	void** value, uint32* size)
544299aba38Shyche {
545299aba38Shyche 	if (fTree == NULL)
546299aba38Shyche 		return B_INTERRUPTED;
547299aba38Shyche 
548299aba38Shyche 	fCurrentKey.SetOffset(fCurrentKey.Offset() + direction);
549*3216460dShyche 	BTree::Path path(fTree);
550*3216460dShyche 	status_t status = fTree->_Find(&path, fCurrentKey, value, size, direction);
551299aba38Shyche 	if (status != B_OK) {
552299aba38Shyche 		TRACE("TreeIterator::Traverse() Find failed\n");
553299aba38Shyche 		return B_ENTRY_NOT_FOUND;
554299aba38Shyche 	}
555299aba38Shyche 
556299aba38Shyche 	return B_OK;
557299aba38Shyche }
558299aba38Shyche 
559299aba38Shyche 
560299aba38Shyche /*!	just sets the current key in the iterator.
561299aba38Shyche */
562299aba38Shyche status_t
563299aba38Shyche TreeIterator::Find(btrfs_key& key)
564299aba38Shyche {
565299aba38Shyche 	if (fTree == NULL)
566299aba38Shyche 		return B_INTERRUPTED;
567299aba38Shyche 	fCurrentKey = key;
568299aba38Shyche 	return B_OK;
569299aba38Shyche }
570299aba38Shyche 
571299aba38Shyche 
572299aba38Shyche void
573299aba38Shyche TreeIterator::Stop()
574299aba38Shyche {
575299aba38Shyche 	fTree = NULL;
576299aba38Shyche }
577