flush_set_callback(flush_callback), flush_set_callback_arg(flush_callback_arg),
flusher_stop(false), flusher_thread(this), finisher(cct),
stat_clean(0), stat_zero(0), stat_dirty(0), stat_rx(0), stat_tx(0), stat_missing(0),
- stat_error(0), stat_dirty_waiting(0)
+ stat_error(0), stat_dirty_waiting(0), reads_outstanding(0)
{
this->max_dirty_age.set_from_double(max_dirty_age);
perf_start();
void ObjectCacher::bh_read(BufferHead *bh)
{
assert(lock.is_locked());
- ldout(cct, 7) << "bh_read on " << *bh << dendl;
+ ldout(cct, 7) << "bh_read on " << *bh << " outstanding reads "
+ << reads_outstanding << dendl;
mark_rx(bh);
bh->start(), bh->length(), bh->ob->get_snap(),
&onfinish->bl, oset->truncate_size, oset->truncate_seq,
onfinish);
+ ++reads_outstanding;
}
void ObjectCacher::bh_read_finish(int64_t poolid, sobject_t oid, loff_t start,
<< " " << start << "~" << length
<< " (bl is " << bl.length() << ")"
<< " returned " << r
+ << " outstanding reads " << reads_outstanding
<< dendl;
if (bl.length() < length) {
ldout(cct, 20) << "finishing waiters " << ls << dendl;
finish_contexts(cct, ls, err);
+ --reads_outstanding;
+ read_cond.Signal();
}
break;
flusher_cond.WaitInterval(cct, lock, utime_t(1,0));
}
+
+ /* Wait for reads to finish. This is only possible if handling
+ * -ENOENT made some read completions finish before their rados read
+ * came back. If we don't wait for them, and destroy the cache, when
+ * the rados reads do come back their callback will try to access the
+ * no-longer-valid ObjectCacher.
+ */
+ while (reads_outstanding > 0) {
+ ldout(cct, 10) << "Waiting for all reads to complete. Number left: "
+ << reads_outstanding << dendl;
+ read_cond.Wait(lock);
+ }
+
lock.Unlock();
ldout(cct, 10) << "flusher finish" << dendl;
}