diff --git a/Makefile b/Makefile index 250f8e1..ad03c7a 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ SOURCE=\ OBJECTS=$(subst .cc,.o,$(SOURCE)) TOP_DIR:=$(PWD) -CPPFLAGS=-Wall -g -I$(TOP_DIR) +CPPFLAGS=-Wall -g -I$(TOP_DIR) -O8 #CPPFLAGS=-Wall -std=c++0x -g -I$(TOP_DIR) LIBS=-lstdc++ -lboost_program_options diff --git a/metadata.cc b/metadata.cc index 851d81d..cc3d189 100644 --- a/metadata.cc +++ b/metadata.cc @@ -3,6 +3,7 @@ #include "btree_checker.h" #include "core_map.h" #include "math_utils.h" +#include "space_map_disk.h" #include #include @@ -396,26 +397,37 @@ metadata::device_exists(thin_dev_t dev) const } namespace { - optional - check_ref_counts(string const &desc, block_counter const &counts, - space_map::ptr sm) { - error_set::ptr errors(new error_set(desc)); + struct check_count : public space_map::iterator { + check_count(string const &desc, block_counter const &expected) + : bad_(false), + expected_(expected), + errors_(new error_set(desc)) { + } - bool bad = false; - for (block_address b = 0; b < sm->get_nr_blocks(); b++) { - uint32_t actual = sm->get_count(b); - uint32_t expected = counts.get_count(b); + virtual void operator() (block_address b, ref_t actual) { + ref_t expected = expected_.get_count(b); if (actual != expected) { ostringstream out; out << b << ": was " << actual << ", expected " << expected; - errors->add_child(out.str()); - bad = true; + errors_->add_child(out.str()); + bad_ = true; } } - return bad ? optional(errors) : optional(); + bool bad_; + block_counter const &expected_; + error_set::ptr errors_; + }; + + optional + check_ref_counts(string const &desc, block_counter const &counts, + space_map::ptr sm) { + + check_count checker(desc, counts); + sm->iterate(checker); + return checker.bad_ ? optional(checker.errors_) : optional(); } } diff --git a/space_map.h b/space_map.h index a6735d9..13a4f29 100644 --- a/space_map.h +++ b/space_map.h @@ -29,6 +29,16 @@ namespace persistent_data { virtual bool count_possibly_greater_than_one(block_address b) const = 0; virtual void extend(block_address extra_blocks) = 0; + + struct iterator { + virtual ~iterator() {} + + virtual void operator() (block_address b, ref_t c) = 0; + }; + + virtual void iterate(iterator &it) const { + throw std::runtime_error("not implemented"); + } }; class persistent_space_map : public space_map { diff --git a/space_map_disk.cc b/space_map_disk.cc index 74cb2b9..26a4e9e 100644 --- a/space_map_disk.cc +++ b/space_map_disk.cc @@ -80,6 +80,19 @@ namespace { return ie_; } + void iterate(block_address offset, block_address hi, space_map::iterator &it) const { + read_ref rr = tm_->read_lock(ie_.blocknr_); + void const *bits = bitmap_data(rr); + + for (unsigned b = 0; b < hi; b++) { + ref_t b1 = test_bit_le(bits, b * 2); + ref_t b2 = test_bit_le(bits, b * 2 + 1); + ref_t result = b2 ? 1 : 0; + result |= b1 ? 0b10 : 0; + it(offset + b, result); + } + } + private: void check_crc(transaction_manager::read_ref &rr) { crc32c sum(240779); @@ -248,6 +261,34 @@ namespace { ref_counts_.visit(v); } + struct look_aside_iterator : public iterator { + look_aside_iterator(sm_disk_base const &smd, iterator &it) + : smd_(smd), + it_(it) { + } + + virtual void operator () (block_address b, ref_t c) { + it_(b, c == 3 ? smd_.lookup_ref_count(b) : c); + } + + sm_disk_base const &smd_; + iterator &it_; + }; + + friend struct look_aside_iterator; + + virtual void iterate(iterator &it) const { + look_aside_iterator wrapper(*this, it); + unsigned nr_indexes = div_up(nr_blocks_, entries_per_block_); + + for (unsigned i = 0; i < nr_indexes; i++) { + unsigned hi = (i == nr_indexes - 1) ? (nr_blocks_ % entries_per_block_) : entries_per_block_; + index_entry ie = find_ie(i); + bitmap bm(tm_, ie); + bm.iterate(i * entries_per_block_, hi, wrapper); + } + } + protected: transaction_manager::ptr get_tm() const { return tm_;