135 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "base/endian_utils.h"
 | |
| #include "caching/mapping_array.h"
 | |
| 
 | |
| #include <set>
 | |
| 
 | |
| using namespace caching;
 | |
| using namespace caching::mapping_array_damage;
 | |
| using namespace std;
 | |
| 
 | |
| //----------------------------------------------------------------
 | |
| 
 | |
| namespace {
 | |
| 	const uint64_t FLAGS_MASK = (1 << 16) - 1;
 | |
| }
 | |
| 
 | |
| void
 | |
| mapping_traits::unpack(disk_type const &disk, value_type &value)
 | |
| {
 | |
| 	uint64_t v = base::to_cpu<uint64_t>(disk);
 | |
| 	value.oblock_ = v >> 16;
 | |
| 	value.flags_ = v & FLAGS_MASK;
 | |
| }
 | |
| 
 | |
| void
 | |
| mapping_traits::pack(value_type const &value, disk_type &disk)
 | |
| {
 | |
| 	uint64_t packed = value.oblock_ << 16;
 | |
| 	packed = packed | (value.flags_ & FLAGS_MASK);
 | |
| 	disk = base::to_disk<le64>(packed);
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------
 | |
| 
 | |
| missing_mappings::missing_mappings(std::string const &desc, run<uint32_t> const &keys)
 | |
| 	: damage(desc),
 | |
| 	  keys_(keys)
 | |
| {
 | |
| }
 | |
| 
 | |
| void
 | |
| missing_mappings::visit(damage_visitor &v) const
 | |
| {
 | |
| 	v.visit(*this);
 | |
| }
 | |
| 
 | |
| invalid_mapping::invalid_mapping(std::string const &desc,
 | |
| 				 block_address cblock, mapping const &m)
 | |
| 	: damage(desc),
 | |
| 	  cblock_(cblock),
 | |
| 	  m_(m)
 | |
| {
 | |
| }
 | |
| 
 | |
| void
 | |
| invalid_mapping::visit(damage_visitor &v) const
 | |
| {
 | |
| 	v.visit(*this);
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 	class check_mapping_visitor : public mapping_visitor {
 | |
| 	public:
 | |
| 		check_mapping_visitor(damage_visitor &visitor, unsigned metadata_version)
 | |
| 		: visitor_(visitor),
 | |
| 		  allowed_flags_(metadata_version == 1 ? (M_VALID | M_DIRTY) : M_VALID) {
 | |
| 		}
 | |
| 
 | |
| 		virtual void visit(block_address cblock, mapping const &m) {
 | |
| 			if (!valid_mapping(m))
 | |
| 				return;
 | |
| 
 | |
| 			if (seen_oblock(m))
 | |
| 				visitor_.visit(invalid_mapping("origin block already mapped", cblock, m));
 | |
| 			else
 | |
| 				record_oblock(m);
 | |
| 
 | |
| 			if (unknown_flags(m))
 | |
| 				visitor_.visit(invalid_mapping("unknown flags in mapping", cblock, m));
 | |
| 		}
 | |
| 
 | |
| 	private:
 | |
| 		static bool valid_mapping(mapping const &m) {
 | |
| 			return !!(m.flags_ & M_VALID);
 | |
| 		}
 | |
| 
 | |
| 		bool seen_oblock(mapping const &m) const {
 | |
| 			return seen_oblocks_.find(m.oblock_) != seen_oblocks_.end();
 | |
| 		}
 | |
| 
 | |
| 		void record_oblock(mapping const &m) {
 | |
| 			seen_oblocks_.insert(m.oblock_);
 | |
| 		}
 | |
| 
 | |
| 		bool unknown_flags(mapping const &m) {
 | |
| 			return m.flags_ & ~allowed_flags_;
 | |
| 		}
 | |
| 
 | |
| 		damage_visitor &visitor_;
 | |
| 		set<block_address> seen_oblocks_;
 | |
| 		uint32_t allowed_flags_;
 | |
| 	};
 | |
| 
 | |
| 	class ll_damage_visitor {
 | |
| 	public:
 | |
| 		ll_damage_visitor(damage_visitor &v)
 | |
| 		: v_(v) {
 | |
| 		}
 | |
| 
 | |
| 		virtual void visit(array_detail::damage const &d) {
 | |
| 			v_.visit(missing_mappings(d.desc_, d.lost_keys_));
 | |
| 		}
 | |
| 
 | |
| 	private:
 | |
| 		damage_visitor &v_;
 | |
| 	};
 | |
| }
 | |
| 
 | |
| void
 | |
| caching::walk_mapping_array(mapping_array const &array,
 | |
| 			    mapping_visitor &mv,
 | |
| 			    damage_visitor &dv)
 | |
| {
 | |
| 	ll_damage_visitor ll(dv);
 | |
| 	array.visit_values(mv, ll);
 | |
| }
 | |
| 
 | |
| void
 | |
| caching::check_mapping_array(mapping_array const &array, damage_visitor &visitor, unsigned metadata_version)
 | |
| {
 | |
| 	check_mapping_visitor mv(visitor, metadata_version);
 | |
| 	walk_mapping_array(array, mv, visitor);
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------
 |