diff --git a/objectstore/BackendRados.cpp b/objectstore/BackendRados.cpp index 6308f7ab56d5930637f30e124693367420f30acd..58b3e5e3d31b4d5a148d7d19c4fc13f71c1ea17e 100644 --- a/objectstore/BackendRados.cpp +++ b/objectstore/BackendRados.cpp @@ -204,13 +204,14 @@ BackendRados::ScopedLock::~ScopedLock() { BackendRados::LockWatcher::LockWatcher(librados::IoCtx& context, const std::string& name): m_context(context), m_name(name) { - m_future = m_promise.get_future(); + m_internal.reset(new Internal); + m_internal->m_future = m_internal->m_promise.get_future(); TIMESTAMPEDPRINT("Pre-watch2"); - cta::exception::Errnum::throwOnReturnedErrno(-m_context.watch2(name, &m_watchHandle, this)); + cta::exception::Errnum::throwOnReturnedErrno(-m_context.watch2(name, &m_watchHandle, m_internal.get())); TIMESTAMPEDPRINT("Post-watch2"); } -void BackendRados::LockWatcher::handle_error(uint64_t cookie, int err) { +void BackendRados::LockWatcher::Internal::handle_error(uint64_t cookie, int err) { threading::MutexLocker ml(m_promiseMutex); if (m_promiseSet) return; m_promise.set_value(); @@ -218,7 +219,7 @@ void BackendRados::LockWatcher::handle_error(uint64_t cookie, int err) { m_promiseSet = true; } -void BackendRados::LockWatcher::handle_notify(uint64_t notify_id, uint64_t cookie, uint64_t notifier_id, librados::bufferlist& bl) { +void BackendRados::LockWatcher::Internal::handle_notify(uint64_t notify_id, uint64_t cookie, uint64_t notifier_id, librados::bufferlist& bl) { threading::MutexLocker ml(m_promiseMutex); if (m_promiseSet) return; m_promise.set_value(); @@ -228,16 +229,20 @@ void BackendRados::LockWatcher::handle_notify(uint64_t notify_id, uint64_t cooki void BackendRados::LockWatcher::wait(const durationUs& timeout) { TIMESTAMPEDPRINT("Pre-wait"); - m_future.wait_for(timeout); + m_internal->m_future.wait_for(timeout); TIMESTAMPEDPRINT("Post-wait"); } BackendRados::LockWatcher::~LockWatcher() { TIMESTAMPEDPRINT("Pre-unwatch2"); - m_context.unwatch2(m_watchHandle); + librados::Rados::aio_create_completion(m_internal.release(), nullptr, Internal::deleter); TIMESTAMPEDPRINT("Post-unwatch2"); } +void BackendRados::LockWatcher::Internal::deleter(librados::completion_t cb, void* i) { + delete (Internal *) i; +} + std::string BackendRados::createUniqueClientId() { // Build a unique client name: host:thread char buff[200]; @@ -290,7 +295,7 @@ void BackendRados::lock(std::string name, uint64_t timeout_us, LockType lockType TIMESTAMPEDPRINT(lockType==LockType::Shared?"Post-relock (shared)":"Post-relock (exclusive)"); } if (-EBUSY != rc) break; - LockWatcher::durationUs watchTimeout = LockWatcher::durationUs(5L * 1000 * 1000); // We will poll at least every 5 second. + LockWatcher::durationUs watchTimeout = LockWatcher::durationUs(15L * 1000 * 1000); // We will poll at least every 15 second. // If we are dealing with a user-defined timeout, take it into account. if (timeout_us) { watchTimeout = std::min(watchTimeout, diff --git a/objectstore/BackendRados.hpp b/objectstore/BackendRados.hpp index 3ed5f5c3fb8d8a538ffc2ab819db7d0ac3dae8c2..927599643011ad99298fd078bcabbbefde9f8900 100644 --- a/objectstore/BackendRados.hpp +++ b/objectstore/BackendRados.hpp @@ -97,21 +97,29 @@ private: /** * A class handling the watch part when waiting for a lock. */ - class LockWatcher: public librados::WatchCtx2 { + class LockWatcher { public: LockWatcher(librados::IoCtx & context, const std::string & name); - void handle_error(uint64_t cookie, int err) override; - void handle_notify(uint64_t notify_id, uint64_t cookie, uint64_t notifier_id, librados::bufferlist& bl) override; virtual ~LockWatcher(); typedef std::chrono::microseconds durationUs; void wait(const durationUs & timeout); private: - // We could receive several notifications. The promise should be set only - // on the first occurrence. - threading::Mutex m_promiseMutex; - bool m_promiseSet = false; - std::promise<void> m_promise; - std::future<void> m_future; + /** An internal class containing the internals exposed to the callback of Rados. + * The internals are kept separated so we can used asynchronous unwatch and forget + * about the structure. The callback of aio_unwatch will take care of releasing the + * object */ + struct Internal: public librados::WatchCtx2 { + void handle_error(uint64_t cookie, int err) override; + void handle_notify(uint64_t notify_id, uint64_t cookie, uint64_t notifier_id, librados::bufferlist& bl) override; + static void deleter(librados::completion_t cb, void * i); + // We could receive several notifications. The promise should be set only + // on the first occurrence. + threading::Mutex m_promiseMutex; + bool m_promiseSet = false; + std::promise<void> m_promise; + std::future<void> m_future; + }; + std::unique_ptr<Internal> m_internal; librados::IoCtx & m_context; std::string m_name; uint64_t m_watchHandle;