xref: /haiku/src/add-ons/kernel/file_systems/btrfs/BTree.cpp (revision 370ee09fe5619ef2163545847485362f7adead78)
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 
23548a0d80Shyche BTree::Node::Node(void* cache)
241481c49cShyche 	:
251481c49cShyche 	fNode(NULL),
261481c49cShyche 	fCache(cache),
271481c49cShyche 	fBlockNumber(0),
281481c49cShyche 	fCurrentSlot(0),
291481c49cShyche 	fWritable(false)
301481c49cShyche {
311481c49cShyche }
321481c49cShyche 
331481c49cShyche 
34548a0d80Shyche BTree::Node::Node(void* cache, off_t block)
351481c49cShyche 	:
361481c49cShyche 	fNode(NULL),
371481c49cShyche 	fCache(cache),
381481c49cShyche 	fBlockNumber(0),
391481c49cShyche 	fCurrentSlot(0),
401481c49cShyche 	fWritable(false)
411481c49cShyche {
421481c49cShyche 	SetTo(block);
431481c49cShyche }
441481c49cShyche 
451481c49cShyche 
46548a0d80Shyche BTree::Node::~Node()
471481c49cShyche {
481481c49cShyche 	Unset();
491481c49cShyche }
501481c49cShyche 
511481c49cShyche 
521481c49cShyche void
53548a0d80Shyche BTree::Node::Keep()
541481c49cShyche {
551481c49cShyche 	fNode = NULL;
561481c49cShyche }
571481c49cShyche 
581481c49cShyche void
59548a0d80Shyche BTree::Node::Unset()
601481c49cShyche {
611481c49cShyche 	if (fNode != NULL) {
621481c49cShyche 		block_cache_put(fCache, fBlockNumber);
631481c49cShyche 		fNode = NULL;
641481c49cShyche 	}
651481c49cShyche }
661481c49cShyche 
671481c49cShyche 
681481c49cShyche void
69548a0d80Shyche BTree::Node::SetTo(off_t block)
701481c49cShyche {
711481c49cShyche 	Unset();
721481c49cShyche 	fBlockNumber = block;
731481c49cShyche 	fNode = (btrfs_stream*)block_cache_get(fCache, block);
741481c49cShyche }
751481c49cShyche 
761481c49cShyche 
771481c49cShyche void
78548a0d80Shyche BTree::Node::SetToWritable(off_t block, int32 transactionId, bool empty)
791481c49cShyche {
801481c49cShyche 	Unset();
811481c49cShyche 	fBlockNumber = block;
821481c49cShyche 	fWritable = true;
831481c49cShyche 	if (empty) {
841481c49cShyche 		fNode = (btrfs_stream*)block_cache_get_empty(fCache, block,
851481c49cShyche 			transactionId);
861481c49cShyche 	} else {
871481c49cShyche 		fNode = (btrfs_stream*)block_cache_get_writable(fCache, block,
881481c49cShyche 			transactionId);
891481c49cShyche 	}
901481c49cShyche }
911481c49cShyche 
921481c49cShyche 
9391d7f850Shyche int32
94548a0d80Shyche BTree::Node::SearchSlot(const btrfs_key& key, int* slot, btree_traversing type) const
9591d7f850Shyche {
9691d7f850Shyche 	//binary search for item slot in a node
9791d7f850Shyche 	int entrySize = sizeof(btrfs_entry);
9891d7f850Shyche 	if (Level() != 0) {
9991d7f850Shyche 		// internal node
10091d7f850Shyche 		entrySize = sizeof(btrfs_index);
10191d7f850Shyche 	}
10291d7f850Shyche 
10391d7f850Shyche 	int low = 0;
10491d7f850Shyche 	int high = ItemCount();
1050d726c5cShyche 	int mid, comp;
10691d7f850Shyche 	int base = sizeof(btrfs_header);
10791d7f850Shyche 	const btrfs_key* other;
10891d7f850Shyche 	while (low < high) {
10991d7f850Shyche 		mid = (low + high) / 2;
11091d7f850Shyche 		other = (const btrfs_key*)((uint8*)fNode + base + mid * entrySize);
1110d726c5cShyche 		comp = key.Compare(*other);
11291d7f850Shyche 		if (comp < 0)
11391d7f850Shyche 			high = mid;
11491d7f850Shyche 		else if (comp > 0)
11591d7f850Shyche 			low = mid + 1;
11691d7f850Shyche 		else {
11791d7f850Shyche 			*slot = mid;
1180d726c5cShyche 			return B_OK; 		//if key is in node
11991d7f850Shyche 		}
12091d7f850Shyche 	}
1210d726c5cShyche 
1220d726c5cShyche 	TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n",
1230d726c5cShyche 		*slot, comp);
1240d726c5cShyche 	if (type == BTREE_BACKWARD)
1250d726c5cShyche 		*slot = low - 1;
1260d726c5cShyche 	else if (type == BTREE_FORWARD)
12791d7f850Shyche 		*slot = low;
1280d726c5cShyche 
1290d726c5cShyche 	if (*slot < 0 || type == BTREE_EXACT)
13091d7f850Shyche 		return B_ENTRY_NOT_FOUND;
1310d726c5cShyche 	return B_OK;
13291d7f850Shyche }
13391d7f850Shyche 
13491d7f850Shyche 
1351481c49cShyche //-pragma mark
1361481c49cShyche 
1371481c49cShyche 
138fc4a1e78Shyche BTree::BTree(Volume* volume)
139fc4a1e78Shyche 	:
140fc4a1e78Shyche 	fRootBlock(0),
141fc4a1e78Shyche 	fVolume(volume)
142fc4a1e78Shyche {
143fc4a1e78Shyche 	mutex_init(&fIteratorLock, "btrfs b+tree iterator");
144fc4a1e78Shyche }
145fc4a1e78Shyche 
146fc4a1e78Shyche 
147299aba38Shyche BTree::BTree(Volume* volume, btrfs_stream* stream)
148299aba38Shyche 	:
149299aba38Shyche 	fRootBlock(0),
150299aba38Shyche 	fVolume(volume)
151299aba38Shyche {
152299aba38Shyche 	mutex_init(&fIteratorLock, "btrfs b+tree iterator");
153299aba38Shyche }
154299aba38Shyche 
155299aba38Shyche 
156299aba38Shyche BTree::BTree(Volume* volume, fsblock_t rootBlock)
157299aba38Shyche 	:
158299aba38Shyche 	fRootBlock(rootBlock),
159299aba38Shyche 	fVolume(volume)
160299aba38Shyche {
161299aba38Shyche 	mutex_init(&fIteratorLock, "btrfs b+tree iterator");
162299aba38Shyche }
163299aba38Shyche 
164299aba38Shyche 
165299aba38Shyche BTree::~BTree()
166299aba38Shyche {
167299aba38Shyche 	// if there are any TreeIterators left, we need to stop them
168299aba38Shyche 	// (can happen when the tree's inode gets deleted while
169299aba38Shyche 	// traversing the tree - a TreeIterator doesn't lock the inode)
170299aba38Shyche 	mutex_lock(&fIteratorLock);
171299aba38Shyche 
172299aba38Shyche 	SinglyLinkedList<TreeIterator>::Iterator iterator
173299aba38Shyche 		= fIterators.GetIterator();
174299aba38Shyche 	while (iterator.HasNext())
175299aba38Shyche 		iterator.Next()->Stop();
176299aba38Shyche 	mutex_destroy(&fIteratorLock);
177299aba38Shyche }
178299aba38Shyche 
179299aba38Shyche 
180299aba38Shyche int32
181875a0552Shyche btrfs_key::Compare(const btrfs_key& key) const
182299aba38Shyche {
183875a0552Shyche 	if (ObjectID() > key.ObjectID())
184299aba38Shyche 		return 1;
185875a0552Shyche 	if (ObjectID() < key.ObjectID())
186299aba38Shyche 		return -1;
187875a0552Shyche 	if (Type() > key.Type())
188299aba38Shyche 		return 1;
189875a0552Shyche 	if (Type() < key.Type())
190299aba38Shyche 		return -1;
191875a0552Shyche 	if (Offset() > key.Offset())
192299aba38Shyche 		return 1;
193875a0552Shyche 	if (Offset() < key.Offset())
194299aba38Shyche 		return -1;
195299aba38Shyche 	return 0;
196299aba38Shyche }
197299aba38Shyche 
198299aba38Shyche 
199299aba38Shyche /*!	Searches the key in the tree, and stores the allocated found item in
200299aba38Shyche 	_value, if successful.
201299aba38Shyche 	Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not.
202299aba38Shyche 	It can also return other errors to indicate that something went wrong.
203299aba38Shyche */
204299aba38Shyche status_t
205299aba38Shyche BTree::_Find(btrfs_key& key, void** _value, size_t* _size,
206299aba38Shyche 	btree_traversing type)
207299aba38Shyche {
208299aba38Shyche 	TRACE("Find() objectid %" B_PRId64 " type %d offset %" B_PRId64 " \n",
209299aba38Shyche 		key.ObjectID(),	key.Type(), key.Offset());
210548a0d80Shyche 	BTree::Node node(fVolume->BlockCache(), fRootBlock);
21135a5e5adShyche 	int slot, ret;
21235a5e5adShyche 	fsblock_t physicalBlock;
213299aba38Shyche 
21435a5e5adShyche 	while (node.Level() != 0) {
21535a5e5adShyche 		TRACE("Find() level %d\n", node.Level());
21635a5e5adShyche 		ret = node.SearchSlot(key, &slot, BTREE_BACKWARD);
21735a5e5adShyche 		if (ret != B_OK)
21835a5e5adShyche 			return ret;
21935a5e5adShyche 		TRACE("Find() getting index %" B_PRIu32 "\n", slot);
220299aba38Shyche 
22135a5e5adShyche 		if (fVolume->FindBlock(node.Index(slot)->LogicalAddress(), physicalBlock)
222299aba38Shyche 			!= B_OK) {
223299aba38Shyche 			ERROR("Find() unmapped block %" B_PRId64 "\n",
22435a5e5adShyche 				node.Index(slot)->LogicalAddress());
225299aba38Shyche 			return B_ERROR;
226299aba38Shyche 		}
22735a5e5adShyche 		node.SetTo(physicalBlock);
228299aba38Shyche 	}
229299aba38Shyche 
23035a5e5adShyche 	TRACE("Find() dump count %" B_PRId32 "\n", node.ItemCount());
23135a5e5adShyche 	ret = node.SearchSlot(key, &slot, type);
232299aba38Shyche 
23335a5e5adShyche 	if ( ret == B_OK && node.Item(slot)->key.Type() == key.Type()) {
234299aba38Shyche 		TRACE("Find() found %" B_PRIu32 " %" B_PRIu32 "\n",
23535a5e5adShyche 			node.Item(slot)->Offset(), node.Item(slot)->Size());
236299aba38Shyche 
237299aba38Shyche 		if (_value != NULL) {
23835a5e5adShyche 			*_value = malloc(node.Item(slot)->Size());
23935a5e5adShyche 			memcpy(*_value, node.ItemData(slot),
24035a5e5adShyche 				node.Item(slot)->Size());
24135a5e5adShyche 			key.SetOffset(node.Item(slot)->key.Offset());
242299aba38Shyche 			if (_size != NULL)
24335a5e5adShyche 				*_size = node.Item(slot)->Size();
244299aba38Shyche 		}
245299aba38Shyche 		return B_OK;
246299aba38Shyche 	}
247299aba38Shyche 
248299aba38Shyche 
249299aba38Shyche 	TRACE("Find() not found %" B_PRId64 " %" B_PRId64 "\n", key.Offset(),
250299aba38Shyche 		key.ObjectID());
251299aba38Shyche 
252299aba38Shyche 	return B_ENTRY_NOT_FOUND;
253299aba38Shyche }
254299aba38Shyche 
255299aba38Shyche 
256299aba38Shyche status_t
257299aba38Shyche BTree::FindNext(btrfs_key& key, void** _value, size_t* _size)
258299aba38Shyche {
259299aba38Shyche 	return _Find(key, _value, _size, BTREE_FORWARD);
260299aba38Shyche }
261299aba38Shyche 
262299aba38Shyche 
263299aba38Shyche status_t
264299aba38Shyche BTree::FindPrevious(btrfs_key& key, void** _value, size_t* _size)
265299aba38Shyche {
266299aba38Shyche 	return _Find(key, _value, _size, BTREE_BACKWARD);
267299aba38Shyche }
268299aba38Shyche 
269299aba38Shyche 
270299aba38Shyche status_t
271299aba38Shyche BTree::FindExact(btrfs_key& key, void** _value, size_t* _size)
272299aba38Shyche {
273299aba38Shyche 	return _Find(key, _value, _size, BTREE_EXACT);
274299aba38Shyche }
275299aba38Shyche 
276299aba38Shyche 
277fc4a1e78Shyche status_t
278fc4a1e78Shyche BTree::SetRoot(off_t logical, fsblock_t* block)
279fc4a1e78Shyche {
280fc4a1e78Shyche 	if (block != NULL) {
281fc4a1e78Shyche 		fRootBlock = *block;
282*370ee09fShyche 		//TODO: mapping physical block -> logical address
283fc4a1e78Shyche 	} else {
284*370ee09fShyche 		fLogicalRoot = logical;
285fc4a1e78Shyche 		if (fVolume->FindBlock(logical, fRootBlock) != B_OK) {
286fc4a1e78Shyche 			ERROR("Find() unmapped block %" B_PRId64 "\n", fRootBlock);
287fc4a1e78Shyche 			return B_ERROR;
288fc4a1e78Shyche 		}
289fc4a1e78Shyche 	}
290fc4a1e78Shyche 	return B_OK;
291fc4a1e78Shyche }
292fc4a1e78Shyche 
293fc4a1e78Shyche 
294299aba38Shyche void
295299aba38Shyche BTree::_AddIterator(TreeIterator* iterator)
296299aba38Shyche {
297299aba38Shyche 	MutexLocker _(fIteratorLock);
298299aba38Shyche 	fIterators.Add(iterator);
299299aba38Shyche }
300299aba38Shyche 
301299aba38Shyche 
302299aba38Shyche void
303299aba38Shyche BTree::_RemoveIterator(TreeIterator* iterator)
304299aba38Shyche {
305299aba38Shyche 	MutexLocker _(fIteratorLock);
306299aba38Shyche 	fIterators.Remove(iterator);
307299aba38Shyche }
308299aba38Shyche 
309299aba38Shyche 
310299aba38Shyche //	#pragma mark -
311299aba38Shyche 
312299aba38Shyche 
313299aba38Shyche TreeIterator::TreeIterator(BTree* tree, btrfs_key& key)
314299aba38Shyche 	:
315299aba38Shyche 	fTree(tree),
316299aba38Shyche 	fCurrentKey(key)
317299aba38Shyche {
318299aba38Shyche 	Rewind();
319299aba38Shyche 	tree->_AddIterator(this);
320299aba38Shyche }
321299aba38Shyche 
322299aba38Shyche 
323299aba38Shyche TreeIterator::~TreeIterator()
324299aba38Shyche {
325299aba38Shyche 	if (fTree)
326299aba38Shyche 		fTree->_RemoveIterator(this);
327299aba38Shyche }
328299aba38Shyche 
329299aba38Shyche 
330299aba38Shyche /*!	Iterates through the tree in the specified direction.
331299aba38Shyche */
332299aba38Shyche status_t
333299aba38Shyche TreeIterator::Traverse(btree_traversing direction, btrfs_key& key,
334299aba38Shyche 	void** value, size_t* size)
335299aba38Shyche {
336299aba38Shyche 	if (fTree == NULL)
337299aba38Shyche 		return B_INTERRUPTED;
338299aba38Shyche 
339299aba38Shyche 	fCurrentKey.SetOffset(fCurrentKey.Offset() + direction);
340299aba38Shyche 	status_t status = fTree->_Find(fCurrentKey, value, size,
341299aba38Shyche 		direction);
342299aba38Shyche 	if (status != B_OK) {
343299aba38Shyche 		TRACE("TreeIterator::Traverse() Find failed\n");
344299aba38Shyche 		return B_ENTRY_NOT_FOUND;
345299aba38Shyche 	}
346299aba38Shyche 
347299aba38Shyche 	return B_OK;
348299aba38Shyche }
349299aba38Shyche 
350299aba38Shyche 
351299aba38Shyche /*!	just sets the current key in the iterator.
352299aba38Shyche */
353299aba38Shyche status_t
354299aba38Shyche TreeIterator::Find(btrfs_key& key)
355299aba38Shyche {
356299aba38Shyche 	if (fTree == NULL)
357299aba38Shyche 		return B_INTERRUPTED;
358299aba38Shyche 	fCurrentKey = key;
359299aba38Shyche 	return B_OK;
360299aba38Shyche }
361299aba38Shyche 
362299aba38Shyche 
363299aba38Shyche void
364299aba38Shyche TreeIterator::Stop()
365299aba38Shyche {
366299aba38Shyche 	fTree = NULL;
367299aba38Shyche }
368