BTRFS: Implement some copy relevant helpers.

Copy() copys data from other node, MoveEntries() changes data on the current node.

Signed-off-by: Augustin Cavalier <waddlesplash@gmail.com>
This commit is contained in:
hyche 2017-08-24 02:26:49 +07:00 committed by Augustin Cavalier
parent 27ffe0583b
commit 89484dc08d
3 changed files with 125 additions and 0 deletions

View File

@ -185,6 +185,30 @@ BTree::Node::SpaceLeft() const
} }
void
BTree::Node::_Copy(const Node* origin, uint32 at, uint32 from, uint32 to,
int length) const
{
TRACE("Node::_Copy() at: %d from: %d to: %d length: %d\n",
at, from, to, length);
if (Level() == 0) {
memcpy(Item(at), origin->Item(from), origin->_CalculateSpace(from, to));
// Item offset of copied node must be changed to get the
// item data offset correctly. length can be zero
// but let it there doesn't harm anything.
for (uint32 i = at; i - at <= to - from; ++i)
Item(i)->SetOffset(Item(i)->Offset() - length);
memcpy(ItemData(at + to - from), origin->ItemData(to),
origin->_CalculateSpace(from, to, 2));
} else {
memcpy(Index(at), origin->Index(from),
origin->_CalculateSpace(from, to));
}
}
status_t status_t
BTree::Node::_SpaceCheck(int length) const BTree::Node::_SpaceCheck(int length) const
{ {
@ -198,6 +222,101 @@ BTree::Node::_SpaceCheck(int length) const
} }
/*
* copy node header, items and items data
* length is size to insert/remove
* if node is a internal node, length isnt used
* length = 0: Copy a whole
* length < 0: removing
* length > 0: inserting
*/
status_t
BTree::Node::Copy(const Node* origin, uint32 start, uint32 end, int length)
const
{
status_t status = origin->_SpaceCheck(length);
if (status != B_OK)
return status;
memcpy(fNode, origin->fNode, sizeof(btrfs_header));
if (length == 0) {
// like removing [0, start - 1] and keeping [start, end]
length = -origin->_CalculateSpace(0, start - 1, 2);
_Copy(origin, 0, start, end, length);
} else if (length < 0) {
//removing all items in [start, end]
if (start > 0)
_Copy(origin, 0, 0, start - 1, 0); // <-- [start,...
if (end + 1 < origin->ItemCount()) {
// ..., end] -->
// we only care data size
length += origin->_CalculateSpace(start, end);
_Copy(origin, start, end + 1, origin->ItemCount() - 1, length);
}
} else {
//inserting in [start, end] - make a hole for later
if (start > 0)
_Copy(origin, 0, 0, start - 1, 0);
if (start < origin->ItemCount()) {
length -= origin->_CalculateSpace(start, end);
_Copy(origin, end + 1, start, origin->ItemCount() - 1, length);
}
}
return B_OK;
}
/* Like copy but here we use memmove on current node.
*/
status_t
BTree::Node::MoveEntries(uint32 start, uint32 end, int length) const
{
status_t status = _SpaceCheck(length);
if (status != B_OK || length == 0/*B_OK*/)
return status;
int entrySize = sizeof(btrfs_entry);
if (Level() != 0)
entrySize = sizeof(btrfs_index);
uint8* base = (uint8*)fNode + sizeof(btrfs_header);
end++;
if (length < 0) {
// removing [start, end]
TRACE("Node::MoveEntries() removing ... start %" B_PRIu32 " end %"
B_PRIu32 " length %i\n", start, end, length);
length += _CalculateSpace(start, end - 1);
} else {
// length > 0
// inserting into [start, end] - make room for later
TRACE("Node::MoveEntries() inserting ... start %" B_PRIu32 " end %"
B_PRIu32 " length %i\n", start, end, length);
length -= _CalculateSpace(start, end - 1);
std::swap(start, end);
}
if (end >= ItemCount())
return B_OK;
int dataSize = _CalculateSpace(end, ItemCount() - 1, 2);
// moving items/block pointers
memmove(base + start * entrySize, base + end * entrySize,
_CalculateSpace(end, ItemCount() - 1));
if (Level() == 0) {
// moving item data
int num = start - end;
for(uint32 i = start; i < ItemCount() + num; ++i)
Item(i)->SetOffset(Item(i)->Offset() - length);
memmove(ItemData(ItemCount() - 1) - length, ItemData(ItemCount() - 1),
dataSize);
}
return B_OK;
}
// #pragma mark - BTree::Path implementation // #pragma mark - BTree::Path implementation

View File

@ -133,6 +133,9 @@ public:
off_t BlockNum() const { return fBlockNumber;} off_t BlockNum() const { return fBlockNumber;}
bool IsWritable() const { return fWritable; } bool IsWritable() const { return fWritable; }
status_t Copy(const Node* origin, uint32 start, uint32 end,
int length) const;
status_t MoveEntries(uint32 start, uint32 end, int length) const;
status_t SearchSlot(const btrfs_key& key, int* slot, status_t SearchSlot(const btrfs_key& key, int* slot,
btree_traversing type) const; btree_traversing type) const;
@ -141,6 +144,8 @@ public:
Node& operator=(const Node&); Node& operator=(const Node&);
//no implementation //no implementation
void _Copy(const Node* origin, uint32 at, uint32 from, uint32 to,
int length) const;
status_t _SpaceCheck(int length) const; status_t _SpaceCheck(int length) const;
int _CalculateSpace(uint32 from, uint32 to, uint8 type = 1) const; int _CalculateSpace(uint32 from, uint32 to, uint8 type = 1) const;

View File

@ -132,6 +132,7 @@ struct btrfs_entry {
{ return B_LENDIAN_TO_HOST_INT32(offset); } { return B_LENDIAN_TO_HOST_INT32(offset); }
uint32 Size() const uint32 Size() const
{ return B_LENDIAN_TO_HOST_INT32(size); } { return B_LENDIAN_TO_HOST_INT32(size); }
void SetOffset(uint32 off) { offset = B_HOST_TO_LENDIAN_INT32(off); }
} _PACKED; } _PACKED;