| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #ifndef GEODE_EXPIRYTASK_H_ |
| #define GEODE_EXPIRYTASK_H_ |
| |
| #include <chrono> |
| #include <functional> |
| #include <limits> |
| #include <memory> |
| #include <mutex> |
| |
| #include <boost/asio/io_context.hpp> |
| #include <boost/asio/steady_timer.hpp> |
| |
| namespace apache { |
| namespace geode { |
| namespace client { |
| |
| class ExpiryTaskManager; |
| |
| /** |
| * @class ExpiryTask ExpiryTask.hpp |
| * |
| * This is the base class for all expiry tasks. |
| */ |
| class ExpiryTask : public std::enable_shared_from_this<ExpiryTask> { |
| public: |
| using id_t = uint64_t; |
| |
| public: |
| /// Class constructors |
| |
| /** |
| * Class constructor |
| * @param manager A reference to the ExpiryTaskManager |
| */ |
| explicit ExpiryTask(ExpiryTaskManager& manager); |
| |
| /** |
| * Class destructor |
| */ |
| virtual ~ExpiryTask() = default; |
| |
| /** |
| * Returns the task ID |
| */ |
| id_t id() const { return id_; } |
| |
| /** |
| * Returns whether the task is periodic |
| */ |
| bool periodic() const { |
| return interval_ != std::chrono::nanoseconds::zero(); |
| } |
| |
| /** |
| * Returns an ID which represents an invalid task |
| */ |
| static constexpr id_t invalid() { return (std::numeric_limits<id_t>::max)(); } |
| |
| protected: |
| using timer_t = boost::asio::steady_timer; |
| using clock_t = timer_t::clock_type; |
| using time_point_t = timer_t::time_point; |
| using duration_t = time_point_t::duration; |
| |
| protected: |
| friend class ExpiryTaskManager; |
| |
| /** |
| * Callback called upon task expiration |
| * @return Returns true if the task can normally complete and false if it has |
| * been reset. Specifically if false is returned it will mean:<br> |
| * - For periodic tasks. They won't re-trigger, as the task was |
| * re-scheduled. |
| * - For non-periodic tasks. They won't be removed from the manager, |
| * as the task was re-scheduled. |
| * @note Note that as this is an abstract method, each implementer of |
| * ExpiryTask should write its own version |
| */ |
| virtual bool on_expire() = 0; |
| |
| /** |
| * Sets task ID |
| * @param id Task ID |
| * @return A reference to itself |
| */ |
| ExpiryTask& id(id_t id) { |
| id_ = id; |
| return *this; |
| } |
| |
| /** |
| * Sets the task execution interval |
| * @param interval Task execution interval |
| * @return A reference to itself |
| */ |
| ExpiryTask& interval(const duration_t& interval) { |
| interval_ = interval; |
| return *this; |
| } |
| |
| /** |
| * Cancels the task |
| * @return Returns the number of pending executions. Take into account |
| * that if 0 is returned it means the task was being executed |
| * while cancel was called. |
| */ |
| int32_t cancel(); |
| |
| /** |
| * Resets the task timer |
| * @param at Time point at which the task is to be re-triggered. |
| * @return Returns -1 if the task was cancelled, and otherwise it |
| * returns the number of pending executions. Take into account |
| * that if 0 is returned it means the task was being executed |
| * while reset was called. |
| */ |
| int32_t reset(const time_point_t& at); |
| |
| /** |
| * Resets the task timer |
| * @param delay Amount of nano-seconds until the task is triggered. |
| * @return Returns -1 if the task was cancelled, and otherwise it |
| * returns the number of pending executions. Take into account |
| * that if 0 is returned it means the task was being executed |
| * while reset was called. |
| */ |
| int32_t reset(const duration_t& delay); |
| |
| /** |
| * Function triggered by the timer implementation. |
| * @param err Boost error passed by the timer. |
| */ |
| void on_callback(const boost::system::error_code& err); |
| |
| protected: |
| /// Member attributes |
| |
| /** |
| * Unique identifier of the task |
| */ |
| id_t id_; |
| |
| /** |
| * Specific timer implementation instance |
| */ |
| timer_t timer_; |
| |
| /** |
| * Reference to the expiry manager |
| */ |
| ExpiryTaskManager& manager_; |
| |
| /** |
| * Re-triggering interval |
| * @note This is used in order to define periodic tasks |
| */ |
| duration_t interval_; |
| |
| /** |
| * Exclusive mutex used to avoid race conditions for the following member |
| * functions:<br> |
| * - cancel |
| * - reset |
| */ |
| std::mutex mutex_; |
| |
| /** |
| * Flag indicating whether or not the task has been cancelled |
| * @note This is necessary in order to guarantee that whenever the task is |
| * reset the task won't be removed from the ExpiryTaskManager. |
| * The reason why is because reset cancels the execution of all the |
| * functions to be called by the timer and given they all share the |
| * same ExpiryTask instance there was no way to tell whether the |
| * task was cancelled or reset. |
| */ |
| bool cancelled_{false}; |
| }; |
| |
| } // namespace client |
| } // namespace geode |
| } // namespace apache |
| |
| #endif // GEODE_EXPIRYTASKMANAGER_H_ |