blob: 10d2c967334f236cba4b713218049a9d39bd3a96 [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_EXPIRYTASKMANAGER_H_
#define GEODE_EXPIRYTASKMANAGER_H_
#include <chrono>
#include <condition_variable>
#include <map>
#include <mutex>
#include <thread>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/io_context.hpp>
#include "ExpiryTask.hpp"
namespace apache {
namespace geode {
namespace client {
/**
* @class ExpiryTaskManager ExpiryTaskManager.hpp
*
* This class manages all the ExpiryTaskManagers
* It uses Boost.Asio and Boost timers to schedule ExpiryTasks
*/
class ExpiryTaskManager {
public:
/**
* Default class constructor
*/
ExpiryTaskManager();
/**
* Class destructor
*/
virtual ~ExpiryTaskManager() noexcept;
/**
* Starts the manager
* @throw IllegalStateException An exception is thrown if the manager is
* already started.
*/
void start();
/**
* Stops the manager
* @throw IllegalStateException An exception is thrown if the manager is
* already stopped.
*/
void stop();
/**
* Returns whether or not the manager is running.
*/
bool running() const { return running_; }
/**
* Returns the number of scheduled tasks.
*/
std::size_t count() const { return task_map_.size(); }
/**
* Schedules a new expiry task.
* @param task Reference to the task.
* @param delay Amount of nano-seconds in which the task expires.
* @param interval Amount of nano-seconds in which the task is executed again.
* If this parameter is set to zero, the task will only
* execute once and finish, otherwise it will execute
* continuously every interval nano-seconds until cancelled.
* @return ID of the created task. If there was any error during the
* task creation ExpiryTask::invalid() is returned as ID.
* @note Possible errors are:<br>
* - Manager is not running
*/
ExpiryTask::id_t schedule(std::shared_ptr<ExpiryTask> task,
const ExpiryTask::duration_t &delay,
const ExpiryTask::duration_t &interval);
/**
* Schedules a new expiry task.
* @param task Task reference.
* @param delay Amount of nano-seconds in which the task expires.
* @return ID of the created task. If there was any error during the
* task creation ExpiryTask::invalid() is returned as ID.
* @note Possible errors are:<br>
* - Manager is not running
*/
ExpiryTask::id_t schedule(std::shared_ptr<ExpiryTask> task,
const ExpiryTask::duration_t &delay) {
return schedule(std::move(task), delay, ExpiryTask::duration_t::zero());
}
/**
* Re-triggers a task to run in the given delay.
* @param task_id ID of the task to be re-triggered.
* @param delay Amount of nano-seconds in which the task expires.
* @return Returns -1 if the task did not existed, 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(ExpiryTask::id_t task_id, const ExpiryTask::duration_t &delay);
/**
* Cancels an already scheduled expiry task
* @param task_id ID of the task to be cancelled.
* @return Returns -1 if the task did not existed, 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 cancel was called.
*/
int32_t cancel(ExpiryTask::id_t task_id);
protected:
/// Internal types
using duration_t = std::chrono::nanoseconds;
using task_map_t = std::map<ExpiryTask::id_t, std::shared_ptr<ExpiryTask>>;
protected:
friend class ExpiryTask;
/**
* Cancels all scheduled tasks
*/
void cancel_all();
/**
* Removes the reference to the task matching the given ID
* @param task_id ID of the task
*/
void remove(ExpiryTask::id_t task_id);
/**
* Returns Boost IO context
*/
boost::asio::io_context &io_context() { return io_context_; }
protected:
/// Class member attributes
/**
* Flag indicating whether or not the manager is running.
*/
bool running_;
/**
* Thread running the io_context.
*/
std::thread runner_;
/*
* Boost IO context processing expiry tasks events.
*/
boost::asio::io_context io_context_;
/**
* Executor guard. It keeps the IO context running even when there are
* no task scheduled.
*/
boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
work_guard_;
/**
* Manager mutex. It has the following uses:<br>
* - Avoids race conditions involving the task container.
* - Avoids creation of new task while the expiry task is being stopped.
* - Avoids concurrent modification of the task counter.
*/
std::mutex mutex_;
/**
* Task container
*/
task_map_t task_map_;
/**
* Task counter. It's used to assign tasks an UID.
*/
ExpiryTask::id_t last_task_id_;
};
} // namespace client
} // namespace geode
} // namespace apache
#endif // GEODE_EXPIRYTASKMANAGER_H_