From 8ecf2f27ed2295f4e6c8584a9384fd0343687171 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 9 May 2013 13:31:04 +0100 Subject: [PATCH] btree_damage_visitor stuff. --- .../data-structures/btree_damage_visitor.h | 18 ++- unit-tests/btree_damage_visitor_t.cc | 115 +++++++++++++----- 2 files changed, 103 insertions(+), 30 deletions(-) diff --git a/persistent-data/data-structures/btree_damage_visitor.h b/persistent-data/data-structures/btree_damage_visitor.h index 7dd8738..d6c7cba 100644 --- a/persistent-data/data-structures/btree_damage_visitor.h +++ b/persistent-data/data-structures/btree_damage_visitor.h @@ -83,7 +83,16 @@ namespace persistent_data { bool visit_leaf(node_location const &loc, btree_detail::node_ref const &n) { - return check_leaf(loc, n); + bool r = check_leaf(loc, n); + + // If anything goes wrong with the checks, we skip + // the value visiting. + if (!r) + return false; + + visit_values(n); + + return true; } typedef typename btree::visitor::error_outcome error_outcome; @@ -94,8 +103,13 @@ namespace persistent_data { return btree::visitor::EXCEPTION_HANDLED; } - private: + void visit_values(btree_detail::node_ref const &n) { + unsigned nr = n.get_nr_entries(); + for (unsigned i = 0; i < nr; i++) + value_visitor_.visit(n.value_at(i)); + } + bool check_internal(node_location const &loc, btree_detail::node_ref const &n) { if (!already_visited(n) && diff --git a/unit-tests/btree_damage_visitor_t.cc b/unit-tests/btree_damage_visitor_t.cc index 300d758..400606c 100644 --- a/unit-tests/btree_damage_visitor_t.cc +++ b/unit-tests/btree_damage_visitor_t.cc @@ -17,14 +17,24 @@ using namespace testing; namespace { block_address const BLOCK_SIZE = 4096; block_address const NR_BLOCKS = 102400; + block_address const SUPERBLOCK = 0; struct thing { - uint32_t x; + thing(/* uint32_t x_ = 0, */ uint64_t y_ = 0) + : /* x(x_), */ + y(y_) { + } + + bool operator ==(thing const &rhs) const { + return /* (x == rhs.x) && */ (y == rhs.y); + } + + //uint32_t x; uint64_t y; }; struct thing_disk { - le32 x; + //le32 x; le64 y; }; @@ -34,12 +44,12 @@ namespace { typedef persistent_data::no_op_ref_counter ref_counter; static void unpack(thing_disk const &disk, thing &value) { - value.x = to_cpu(disk.x); + // value.x = to_cpu(disk.x); value.y = to_cpu(disk.y); } static void pack(thing const &value, thing_disk &disk) { - disk.x = to_disk(value.x); + // disk.x = to_disk(value.x); disk.y = to_disk(value.y); } }; @@ -58,22 +68,74 @@ namespace { public: BTreeDamageVisitorTests() : bm_(create_bm(NR_BLOCKS)), - sm_(new core_map(NR_BLOCKS)), + sm_(setup_core_map()), tm_(new transaction_manager(bm_, sm_)), - tree_(new btree<2, thing_traits>(tm_, rc_)) { + tree_(new btree<1, thing_traits>(tm_, rc_)) { } - void zero_block(block_address b) { + space_map::ptr setup_core_map() { + space_map::ptr sm(new core_map(NR_BLOCKS)); + sm->inc(SUPERBLOCK); + return sm; + } + + void commit() { + block_manager<>::write_ref superblock(bm_->superblock(SUPERBLOCK)); + } + + void trash_block(block_address b) { ::test::zero_block(bm_, b); } + void insert_values(unsigned nr) { + for (unsigned i = 0; i < nr; i++) { + uint64_t key[1] = {i}; + thing value(i /*, i + 1234 */); + + tree_->insert(key, value); + } + } + + void expect_no_values() { + EXPECT_CALL(value_visitor_, visit(_)).Times(0); + } + + void expect_nr_values(unsigned nr) { + for (unsigned i = 0; i < nr; i++) + EXPECT_CALL(value_visitor_, visit(Eq(thing(i /*, i + 1234 */)))).Times(1); + } + + void expect_value(unsigned n) { + EXPECT_CALL(value_visitor_, visit(Eq(thing(n /*, n + 1234 */)))).Times(1); + } + + void expect_no_damage() { + EXPECT_CALL(damage_visitor_, visit(_)).Times(0); + } + + void expect_damage(unsigned level, range keys) { + EXPECT_CALL(damage_visitor_, visit(Eq(damage(level, keys, "foo")))).Times(1); + } + + void run() { + // We must commit before we do the test to ensure + // all the block numbers and checksums are written + // to the btree nodes. + commit(); + + block_counter counter; + btree_damage_visitor + visitor(counter, value_visitor_, damage_visitor_); + tree_->visit_depth_first(visitor); + } + with_temp_directory dir_; block_manager<>::ptr bm_; space_map::ptr sm_; transaction_manager::ptr tm_; thing_traits::ref_counter rc_; - btree<2, thing_traits>::ptr tree_; + btree<1, thing_traits>::ptr tree_; value_visitor_mock value_visitor_; damage_visitor_mock damage_visitor_; @@ -82,35 +144,32 @@ namespace { //---------------------------------------------------------------- -TEST_F(BTreeDamageVisitorTests, visiting_an_empty_btree_visits_nothing) +TEST_F(BTreeDamageVisitorTests, visiting_an_empty_tree) { - block_counter counter; + expect_no_values(); + expect_no_damage(); - EXPECT_CALL(value_visitor_, visit(_)).Times(0); - EXPECT_CALL(damage_visitor_, visit(_)).Times(0); - - btree_damage_visitor - visitor(counter, value_visitor_, damage_visitor_); - tree_->visit_depth_first(visitor); + run(); } TEST_F(BTreeDamageVisitorTests, visiting_an_tree_with_a_trashed_root) { - zero_block(tree_->get_root()); - EXPECT_CALL(value_visitor_, visit(_)).Times(0); - EXPECT_CALL(damage_visitor_, visit(Eq(damage(0, range(), "foo")))).Times(1); + trash_block(tree_->get_root()); - block_counter counter; + expect_no_values(); + expect_damage(0, range()); - btree_damage_visitor - visitor(counter, value_visitor_, damage_visitor_); - tree_->visit_depth_first(visitor); + run(); } -#if 0 - uint64_t key[2] = {1, 2}; - thing value = {0, 0}; - tree_->insert(key, value); -#endif +TEST_F(BTreeDamageVisitorTests, visiting_a_populated_tree_with_no_damage) +{ + insert_values(1000); + + expect_nr_values(1000); + expect_no_damage(); + + run(); +} //----------------------------------------------------------------