}
ldout(store->ctx(), 0) << "NOTICE: resharding operation on bucket index detected, blocking" << dendl;
string new_bucket_id;
- r = store->block_while_resharding(bs, &new_bucket_id, target->bucket_info);
+ r = store->block_while_resharding(bs, &new_bucket_id,
+ target->bucket_info, null_yield);
if (r == -ERR_BUSY_RESHARDING) {
continue;
}
}
ldout(cct, 0) << "NOTICE: resharding operation on bucket index detected, blocking" << dendl;
string new_bucket_id;
- r = block_while_resharding(bs, &new_bucket_id, bucket_info);
+ r = block_while_resharding(bs, &new_bucket_id, bucket_info, null_yield);
if (r == -ERR_BUSY_RESHARDING) {
continue;
}
int RGWRados::block_while_resharding(RGWRados::BucketShard *bs,
string *new_bucket_id,
- const RGWBucketInfo& bucket_info)
+ const RGWBucketInfo& bucket_info,
+ optional_yield y)
{
std::shared_ptr<RGWReshardWait> waiter = reshard_wait;
- return waiter->block_while_resharding(bs, new_bucket_id, bucket_info);
+ return waiter->block_while_resharding(bs, new_bucket_id, bucket_info, y);
}
int RGWRados::bucket_index_link_olh(const RGWBucketInfo& bucket_info, RGWObjState& olh_state, const rgw_obj& obj_instance,
std::function<int(BucketShard *)> call);
int block_while_resharding(RGWRados::BucketShard *bs,
string *new_bucket_id,
- const RGWBucketInfo& bucket_info);
+ const RGWBucketInfo& bucket_info,
+ optional_yield y);
void bucket_index_guard_olh_op(RGWObjState& olh_state, librados::ObjectOperation& op);
int olh_init_modification(const RGWBucketInfo& bucket_info, RGWObjState& state, const rgw_obj& olh_obj, string *op_tag);
const int num_retries = 10;
static const std::chrono::seconds default_reshard_sleep_duration(5);
-int RGWReshardWait::do_wait()
+int RGWReshardWait::do_wait(optional_yield y)
{
std::unique_lock lock(mutex);
+ if (going_down) {
+ return -ECANCELED;
+ }
+
+#ifdef HAVE_BOOST_CONTEXT
+ if (y) {
+ auto& context = y.get_io_context();
+ auto& yield = y.get_yield_context();
+
+ Waiter waiter(context);
+ waiters.push_back(waiter);
+ lock.unlock();
+
+ waiter.timer.expires_after(default_reshard_sleep_duration);
+
+ boost::system::error_code ec;
+ waiter.timer.async_wait(yield[ec]);
+
+ lock.lock();
+ waiters.erase(waiters.iterator_to(waiter));
+ return -ec.value();
+ }
+#endif
+
cond.wait_for(lock, default_reshard_sleep_duration);
if (going_down) {
return 0;
}
+void RGWReshardWait::stop()
+{
+ std::scoped_lock lock(mutex);
+ going_down = true;
+ cond.notify_all();
+ for (auto& waiter : waiters) {
+ // unblock any waiters with ECANCELED
+ waiter.timer.cancel();
+ }
+}
+
int RGWReshardWait::block_while_resharding(RGWRados::BucketShard *bs,
string *new_bucket_id,
- const RGWBucketInfo& bucket_info)
+ const RGWBucketInfo& bucket_info,
+ optional_yield y)
{
int ret = 0;
cls_rgw_bucket_instance_entry entry;
} // if taking of lock succeeded
} // block to encapsulate recovery from incomplete reshard
- ret = do_wait();
+ ret = do_wait(y);
if (ret < 0) {
ldout(store->ctx(), 0) << __func__ << " ERROR: bucket is still resharding, please retry" << dendl;
return ret;
#include <vector>
#include <functional>
+#include <boost/intrusive/list.hpp>
+
#include "include/rados/librados.hpp"
#include "common/ceph_time.h"
#include "cls/rgw/cls_rgw_types.h"
ceph::mutex mutex = ceph::make_mutex("RGWReshardWait::lock");
ceph::condition_variable cond;
+ using Clock = ceph::coarse_real_clock;
+ struct Waiter : boost::intrusive::list_base_hook<> {
+ boost::asio::basic_waitable_timer<Clock> timer;
+ explicit Waiter(boost::asio::io_context& ioc) : timer(ioc) {}
+ };
+ boost::intrusive::list<Waiter> waiters;
+
bool going_down{false};
- int do_wait();
+ int do_wait(optional_yield y);
public:
explicit RGWReshardWait(RGWRados *_store) : store(_store) {}
~RGWReshardWait() {
}
int block_while_resharding(RGWRados::BucketShard *bs,
string *new_bucket_id,
- const RGWBucketInfo& bucket_info);
-
- void stop() {
- std::scoped_lock lock(mutex);
- going_down = true;
- cond.notify_all();
- }
+ const RGWBucketInfo& bucket_info,
+ optional_yield y);
+ // unblock any threads waiting on reshard
+ void stop();
};
#endif