mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
Refactor ApplyView::dirAdd to give access to low-level operations
- Takes a page from #5362, which may turn out to be useful!
This commit is contained in:
@@ -383,6 +383,45 @@ public:
|
|||||||
emptyDirDelete(Keylet const& directory);
|
emptyDirDelete(Keylet const& directory);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace directory {
|
||||||
|
/** Helper functions for managing low-level directory operations.
|
||||||
|
These are not part of the ApplyView interface.
|
||||||
|
|
||||||
|
Don't use them unless you really, really know what you're doing.
|
||||||
|
Instead use dirAdd, dirInsert, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::uint64_t
|
||||||
|
createRoot(
|
||||||
|
ApplyView& view,
|
||||||
|
Keylet const& directory,
|
||||||
|
uint256 const& key,
|
||||||
|
std::function<void(std::shared_ptr<SLE> const&)> const& describe);
|
||||||
|
|
||||||
|
auto
|
||||||
|
findPreviousPage(ApplyView& view, Keylet const& directory, SLE::ref start);
|
||||||
|
|
||||||
|
std::uint64_t
|
||||||
|
insertKey(
|
||||||
|
ApplyView& view,
|
||||||
|
SLE::ref node,
|
||||||
|
std::uint64_t page,
|
||||||
|
bool preserveOrder,
|
||||||
|
STVector256& indexes,
|
||||||
|
uint256 const& key);
|
||||||
|
|
||||||
|
std::optional<std::uint64_t>
|
||||||
|
insertPage(
|
||||||
|
ApplyView& view,
|
||||||
|
std::uint64_t page,
|
||||||
|
SLE::pointer node,
|
||||||
|
std::uint64_t nextPage,
|
||||||
|
SLE::ref next,
|
||||||
|
uint256 const& key,
|
||||||
|
Keylet const& directory,
|
||||||
|
std::function<void(std::shared_ptr<SLE> const&)> const& describe);
|
||||||
|
|
||||||
|
} // namespace directory
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,6 +25,128 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
namespace directory {
|
||||||
|
|
||||||
|
std::uint64_t
|
||||||
|
createRoot(
|
||||||
|
ApplyView& view,
|
||||||
|
Keylet const& directory,
|
||||||
|
uint256 const& key,
|
||||||
|
std::function<void(std::shared_ptr<SLE> const&)> const& describe)
|
||||||
|
{
|
||||||
|
auto newRoot = std::make_shared<SLE>(directory);
|
||||||
|
newRoot->setFieldH256(sfRootIndex, directory.key);
|
||||||
|
describe(newRoot);
|
||||||
|
|
||||||
|
STVector256 v;
|
||||||
|
v.push_back(key);
|
||||||
|
newRoot->setFieldV256(sfIndexes, v);
|
||||||
|
|
||||||
|
view.insert(newRoot);
|
||||||
|
return std::uint64_t{0};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
findPreviousPage(ApplyView& view, Keylet const& directory, SLE::ref start)
|
||||||
|
{
|
||||||
|
std::uint64_t page = start->getFieldU64(sfIndexPrevious);
|
||||||
|
|
||||||
|
auto node = start;
|
||||||
|
|
||||||
|
if (page)
|
||||||
|
{
|
||||||
|
node = view.peek(keylet::page(directory, page));
|
||||||
|
if (!node)
|
||||||
|
LogicError("Directory chain: root back-pointer broken.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto indexes = node->getFieldV256(sfIndexes);
|
||||||
|
return std::make_tuple(page, node, indexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t
|
||||||
|
insertKey(
|
||||||
|
ApplyView& view,
|
||||||
|
SLE::ref node,
|
||||||
|
std::uint64_t page,
|
||||||
|
bool preserveOrder,
|
||||||
|
STVector256& indexes,
|
||||||
|
uint256 const& key)
|
||||||
|
{
|
||||||
|
if (preserveOrder)
|
||||||
|
{
|
||||||
|
if (std::find(indexes.begin(), indexes.end(), key) != indexes.end())
|
||||||
|
LogicError("dirInsert: double insertion");
|
||||||
|
|
||||||
|
indexes.push_back(key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We can't be sure if this page is already sorted because
|
||||||
|
// it may be a legacy page we haven't yet touched. Take
|
||||||
|
// the time to sort it.
|
||||||
|
std::sort(indexes.begin(), indexes.end());
|
||||||
|
|
||||||
|
auto pos = std::lower_bound(indexes.begin(), indexes.end(), key);
|
||||||
|
|
||||||
|
if (pos != indexes.end() && key == *pos)
|
||||||
|
LogicError("dirInsert: double insertion");
|
||||||
|
|
||||||
|
indexes.insert(pos, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->setFieldV256(sfIndexes, indexes);
|
||||||
|
view.update(node);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::uint64_t>
|
||||||
|
insertPage(
|
||||||
|
ApplyView& view,
|
||||||
|
std::uint64_t page,
|
||||||
|
SLE::pointer node,
|
||||||
|
std::uint64_t nextPage,
|
||||||
|
SLE::ref next,
|
||||||
|
uint256 const& key,
|
||||||
|
Keylet const& directory,
|
||||||
|
std::function<void(std::shared_ptr<SLE> const&)> const& describe)
|
||||||
|
{
|
||||||
|
// Check whether we're out of pages.
|
||||||
|
if (++page >= dirNodeMaxPages)
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are about to create a new node; we'll link it to
|
||||||
|
// the chain first:
|
||||||
|
node->setFieldU64(sfIndexNext, page);
|
||||||
|
view.update(node);
|
||||||
|
|
||||||
|
next->setFieldU64(sfIndexPrevious, page);
|
||||||
|
view.update(next);
|
||||||
|
|
||||||
|
// Insert the new key:
|
||||||
|
STVector256 indexes;
|
||||||
|
indexes.push_back(key);
|
||||||
|
|
||||||
|
node = std::make_shared<SLE>(keylet::page(directory, page));
|
||||||
|
node->setFieldH256(sfRootIndex, directory.key);
|
||||||
|
node->setFieldV256(sfIndexes, indexes);
|
||||||
|
|
||||||
|
// Save some space by not specifying the value 0 since
|
||||||
|
// it's the default.
|
||||||
|
if (page != 1)
|
||||||
|
node->setFieldU64(sfIndexPrevious, page - 1);
|
||||||
|
if (nextPage)
|
||||||
|
node->setFieldU64(sfIndexNext, nextPage);
|
||||||
|
describe(node);
|
||||||
|
view.insert(node);
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace directory
|
||||||
|
|
||||||
std::optional<std::uint64_t>
|
std::optional<std::uint64_t>
|
||||||
ApplyView::dirAdd(
|
ApplyView::dirAdd(
|
||||||
bool preserveOrder,
|
bool preserveOrder,
|
||||||
@@ -37,89 +159,21 @@ ApplyView::dirAdd(
|
|||||||
if (!root)
|
if (!root)
|
||||||
{
|
{
|
||||||
// No root, make it.
|
// No root, make it.
|
||||||
root = std::make_shared<SLE>(directory);
|
return directory::createRoot(*this, directory, key, describe);
|
||||||
root->setFieldH256(sfRootIndex, directory.key);
|
|
||||||
describe(root);
|
|
||||||
|
|
||||||
STVector256 v;
|
|
||||||
v.push_back(key);
|
|
||||||
root->setFieldV256(sfIndexes, v);
|
|
||||||
|
|
||||||
insert(root);
|
|
||||||
return std::uint64_t{0};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t page = root->getFieldU64(sfIndexPrevious);
|
auto [page, node, indexes] =
|
||||||
|
directory::findPreviousPage(*this, directory, root);
|
||||||
auto node = root;
|
|
||||||
|
|
||||||
if (page)
|
|
||||||
{
|
|
||||||
node = peek(keylet::page(directory, page));
|
|
||||||
if (!node)
|
|
||||||
LogicError("Directory chain: root back-pointer broken.");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto indexes = node->getFieldV256(sfIndexes);
|
|
||||||
|
|
||||||
// If there's space, we use it:
|
// If there's space, we use it:
|
||||||
if (indexes.size() < dirNodeMaxEntries)
|
if (indexes.size() < dirNodeMaxEntries)
|
||||||
{
|
{
|
||||||
if (preserveOrder)
|
return directory::insertKey(
|
||||||
{
|
*this, node, page, preserveOrder, indexes, key);
|
||||||
if (std::find(indexes.begin(), indexes.end(), key) != indexes.end())
|
|
||||||
LogicError("dirInsert: double insertion");
|
|
||||||
|
|
||||||
indexes.push_back(key);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We can't be sure if this page is already sorted because
|
|
||||||
// it may be a legacy page we haven't yet touched. Take
|
|
||||||
// the time to sort it.
|
|
||||||
std::sort(indexes.begin(), indexes.end());
|
|
||||||
|
|
||||||
auto pos = std::lower_bound(indexes.begin(), indexes.end(), key);
|
|
||||||
|
|
||||||
if (pos != indexes.end() && key == *pos)
|
|
||||||
LogicError("dirInsert: double insertion");
|
|
||||||
|
|
||||||
indexes.insert(pos, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
node->setFieldV256(sfIndexes, indexes);
|
|
||||||
update(node);
|
|
||||||
return page;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether we're out of pages.
|
return directory::insertPage(
|
||||||
if (++page >= dirNodeMaxPages)
|
*this, page, node, 0, root, key, directory, describe);
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
// We are about to create a new node; we'll link it to
|
|
||||||
// the chain first:
|
|
||||||
node->setFieldU64(sfIndexNext, page);
|
|
||||||
update(node);
|
|
||||||
|
|
||||||
root->setFieldU64(sfIndexPrevious, page);
|
|
||||||
update(root);
|
|
||||||
|
|
||||||
// Insert the new key:
|
|
||||||
indexes.clear();
|
|
||||||
indexes.push_back(key);
|
|
||||||
|
|
||||||
node = std::make_shared<SLE>(keylet::page(directory, page));
|
|
||||||
node->setFieldH256(sfRootIndex, directory.key);
|
|
||||||
node->setFieldV256(sfIndexes, indexes);
|
|
||||||
|
|
||||||
// Save some space by not specifying the value 0 since
|
|
||||||
// it's the default.
|
|
||||||
if (page != 1)
|
|
||||||
node->setFieldU64(sfIndexPrevious, page - 1);
|
|
||||||
describe(node);
|
|
||||||
insert(node);
|
|
||||||
|
|
||||||
return page;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|||||||
Reference in New Issue
Block a user