1299aba38Shyche /*
299768086Shyche * Copyright 2017, Chế Vũ Gia Hy, cvghy116@gmail.com.
3299aba38Shyche * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
4299aba38Shyche * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
5299aba38Shyche * This file may be used under the terms of the MIT License.
6299aba38Shyche */
7299aba38Shyche
8299aba38Shyche
9299aba38Shyche //! BTree implementation
10299aba38Shyche
11299aba38Shyche
12299aba38Shyche #include "BTree.h"
13883b9bf2Shyche #include "Journal.h"
14299aba38Shyche
15299aba38Shyche
16299aba38Shyche //#define TRACE_BTRFS
17299aba38Shyche #ifdef TRACE_BTRFS
18299aba38Shyche # define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
19299aba38Shyche #else
20299aba38Shyche # define TRACE(x...) ;
21299aba38Shyche #endif
22299aba38Shyche # define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
23299aba38Shyche
24299aba38Shyche
Node(Volume * volume)258160f31fShyche BTree::Node::Node(Volume* volume)
261481c49cShyche :
271481c49cShyche fNode(NULL),
288160f31fShyche fVolume(volume),
291481c49cShyche fBlockNumber(0),
301481c49cShyche fWritable(false)
311481c49cShyche {
321481c49cShyche }
331481c49cShyche
341481c49cShyche
Node(Volume * volume,off_t block)358160f31fShyche BTree::Node::Node(Volume* volume, off_t block)
361481c49cShyche :
371481c49cShyche fNode(NULL),
388160f31fShyche fVolume(volume),
391481c49cShyche fBlockNumber(0),
401481c49cShyche fWritable(false)
411481c49cShyche {
421481c49cShyche SetTo(block);
431481c49cShyche }
441481c49cShyche
451481c49cShyche
~Node()46548a0d80Shyche BTree::Node::~Node()
471481c49cShyche {
481481c49cShyche Unset();
491481c49cShyche }
501481c49cShyche
511481c49cShyche
521481c49cShyche void
Unset()53548a0d80Shyche BTree::Node::Unset()
541481c49cShyche {
551481c49cShyche if (fNode != NULL) {
568160f31fShyche block_cache_put(fVolume->BlockCache(), fBlockNumber);
571481c49cShyche fNode = NULL;
581481c49cShyche }
591481c49cShyche }
601481c49cShyche
611481c49cShyche
621481c49cShyche void
SetTo(off_t block)63548a0d80Shyche BTree::Node::SetTo(off_t block)
641481c49cShyche {
651481c49cShyche Unset();
661481c49cShyche fBlockNumber = block;
678160f31fShyche fNode = (btrfs_stream*)block_cache_get(fVolume->BlockCache(), block);
681481c49cShyche }
691481c49cShyche
701481c49cShyche
711481c49cShyche void
SetToWritable(off_t block,int32 transactionId,bool empty)72548a0d80Shyche BTree::Node::SetToWritable(off_t block, int32 transactionId, bool empty)
731481c49cShyche {
741481c49cShyche Unset();
751481c49cShyche fBlockNumber = block;
761481c49cShyche fWritable = true;
771481c49cShyche if (empty) {
788160f31fShyche fNode = (btrfs_stream*)block_cache_get_empty(fVolume->BlockCache(),
798160f31fShyche block, transactionId);
801481c49cShyche } else {
818160f31fShyche fNode = (btrfs_stream*)block_cache_get_writable(fVolume->BlockCache(),
828160f31fShyche block, transactionId);
831481c49cShyche }
841481c49cShyche }
851481c49cShyche
861481c49cShyche
872ed88a48Shyche status_t
SearchSlot(const btrfs_key & key,int * slot,btree_traversing type) const882ed88a48Shyche BTree::Node::SearchSlot(const btrfs_key& key, int* slot, btree_traversing type)
892ed88a48Shyche const
9091d7f850Shyche {
9191d7f850Shyche // binary search for item slot in a node
9291d7f850Shyche int entrySize = sizeof(btrfs_entry);
9391d7f850Shyche if (Level() != 0) {
9491d7f850Shyche // internal node
9591d7f850Shyche entrySize = sizeof(btrfs_index);
9691d7f850Shyche }
9791d7f850Shyche
9891d7f850Shyche int high = ItemCount();
992ed88a48Shyche int low = 0, mid = 0, comp = 0;
1002ed88a48Shyche uint8* base = (uint8*)fNode + sizeof(btrfs_header);
10191d7f850Shyche const btrfs_key* other;
10291d7f850Shyche while (low < high) {
10391d7f850Shyche mid = (low + high) / 2;
1042ed88a48Shyche other = (const btrfs_key*)(base + mid * entrySize);
1050d726c5cShyche comp = key.Compare(*other);
10691d7f850Shyche if (comp < 0)
10791d7f850Shyche high = mid;
10891d7f850Shyche else if (comp > 0)
10991d7f850Shyche low = mid + 1;
11091d7f850Shyche else {
11191d7f850Shyche *slot = mid;
1120d726c5cShyche return B_OK; // if key is in node
11391d7f850Shyche }
11491d7f850Shyche }
1150d726c5cShyche
1162ed88a48Shyche // |--item1--|--item2--|--item3--|--etc--|
1172ed88a48Shyche // m-1 m m+1
1182ed88a48Shyche // k : comp < 0
1192ed88a48Shyche // k : comp > 0
120b568492fShyche if (type == BTREE_BACKWARD && comp < 0)
121b568492fShyche mid--;
122b568492fShyche else if (type == BTREE_FORWARD && comp > 0)
123b568492fShyche mid++;
1242ed88a48Shyche
125b568492fShyche if (type == BTREE_EXACT || mid < 0)
1262ed88a48Shyche return B_ENTRY_NOT_FOUND;
1272ed88a48Shyche
128b568492fShyche *slot = mid;
1290d726c5cShyche TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n",
1300d726c5cShyche *slot, comp);
1310d726c5cShyche return B_OK;
13291d7f850Shyche }
13391d7f850Shyche
13491d7f850Shyche
13527ffe058Shyche int
_CalculateSpace(uint32 from,uint32 to,uint8 type) const13627ffe058Shyche BTree::Node::_CalculateSpace(uint32 from, uint32 to, uint8 type) const
13727ffe058Shyche {
13827ffe058Shyche if (to < from || to >= ItemCount())
13927ffe058Shyche return 0;
14027ffe058Shyche
14127ffe058Shyche if (Level() != 0)
14227ffe058Shyche return sizeof(btrfs_index) * (to - from + 1);
14327ffe058Shyche
14427ffe058Shyche uint32 result = 0;
14527ffe058Shyche if ((type & 1) == 1) {
14627ffe058Shyche result += sizeof(btrfs_entry) * (to - from + 1);
14727ffe058Shyche }
14827ffe058Shyche if ((type & 2) == 2) {
14927ffe058Shyche result += Item(from)->Offset() + Item(from)->Size()
15027ffe058Shyche - Item(to)->Offset();
15127ffe058Shyche }
15227ffe058Shyche
15327ffe058Shyche return result;
15427ffe058Shyche }
15527ffe058Shyche
15627ffe058Shyche
15727ffe058Shyche int
SpaceUsed() const15827ffe058Shyche BTree::Node::SpaceUsed() const
15927ffe058Shyche {
16027ffe058Shyche if (Level() == 0)
16127ffe058Shyche return _CalculateSpace(0, ItemCount() - 1, 3);
16227ffe058Shyche return _CalculateSpace(0, ItemCount() - 1, 0);
16327ffe058Shyche }
16427ffe058Shyche
16527ffe058Shyche
16627ffe058Shyche int
SpaceLeft() const16727ffe058Shyche BTree::Node::SpaceLeft() const
16827ffe058Shyche {
16927ffe058Shyche return fVolume->BlockSize() - SpaceUsed() - sizeof(btrfs_header);
17027ffe058Shyche }
17127ffe058Shyche
17227ffe058Shyche
17389484dc0Shyche void
_Copy(const Node * origin,uint32 at,uint32 from,uint32 to,int length) const17489484dc0Shyche BTree::Node::_Copy(const Node* origin, uint32 at, uint32 from, uint32 to,
17589484dc0Shyche int length) const
17689484dc0Shyche {
17789484dc0Shyche TRACE("Node::_Copy() at: %d from: %d to: %d length: %d\n",
17889484dc0Shyche at, from, to, length);
17989484dc0Shyche
18089484dc0Shyche if (Level() == 0) {
18189484dc0Shyche memcpy(Item(at), origin->Item(from), origin->_CalculateSpace(from, to));
18289484dc0Shyche // Item offset of copied node must be changed to get the
18389484dc0Shyche // item data offset correctly. length can be zero
18489484dc0Shyche // but let it there doesn't harm anything.
18589484dc0Shyche for (uint32 i = at; i - at <= to - from; ++i)
18689484dc0Shyche Item(i)->SetOffset(Item(i)->Offset() - length);
18789484dc0Shyche
18889484dc0Shyche memcpy(ItemData(at + to - from), origin->ItemData(to),
18989484dc0Shyche origin->_CalculateSpace(from, to, 2));
19089484dc0Shyche } else {
19189484dc0Shyche memcpy(Index(at), origin->Index(from),
19289484dc0Shyche origin->_CalculateSpace(from, to));
19389484dc0Shyche }
19489484dc0Shyche }
19589484dc0Shyche
19689484dc0Shyche
19727ffe058Shyche status_t
_SpaceCheck(int length) const19827ffe058Shyche BTree::Node::_SpaceCheck(int length) const
19927ffe058Shyche {
20027ffe058Shyche // this is a little bit weird here because we can't find
20127ffe058Shyche // any suitable error code
202bb2b9b02SNiels Sascha Reedijk if (length < 0 && abs(length) >= SpaceUsed())
20327ffe058Shyche return B_DIRECTORY_NOT_EMPTY; // not enough data to delete
20427ffe058Shyche if (length > 0 && length >= SpaceLeft())
20527ffe058Shyche return B_DEVICE_FULL; // no spare space
20627ffe058Shyche return B_OK;
20727ffe058Shyche }
20827ffe058Shyche
20927ffe058Shyche
21089484dc0Shyche status_t
Copy(const Node * origin,uint32 start,uint32 end,int length) const21189484dc0Shyche BTree::Node::Copy(const Node* origin, uint32 start, uint32 end, int length)
21289484dc0Shyche const
21389484dc0Shyche {
21489484dc0Shyche status_t status = origin->_SpaceCheck(length);
21589484dc0Shyche if (status != B_OK)
21689484dc0Shyche return status;
21789484dc0Shyche
21889484dc0Shyche memcpy(fNode, origin->fNode, sizeof(btrfs_header));
21989484dc0Shyche if (length == 0) {
22089484dc0Shyche // like removing [0, start - 1] and keeping [start, end]
22189484dc0Shyche length = -origin->_CalculateSpace(0, start - 1, 2);
22289484dc0Shyche _Copy(origin, 0, start, end, length);
22389484dc0Shyche } else if (length < 0) {
22489484dc0Shyche // removing all items in [start, end]
22589484dc0Shyche if (start > 0)
22689484dc0Shyche _Copy(origin, 0, 0, start - 1, 0); // <-- [start,...
22789484dc0Shyche if (end + 1 < origin->ItemCount()) {
22889484dc0Shyche // ..., end] -->
22989484dc0Shyche // we only care data size
23089484dc0Shyche length += origin->_CalculateSpace(start, end);
23189484dc0Shyche _Copy(origin, start, end + 1, origin->ItemCount() - 1, length);
23289484dc0Shyche }
23389484dc0Shyche } else {
23489484dc0Shyche // inserting in [start, end] - make a hole for later
23589484dc0Shyche if (start > 0)
23689484dc0Shyche _Copy(origin, 0, 0, start - 1, 0);
23789484dc0Shyche if (start < origin->ItemCount()) {
23889484dc0Shyche length -= origin->_CalculateSpace(start, end);
23989484dc0Shyche _Copy(origin, end + 1, start, origin->ItemCount() - 1, length);
24089484dc0Shyche }
24189484dc0Shyche }
24289484dc0Shyche
24389484dc0Shyche return B_OK;
24489484dc0Shyche }
24589484dc0Shyche
24689484dc0Shyche
24789484dc0Shyche status_t
MoveEntries(uint32 start,uint32 end,int length) const24889484dc0Shyche BTree::Node::MoveEntries(uint32 start, uint32 end, int length) const
24989484dc0Shyche {
25089484dc0Shyche status_t status = _SpaceCheck(length);
25189484dc0Shyche if (status != B_OK || length == 0/*B_OK*/)
25289484dc0Shyche return status;
25389484dc0Shyche
25489484dc0Shyche int entrySize = sizeof(btrfs_entry);
25589484dc0Shyche if (Level() != 0)
25689484dc0Shyche entrySize = sizeof(btrfs_index);
25789484dc0Shyche
25889484dc0Shyche uint8* base = (uint8*)fNode + sizeof(btrfs_header);
25989484dc0Shyche end++;
26089484dc0Shyche if (length < 0) {
26189484dc0Shyche // removing [start, end]
26289484dc0Shyche TRACE("Node::MoveEntries() removing ... start %" B_PRIu32 " end %"
26389484dc0Shyche B_PRIu32 " length %i\n", start, end, length);
26489484dc0Shyche length += _CalculateSpace(start, end - 1);
26589484dc0Shyche } else {
26689484dc0Shyche // length > 0
26789484dc0Shyche // inserting into [start, end] - make room for later
26889484dc0Shyche TRACE("Node::MoveEntries() inserting ... start %" B_PRIu32 " end %"
26989484dc0Shyche B_PRIu32 " length %i\n", start, end, length);
27089484dc0Shyche length -= _CalculateSpace(start, end - 1);
271cddaf762SAdrien Destugues uint32 tmp = start;
272cddaf762SAdrien Destugues start = end;
273cddaf762SAdrien Destugues end = tmp;
27489484dc0Shyche }
27589484dc0Shyche
27689484dc0Shyche if (end >= ItemCount())
27789484dc0Shyche return B_OK;
27889484dc0Shyche
27989484dc0Shyche int dataSize = _CalculateSpace(end, ItemCount() - 1, 2);
28089484dc0Shyche // moving items/block pointers
28189484dc0Shyche memmove(base + start * entrySize, base + end * entrySize,
28289484dc0Shyche _CalculateSpace(end, ItemCount() - 1));
28389484dc0Shyche if (Level() == 0) {
28489484dc0Shyche // moving item data
28589484dc0Shyche int num = start - end;
28689484dc0Shyche for (uint32 i = start; i < ItemCount() + num; ++i)
28789484dc0Shyche Item(i)->SetOffset(Item(i)->Offset() - length);
28889484dc0Shyche
28989484dc0Shyche memmove(ItemData(ItemCount() - 1) - length, ItemData(ItemCount() - 1),
29089484dc0Shyche dataSize);
29189484dc0Shyche }
29289484dc0Shyche
29389484dc0Shyche return B_OK;
29489484dc0Shyche }
29589484dc0Shyche
29689484dc0Shyche
2973216460dShyche // #pragma mark - BTree::Path implementation
2983216460dShyche
2993216460dShyche
Path(BTree * tree)3003216460dShyche BTree::Path::Path(BTree* tree)
3013216460dShyche :
3023216460dShyche fTree(tree)
3033216460dShyche {
3043216460dShyche for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) {
3053216460dShyche fNodes[i] = NULL;
3063216460dShyche fSlots[i] = 0;
3073216460dShyche }
3083216460dShyche }
3093216460dShyche
3103216460dShyche
~Path()3113216460dShyche BTree::Path::~Path()
3123216460dShyche {
3133216460dShyche for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) {
3143216460dShyche delete fNodes[i];
3153216460dShyche fNodes[i] = NULL;
3163216460dShyche fSlots[i] = 0;
3173216460dShyche }
3183216460dShyche }
3193216460dShyche
3203216460dShyche
3213216460dShyche BTree::Node*
GetNode(int level,int * _slot) const3223216460dShyche BTree::Path::GetNode(int level, int* _slot) const
3233216460dShyche {
3243216460dShyche if (_slot != NULL)
3253216460dShyche *_slot = fSlots[level];
3263216460dShyche return fNodes[level];
3273216460dShyche }
3283216460dShyche
3293216460dShyche
3303216460dShyche BTree::Node*
SetNode(off_t block,int slot)3313216460dShyche BTree::Path::SetNode(off_t block, int slot)
3323216460dShyche {
3333216460dShyche Node node(fTree->SystemVolume(), block);
3343216460dShyche return SetNode(&node, slot);
3353216460dShyche }
3363216460dShyche
3373216460dShyche
3383216460dShyche BTree::Node*
SetNode(const Node * node,int slot)3393216460dShyche BTree::Path::SetNode(const Node* node, int slot)
3403216460dShyche {
3413216460dShyche uint8 level = node->Level();
3423216460dShyche if (fNodes[level] == NULL) {
3433216460dShyche fNodes[level] = new Node(fTree->SystemVolume(), node->BlockNum());
3443216460dShyche if (fNodes[level] == NULL)
3453216460dShyche return NULL;
3463216460dShyche } else
3473216460dShyche fNodes[level]->SetTo(node->BlockNum());
3483216460dShyche
3493216460dShyche if (slot == -1)
3503216460dShyche fSlots[level] = fNodes[level]->ItemCount() - 1;
3513216460dShyche else
3523216460dShyche fSlots[level] = slot;
3533216460dShyche return fNodes[level];
3543216460dShyche }
3553216460dShyche
3563216460dShyche
3573216460dShyche int
Move(int level,int step)3583216460dShyche BTree::Path::Move(int level, int step)
3593216460dShyche {
3603216460dShyche fSlots[level] += step;
3613216460dShyche if (fSlots[level] < 0)
3623216460dShyche return -1;
3633216460dShyche if (fSlots[level] >= fNodes[level]->ItemCount())
3643216460dShyche return 1;
3653216460dShyche return 0;
3663216460dShyche }
3673216460dShyche
3683216460dShyche
3693216460dShyche status_t
GetEntry(int slot,btrfs_key * _key,void ** _value,uint32 * _size,uint32 * _offset)3703216460dShyche BTree::Path::GetEntry(int slot, btrfs_key* _key, void** _value, uint32* _size,
3713216460dShyche uint32* _offset)
3723216460dShyche {
3733216460dShyche BTree::Node* leaf = fNodes[0];
3743216460dShyche if (slot < 0 || slot >= leaf->ItemCount())
3753216460dShyche return B_ENTRY_NOT_FOUND;
3763216460dShyche
3773216460dShyche if (_key != NULL)
3783216460dShyche *_key = leaf->Item(slot)->key;
3793216460dShyche
3803216460dShyche uint32 itemSize = leaf->Item(slot)->Size();
3813216460dShyche if (_value != NULL) {
3823216460dShyche *_value = malloc(itemSize);
3833216460dShyche if (*_value == NULL)
3843216460dShyche return B_NO_MEMORY;
3853216460dShyche
3863216460dShyche memcpy(*_value, leaf->ItemData(slot), itemSize);
3873216460dShyche }
3883216460dShyche
3893216460dShyche if (_size != NULL)
3903216460dShyche *_size = itemSize;
3913216460dShyche
3923216460dShyche if (_offset != NULL)
3933216460dShyche *_offset = leaf->Item(slot)->Offset();
3943216460dShyche
3953216460dShyche return B_OK;
3963216460dShyche }
3973216460dShyche
3983216460dShyche
39984bc447cShyche status_t
SetEntry(int slot,const btrfs_entry & entry,void * value)40084bc447cShyche BTree::Path::SetEntry(int slot, const btrfs_entry& entry, void* value)
40184bc447cShyche {
40284bc447cShyche if (slot < 0)
40384bc447cShyche return B_ENTRY_NOT_FOUND;
40484bc447cShyche
40584bc447cShyche memcpy(fNodes[0]->Item(slot), &entry, sizeof(btrfs_entry));
40684bc447cShyche memcpy(fNodes[0]->ItemData(slot), value, entry.Size());
40784bc447cShyche return B_OK;
40884bc447cShyche }
40984bc447cShyche
41084bc447cShyche
411883b9bf2Shyche status_t
CopyOnWrite(Transaction & transaction,int level,uint32 start,int num,int length)412883b9bf2Shyche BTree::Path::CopyOnWrite(Transaction& transaction, int level, uint32 start,
413883b9bf2Shyche int num, int length)
414883b9bf2Shyche {
415883b9bf2Shyche Node* node = fNodes[level];
416883b9bf2Shyche if (node == NULL)
417883b9bf2Shyche return B_BAD_VALUE;
418883b9bf2Shyche
419883b9bf2Shyche status_t status;
420883b9bf2Shyche if (transaction.HasBlock(node->BlockNum())) {
421883b9bf2Shyche // cow-ed block can not be cow-ed again
422883b9bf2Shyche status = node->MoveEntries(start, start + num - 1, length);
423883b9bf2Shyche if (status != B_OK)
424883b9bf2Shyche return status;
425883b9bf2Shyche
426883b9bf2Shyche node->SetGeneration(transaction.SystemID());
427883b9bf2Shyche if (length < 0)
428883b9bf2Shyche node->SetItemCount(node->ItemCount() - num);
429883b9bf2Shyche else if (length > 0)
430883b9bf2Shyche node->SetItemCount(node->ItemCount() + num);
431883b9bf2Shyche
432883b9bf2Shyche return B_OK;
433883b9bf2Shyche }
434883b9bf2Shyche
435883b9bf2Shyche uint64 address;
436883b9bf2Shyche fsblock_t block;
437883b9bf2Shyche status = fTree->SystemVolume()->GetNewBlock(address, block);
438883b9bf2Shyche if (status != B_OK)
439883b9bf2Shyche return status;
440883b9bf2Shyche
441883b9bf2Shyche fNodes[level] = new(std::nothrow) BTree::Node(fTree->SystemVolume());
442883b9bf2Shyche if (fNodes[level] == NULL)
443883b9bf2Shyche return B_NO_MEMORY;
444883b9bf2Shyche
445883b9bf2Shyche fNodes[level]->SetToWritable(block, transaction.ID(), true);
446883b9bf2Shyche
447883b9bf2Shyche status = fNodes[level]->Copy(node, start, start + num - 1, length);
448883b9bf2Shyche if (status != B_OK)
449883b9bf2Shyche return status;
450883b9bf2Shyche
451883b9bf2Shyche fNodes[level]->SetGeneration(transaction.SystemID());
452883b9bf2Shyche fNodes[level]->SetLogicalAddress(address);
453883b9bf2Shyche if (length < 0)
454883b9bf2Shyche fNodes[level]->SetItemCount(node->ItemCount() - num);
455883b9bf2Shyche else if (length > 0)
456883b9bf2Shyche fNodes[level]->SetItemCount(node->ItemCount() + num);
457883b9bf2Shyche else
458883b9bf2Shyche fNodes[level]->SetItemCount(num);
459883b9bf2Shyche
460883b9bf2Shyche // change pointer of this node in parent
461883b9bf2Shyche int parentSlot;
462883b9bf2Shyche Node* parentNode = GetNode(level + 1, &parentSlot);
463883b9bf2Shyche if (parentNode != NULL)
464883b9bf2Shyche parentNode->Index(parentSlot)->SetLogicalAddress(address);
465883b9bf2Shyche
466883b9bf2Shyche if (level == fTree->RootLevel())
467883b9bf2Shyche fTree->SetRoot(fNodes[level]);
468883b9bf2Shyche
469883b9bf2Shyche delete node;
470883b9bf2Shyche return B_OK;
471883b9bf2Shyche }
472883b9bf2Shyche
473883b9bf2Shyche
474883b9bf2Shyche status_t
InternalCopy(Transaction & transaction,int level)475883b9bf2Shyche BTree::Path::InternalCopy(Transaction& transaction, int level)
476883b9bf2Shyche {
477bb2b9b02SNiels Sascha Reedijk if (abs(level) >= fTree->RootLevel())
478883b9bf2Shyche return B_OK;
479883b9bf2Shyche
480883b9bf2Shyche TRACE("Path::InternalCopy() level %i\n", level);
481883b9bf2Shyche int from, to;
482883b9bf2Shyche if (level > 0) {
483883b9bf2Shyche from = level;
484883b9bf2Shyche to = fTree->RootLevel();
485883b9bf2Shyche } else {
486b951cbd3Sbrjhaiku
487b951cbd3Sbrjhaiku
488883b9bf2Shyche from = 0;
489bb2b9b02SNiels Sascha Reedijk to = abs(level);
490883b9bf2Shyche }
491883b9bf2Shyche
492883b9bf2Shyche Node* node = NULL;
493883b9bf2Shyche status_t status;
494883b9bf2Shyche while (from <= to) {
495883b9bf2Shyche node = fNodes[from];
496883b9bf2Shyche status = CopyOnWrite(transaction, from, 0, node->ItemCount(), 0);
497883b9bf2Shyche from++;
498883b9bf2Shyche if (status != B_OK)
499883b9bf2Shyche return status;
500883b9bf2Shyche }
501883b9bf2Shyche
502883b9bf2Shyche return B_OK;
503883b9bf2Shyche }
504883b9bf2Shyche
505883b9bf2Shyche
5063216460dShyche // #pragma mark - BTree implementation
5071481c49cShyche
5081481c49cShyche
BTree(Volume * volume)509fc4a1e78Shyche BTree::BTree(Volume* volume)
510fc4a1e78Shyche :
511fc4a1e78Shyche fRootBlock(0),
512883b9bf2Shyche fRootLevel(0),
513fc4a1e78Shyche fVolume(volume)
514fc4a1e78Shyche {
515fc4a1e78Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator");
516fc4a1e78Shyche }
517fc4a1e78Shyche
518fc4a1e78Shyche
BTree(Volume * volume,btrfs_stream * stream)519299aba38Shyche BTree::BTree(Volume* volume, btrfs_stream* stream)
520299aba38Shyche :
521299aba38Shyche fRootBlock(0),
522883b9bf2Shyche fRootLevel(0),
523299aba38Shyche fVolume(volume)
524299aba38Shyche {
525299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator");
526299aba38Shyche }
527299aba38Shyche
528299aba38Shyche
BTree(Volume * volume,fsblock_t rootBlock)529299aba38Shyche BTree::BTree(Volume* volume, fsblock_t rootBlock)
530299aba38Shyche :
531299aba38Shyche fRootBlock(rootBlock),
532299aba38Shyche fVolume(volume)
533299aba38Shyche {
534299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator");
535299aba38Shyche }
536299aba38Shyche
537299aba38Shyche
~BTree()538299aba38Shyche BTree::~BTree()
539299aba38Shyche {
540299aba38Shyche // if there are any TreeIterators left, we need to stop them
541299aba38Shyche // (can happen when the tree's inode gets deleted while
542299aba38Shyche // traversing the tree - a TreeIterator doesn't lock the inode)
543299aba38Shyche mutex_lock(&fIteratorLock);
544299aba38Shyche
545*df44e515SAugustin Cavalier SinglyLinkedList<TreeIterator>::ConstIterator iterator
546299aba38Shyche = fIterators.GetIterator();
547299aba38Shyche while (iterator.HasNext())
548299aba38Shyche iterator.Next()->Stop();
549299aba38Shyche mutex_destroy(&fIteratorLock);
550299aba38Shyche }
551299aba38Shyche
552299aba38Shyche
553299aba38Shyche int32
Compare(const btrfs_key & key) const554875a0552Shyche btrfs_key::Compare(const btrfs_key& key) const
555299aba38Shyche {
556875a0552Shyche if (ObjectID() > key.ObjectID())
557299aba38Shyche return 1;
558875a0552Shyche if (ObjectID() < key.ObjectID())
559299aba38Shyche return -1;
560875a0552Shyche if (Type() > key.Type())
561299aba38Shyche return 1;
562875a0552Shyche if (Type() < key.Type())
563299aba38Shyche return -1;
564875a0552Shyche if (Offset() > key.Offset())
565299aba38Shyche return 1;
566875a0552Shyche if (Offset() < key.Offset())
567299aba38Shyche return -1;
568299aba38Shyche return 0;
569299aba38Shyche }
570299aba38Shyche
571299aba38Shyche
5723216460dShyche status_t
Traverse(btree_traversing type,Path * path,const btrfs_key & key) const5733216460dShyche BTree::Traverse(btree_traversing type, Path* path, const btrfs_key& key)
5743216460dShyche const
5753216460dShyche {
5763216460dShyche TRACE("BTree::Traverse() objectid %" B_PRId64 " type %d offset %"
5773216460dShyche B_PRId64 " \n", key.ObjectID(), key.Type(), key.Offset());
5783216460dShyche fsblock_t physicalBlock = fRootBlock;
5793216460dShyche Node node(fVolume, physicalBlock);
5803216460dShyche int slot;
5813216460dShyche status_t status = B_OK;
5823216460dShyche
5833216460dShyche while (node.Level() != 0) {
5843216460dShyche TRACE("BTree::Traverse() level %d count %d\n", node.Level(),
5853216460dShyche node.ItemCount());
5863216460dShyche status = node.SearchSlot(key, &slot, BTREE_BACKWARD);
5873216460dShyche if (status != B_OK)
5883216460dShyche return status;
5893216460dShyche if (path->SetNode(&node, slot) == NULL)
5903216460dShyche return B_NO_MEMORY;
5913216460dShyche
5923216460dShyche TRACE("BTree::Traverse() getting index %" B_PRIu32 "\n", slot);
5933216460dShyche
5943216460dShyche status = fVolume->FindBlock(node.Index(slot)->LogicalAddress(),
5953216460dShyche physicalBlock);
5963216460dShyche if (status != B_OK) {
5973216460dShyche ERROR("BTree::Traverse() unmapped block %" B_PRId64 "\n",
5983216460dShyche node.Index(slot)->LogicalAddress());
5993216460dShyche return status;
6003216460dShyche }
6013216460dShyche node.SetTo(physicalBlock);
6023216460dShyche }
6033216460dShyche
6043216460dShyche TRACE("BTree::Traverse() dump count %" B_PRId32 "\n", node.ItemCount());
6053216460dShyche status = node.SearchSlot(key, &slot, type);
6063216460dShyche if (status != B_OK)
6073216460dShyche return status;
6083216460dShyche if (path->SetNode(&node, slot) == NULL)
6093216460dShyche return B_NO_MEMORY;
6103216460dShyche
6113216460dShyche TRACE("BTree::Traverse() found %" B_PRIu32 " %" B_PRIu32 "\n",
6123216460dShyche node.Item(slot)->Offset(), node.Item(slot)->Size());
6133216460dShyche return slot;
6143216460dShyche }
6153216460dShyche
6163216460dShyche
617299aba38Shyche status_t
_Find(Path * path,btrfs_key & wanted,void ** _value,uint32 * _size,uint32 * _offset,btree_traversing type) const6183216460dShyche BTree::_Find(Path* path, btrfs_key& wanted, void** _value, uint32* _size,
6193216460dShyche uint32* _offset, btree_traversing type) const
620299aba38Shyche {
6213216460dShyche status_t status = Traverse(type, path, wanted);
6223216460dShyche if (status < B_OK)
6233216460dShyche return status;
624299aba38Shyche
6253216460dShyche btrfs_key found;
6263216460dShyche status = path->GetCurrentEntry(&found, _value, _size, _offset);
6273216460dShyche if (status != B_OK)
6283216460dShyche return status;
629299aba38Shyche
630690d16c6Shyche if (found.Type() != wanted.Type() && wanted.Type() != BTRFS_KEY_TYPE_ANY) {
631690d16c6Shyche ERROR("Find() not found wanted: %" B_PRIu64 " %" B_PRIu8 " %"
632690d16c6Shyche B_PRIu64 " found: %" B_PRIu64 " %" B_PRIu8 " %" B_PRIu64 "\n",
633690d16c6Shyche wanted.ObjectID(), wanted.Type(), wanted.Offset(), found.ObjectID(),
634690d16c6Shyche found.Type(), found.Offset());
63546eba5c0Shyche return B_ENTRY_NOT_FOUND;
636690d16c6Shyche }
637299aba38Shyche
6383216460dShyche wanted = found;
639299aba38Shyche return B_OK;
640299aba38Shyche }
641299aba38Shyche
642299aba38Shyche
64346eba5c0Shyche status_t
FindNext(Path * path,btrfs_key & key,void ** _value,uint32 * _size,uint32 * _offset) const6443216460dShyche BTree::FindNext(Path* path, btrfs_key& key, void** _value, uint32* _size,
6453216460dShyche uint32* _offset) const
64646eba5c0Shyche {
6473216460dShyche return _Find(path, key, _value, _size, _offset, BTREE_FORWARD);
648299aba38Shyche }
649299aba38Shyche
650299aba38Shyche
651299aba38Shyche status_t
FindPrevious(Path * path,btrfs_key & key,void ** _value,uint32 * _size,uint32 * _offset) const6523216460dShyche BTree::FindPrevious(Path* path, btrfs_key& key, void** _value, uint32* _size,
6533216460dShyche uint32* _offset) const
654299aba38Shyche {
6553216460dShyche return _Find(path, key, _value, _size, _offset, BTREE_BACKWARD);
656299aba38Shyche }
657299aba38Shyche
658299aba38Shyche
659299aba38Shyche status_t
FindExact(Path * path,btrfs_key & key,void ** _value,uint32 * _size,uint32 * _offset) const6603216460dShyche BTree::FindExact(Path* path, btrfs_key& key, void** _value, uint32* _size,
6613216460dShyche uint32* _offset) const
662299aba38Shyche {
6633216460dShyche return _Find(path, key, _value, _size, _offset, BTREE_EXACT);
6643216460dShyche }
6653216460dShyche
6663216460dShyche
66784bc447cShyche status_t
MakeEntries(Transaction & transaction,Path * path,const btrfs_key & startKey,int num,int length)66884bc447cShyche BTree::MakeEntries(Transaction& transaction, Path* path,
66984bc447cShyche const btrfs_key& startKey, int num, int length)
67084bc447cShyche {
67184bc447cShyche TRACE("BTree::MakeEntries() num %i key (% " B_PRIu64 " %" B_PRIu8 " %"
67284bc447cShyche B_PRIu64 ")\n", num, startKey.ObjectID(), startKey.Type(),
67384bc447cShyche startKey.Offset());
67484bc447cShyche
67584bc447cShyche status_t status = Traverse(BTREE_FORWARD, path, startKey);
67684bc447cShyche if (status < B_OK)
67784bc447cShyche return status;
67884bc447cShyche
67984bc447cShyche int slot = status;
68084bc447cShyche status = path->InternalCopy(transaction, 1);
68184bc447cShyche if (status != B_OK)
68284bc447cShyche return status;
68384bc447cShyche
68484bc447cShyche status = path->CopyOnWrite(transaction, 0, slot, num, length);
68584bc447cShyche if (status == B_DEVICE_FULL) {
68684bc447cShyche // TODO: push data or split node
68784bc447cShyche return status;
68884bc447cShyche }
68984bc447cShyche
69084bc447cShyche if (status != B_OK)
69184bc447cShyche return status;
69284bc447cShyche return slot;
69384bc447cShyche }
69484bc447cShyche
69584bc447cShyche
69684bc447cShyche status_t
InsertEntries(Transaction & transaction,Path * path,btrfs_entry * entries,void ** data,int num)69784bc447cShyche BTree::InsertEntries(Transaction& transaction, Path* path,
69884bc447cShyche btrfs_entry* entries, void** data, int num)
69984bc447cShyche {
70084bc447cShyche int totalLength = sizeof(btrfs_entry) * num;
70184bc447cShyche for (int i = 0; i < num; i++)
70284bc447cShyche totalLength += entries[i].Size();
70384bc447cShyche
70484bc447cShyche status_t slot = MakeEntries(transaction, path, entries[0].key, num,
70584bc447cShyche totalLength);
70684bc447cShyche if (slot < B_OK)
70784bc447cShyche return slot;
70884bc447cShyche
70984bc447cShyche uint32 upperLimit;
71084bc447cShyche if (slot > 0) {
71184bc447cShyche path->GetEntry(slot - 1, NULL, NULL, NULL, &upperLimit);
71284bc447cShyche } else
71384bc447cShyche upperLimit = fVolume->BlockSize() - sizeof(btrfs_header);
71484bc447cShyche
71584bc447cShyche TRACE("BTree::InsertEntries() num: %i upper limit %" B_PRIu32 "\n", num,
71684bc447cShyche upperLimit);
71784bc447cShyche for (int i = 0; i < num; i++) {
71884bc447cShyche upperLimit -= entries[i].Size();
71984bc447cShyche entries[i].SetOffset(upperLimit);
72084bc447cShyche path->SetEntry(slot + i, entries[i], data[i]);
72184bc447cShyche }
72284bc447cShyche
72384bc447cShyche return B_OK;
72484bc447cShyche }
72584bc447cShyche
72684bc447cShyche
72720185bb9Shyche status_t
RemoveEntries(Transaction & transaction,Path * path,const btrfs_key & startKey,void ** _data,int num)72820185bb9Shyche BTree::RemoveEntries(Transaction& transaction, Path* path,
72920185bb9Shyche const btrfs_key& startKey, void** _data, int num)
73020185bb9Shyche {
73120185bb9Shyche TRACE("BTree::RemoveEntries() num %i key (% " B_PRIu64 " %" B_PRIu8 " %"
73220185bb9Shyche B_PRIu64 ")\n", num, startKey.ObjectID(), startKey.Type(),
73320185bb9Shyche startKey.Offset());
73420185bb9Shyche
73520185bb9Shyche status_t status = Traverse(BTREE_EXACT, path, startKey);
73620185bb9Shyche if (status < B_OK)
73720185bb9Shyche return status;
73820185bb9Shyche
73920185bb9Shyche int slot = status;
74020185bb9Shyche int length = -sizeof(btrfs_entry) * num;
74120185bb9Shyche for (int i = 0; i < num; i++) {
74220185bb9Shyche uint32 itemSize;
74320185bb9Shyche path->GetEntry(slot + i, NULL, &_data[i], &itemSize);
74420185bb9Shyche length -= itemSize;
74520185bb9Shyche }
74620185bb9Shyche
74720185bb9Shyche status = path->InternalCopy(transaction, 1);
74820185bb9Shyche if (status != B_OK)
74920185bb9Shyche return status;
75020185bb9Shyche
75120185bb9Shyche status = path->CopyOnWrite(transaction, 0, slot, num, length);
75220185bb9Shyche if (status == B_DIRECTORY_NOT_EMPTY) {
75320185bb9Shyche // TODO: merge node or push data
75420185bb9Shyche }
75520185bb9Shyche
75620185bb9Shyche return status;
75720185bb9Shyche }
75820185bb9Shyche
75920185bb9Shyche
7603216460dShyche status_t
PreviousLeaf(Path * path) const7613216460dShyche BTree::PreviousLeaf(Path* path) const
7623216460dShyche {
7633216460dShyche // TODO: use Traverse() ???
7643216460dShyche int level = 0;
7653216460dShyche int slot;
7663216460dShyche Node* node = NULL;
7673216460dShyche // iterate to the root until satisfy the condition
7683216460dShyche while (true) {
7693216460dShyche node = path->GetNode(level, &slot);
7703216460dShyche if (node == NULL || slot != 0)
7713216460dShyche break;
7723216460dShyche level++;
7733216460dShyche }
7743216460dShyche
7753216460dShyche // the current leaf is already the left most leaf or
7763216460dShyche // path was not initialized
7773216460dShyche if (node == NULL)
7783216460dShyche return B_ENTRY_NOT_FOUND;
7793216460dShyche
7803216460dShyche path->Move(level, BTREE_BACKWARD);
7813216460dShyche fsblock_t physicalBlock;
7823216460dShyche // change all nodes below this level and slot to the ending
7833216460dShyche do {
7843216460dShyche status_t status = fVolume->FindBlock(
7853216460dShyche node->Index(slot)->LogicalAddress(), physicalBlock);
7863216460dShyche if (status != B_OK)
7873216460dShyche return status;
7883216460dShyche
7893216460dShyche node = path->SetNode(physicalBlock, -1);
7903216460dShyche if (node == NULL)
7913216460dShyche return B_NO_MEMORY;
7923216460dShyche slot = node->ItemCount() - 1;
7933216460dShyche level--;
7943216460dShyche } while (level != 0);
7953216460dShyche
7963216460dShyche return B_OK;
7973216460dShyche }
7983216460dShyche
7993216460dShyche
8003216460dShyche status_t
NextLeaf(Path * path) const8013216460dShyche BTree::NextLeaf(Path* path) const
8023216460dShyche {
8033216460dShyche int level = 0;
8043216460dShyche int slot;
8053216460dShyche Node* node = NULL;
8063216460dShyche // iterate to the root until satisfy the condition
8073216460dShyche while (true) {
8083216460dShyche node = path->GetNode(level, &slot);
8093216460dShyche if (node == NULL || slot < node->ItemCount() - 1)
8103216460dShyche break;
8113216460dShyche level++;
8123216460dShyche }
8133216460dShyche
8143216460dShyche // the current leaf is already the right most leaf or
8153216460dShyche // path was not initialized
8163216460dShyche if (node == NULL)
8173216460dShyche return B_ENTRY_NOT_FOUND;
8183216460dShyche
8193216460dShyche path->Move(level, BTREE_FORWARD);
8203216460dShyche fsblock_t physicalBlock;
8213216460dShyche // change all nodes below this level and slot to the beginning
8223216460dShyche do {
8233216460dShyche status_t status = fVolume->FindBlock(
8243216460dShyche node->Index(slot)->LogicalAddress(), physicalBlock);
8253216460dShyche if (status != B_OK)
8263216460dShyche return status;
8273216460dShyche
8283216460dShyche node = path->SetNode(physicalBlock, 0);
8293216460dShyche if (node == NULL)
8303216460dShyche return B_NO_MEMORY;
8313216460dShyche slot = 0;
8323216460dShyche level--;
8333216460dShyche } while (level != 0);
8343216460dShyche
8353216460dShyche return B_OK;
836299aba38Shyche }
837299aba38Shyche
838299aba38Shyche
839fc4a1e78Shyche status_t
SetRoot(off_t logical,fsblock_t * block)840fc4a1e78Shyche BTree::SetRoot(off_t logical, fsblock_t* block)
841fc4a1e78Shyche {
842fc4a1e78Shyche if (block != NULL) {
843fc4a1e78Shyche fRootBlock = *block;
844fc4a1e78Shyche } else {
845fc4a1e78Shyche if (fVolume->FindBlock(logical, fRootBlock) != B_OK) {
846ce029df2Shyche ERROR("SetRoot() unmapped block %" B_PRId64 " %" B_PRId64 "\n",
847ce029df2Shyche logical, fRootBlock);
848fc4a1e78Shyche return B_ERROR;
849fc4a1e78Shyche }
850fc4a1e78Shyche }
851883b9bf2Shyche
852883b9bf2Shyche btrfs_header header;
853883b9bf2Shyche read_pos(fVolume->Device(), fRootBlock * fVolume->BlockSize(), &header,
854883b9bf2Shyche sizeof(btrfs_header));
855883b9bf2Shyche fRootLevel = header.Level();
856883b9bf2Shyche fLogicalRoot = header.LogicalAddress();
857fc4a1e78Shyche return B_OK;
858fc4a1e78Shyche }
859fc4a1e78Shyche
860fc4a1e78Shyche
861299aba38Shyche void
SetRoot(Node * root)862883b9bf2Shyche BTree::SetRoot(Node* root)
863883b9bf2Shyche {
864883b9bf2Shyche fRootBlock = root->BlockNum();
865883b9bf2Shyche fLogicalRoot = root->LogicalAddress();
866883b9bf2Shyche fRootLevel = root->Level();
867883b9bf2Shyche }
868883b9bf2Shyche
869883b9bf2Shyche
870883b9bf2Shyche void
_AddIterator(TreeIterator * iterator)871299aba38Shyche BTree::_AddIterator(TreeIterator* iterator)
872299aba38Shyche {
873299aba38Shyche MutexLocker _(fIteratorLock);
874299aba38Shyche fIterators.Add(iterator);
875299aba38Shyche }
876299aba38Shyche
877299aba38Shyche
878299aba38Shyche void
_RemoveIterator(TreeIterator * iterator)879299aba38Shyche BTree::_RemoveIterator(TreeIterator* iterator)
880299aba38Shyche {
881299aba38Shyche MutexLocker _(fIteratorLock);
882299aba38Shyche fIterators.Remove(iterator);
883299aba38Shyche }
884299aba38Shyche
885299aba38Shyche
886299aba38Shyche // #pragma mark -
887299aba38Shyche
888299aba38Shyche
TreeIterator(BTree * tree,const btrfs_key & key)889bfd7a4fbShyche TreeIterator::TreeIterator(BTree* tree, const btrfs_key& key)
890299aba38Shyche :
891299aba38Shyche fTree(tree),
892bfd7a4fbShyche fKey(key),
893bfd7a4fbShyche fIteratorStatus(B_NO_INIT)
894299aba38Shyche {
895299aba38Shyche tree->_AddIterator(this);
896bfd7a4fbShyche fPath = new(std::nothrow) BTree::Path(tree);
897bfd7a4fbShyche if (fPath == NULL)
898bfd7a4fbShyche fIteratorStatus = B_NO_MEMORY;
899299aba38Shyche }
900299aba38Shyche
901299aba38Shyche
~TreeIterator()902299aba38Shyche TreeIterator::~TreeIterator()
903299aba38Shyche {
904299aba38Shyche if (fTree)
905299aba38Shyche fTree->_RemoveIterator(this);
906bfd7a4fbShyche
907bfd7a4fbShyche delete fPath;
908bfd7a4fbShyche fPath = NULL;
909bfd7a4fbShyche }
910bfd7a4fbShyche
911bfd7a4fbShyche
912bfd7a4fbShyche void
Rewind(bool inverse)913bfd7a4fbShyche TreeIterator::Rewind(bool inverse)
914bfd7a4fbShyche {
915bfd7a4fbShyche if (inverse)
916bfd7a4fbShyche fKey.SetOffset(BTREE_END);
917bfd7a4fbShyche else
918bfd7a4fbShyche fKey.SetOffset(BTREE_BEGIN);
919bfd7a4fbShyche fIteratorStatus = B_NO_INIT;
920299aba38Shyche }
921299aba38Shyche
922299aba38Shyche
923299aba38Shyche status_t
_Traverse(btree_traversing direction)924bfd7a4fbShyche TreeIterator::_Traverse(btree_traversing direction)
925299aba38Shyche {
926bfd7a4fbShyche status_t status = fTree->Traverse(direction, fPath, fKey);
927bfd7a4fbShyche if (status < B_OK) {
928bfd7a4fbShyche ERROR("TreeIterator::Traverse() Find failed\n");
929bfd7a4fbShyche return status;
930299aba38Shyche }
931299aba38Shyche
932bfd7a4fbShyche return (fIteratorStatus = B_OK);
933bfd7a4fbShyche }
934bfd7a4fbShyche
935bfd7a4fbShyche
936bfd7a4fbShyche status_t
_GetEntry(btree_traversing type,void ** _value,uint32 * _size,uint32 * _offset)937bfd7a4fbShyche TreeIterator::_GetEntry(btree_traversing type, void** _value, uint32* _size,
938bfd7a4fbShyche uint32* _offset)
939bfd7a4fbShyche {
9405686d4e1Shyche status_t status = B_OK;
941bfd7a4fbShyche if (fIteratorStatus == B_NO_INIT) {
942bfd7a4fbShyche status = _Traverse(type);
943bfd7a4fbShyche if (status != B_OK)
944bfd7a4fbShyche return status;
945bfd7a4fbShyche type = BTREE_EXACT;
946bfd7a4fbShyche }
947bfd7a4fbShyche
948bfd7a4fbShyche if (fIteratorStatus != B_OK)
949bfd7a4fbShyche return fIteratorStatus;
950bfd7a4fbShyche
951bfd7a4fbShyche int move = fPath->Move(0, type);
952bfd7a4fbShyche if (move > 0)
953bfd7a4fbShyche status = fTree->NextLeaf(fPath);
954bfd7a4fbShyche else if (move < 0)
955bfd7a4fbShyche status = fTree->PreviousLeaf(fPath);
956bfd7a4fbShyche if (status != B_OK)
957bfd7a4fbShyche return status;
958bfd7a4fbShyche
959bfd7a4fbShyche btrfs_key found;
960bfd7a4fbShyche status = fPath->GetCurrentEntry(&found, _value, _size, _offset);
961bfd7a4fbShyche if (status != B_OK)
962bfd7a4fbShyche return status;
963bfd7a4fbShyche
964bfd7a4fbShyche fKey.SetObjectID(found.ObjectID());
965bfd7a4fbShyche fKey.SetOffset(found.Offset());
966bfd7a4fbShyche if (fKey.Type() != found.Type() && fKey.Type() != BTRFS_KEY_TYPE_ANY)
967bfd7a4fbShyche return B_ENTRY_NOT_FOUND;
968bfd7a4fbShyche
969299aba38Shyche return B_OK;
970299aba38Shyche }
971299aba38Shyche
972299aba38Shyche
973299aba38Shyche status_t
Find(const btrfs_key & key)974bfd7a4fbShyche TreeIterator::Find(const btrfs_key& key)
975299aba38Shyche {
976bfd7a4fbShyche if (fIteratorStatus == B_INTERRUPTED)
977bfd7a4fbShyche return fIteratorStatus;
978bfd7a4fbShyche
979bfd7a4fbShyche fKey = key;
980bfd7a4fbShyche fIteratorStatus = B_NO_INIT;
981299aba38Shyche return B_OK;
982299aba38Shyche }
983299aba38Shyche
984299aba38Shyche
985299aba38Shyche void
Stop()986299aba38Shyche TreeIterator::Stop()
987299aba38Shyche {
988299aba38Shyche fTree = NULL;
989bfd7a4fbShyche fIteratorStatus = B_INTERRUPTED;
990299aba38Shyche }
991