diff --git a/block-cache/copier.cc b/block-cache/copier.cc new file mode 100644 index 0000000..60ca93b --- /dev/null +++ b/block-cache/copier.cc @@ -0,0 +1,7 @@ +#include "block-cache/copier.h" + +//---------------------------------------------------------------- + + + +//---------------------------------------------------------------- diff --git a/block-cache/copier.h b/block-cache/copier.h new file mode 100644 index 0000000..41ed82e --- /dev/null +++ b/block-cache/copier.h @@ -0,0 +1,30 @@ +#ifndef BLOCK_CACHE_COPIER_H +#define BLOCK_CACHE_COPIER_H + +#include "block_cache.h" + +#include + +//---------------------------------------------------------------- + +namespace bcache { + class copier { + public: + // block size in sectors + copier(std::string const &src, std::string const &dest, + unsigned block_size); + ~copier(); + + // Returns the number of sectors copied + unsigned copy(block_address from, block_address to); + + unsigned get_block_size() const; + + private: + unsigned block_size_; + }; +} + +//---------------------------------------------------------------- + +#endif diff --git a/caching/cache_writeback.cc b/caching/cache_writeback.cc index a3d27d1..042ae74 100644 --- a/caching/cache_writeback.cc +++ b/caching/cache_writeback.cc @@ -1,13 +1,16 @@ -#ifndef CACHING_CACHE_WRITEBACK_H -#define CACHING_CACHE_WRITEBACK_H - +#include "persistent-data/file_utils.h" +#include "block-cache/copier.h" #include "caching/commands.h" +#include "caching/mapping_array.h" +#include "caching/metadata.h" #include "version.h" #include #include #include +#include +using namespace bcache; using namespace caching; using namespace boost; using namespace std; @@ -23,8 +26,117 @@ namespace { maybe_string fast_dev; }; + class copy_visitor : public mapping_visitor { + public: + copy_visitor(copier &c, bool only_dirty) + : copier_(c), + block_size_(c.get_block_size()), + only_dirty_(only_dirty) { + } + + virtual void visit(block_address cblock, mapping const &m) { + if (!(m.flags_ & M_VALID)) + return; + + if (only_dirty_ && !(m.flags_ & M_DIRTY)) + return; + + auto sectors_copied = copier_.copy(cblock, m.oblock_); + + stats_.blocks_issued++; + if (sectors_copied < block_size_) { + stats_.blocks_failed++; + stats_.sectors_failed += block_size_ - sectors_copied; + } + } + + struct copy_stats { + copy_stats() + : blocks_issued(0), + blocks_failed(0), + sectors_failed(0) { + } + + block_address blocks_issued; + block_address blocks_failed; + block_address sectors_failed; + }; + + copy_stats const &get_stats() const { + return stats_; + } + + private: + copier &copier_; + unsigned block_size_; + bool only_dirty_; + copy_stats stats_; + }; + + using namespace mapping_array_damage; + + class ignore_damage_visitor : public damage_visitor { + public: + ignore_damage_visitor() + : corruption_(false) { + } + + void visit(missing_mappings const &d) { + cerr << "missing mappings (" << d.keys_.begin_ << ", " << d.keys_.end_ << "]\n"; + corruption_ = true; + } + + void visit(invalid_mapping const &d) { + cerr << "invalid mapping cblock = " << d.cblock_ << ", oblock = " << d.m_.oblock_ << "\n"; + corruption_ = true; + } + + bool was_corruption() const { + return corruption_; + } + + private: + bool corruption_; + }; + + bool clean_shutdown(metadata const &md) { + return md.sb_.flags.get_flag(superblock_flags::CLEAN_SHUTDOWN); + } + + int writeback_(flags const &f) { + block_manager<>::ptr bm = open_bm(*f.metadata_dev, block_manager<>::READ_ONLY); + metadata md(bm, metadata::OPEN); + + copier c(*f.fast_dev, *f.origin_dev, md.sb_.data_block_size); + copy_visitor cv(c, clean_shutdown(md)); + ignore_damage_visitor dv; + walk_mapping_array(*md.mappings_, cv, dv); + + auto stats = cv.get_stats(); + cout << stats.blocks_issued << " copies issued\n" + << stats.blocks_failed << " copies failed\n"; + + if (stats.blocks_failed) + cout << stats.sectors_failed << " sectors were not copied\n"; + + if (dv.was_corruption()) + cout << "Metadata corruption was found, some data may not have been copied.\n"; + + return (stats.blocks_failed || dv.was_corruption()) ? 1 : 0; + } + int writeback(flags const &f) { - return 1; + int r; + + try { + r = writeback_(f); + + } catch (std::exception &e) { + cerr << e.what() << endl; + return 1; + } + + return r; } } @@ -118,5 +230,3 @@ cache_writeback_cmd::run(int argc, char **argv) } //---------------------------------------------------------------- - -#endif