diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index f84ce373f..b52b69cb5 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -961,7 +961,7 @@ CurlEasyRequest::~CurlEasyRequest() revokeCallbacks(); if (mPerHostPtr) { - PerHostRequestQueue::release(mPerHostPtr); + AIPerHostRequestQueue::release(mPerHostPtr); } // This wasn't freed yet if the request never finished. curl_slist_free_all(mHeaders); @@ -1286,14 +1286,14 @@ void CurlEasyRequest::queued_for_removal(AICurlEasyRequest_wat& curl_easy_reques } #endif -PerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void) +AIPerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void) { if (!mPerHostPtr) { // mPerHostPtr is really just a speed-up cache. // The reason we can cache it is because mLowercaseHostname is only set // in finalizeRequest which may only be called once: it never changes. - mPerHostPtr = PerHostRequestQueue::instance(mLowercaseHostname); + mPerHostPtr = AIPerHostRequestQueue::instance(mLowercaseHostname); } return mPerHostPtr; } diff --git a/indra/llmessage/aicurlperhost.cpp b/indra/llmessage/aicurlperhost.cpp index 681dd769e..608bb1857 100644 --- a/indra/llmessage/aicurlperhost.cpp +++ b/indra/llmessage/aicurlperhost.cpp @@ -1,8 +1,8 @@ /** * @file aiperhost.cpp - * @brief Implementation of PerHostRequestQueue + * @brief Implementation of AIPerHostRequestQueue * - * Copyright (c) 2012, Aleric Inglewood. + * Copyright (c) 2012, 2013, Aleric Inglewood. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,36 +26,60 @@ * * 04/11/2012 * Initial version, written by Aleric Inglewood @ SL + * + * 06/04/2013 + * Renamed AICurlPrivate::PerHostRequestQueue[Ptr] to AIPerHostRequestQueue[Ptr] + * to allow public access. */ #include "sys.h" #include "aicurlperhost.h" #include "aicurlthread.h" +AIPerHostRequestQueue::threadsafe_instance_map_type AIPerHostRequestQueue::sInstanceMap; +LLAtomicS32 AIPerHostRequestQueue::sTotalQueued; + #undef AICurlPrivate namespace AICurlPrivate { -PerHostRequestQueue::threadsafe_instance_map_type PerHostRequestQueue::sInstanceMap; -LLAtomicS32 PerHostRequestQueue::sTotalQueued; U32 curl_concurrent_connections_per_host; +// Friend functions of RefCountedThreadSafePerHostRequestQueue + +void intrusive_ptr_add_ref(RefCountedThreadSafePerHostRequestQueue* per_host) +{ + per_host->mReferenceCount++; +} + +void intrusive_ptr_release(RefCountedThreadSafePerHostRequestQueue* per_host) +{ + if (--per_host->mReferenceCount == 0) + { + delete per_host; + } +} + +} // namespace AICurlPrivate + +using namespace AICurlPrivate; + //static -PerHostRequestQueuePtr PerHostRequestQueue::instance(std::string const& hostname) +AIPerHostRequestQueuePtr AIPerHostRequestQueue::instance(std::string const& hostname) { llassert(!hostname.empty()); instance_map_wat instance_map_w(sInstanceMap); - PerHostRequestQueue::iterator iter = instance_map_w->find(hostname); + AIPerHostRequestQueue::iterator iter = instance_map_w->find(hostname); if (iter == instance_map_w->end()) { iter = instance_map_w->insert(instance_map_type::value_type(hostname, new RefCountedThreadSafePerHostRequestQueue)).first; } - // Note: the creation of PerHostRequestQueuePtr MUST be protected by the lock on sInstanceMap (see release()). + // Note: the creation of AIPerHostRequestQueuePtr MUST be protected by the lock on sInstanceMap (see release()). return iter->second; } //static -void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance) +void AIPerHostRequestQueue::release(AIPerHostRequestQueuePtr& instance) { if (instance->exactly_two_left()) // Being 'instance' and the one in sInstanceMap. { @@ -91,31 +115,31 @@ void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance) instance.reset(); } -bool PerHostRequestQueue::throttled() const +bool AIPerHostRequestQueue::throttled() const { llassert(mAdded <= int(curl_concurrent_connections_per_host)); return mAdded == int(curl_concurrent_connections_per_host); } -void PerHostRequestQueue::added_to_multi_handle(void) +void AIPerHostRequestQueue::added_to_multi_handle(void) { llassert(mAdded < int(curl_concurrent_connections_per_host)); ++mAdded; } -void PerHostRequestQueue::removed_from_multi_handle(void) +void AIPerHostRequestQueue::removed_from_multi_handle(void) { --mAdded; llassert(mAdded >= 0); } -void PerHostRequestQueue::queue(AICurlEasyRequest const& easy_request) +void AIPerHostRequestQueue::queue(AICurlEasyRequest const& easy_request) { mQueuedRequests.push_back(easy_request.get_ptr()); sTotalQueued++; } -bool PerHostRequestQueue::cancel(AICurlEasyRequest const& easy_request) +bool AIPerHostRequestQueue::cancel(AICurlEasyRequest const& easy_request) { queued_request_type::iterator const end = mQueuedRequests.end(); queued_request_type::iterator cur = std::find(mQueuedRequests.begin(), end, easy_request.get_ptr()); @@ -128,7 +152,7 @@ bool PerHostRequestQueue::cancel(AICurlEasyRequest const& easy_request) // the back with swap (could just swap with the end immediately, but I don't // want to break the order in which requests where added). Swap is also not // thread-safe, but OK here because it only touches the objects in the deque, - // and the deque is protected by the lock on the PerHostRequestQueue object. + // and the deque is protected by the lock on the AIPerHostRequestQueue object. queued_request_type::iterator prev = cur; while (++cur != end) { @@ -141,7 +165,7 @@ bool PerHostRequestQueue::cancel(AICurlEasyRequest const& easy_request) return true; } -void PerHostRequestQueue::add_queued_to(curlthread::MultiHandle* multi_handle) +void AIPerHostRequestQueue::add_queued_to(curlthread::MultiHandle* multi_handle) { if (!mQueuedRequests.empty()) { @@ -153,7 +177,7 @@ void PerHostRequestQueue::add_queued_to(curlthread::MultiHandle* multi_handle) } //static -void PerHostRequestQueue::purge(void) +void AIPerHostRequestQueue::purge(void) { instance_map_wat instance_map_w(sInstanceMap); for (iterator host = instance_map_w->begin(); host != instance_map_w->end(); ++host) @@ -167,19 +191,3 @@ void PerHostRequestQueue::purge(void) } } -// Friend functions of RefCountedThreadSafePerHostRequestQueue - -void intrusive_ptr_add_ref(RefCountedThreadSafePerHostRequestQueue* per_host) -{ - per_host->mReferenceCount++; -} - -void intrusive_ptr_release(RefCountedThreadSafePerHostRequestQueue* per_host) -{ - if (--per_host->mReferenceCount == 0) - { - delete per_host; - } -} - -} // namespace AICurlPrivate diff --git a/indra/llmessage/aicurlperhost.h b/indra/llmessage/aicurlperhost.h index 27107d7c2..238cb622e 100644 --- a/indra/llmessage/aicurlperhost.h +++ b/indra/llmessage/aicurlperhost.h @@ -1,8 +1,8 @@ /** * @file aicurlperhost.h - * @brief Definition of class PerHostRequestQueue + * @brief Definition of class AIPerHostRequestQueue * - * Copyright (c) 2012, Aleric Inglewood. + * Copyright (c) 2012, 2013, Aleric Inglewood. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,10 @@ * * 04/11/2012 * Initial version, written by Aleric Inglewood @ SL + * + * 06/04/2013 + * Renamed AIPrivate::PerHostRequestQueue[Ptr] to AIPerHostRequestQueue[Ptr] + * to allow public access. */ #ifndef AICURLPERHOST_H @@ -39,68 +43,70 @@ #include "aithreadsafe.h" class AICurlEasyRequest; +class AIPerHostRequestQueue; namespace AICurlPrivate { namespace curlthread { class MultiHandle; } -class PerHostRequestQueue; class RefCountedThreadSafePerHostRequestQueue; class ThreadSafeBufferedCurlEasyRequest; // Forward declaration of BufferedCurlEasyRequestPtr (see aicurlprivate.h). typedef boost::intrusive_ptr BufferedCurlEasyRequestPtr; -// PerHostRequestQueue objects are created by the curl thread and destructed by the main thread. +// AIPerHostRequestQueue objects are created by the curl thread and destructed by the main thread. // We need locking. -typedef AIThreadSafeSimpleDC threadsafe_PerHostRequestQueue; -typedef AIAccessConst PerHostRequestQueue_crat; -typedef AIAccess PerHostRequestQueue_rat; -typedef AIAccess PerHostRequestQueue_wat; +typedef AIThreadSafeSimpleDC threadsafe_PerHostRequestQueue; +typedef AIAccessConst PerHostRequestQueue_crat; +typedef AIAccess PerHostRequestQueue_rat; +typedef AIAccess PerHostRequestQueue_wat; + +} // namespace AICurlPrivate // We can't put threadsafe_PerHostRequestQueue in a std::map because you can't copy a mutex. // Therefore, use an intrusive pointer for the threadsafe type. -typedef boost::intrusive_ptr PerHostRequestQueuePtr; +typedef boost::intrusive_ptr AIPerHostRequestQueuePtr; //----------------------------------------------------------------------------- -// PerHostRequestQueue +// AIPerHostRequestQueue // This class provides a static interface to create and maintain instances -// of PerHostRequestQueue objects, so that at any moment there is at most +// of AIPerHostRequestQueue objects, so that at any moment there is at most // one instance per hostname. Those instances then are used to queue curl // requests when the maximum number of connections for that host already // have been reached. -class PerHostRequestQueue { +class AIPerHostRequestQueue { private: - typedef std::map instance_map_type; + typedef std::map instance_map_type; typedef AIThreadSafeSimpleDC threadsafe_instance_map_type; typedef AIAccess instance_map_rat; typedef AIAccess instance_map_wat; - static threadsafe_instance_map_type sInstanceMap; // Map of PerHostRequestQueue instances with the hostname as key. + static threadsafe_instance_map_type sInstanceMap; // Map of AIPerHostRequestQueue instances with the hostname as key. - friend class AIThreadSafeSimpleDC; //threadsafe_PerHostRequestQueue - PerHostRequestQueue(void) : mAdded(0) { } + friend class AIThreadSafeSimpleDC; //threadsafe_PerHostRequestQueue + AIPerHostRequestQueue(void) : mAdded(0) { } public: typedef instance_map_type::iterator iterator; typedef instance_map_type::const_iterator const_iterator; // Return (possibly create) a unique instance for the given hostname. - static PerHostRequestQueuePtr instance(std::string const& hostname); + static AIPerHostRequestQueuePtr instance(std::string const& hostname); // Release instance (object will be deleted if this was the last instance). - static void release(PerHostRequestQueuePtr& instance); + static void release(AIPerHostRequestQueuePtr& instance); // Remove everything. Called upon viewer exit. static void purge(void); private: - typedef std::deque queued_request_type; + typedef std::deque queued_request_type; int mAdded; // Number of active easy handles with this host. queued_request_type mQueuedRequests; // Waiting (throttled) requests. - static LLAtomicS32 sTotalQueued; // The sum of mQueuedRequests.size() of all PerHostRequestQueue objects together. + static LLAtomicS32 sTotalQueued; // The sum of mQueuedRequests.size() of all AIPerHostRequestQueue objects together. public: void added_to_multi_handle(void); // Called when an easy handle for this host has been added to the multi handle. @@ -110,7 +116,8 @@ class PerHostRequestQueue { void queue(AICurlEasyRequest const& easy_request); // Add easy_request to the queue. bool cancel(AICurlEasyRequest const& easy_request); // Remove easy_request from the queue (if it's there). - void add_queued_to(curlthread::MultiHandle* mh); // Add queued easy handle (if any) to the multi handle. The request is removed from the queue, + void add_queued_to(AICurlPrivate::curlthread::MultiHandle* mh); + // Add queued easy handle (if any) to the multi handle. The request is removed from the queue, // followed by either a call to added_to_multi_handle() or to queue() to add it back. S32 host_queued_plus_added_size(void) const { return mQueuedRequests.size() + mAdded; } @@ -118,16 +125,18 @@ class PerHostRequestQueue { private: // Disallow copying. - PerHostRequestQueue(PerHostRequestQueue const&) { } + AIPerHostRequestQueue(AIPerHostRequestQueue const&) { } }; +namespace AICurlPrivate { + class RefCountedThreadSafePerHostRequestQueue : public threadsafe_PerHostRequestQueue { public: RefCountedThreadSafePerHostRequestQueue(void) : mReferenceCount(0) { } bool exactly_two_left(void) const { return mReferenceCount == 2; } private: - // Used by PerHostRequestQueuePtr. Object is deleted when reference count reaches zero. + // Used by AIPerHostRequestQueuePtr. Object is deleted when reference count reaches zero. LLAtomicU32 mReferenceCount; friend void intrusive_ptr_add_ref(RefCountedThreadSafePerHostRequestQueue* p); diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index cfd4b5d91..9d8d51fb0 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -305,7 +305,7 @@ class CurlEasyRequest : public CurlEasyHandle { AIHTTPTimeoutPolicy const* mTimeoutPolicy; std::string mLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url. - PerHostRequestQueuePtr mPerHostPtr; // Pointer to the corresponding PerHostRequestQueue. + AIPerHostRequestQueuePtr mPerHostPtr; // Pointer to the corresponding AIPerHostRequestQueue. LLPointer mTimeout;// Timeout administration object associated with last created CurlSocketInfo. bool mTimeoutIsOrphan; // Set to true when mTimeout is not (yet) associated with a CurlSocketInfo. #if defined(CWDEBUG) || defined(DEBUG_CURLIO) @@ -348,8 +348,8 @@ class CurlEasyRequest : public CurlEasyHandle { inline ThreadSafeBufferedCurlEasyRequest const* get_lockobj(void) const; // PerHost API. - PerHostRequestQueuePtr getPerHostPtr(void); // (Optionally create and) return a pointer to the unique - // PerHostRequestQueue corresponding to mLowercaseHostname. + AIPerHostRequestQueuePtr getPerHostPtr(void); // (Optionally create and) return a pointer to the unique + // AIPerHostRequestQueue corresponding to mLowercaseHostname. bool removeFromPerHostQueue(AICurlEasyRequest const&) const; // Remove this request from the per-host queue, if queued at all. // Returns true if it was queued. protected: diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 336993da5..6ed1b19b7 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -1573,7 +1573,7 @@ void AICurlThread::run(void) multi_handle_w->check_msg_queue(); } // Clear the queued requests. - PerHostRequestQueue::purge(); + AIPerHostRequestQueue::purge(); } AICurlMultiHandle::destroyInstance(); } @@ -1700,7 +1700,7 @@ static U32 curl_max_total_concurrent_connections = 32; // Initialized on st void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request) { bool throttled = true; // Default. - PerHostRequestQueuePtr per_host; + AIPerHostRequestQueuePtr per_host; { AICurlEasyRequest_wat curl_easy_request_w(*easy_request); per_host = curl_easy_request_w->getPerHostPtr(); @@ -1759,7 +1759,7 @@ CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command) { CURLMcode res; - PerHostRequestQueuePtr per_host; + AIPerHostRequestQueuePtr per_host; { AICurlEasyRequest_wat curl_easy_request_w(**iter); res = curl_easy_request_w->remove_handle_from_multi(curl_easy_request_w, mMultiHandle); diff --git a/indra/llmessage/aicurlthread.h b/indra/llmessage/aicurlthread.h index 44105eefa..4c96b790c 100644 --- a/indra/llmessage/aicurlthread.h +++ b/indra/llmessage/aicurlthread.h @@ -81,7 +81,7 @@ class MultiHandle : public CurlMultiHandle // Store result and trigger events for easy request. void finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result); // Remove easy request at iter (must exist). - // Note that it's possible that a new request from a PerHostRequestQueue::mQueuedRequests is inserted before iter. + // Note that it's possible that a new request from a AIPerHostRequestQueue::mQueuedRequests is inserted before iter. CURLMcode remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command); static int socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp);