blob: 0a6a11c5187c6a282dcd7dad7fefeaf323abff7e [file] [log] [blame]
/*
* 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_