// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "SnapMapper.h" using std::string; const string SnapMapper::MAPPING_PREFIX = "MAP_"; const string SnapMapper::OBJECT_PREFIX = "OBJ_"; int OSDriver::get_keys( const std::set &keys, std::map *out) { return os->omap_get_values(cid, hoid, keys, out); } int OSDriver::get_next( const std::string &key, pair *next) { ObjectMap::ObjectMapIterator iter = os->get_omap_iterator(cid, hoid); if (!iter) { assert(0); return -EINVAL; } iter->upper_bound(key); if (iter->valid()) { if (next) *next = make_pair(iter->key(), iter->value()); return 0; } else { return -ENOENT; } } struct Mapping { snapid_t snap; hobject_t hoid; Mapping(const pair &in) : snap(in.first), hoid(in.second) {} Mapping() : snap(0) {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(snap, bl); ::encode(hoid, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(snap, bl); ::decode(hoid, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(Mapping); string SnapMapper::get_prefix(snapid_t snap) { char buf[100]; int len = snprintf( buf, sizeof(buf), "%.*X_", (int)(sizeof(snap)*2), static_cast(snap)); return MAPPING_PREFIX + string(buf, len); } string SnapMapper::to_raw_key( const pair &in) { return get_prefix(in.first) + in.second.to_str(); } pair SnapMapper::to_raw( const pair &in) { bufferlist bl; ::encode(Mapping(in), bl); return make_pair( to_raw_key(in), bl); } pair SnapMapper::from_raw( const pair &image) { Mapping map; bufferlist bl(image.second); bufferlist::iterator bp(bl.begin()); ::decode(map, bp); return make_pair(map.snap, map.hoid); } bool SnapMapper::is_mapping(const string &to_test) { return to_test.substr(0, MAPPING_PREFIX.size()) == MAPPING_PREFIX; } string SnapMapper::to_object_key(const hobject_t &hoid) { return OBJECT_PREFIX + hoid.to_str(); } void SnapMapper::object_snaps::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(oid, bl); ::encode(snaps, bl); ENCODE_FINISH(bl); } void SnapMapper::object_snaps::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(oid, bl); ::decode(snaps, bl); DECODE_FINISH(bl); } int SnapMapper::get_snaps( const hobject_t &oid, object_snaps *out) { assert(check(oid)); set keys; map got; keys.insert(to_object_key(oid)); int r = backend.get_keys(keys, &got); if (r < 0) return r; if (got.empty()) return -ENOENT; if (out) { bufferlist::iterator bp = got.begin()->second.begin(); ::decode(*out, bp); assert(!out->snaps.empty()); } return 0; } void SnapMapper::clear_snaps( const hobject_t &oid, MapCacher::Transaction *t) { assert(check(oid)); set to_remove; to_remove.insert(to_object_key(oid)); backend.remove_keys(to_remove, t); } void SnapMapper::set_snaps( const hobject_t &oid, const object_snaps &in, MapCacher::Transaction *t) { assert(check(oid)); map to_set; bufferlist bl; ::encode(in, bl); to_set[to_object_key(oid)] = bl; backend.set_keys(to_set, t); } int SnapMapper::update_snaps( const hobject_t &oid, const set &new_snaps, const set *old_snaps_check, MapCacher::Transaction *t) { assert(check(oid)); if (new_snaps.empty()) return remove_oid(oid, t); object_snaps out; int r = get_snaps(oid, &out); if (r < 0) return r; if (old_snaps_check) assert(out.snaps == *old_snaps_check); object_snaps in(oid, new_snaps); set_snaps(oid, in, t); set to_remove; for (set::iterator i = out.snaps.begin(); i != out.snaps.end(); ++i) { if (!new_snaps.count(*i)) { to_remove.insert(to_raw_key(make_pair(*i, oid))); } } backend.remove_keys(to_remove, t); return 0; } void SnapMapper::add_oid( const hobject_t &oid, set snaps, MapCacher::Transaction *t) { assert(check(oid)); { object_snaps out; int r = get_snaps(oid, &out); assert(r == -ENOENT); } object_snaps _snaps(oid, snaps); set_snaps(oid, _snaps, t); map to_add; for (set::iterator i = snaps.begin(); i != snaps.end(); ++i) { to_add.insert(to_raw(make_pair(*i, oid))); } backend.set_keys(to_add, t); } int SnapMapper::get_next_object_to_trim( snapid_t snap, hobject_t *hoid) { for (set::iterator i = prefixes.begin(); i != prefixes.end(); ++i) { string list_after(get_prefix(snap) + *i); pair next; int r = backend.get_next(list_after, &next); if (r < 0) { break; // Done } if (next.first.substr(0, list_after.size()) != list_after) { continue; // Done with this prefix } assert(is_mapping(next.first)); pair next_decoded(from_raw(next)); assert(next_decoded.first == snap); assert(check(next_decoded.second)); if (hoid) *hoid = next_decoded.second; return 0; } return -ENOENT; } int SnapMapper::remove_oid( const hobject_t &oid, MapCacher::Transaction *t) { assert(check(oid)); return _remove_oid(oid, t); } int SnapMapper::_remove_oid( const hobject_t &oid, MapCacher::Transaction *t) { object_snaps out; int r = get_snaps(oid, &out); if (r < 0) return r; clear_snaps(oid, t); set to_remove; for (set::iterator i = out.snaps.begin(); i != out.snaps.end(); ++i) { to_remove.insert(to_raw_key(make_pair(*i, oid))); } backend.remove_keys(to_remove, t); return 0; } int SnapMapper::get_snaps( const hobject_t &oid, std::set *snaps) { assert(check(oid)); object_snaps out; int r = get_snaps(oid, &out); if (r < 0) return r; if (snaps) snaps->swap(out.snaps); return 0; }