The problem is the try_* functions may change the mode, but a start_write
may not follow if the op doesn't execute (for any number of reasons). So
the next time we come around, we may need to reset back to IDLE if
num_wr == 0. Be careful about the wake flag.
This fixes osd op hangs (particularly after mds restart, and lots of
failed stats on objects during file size/mtime recovery).
bool ok;
dout(10) << "do_op mode is " << mode << dendl;
+ assert(!mode.wake); // we should never have woken waiters here.
if (op->may_read() && op->may_write())
ok = mode.try_rmw(client);
else if (op->may_write())
AccessMode() : state(IDLE),
num_wr(0), wake(false) {}
+ void check_mode() {
+ if (num_wr == 0)
+ state = IDLE;
+ }
+
bool try_read(entity_inst_t& c) {
+ check_mode();
switch (state) {
case IDLE:
case DELAYED:
}
}
bool try_write(entity_inst_t& c) {
+ check_mode();
switch (state) {
case IDLE:
state = DELAYED;
}
}
bool try_rmw(entity_inst_t& c) {
+ check_mode();
switch (state) {
case IDLE:
state = RMW;
void finish_write() {
assert(num_wr > 0);
--num_wr;
- if (num_wr == 0)
- switch (state) {
- case DELAYED:
- state = IDLE;
- wake = true;
- break;
- case RMW:
- case DELAYED_FLUSHING:
- case RMW_FLUSHING:
- state = IDLE;
- wake = true;
- break;
- default:
- assert(0);
- }
+ if (num_wr == 0) {
+ state = IDLE;
+ wake = true;
+ }
}
};
inline ostream& operator<<(ostream& out, ReplicatedPG::AccessMode& mode)
{
- return out << mode.get_state_name(mode.state) << "(wr=" << mode.num_wr << ")";
+ out << mode.get_state_name(mode.state) << "(wr=" << mode.num_wr;
+ if (mode.wake)
+ out << " WAKE";
+ out << ")";
+ return out;
}
#endif