--- /dev/null
+// -*- 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 ostream& operator<<(ostream& out, const RWState& rw)
+{
+ return out << "rwstate(" << rw.get_state_name()
+ << " n=" << rw.count
+ << " w=" << rw.waiters
+ << ")";
+}
#include "osd_types.h"
#include "OpRequest.h"
+#include "object_state.h"
/*
* keep tabs on object modifications that are in flight.
explicit SnapSetContext(const hobject_t& o) :
oid(o), ref(0), registered(false), exists(true) { }
};
-
-struct ObjectContext;
-
-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_) {}
-};
-
+class ObjectContext;
typedef std::shared_ptr<ObjectContext> ObjectContextRef;
struct ObjectContext {
// attr cache
map<string, bufferlist> attr_cache;
- 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);
- }
-
- std::list<OpRequestRef> waiters; ///< ops waiting on state change
- int count; ///< number of readers or writers
-
- 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)
- {}
- bool get_read(OpRequestRef& op) {
- if (get_read_lock()) {
- return true;
- } // else
+ RWState rwstate;
+ std::list<OpRequestRef> waiters; ///< ops waiting on state change
+ bool get_read(OpRequestRef& op) {
+ if (rwstate.get_read_lock()) {
+ return true;
+ } // else
// Now we really need to bump up the ref-counter.
+ waiters.emplace_back(op);
+ rwstate.inc_waiters();
+ return false;
+ }
+ bool get_write(OpRequestRef& op, bool greedy=false) {
+ if (rwstate.get_write_lock(greedy)) {
+ return true;
+ } // else
+ if (op) {
waiters.emplace_back(op);
- return false;
- }
- /// this function adjusts the counts if necessary
- bool get_read_lock() {
- // don't starve anybody!
- if (!waiters.empty()) {
- 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(OpRequestRef& op, bool greedy=false) {
- if (get_write_lock(greedy)) {
- return true;
- } // else
- if (op)
- waiters.emplace_back(op);
- return false;
- }
- bool get_write_lock(bool greedy=false) {
- if (!greedy) {
- // don't starve anybody!
- if (!waiters.empty() ||
- 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;
- }
- }
- bool get_excl(OpRequestRef& op) {
- if (get_excl_lock()) {
- return true;
- } // else
- if (op)
- waiters.emplace_back(op);
- return false;
+ rwstate.inc_waiters();
}
- /// same as get_write_lock, but ignore starvation
- bool take_write_lock() {
- if (state == RWWRITE) {
- count++;
- return true;
- }
- return get_write_lock();
- }
- void dec(list<OpRequestRef> *requeue) {
- ceph_assert(count > 0);
- ceph_assert(requeue);
- count--;
- if (count == 0) {
- state = RWNONE;
- requeue->splice(requeue->end(), waiters);
- }
- }
- void put_read(list<OpRequestRef> *requeue) {
- ceph_assert(state == RWREAD);
- dec(requeue);
- }
- void put_write(list<OpRequestRef> *requeue) {
- ceph_assert(state == RWWRITE);
- dec(requeue);
+ return false;
+ }
+ bool get_excl(OpRequestRef& op) {
+ if (rwstate.get_excl_lock()) {
+ return true;
+ } // else
+ if (op) {
+ waiters.emplace_back(op);
+ rwstate.inc_waiters();
}
- void put_excl(list<OpRequestRef> *requeue) {
- ceph_assert(state == RWEXCL);
- dec(requeue);
+ return false;
+ }
+ void wake(list<OpRequestRef> *requeue) {
+ rwstate.release_waiters();
+ requeue->splice(requeue->end(), waiters);
+ }
+ void put_read(list<OpRequestRef> *requeue) {
+ if (rwstate.put_read()) {
+ wake(requeue);
}
- bool empty() const { return state == RWNONE; }
- } rwstate;
-
- bool get_read(OpRequestRef& op) {
- return rwstate.get_read(op);
}
- bool get_write(OpRequestRef& op) {
- return rwstate.get_write(op, false);
+ void put_write(list<OpRequestRef> *requeue) {
+ if (rwstate.put_write()) {
+ wake(requeue);
+ }
}
- bool get_excl(OpRequestRef op) {
- return rwstate.get_excl(op);
+ void put_excl(list<OpRequestRef> *requeue) {
+ if (rwstate.put_excl()) {
+ wake(requeue);
+ }
}
+ bool empty() const { return rwstate.empty(); }
+
bool get_lock_type(OpRequestRef& op, RWState::State type) {
switch (type) {
case RWState::RWWRITE:
}
}
bool get_write_greedy(OpRequestRef& op) {
- return rwstate.get_write(op, true);
+ return get_write(op, true);
}
bool get_snaptrimmer_write(bool mark_if_unsuccessful) {
- if (rwstate.get_write_lock()) {
- return true;
- } else {
- if (mark_if_unsuccessful)
- rwstate.snaptrimmer_write_marker = true;
- return false;
- }
+ return rwstate.get_snaptrimmer_write(mark_if_unsuccessful);
}
bool get_recovery_read() {
- rwstate.recovery_read_marker = true;
- if (rwstate.get_read_lock()) {
- return true;
- }
- return false;
+ return rwstate.get_recovery_read();
}
bool try_get_read_lock() {
return rwstate.get_read_lock();
}
void drop_recovery_read(list<OpRequestRef> *ls) {
ceph_assert(rwstate.recovery_read_marker);
- rwstate.put_read(ls);
+ put_read(ls);
rwstate.recovery_read_marker = false;
}
void put_lock_type(
- ObjectContext::RWState::State type,
+ RWState::State type,
list<OpRequestRef> *to_wake,
bool *requeue_recovery,
bool *requeue_snaptrimmer) {
switch (type) {
- case ObjectContext::RWState::RWWRITE:
- rwstate.put_write(to_wake);
+ case RWState::RWWRITE:
+ put_write(to_wake);
break;
- case ObjectContext::RWState::RWREAD:
- rwstate.put_read(to_wake);
+ case RWState::RWREAD:
+ put_read(to_wake);
break;
- case ObjectContext::RWState::RWEXCL:
- rwstate.put_excl(to_wake);
+ case RWState::RWEXCL:
+ put_excl(to_wake);
break;
default:
ceph_abort_msg("invalid lock type");
}
}
bool is_request_pending() {
- return (rwstate.count > 0);
+ return !rwstate.empty();
}
ObjectContext()
return out;
}
-inline ostream& operator<<(ostream& out, const ObjectContext::RWState& rw)
-{
- return out << "rwstate(" << rw.get_state_name()
- << " n=" << rw.count
- << " w=" << rw.waiters.size()
- << ")";
-}
-
inline ostream& operator<<(ostream& out, const ObjectContext& obc)
{
return out << "obc(" << obc.obs << " " << obc.rwstate << ")";
class ObcLockManager {
struct ObjectLockState {
ObjectContextRef obc;
- ObjectContext::RWState::State type;
+ RWState::State type;
ObjectLockState(
ObjectContextRef obc,
- ObjectContext::RWState::State type)
+ RWState::State type)
: obc(std::move(obc)), type(type) {}
};
map<hobject_t, ObjectLockState> locks;
return locks.empty();
}
bool get_lock_type(
- ObjectContext::RWState::State type,
+ RWState::State type,
const hobject_t &hoid,
ObjectContextRef& obc,
OpRequestRef& op) {
if (obc->rwstate.take_write_lock()) {
locks.insert(
make_pair(
- hoid, ObjectLockState(obc, ObjectContext::RWState::RWWRITE)));
+ hoid, ObjectLockState(obc, RWState::RWWRITE)));
return true;
} else {
return false;
if (obc->get_snaptrimmer_write(mark_if_unsuccessful)) {
locks.insert(
make_pair(
- hoid, ObjectLockState(obc, ObjectContext::RWState::RWWRITE)));
+ hoid, ObjectLockState(obc, RWState::RWWRITE)));
return true;
} else {
return false;
if (obc->get_write_greedy(op)) {
locks.insert(
make_pair(
- hoid, ObjectLockState(obc, ObjectContext::RWState::RWWRITE)));
+ hoid, ObjectLockState(obc, RWState::RWWRITE)));
return true;
} else {
return false;
locks.insert(
make_pair(
hoid,
- ObjectLockState(obc, ObjectContext::RWState::RWREAD)));
+ ObjectLockState(obc, RWState::RWREAD)));
return true;
} else {
return false;