From bfd7a4fb427485418bc5f2edec48201fd94a1625 Mon Sep 17 00:00:00 2001 From: hyche Date: Sun, 13 Aug 2017 04:29:18 +0700 Subject: [PATCH] BTRFS: Reimplement TreeIterator, add some error checks and remove redundancies. Add BTree::Path as a attribute so enhance performance, so that everytime we iterate through items it wont search all the root to leaf again. The Iterator is initialized without rewinding to make more flexible. Signed-off-by: Augustin Cavalier --- .../file_systems/btrfs/AttributeIterator.cpp | 7 +- .../kernel/file_systems/btrfs/BTree.cpp | 88 +++++++++++++++---- src/add-ons/kernel/file_systems/btrfs/BTree.h | 49 +++++------ .../file_systems/btrfs/DirectoryIterator.cpp | 9 +- 4 files changed, 101 insertions(+), 52 deletions(-) diff --git a/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp b/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp index f453a11468..b9dfc91964 100644 --- a/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp @@ -22,9 +22,10 @@ AttributeIterator::AttributeIterator(Inode* inode) fInode(inode), fIterator(NULL) { - struct btrfs_key key; + btrfs_key key; key.SetType(BTRFS_KEY_TYPE_XATTR_ITEM); key.SetObjectID(inode->ID()); + key.SetOffset(BTREE_BEGIN); fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(), key); } @@ -33,6 +34,7 @@ AttributeIterator::AttributeIterator(Inode* inode) AttributeIterator::~AttributeIterator() { delete fIterator; + fIterator = NULL; } @@ -46,10 +48,9 @@ AttributeIterator::InitCheck() status_t AttributeIterator::GetNext(char* name, size_t* _nameLength) { - btrfs_key key; btrfs_dir_entry* entries; uint32 entries_length; - status_t status = fIterator->GetPreviousEntry(key, (void**)&entries, + status_t status = fIterator->GetPreviousEntry((void**)&entries, &entries_length); if (status != B_OK) return status; diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp index ce87f5a74f..bf93bf358f 100644 --- a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp @@ -519,13 +519,16 @@ BTree::_RemoveIterator(TreeIterator* iterator) // #pragma mark - -TreeIterator::TreeIterator(BTree* tree, btrfs_key& key) +TreeIterator::TreeIterator(BTree* tree, const btrfs_key& key) : fTree(tree), - fCurrentKey(key) + fKey(key), + fIteratorStatus(B_NO_INIT) { - Rewind(); tree->_AddIterator(this); + fPath = new(std::nothrow) BTree::Path(tree); + if (fPath == NULL) + fIteratorStatus = B_NO_MEMORY; } @@ -533,26 +536,72 @@ TreeIterator::~TreeIterator() { if (fTree) fTree->_RemoveIterator(this); + + delete fPath; + fPath = NULL; +} + + +void +TreeIterator::Rewind(bool inverse) +{ + if (inverse) + fKey.SetOffset(BTREE_END); + else + fKey.SetOffset(BTREE_BEGIN); + fIteratorStatus = B_NO_INIT; } /*! Iterates through the tree in the specified direction. */ status_t -TreeIterator::Traverse(btree_traversing direction, btrfs_key& key, - void** value, uint32* size) +TreeIterator::_Traverse(btree_traversing direction) { - if (fTree == NULL) - return B_INTERRUPTED; - - fCurrentKey.SetOffset(fCurrentKey.Offset() + direction); - BTree::Path path(fTree); - status_t status = fTree->_Find(&path, fCurrentKey, value, size, direction); - if (status != B_OK) { - TRACE("TreeIterator::Traverse() Find failed\n"); - return B_ENTRY_NOT_FOUND; + status_t status = fTree->Traverse(direction, fPath, fKey); + if (status < B_OK) { + ERROR("TreeIterator::Traverse() Find failed\n"); + return status; } + return (fIteratorStatus = B_OK); +} + + +// Like GetEntry in BTree::Path but here we check the type and moving. +status_t +TreeIterator::_GetEntry(btree_traversing type, void** _value, uint32* _size, + uint32* _offset) +{ + status_t status; + if (fIteratorStatus == B_NO_INIT) { + status = _Traverse(type); + if (status != B_OK) + return status; + type = BTREE_EXACT; + } + + if (fIteratorStatus != B_OK) + return fIteratorStatus; + + int move = fPath->Move(0, type); + if (move > 0) + status = fTree->NextLeaf(fPath); + else if (move < 0) + status = fTree->PreviousLeaf(fPath); + if (status != B_OK) + return status; + + btrfs_key found; + status = fPath->GetCurrentEntry(&found, _value, _size, _offset); + if (status != B_OK) + return status; + + fKey.SetObjectID(found.ObjectID()); + fKey.SetOffset(found.Offset()); + if (fKey.Type() != found.Type() && fKey.Type() != BTRFS_KEY_TYPE_ANY) + return B_ENTRY_NOT_FOUND; + return B_OK; } @@ -560,11 +609,13 @@ TreeIterator::Traverse(btree_traversing direction, btrfs_key& key, /*! just sets the current key in the iterator. */ status_t -TreeIterator::Find(btrfs_key& key) +TreeIterator::Find(const btrfs_key& key) { - if (fTree == NULL) - return B_INTERRUPTED; - fCurrentKey = key; + if (fIteratorStatus == B_INTERRUPTED) + return fIteratorStatus; + + fKey = key; + fIteratorStatus = B_NO_INIT; return B_OK; } @@ -573,4 +624,5 @@ void TreeIterator::Stop() { fTree = NULL; + fIteratorStatus = B_INTERRUPTED; } diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.h b/src/add-ons/kernel/file_systems/btrfs/BTree.h index 30afcaf790..d44a40102f 100644 --- a/src/add-ons/kernel/file_systems/btrfs/BTree.h +++ b/src/add-ons/kernel/file_systems/btrfs/BTree.h @@ -176,31 +176,37 @@ public: class TreeIterator : public SinglyLinkedListLinkImpl { public: - TreeIterator(BTree* tree, btrfs_key& key); + TreeIterator(BTree* tree, const btrfs_key& key); ~TreeIterator(); - status_t Traverse(btree_traversing direction, - btrfs_key& key, void** value, - uint32* size = NULL); - status_t Find(btrfs_key& key); + void Rewind(bool inverse = false); + status_t Find(const btrfs_key& key); + status_t GetNextEntry(void** _value, + uint32* _size = NULL, + uint32* _offset = NULL); + status_t GetPreviousEntry(void** _value, + uint32* _size = NULL, + uint32* _offset = NULL); - status_t Rewind(); - status_t GetNextEntry(btrfs_key& key, void** value, - uint32* size = NULL); - status_t GetPreviousEntry(btrfs_key& key, void** value, - uint32* size = NULL); - - BTree* Tree() const { return fTree; } + BTree* Tree() const { return fTree; } + btrfs_key Key() const { return fKey; } private: friend class BTree; + status_t _Traverse(btree_traversing direction); + status_t _Find(btree_traversing type, btrfs_key& key, + void** _value); + status_t _GetEntry(btree_traversing type, void** _value, + uint32* _size, uint32* _offset); // called by BTree void Stop(); private: BTree* fTree; - btrfs_key fCurrentKey; + BTree::Path* fPath; + btrfs_key fKey; + status_t fIteratorStatus; }; @@ -219,25 +225,16 @@ BTree::Path::GetCurrentEntry(btrfs_key* _key, void** _value, uint32* _size, inline status_t -TreeIterator::Rewind() +TreeIterator::GetNextEntry(void** _value, uint32* _size, uint32* _offset) { - fCurrentKey.SetOffset(BTREE_BEGIN); - return B_OK; + return _GetEntry(BTREE_FORWARD, _value, _size, _offset); } inline status_t -TreeIterator::GetNextEntry(btrfs_key& key, void** value, uint32* size) +TreeIterator::GetPreviousEntry(void** _value, uint32* _size, uint32* _offset) { - return Traverse(BTREE_FORWARD, key, value, size); -} - - -inline status_t -TreeIterator::GetPreviousEntry(btrfs_key& key, void** value, - uint32* size) -{ - return Traverse(BTREE_BACKWARD, key, value, size); + return _GetEntry(BTREE_BACKWARD, _value, _size, _offset); } diff --git a/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp b/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp index ccfd1b225b..0be81a4829 100644 --- a/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp @@ -26,6 +26,7 @@ DirectoryIterator::DirectoryIterator(Inode* inode) btrfs_key key; key.SetType(BTRFS_KEY_TYPE_DIR_INDEX); key.SetObjectID(inode->ID()); + key.SetOffset(BTREE_BEGIN); fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(), key); } @@ -33,8 +34,8 @@ DirectoryIterator::DirectoryIterator(Inode* inode) DirectoryIterator::~DirectoryIterator() { - if (fIterator != NULL) - delete fIterator; + delete fIterator; + fIterator = NULL; } @@ -69,11 +70,9 @@ DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id) return fInode->FindParent(_id); } - btrfs_key key; btrfs_dir_entry* entries; uint32 entries_length; - status_t status = fIterator->GetNextEntry(key, (void**)&entries, - &entries_length); + status_t status = fIterator->GetNextEntry((void**)&entries, &entries_length); if (status != B_OK) return status;