// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #pragma once #include "osd_types.h" struct ObjectState { object_info_t oi; bool exists; ///< the stored object exists (i.e., we will remember the object_info_t) ObjectState() : exists(false) {} ObjectState(const object_info_t &oi_, bool exists_) : oi(oi_), exists(exists_) {} ObjectState(object_info_t &&oi_, bool exists_) : oi(std::move(oi_)), exists(exists_) {} ObjectState(const hobject_t &obj) : oi(obj), exists(false) {} }; struct RWState { enum State { RWNONE, RWREAD, RWWRITE, RWEXCL, }; static const char *get_state_name(State s) { switch (s) { case RWNONE: return "none"; case RWREAD: return "read"; case RWWRITE: return "write"; case RWEXCL: return "excl"; default: return "???"; } } const char *get_state_name() const { return get_state_name(state); } int count; ///< number of readers or writers int waiters = 0; ///< number waiting State state:4; ///< rw state /// if set, restart backfill when we can get a read lock bool recovery_read_marker:1; /// if set, requeue snaptrim on lock release bool snaptrimmer_write_marker:1; RWState() : count(0), state(RWNONE), recovery_read_marker(false), snaptrimmer_write_marker(false) {} /// this function adjusts the counts if necessary bool get_read_lock() { // don't starve anybody! if (waiters > 0) { return false; } switch (state) { case RWNONE: ceph_assert(count == 0); state = RWREAD; // fall through case RWREAD: count++; return true; case RWWRITE: return false; case RWEXCL: return false; default: ceph_abort_msg("unhandled case"); return false; } } bool get_write_lock(bool greedy=false) { if (!greedy) { // don't starve anybody! if (waiters > 0 || recovery_read_marker) { return false; } } switch (state) { case RWNONE: ceph_assert(count == 0); state = RWWRITE; // fall through case RWWRITE: count++; return true; case RWREAD: return false; case RWEXCL: return false; default: ceph_abort_msg("unhandled case"); return false; } } bool get_excl_lock() { switch (state) { case RWNONE: ceph_assert(count == 0); state = RWEXCL; count = 1; return true; case RWWRITE: return false; case RWREAD: return false; case RWEXCL: return false; default: ceph_abort_msg("unhandled case"); return false; } } /// same as get_write_lock, but ignore starvation bool take_write_lock() { if (state == RWWRITE) { count++; return true; } return get_write_lock(); } bool dec() { ceph_assert(count > 0); count--; if (count == 0) { state = RWNONE; return true; } else { return false; } } bool put_read() { ceph_assert(state == RWREAD); return dec(); } bool put_write() { ceph_assert(state == RWWRITE); return dec(); } bool put_excl() { ceph_assert(state == RWEXCL); return dec(); } void inc_waiters() { ++waiters; } void release_waiters() { waiters = 0; } void dec_waiters(int count) { ceph_assert(waiters >= count); waiters -= count; } bool empty() const { return state == RWNONE; } bool get_snaptrimmer_write(bool mark_if_unsuccessful) { if (get_write_lock()) { return true; } else { if (mark_if_unsuccessful) snaptrimmer_write_marker = true; return false; } } bool get_recovery_read() { recovery_read_marker = true; if (get_read_lock()) { return true; } return false; } }; inline std::ostream& operator<<(std::ostream& out, const RWState& rw) { return out << "rwstate(" << rw.get_state_name() << " n=" << rw.count << " w=" << rw.waiters << ")"; }