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 <[email protected]>
This commit is contained in:
@@ -22,9 +22,10 @@ AttributeIterator::AttributeIterator(Inode* inode)
|
|||||||
fInode(inode),
|
fInode(inode),
|
||||||
fIterator(NULL)
|
fIterator(NULL)
|
||||||
{
|
{
|
||||||
struct btrfs_key key;
|
btrfs_key key;
|
||||||
key.SetType(BTRFS_KEY_TYPE_XATTR_ITEM);
|
key.SetType(BTRFS_KEY_TYPE_XATTR_ITEM);
|
||||||
key.SetObjectID(inode->ID());
|
key.SetObjectID(inode->ID());
|
||||||
|
key.SetOffset(BTREE_BEGIN);
|
||||||
fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(),
|
fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(),
|
||||||
key);
|
key);
|
||||||
}
|
}
|
||||||
@@ -33,6 +34,7 @@ AttributeIterator::AttributeIterator(Inode* inode)
|
|||||||
AttributeIterator::~AttributeIterator()
|
AttributeIterator::~AttributeIterator()
|
||||||
{
|
{
|
||||||
delete fIterator;
|
delete fIterator;
|
||||||
|
fIterator = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -46,10 +48,9 @@ AttributeIterator::InitCheck()
|
|||||||
status_t
|
status_t
|
||||||
AttributeIterator::GetNext(char* name, size_t* _nameLength)
|
AttributeIterator::GetNext(char* name, size_t* _nameLength)
|
||||||
{
|
{
|
||||||
btrfs_key key;
|
|
||||||
btrfs_dir_entry* entries;
|
btrfs_dir_entry* entries;
|
||||||
uint32 entries_length;
|
uint32 entries_length;
|
||||||
status_t status = fIterator->GetPreviousEntry(key, (void**)&entries,
|
status_t status = fIterator->GetPreviousEntry((void**)&entries,
|
||||||
&entries_length);
|
&entries_length);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|||||||
@@ -519,13 +519,16 @@ BTree::_RemoveIterator(TreeIterator* iterator)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
TreeIterator::TreeIterator(BTree* tree, btrfs_key& key)
|
TreeIterator::TreeIterator(BTree* tree, const btrfs_key& key)
|
||||||
:
|
:
|
||||||
fTree(tree),
|
fTree(tree),
|
||||||
fCurrentKey(key)
|
fKey(key),
|
||||||
|
fIteratorStatus(B_NO_INIT)
|
||||||
{
|
{
|
||||||
Rewind();
|
|
||||||
tree->_AddIterator(this);
|
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)
|
if (fTree)
|
||||||
fTree->_RemoveIterator(this);
|
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.
|
/*! Iterates through the tree in the specified direction.
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
TreeIterator::Traverse(btree_traversing direction, btrfs_key& key,
|
TreeIterator::_Traverse(btree_traversing direction)
|
||||||
void** value, uint32* size)
|
|
||||||
{
|
{
|
||||||
if (fTree == NULL)
|
status_t status = fTree->Traverse(direction, fPath, fKey);
|
||||||
return B_INTERRUPTED;
|
if (status < B_OK) {
|
||||||
|
ERROR("TreeIterator::Traverse() Find failed\n");
|
||||||
fCurrentKey.SetOffset(fCurrentKey.Offset() + direction);
|
return status;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,11 +609,13 @@ TreeIterator::Traverse(btree_traversing direction, btrfs_key& key,
|
|||||||
/*! just sets the current key in the iterator.
|
/*! just sets the current key in the iterator.
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
TreeIterator::Find(btrfs_key& key)
|
TreeIterator::Find(const btrfs_key& key)
|
||||||
{
|
{
|
||||||
if (fTree == NULL)
|
if (fIteratorStatus == B_INTERRUPTED)
|
||||||
return B_INTERRUPTED;
|
return fIteratorStatus;
|
||||||
fCurrentKey = key;
|
|
||||||
|
fKey = key;
|
||||||
|
fIteratorStatus = B_NO_INIT;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,4 +624,5 @@ void
|
|||||||
TreeIterator::Stop()
|
TreeIterator::Stop()
|
||||||
{
|
{
|
||||||
fTree = NULL;
|
fTree = NULL;
|
||||||
|
fIteratorStatus = B_INTERRUPTED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,31 +176,37 @@ public:
|
|||||||
|
|
||||||
class TreeIterator : public SinglyLinkedListLinkImpl<TreeIterator> {
|
class TreeIterator : public SinglyLinkedListLinkImpl<TreeIterator> {
|
||||||
public:
|
public:
|
||||||
TreeIterator(BTree* tree, btrfs_key& key);
|
TreeIterator(BTree* tree, const btrfs_key& key);
|
||||||
~TreeIterator();
|
~TreeIterator();
|
||||||
|
|
||||||
status_t Traverse(btree_traversing direction,
|
void Rewind(bool inverse = false);
|
||||||
btrfs_key& key, void** value,
|
status_t Find(const btrfs_key& key);
|
||||||
uint32* size = NULL);
|
status_t GetNextEntry(void** _value,
|
||||||
status_t Find(btrfs_key& key);
|
uint32* _size = NULL,
|
||||||
|
uint32* _offset = NULL);
|
||||||
|
status_t GetPreviousEntry(void** _value,
|
||||||
|
uint32* _size = NULL,
|
||||||
|
uint32* _offset = NULL);
|
||||||
|
|
||||||
status_t Rewind();
|
BTree* Tree() const { return fTree; }
|
||||||
status_t GetNextEntry(btrfs_key& key, void** value,
|
btrfs_key Key() const { return fKey; }
|
||||||
uint32* size = NULL);
|
|
||||||
status_t GetPreviousEntry(btrfs_key& key, void** value,
|
|
||||||
uint32* size = NULL);
|
|
||||||
|
|
||||||
BTree* Tree() const { return fTree; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class BTree;
|
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
|
// called by BTree
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BTree* fTree;
|
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
|
inline status_t
|
||||||
TreeIterator::Rewind()
|
TreeIterator::GetNextEntry(void** _value, uint32* _size, uint32* _offset)
|
||||||
{
|
{
|
||||||
fCurrentKey.SetOffset(BTREE_BEGIN);
|
return _GetEntry(BTREE_FORWARD, _value, _size, _offset);
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline status_t
|
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);
|
return _GetEntry(BTREE_BACKWARD, _value, _size, _offset);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline status_t
|
|
||||||
TreeIterator::GetPreviousEntry(btrfs_key& key, void** value,
|
|
||||||
uint32* size)
|
|
||||||
{
|
|
||||||
return Traverse(BTREE_BACKWARD, key, value, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ DirectoryIterator::DirectoryIterator(Inode* inode)
|
|||||||
btrfs_key key;
|
btrfs_key key;
|
||||||
key.SetType(BTRFS_KEY_TYPE_DIR_INDEX);
|
key.SetType(BTRFS_KEY_TYPE_DIR_INDEX);
|
||||||
key.SetObjectID(inode->ID());
|
key.SetObjectID(inode->ID());
|
||||||
|
key.SetOffset(BTREE_BEGIN);
|
||||||
fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(),
|
fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(),
|
||||||
key);
|
key);
|
||||||
}
|
}
|
||||||
@@ -33,8 +34,8 @@ DirectoryIterator::DirectoryIterator(Inode* inode)
|
|||||||
|
|
||||||
DirectoryIterator::~DirectoryIterator()
|
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);
|
return fInode->FindParent(_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_key key;
|
|
||||||
btrfs_dir_entry* entries;
|
btrfs_dir_entry* entries;
|
||||||
uint32 entries_length;
|
uint32 entries_length;
|
||||||
status_t status = fIterator->GetNextEntry(key, (void**)&entries,
|
status_t status = fIterator->GetNextEntry((void**)&entries, &entries_length);
|
||||||
&entries_length);
|
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user