Skip to content

Commit

Permalink
fix rtree deletes
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxxen committed Sep 16, 2024
1 parent 4a6cf90 commit 823dea7
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 6 deletions.
4 changes: 4 additions & 0 deletions spatial/include/spatial/core/geometry/bbox.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ struct Box {
Box(const V &min_p, const V &max_p) : min(min_p), max(max_p) {
}

bool IsUnbounded() const {
return *this == Box();
}

// Only does a 2D intersection check
bool Intersects(const Box &other) const {
return !(min.x > other.max.x || max.x < other.min.x || min.y > other.max.y || max.y < other.min.y);
Expand Down
3 changes: 3 additions & 0 deletions spatial/include/spatial/core/index/rtree/rtree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ struct RTree {
RTreePointer MakePage(RTreeNodeType type) const;
static RTreePointer MakeRowId(row_t row_id);

string ToString() const;
void Print() const;

private:
void Free(RTreePointer &pointer);

Expand Down
90 changes: 84 additions & 6 deletions spatial/src/spatial/core/index/rtree/rtree.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "spatial/core/index/rtree/rtree.hpp"
#include "duckdb/common/printer.hpp"

namespace spatial {

Expand Down Expand Up @@ -415,6 +416,9 @@ void RTree::RootInsert(RTreeEntry &root_entry, const RTreeEntry &new_entry) {
// Delete
//------------------------------------------------------------------------------
DeleteResult RTree::NodeDelete(RTreeEntry &entry, const RTreeEntry &target, vector<RTreeEntry> &orphans) {
if(!entry.bounds.Intersects(target.bounds)) {
return {false, false, false};
}
const auto is_leaf = entry.pointer.IsLeafPage();
return is_leaf ? LeafDelete(entry, target, orphans) : BranchDelete(entry, target, orphans);
}
Expand Down Expand Up @@ -461,8 +465,8 @@ DeleteResult RTree::BranchDelete(RTreeEntry &entry, const RTreeEntry &target, ve
entry.bounds = node.GetBounds();
shrunk = entry.bounds != old_bounds;

// Assert that the bounds shrunk
D_ASSERT(entry.bounds.Area() <= old_bounds.Area());
// If the min capacity is zero, the bounds can grow when a node becomes empty
D_ASSERT(entry.bounds.IsUnbounded() || entry.bounds.Area() <= old_bounds.Area());
}
return {true, shrunk, false};
}
Expand All @@ -475,7 +479,8 @@ DeleteResult RTree::BranchDelete(RTreeEntry &entry, const RTreeEntry &target, ve
entry.bounds = node.GetBounds();
shrunk = entry.bounds != old_bounds;

D_ASSERT(entry.bounds.Area() <= old_bounds.Area());
// If the min capacity is zero, the bounds can grow when a node becomes empty
D_ASSERT(entry.bounds.IsUnbounded() || (entry.bounds.Area() <= old_bounds.Area()));
}

return {true, shrunk, false};
Expand All @@ -488,15 +493,21 @@ DeleteResult RTree::LeafDelete(RTreeEntry &entry, const RTreeEntry &target, vect

// Do a binary search with std::lower_bound to find the matching rowid
// This is faster than a linear search
auto it = std::lower_bound(node.begin(), node.end(), target.pointer.GetRowId(),
const auto it = std::lower_bound(node.begin(), node.end(), target.pointer.GetRowId(),
[](const RTreeEntry &item, const row_t &row) { return item.pointer.GetRowId() < row; });
if (it == node.end()) {
// Not found in this leaf
return {false, false, false};
}

auto &child = *it;
auto child_idx = it - node.begin();
const auto &child = *it;

// Ok, did the binary search actually find the rowid?
if(child.pointer.GetRowId() != target.pointer.GetRowId()) {
return {false, false, false};
}

const auto child_idx = it - node.begin();

D_ASSERT(child.pointer.IsRowId());

Expand Down Expand Up @@ -581,6 +592,73 @@ void RTree::RootDelete(RTreeEntry &root, const RTreeEntry &target) {
}
}

// Print as ascii tree
string RTree::ToString() const {
string result;

struct PrintState {
RTreePointer pointer;
idx_t entry_idx;
explicit PrintState(const RTreePointer &pointer_p) : pointer(pointer_p), entry_idx(0) {
}
};

vector<PrintState> stack;
idx_t level = 0;

stack.emplace_back(root.pointer);

while(!stack.empty()) {
auto &frame = stack.back();
const auto &node = Ref(frame.pointer);
const auto count = node.GetCount();

if(frame.pointer.IsLeafPage()) {
while(frame.entry_idx < count) {
auto &entry = node[frame.entry_idx];
// TODO: Print entry
for(idx_t i = 0; i < level; i++) {
result += " ";
}

result += "Leaf: " + std::to_string(entry.pointer.GetRowId()) + "\n";

frame.entry_idx++;
}
stack.pop_back();
level--;
}
else {
D_ASSERT(frame.pointer.IsBranchPage());
if(frame.entry_idx < count) {
auto &entry = node[frame.entry_idx];

// TODO: Print entry
for(idx_t i = 0; i < level; i++) {
result += " ";
}

result += "Branch: " + std::to_string(frame.entry_idx) + "\n";

frame.entry_idx++;
level++;
stack.emplace_back(entry.pointer);
} else {
stack.pop_back();
level--;
}
}
}


return result;
}

void RTree::Print() const {
Printer::Print(ToString());
}


} // namespace core

} // namespace spatial

0 comments on commit 823dea7

Please sign in to comment.