22#ifndef ROCKSDB_LITE
33#include " cloud/cloud_scheduler.h"
44
5+ #include < chrono>
56#include < condition_variable>
67#include < mutex>
78#include < thread>
@@ -23,6 +24,8 @@ struct ScheduledJob {
2324 std::chrono::steady_clock::time_point when;
2425 std::chrono::microseconds frequency;
2526 std::function<void (void *)> callback;
27+
28+ // Caller is responsible for the lifetime of arg.
2629 void * arg;
2730};
2831
@@ -49,9 +52,13 @@ class CloudSchedulerImpl : public CloudScheduler {
4952 long next_id_;
5053
5154 std::mutex mutex_;
52- // Notified when the earliest job to be scheduled has changed.
55+ // Notified when the earliest job to be scheduled has changed or
56+ // currently_running_ has changed.
5357 std::condition_variable jobs_changed_cv_;
5458 std::multiset<ScheduledJob, Comp> scheduled_jobs_;
59+ // Whether the job in the front of scheduled_jobs_ is running
60+ bool currently_running_;
61+
5562 bool shutting_down_{false };
5663
5764 std::unique_ptr<std::thread> thread_;
@@ -97,14 +104,19 @@ class LocalCloudScheduler : public CloudScheduler {
97104 // Cancels the job referred to by handle if it is active and associated with
98105 // this scheduler
99106 bool CancelJob (long handle) override {
100- std::lock_guard<std::mutex> lk (job_mutex_);
101- const auto & it = jobs_.find (handle);
102- if (it != jobs_.end ()) {
103- jobs_.erase (it);
104- return scheduler_->CancelJob (it->second );
105- } else {
106- return false ;
107+ long internal_job_id = -1 ;
108+ {
109+ std::lock_guard<std::mutex> lk (job_mutex_);
110+ const auto & it = jobs_.find (handle);
111+ if (it != jobs_.end ()) {
112+ internal_job_id = it->second ;
113+ jobs_.erase (it);
114+ } else {
115+ return false ;
116+ }
107117 }
118+
119+ return scheduler_->CancelJob (internal_job_id);
108120 }
109121
110122 private:
@@ -127,6 +139,7 @@ std::shared_ptr<CloudScheduler> CloudScheduler::Get() {
127139
128140CloudSchedulerImpl::CloudSchedulerImpl () {
129141 next_id_ = 1 ;
142+ currently_running_ = false ;
130143 auto lambda = [this ]() { DoWork (); };
131144 thread_.reset (new std::thread (lambda));
132145}
@@ -175,7 +188,28 @@ long CloudSchedulerImpl::ScheduleRecurringJob(
175188}
176189
177190bool CloudSchedulerImpl::CancelJob (long id) {
178- std::lock_guard<std::mutex> lk (mutex_);
191+ if (id < 0 ) {
192+ return false ;
193+ }
194+
195+ std::unique_lock<std::mutex> lk (mutex_);
196+ jobs_changed_cv_.wait (lk, [this , id]() {
197+ // No job is scheduled. Good to continue.
198+ if (scheduled_jobs_.empty ()) {
199+ return true ;
200+ }
201+
202+ // Front of the queue is not this job. That means this job is not running.
203+ // We're clear to cancel this job.
204+ if (scheduled_jobs_.begin ()->id != id) {
205+ return true ;
206+ }
207+
208+ // Front of the queue is the current job. That means only continue if this
209+ // job is not running. If it's still running, wait.
210+ return !currently_running_;
211+ });
212+
179213 for (auto it = scheduled_jobs_.begin (); it != scheduled_jobs_.end (); ++it) {
180214 if (it->id == id) {
181215 bool is_first = (it == scheduled_jobs_.begin ());
@@ -205,18 +239,28 @@ void CloudSchedulerImpl::DoWork() {
205239 jobs_changed_cv_.wait_until (lk, earliest_job_time);
206240 continue ;
207241 }
208- // invoke the function
242+
243+ currently_running_ = true ;
209244 lk.unlock ();
210245
246+ // invoke the function
211247 earliest_job->callback (earliest_job->arg );
212248
213249 lk.lock ();
250+ // Finished running the job. Remove it from the queue.
251+ currently_running_ = false ;
252+
253+ // If this is a recurring job, add back to the queue.
214254 if (earliest_job->frequency .count () > 0 ) {
215255 ScheduledJob new_job = *earliest_job;
216256 new_job.when = std::chrono::steady_clock::now () + new_job.frequency ;
217257 scheduled_jobs_.emplace (new_job);
218258 }
219259 scheduled_jobs_.erase (earliest_job);
260+
261+ // We might be waiting for the change in currently_running_job_id_ when
262+ // cancelling a job.
263+ jobs_changed_cv_.notify_all ();
220264 }
221265}
222266} // namespace ROCKSDB_NAMESPACE
0 commit comments