#ifndef __TarPit_h_ #define __TarPit_h_ #include "../shared/Messages.h" class TarPit { public: class INeedsPenalty { public: virtual bool needsPenalty(Request *request) const =0; virtual ~INeedsPenalty() {} }; private: class PenaltyAssessor { private: TimeVal _nextResetTime; TimeVal _nextAllowedTime; int _count; void resetIfNeeded(); public: TimeVal getNextAllowedTime(); void increment(); }; typedef std::map< SocketInfo *, PenaltyAssessor > PenaltyAssessors; PenaltyAssessors _penaltyAssessors; struct Item; typedef std::list< Item * > ItemList; typedef ItemList::iterator ItemIterator; typedef std::map< Request *, Item * > ItemMap; struct Item : public FixedMalloc { Request *request; ItemIterator positionInQueue; }; typedef std::pair< TimeVal, SocketInfo * > TimedListKey; class UserQueue : public FixedMalloc { private: ItemList _fifo; ItemMap _byRequest; SocketInfo *_socket; TimeVal _nextTime; public: bool empty() const; int getCount() const { return _byRequest.size(); } Request *pop(); Request *peek() const; void push(Request *newRequest); // Returns true if something was removed. // If the request was found in this queue, the request is deleleted // and it is removed form the queue. If the request is not in the queue, // nothing happens. bool remove(Request *toDelete); SocketInfo *getSocket() const { return _socket; } void setSocket(SocketInfo *socket) { _socket = socket; } void setNextTime(TimeVal t) { _nextTime = t; } TimedListKey getTimedListKey() const { return TimedListKey(_nextTime, _socket); } UserQueue() : _socket(NULL) {} // This deletes all the requests that are currently in the queue, // along with any internal data. ~UserQueue(); }; typedef std::set< TimedListKey > TimedList; TimedList _timedList; typedef std::map< SocketInfo *, UserQueue > BySocket; BySocket _bySocket; void addToTimedList(UserQueue &userQueue); const INeedsPenalty *const _needsPenalty; bool needsPenalty(Request *request) const; TimeVal increment(Request *request); int _count; timeval _untilNextRequest; public: // Returns true if there is at least one item which is ready now. Returns // false if all items have a delay. This can modify some internal data, but // nothing interesting to the outside world. bool ready(); int getCount() const { return _count; } Request *pop(); // Returns null if we are not ready. void push(Request *newRequest); timeval *untilNextRequest(); // Effeciently removes any and all requests assocatied with the socket. void remove(SocketInfo *socket); // Remove the specific item. If the item is not currently in the queue, then // this does nothing. The second form of the call will work even if the // request has already been deleted. (But be careful. It's possible that // a new request could be added with the same pointer, so we can't tell them // apart.) void remove(Request *toDelete); void remove(SocketInfo *socket, Request *toDelete); TarPit(INeedsPenalty *needsPenalty) : _needsPenalty(needsPenalty), _count(0) { } }; #endif