//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed 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. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Dr. Frank Celler /// @author Martin Schoenert //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGOD_DISPATCHER_DISPATCHER_QUEUE_H #define ARANGOD_DISPATCHER_DISPATCHER_QUEUE_H 1 #include "Basics/Common.h" #include #include "Basics/ConditionVariable.h" #include "Basics/Mutex.h" #include "Dispatcher/Dispatcher.h" namespace arangodb { namespace rest { class DispatcherThread; class Job; //////////////////////////////////////////////////////////////////////////////// /// @brief dispatcher queue //////////////////////////////////////////////////////////////////////////////// class DispatcherQueue { DispatcherQueue(DispatcherQueue const&) = delete; DispatcherQueue& operator=(DispatcherQueue const&) = delete; friend class Dispatcher; friend class DispatcherThread; public: ////////////////////////////////////////////////////////////////////////////// /// @brief constructs a new dispatcher queue ////////////////////////////////////////////////////////////////////////////// DispatcherQueue(Scheduler*, Dispatcher*, size_t id, Dispatcher::newDispatcherThread_fptr, size_t nrThreads, size_t nrExtra, size_t maxSize); ~DispatcherQueue(); public: ////////////////////////////////////////////////////////////////////////////// /// @brief adds a job ////////////////////////////////////////////////////////////////////////////// int addJob(std::unique_ptr&, bool startThread); ////////////////////////////////////////////////////////////////////////////// /// @brief removes a job ////////////////////////////////////////////////////////////////////////////// void removeJob(Job*); ////////////////////////////////////////////////////////////////////////////// /// @brief cancels a job /// /// This will call the method `cancel` of the job. It will not remove the /// the job from the queue. ////////////////////////////////////////////////////////////////////////////// bool cancelJob(uint64_t); ////////////////////////////////////////////////////////////////////////////// /// @brief indicates that thread is doing a blocking operation ////////////////////////////////////////////////////////////////////////////// void blockThread(); ////////////////////////////////////////////////////////////////////////////// /// @brief indicates that thread has resumed work ////////////////////////////////////////////////////////////////////////////// void unblockThread(); ////////////////////////////////////////////////////////////////////////////// /// @brief begins the shutdown sequence the queue ////////////////////////////////////////////////////////////////////////////// void beginShutdown(); ////////////////////////////////////////////////////////////////////////////// /// @brief shuts down the queue ////////////////////////////////////////////////////////////////////////////// void shutdown(); ////////////////////////////////////////////////////////////////////////////// /// @brief starts a new queue thread ////////////////////////////////////////////////////////////////////////////// void startQueueThread(bool force); ////////////////////////////////////////////////////////////////////////////// /// @brief called when a thread has stopped ////////////////////////////////////////////////////////////////////////////// void removeStartedThread(DispatcherThread* thread); ////////////////////////////////////////////////////////////////////////////// /// @brief checks if we have too many threads ////////////////////////////////////////////////////////////////////////////// bool tooManyThreads(); ////////////////////////////////////////////////////////////////////////////// /// @brief checks if we have enough threads ////////////////////////////////////////////////////////////////////////////// bool notEnoughThreads(); ////////////////////////////////////////////////////////////////////////////// /// @brief sets the process affinity ////////////////////////////////////////////////////////////////////////////// void setProcessorAffinity(std::vector const& cores); private: ////////////////////////////////////////////////////////////////////////////// /// @brief deletes old threads ////////////////////////////////////////////////////////////////////////////// void deleteOldThreads(); private: ////////////////////////////////////////////////////////////////////////////// /// @brief id ////////////////////////////////////////////////////////////////////////////// size_t const _id; ////////////////////////////////////////////////////////////////////////////// /// @brief total number of threads /// /// This number is fixed. It is the number of pre-configured threads from the /// configuration file and is the average number of threads running under /// normal condition. Note that at server start not all threads will be /// started instantly, as threads will be created on demand. ////////////////////////////////////////////////////////////////////////////// size_t const _nrThreads; ////////////////////////////////////////////////////////////////////////////// /// @brief total number of extra/overhead threads /// /// This number is fixed. It is the maximum number of extra threads that can /// be created if _nrThreads threads have already been created ////////////////////////////////////////////////////////////////////////////// size_t const _nrExtra; ////////////////////////////////////////////////////////////////////////////// /// @brief maximum queue size (number of jobs) ////////////////////////////////////////////////////////////////////////////// size_t const _maxSize; ////////////////////////////////////////////////////////////////////////////// /// @brief waker for sleeping threads ////////////////////////////////////////////////////////////////////////////// basics::ConditionVariable _waitLock; ////////////////////////////////////////////////////////////////////////////// /// @brief list of ready jobs ////////////////////////////////////////////////////////////////////////////// boost::lockfree::queue _readyJobs; ////////////////////////////////////////////////////////////////////////////// /// @brief statistics /// /// This is for statistics only. Never use this number for decisions. ////////////////////////////////////////////////////////////////////////////// std::atomic _numberJobs; ////////////////////////////////////////////////////////////////////////////// /// @brief guard for hazard pointer ////////////////////////////////////////////////////////////////////////////// Mutex _hazardLock; ////////////////////////////////////////////////////////////////////////////// /// @brief hazard pointer for jobs ////////////////////////////////////////////////////////////////////////////// std::atomic _hazardPointer; ////////////////////////////////////////////////////////////////////////////// /// @brief queue is shutting down ////////////////////////////////////////////////////////////////////////////// std::atomic _stopping; ////////////////////////////////////////////////////////////////////////////// /// @brief guard for _startedThreads ////////////////////////////////////////////////////////////////////////////// Mutex _threadsLock; ////////////////////////////////////////////////////////////////////////////// /// @brief list of started threads ////////////////////////////////////////////////////////////////////////////// std::set _startedThreads; ////////////////////////////////////////////////////////////////////////////// /// @brief list of stopped threads ////////////////////////////////////////////////////////////////////////////// boost::lockfree::queue _stoppedThreads; ////////////////////////////////////////////////////////////////////////////// /// @brief number of running jobs /// /// As soon as a thread enters its main event loop, this number is increased /// by /// one. As soon as the thread leaves its main event loop, this number is /// decreaes by 1. /// /// Note that we ignore race conditions, the worst that can happen is that we /// start one thread too many or shutdown a thread too early. This variable is /// accessed using "memory_order_seq_cst". ////////////////////////////////////////////////////////////////////////////// std::atomic _nrRunning; ////////////////////////////////////////////////////////////////////////////// /// @brief number of waiting jobs /// /// Whenever a threads waits for more work, this number is increased by 1. As /// soon as the thread leaves the wait because it received a signal, this /// number is decreased by 1. /// /// This variable is accessed using "memory_order_seq_cst". ////////////////////////////////////////////////////////////////////////////// std::atomic _nrWaiting; ////////////////////////////////////////////////////////////////////////////// /// @brief number of blocked threads /// /// The number of threads, that are blocked for some reason. /// /// Note that we ignore race conditions, the worst that can happen is that we /// start one thread too many or shutdown a thread too early. This variable is /// accessed using "memory_order_seq_cst". ////////////////////////////////////////////////////////////////////////////// std::atomic _nrBlocked; ////////////////////////////////////////////////////////////////////////////// /// @brief last time we created or deleted a queue thread /// /// Note that we ignore race conditions, the worst that can happen is that we /// start one thread too many or shutdown a thread too early. This variable is /// accessed using "memory_order_seq_cst". ////////////////////////////////////////////////////////////////////////////// std::atomic _lastChanged; ////////////////////////////////////////////////////////////////////////////// /// @brief grace period before shuting down queue threads ////////////////////////////////////////////////////////////////////////////// double const _gracePeriod; ////////////////////////////////////////////////////////////////////////////// /// @brief scheduler ////////////////////////////////////////////////////////////////////////////// Scheduler* const _scheduler; ////////////////////////////////////////////////////////////////////////////// /// @brief dispatcher ////////////////////////////////////////////////////////////////////////////// Dispatcher* const _dispatcher; ////////////////////////////////////////////////////////////////////////////// /// @brief thread creator function ////////////////////////////////////////////////////////////////////////////// Dispatcher::newDispatcherThread_fptr createDispatcherThread; ////////////////////////////////////////////////////////////////////////////// /// @brief cores to use for affinity ////////////////////////////////////////////////////////////////////////////// std::vector _affinityCores; ////////////////////////////////////////////////////////////////////////////// /// @brief next affinity core to use ////////////////////////////////////////////////////////////////////////////// size_t _affinityPos; ////////////////////////////////////////////////////////////////////////////// /// @brief list of jobs /// /// There are at most _maxSize jobs. ////////////////////////////////////////////////////////////////////////////// std::atomic* _jobs; ////////////////////////////////////////////////////////////////////////////// /// @brief list of free job positions /// /// There are at most _maxSize jobs. But _maxSize is only known at runtime. ////////////////////////////////////////////////////////////////////////////// boost::lockfree::queue _jobPositions; }; } } #endif