diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 7e6fc9236..6b8ac5064 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -977,7 +977,6 @@ void CurlEasyRequest::resetState(void) mTimeoutPolicy = NULL; mTimeout = NULL; mHandleEventsTarget = NULL; - mResult = CURLE_FAILED_INIT; applyDefaultOptions(); } diff --git a/indra/llmessage/aicurlperservice.cpp b/indra/llmessage/aicurlperservice.cpp index a0493f1a3..c99264db8 100644 --- a/indra/llmessage/aicurlperservice.cpp +++ b/indra/llmessage/aicurlperservice.cpp @@ -339,7 +339,7 @@ void AIPerService::added_to_multi_handle(AICapabilityType capability_type) ++mTotalAdded; } -void AIPerService::removed_from_multi_handle(AICapabilityType capability_type, bool downloaded_something) +void AIPerService::removed_from_multi_handle(AICapabilityType capability_type, bool downloaded_something, bool success) { CapabilityType& ct(mCapabilityType[capability_type]); llassert(mTotalAdded > 0 && ct.mAdded > 0); @@ -354,6 +354,10 @@ void AIPerService::removed_from_multi_handle(AICapabilityType capability_type, b { mark_unused(capability_type); } + if (success) + { + ct.mFlags |= ctf_success; + } } // Returns true if the request was queued. diff --git a/indra/llmessage/aicurlperservice.h b/indra/llmessage/aicurlperservice.h index 0509dfd95..f81236997 100644 --- a/indra/llmessage/aicurlperservice.h +++ b/indra/llmessage/aicurlperservice.h @@ -134,6 +134,11 @@ class AIPerService { static U16 const ctf_empty = 1; static U16 const ctf_full = 2; static U16 const ctf_starvation = 4; + // Flags used by the HTTP debug console. + static U16 const ctf_success = 8; + static U16 const ctf_progress_mask = 0x70; + static U16 const ctf_progress_shift = 4; + static U16 const ctf_grey = 0x80; struct CapabilityType { typedef std::deque queued_request_type; @@ -145,6 +150,7 @@ class AIPerService { U16 mFlags; // ctf_empty: Set to true when the queue becomes precisely empty. // ctf_full : Set to true when the queue is popped and then still isn't empty; // ctf_starvation: Set to true when the queue was about to be popped but was already empty. + // ctf_success: Set to true when a curl request finished successfully. U32 mDownloading; // The number of active easy handles with this service for which data was received. U16 mMaxPipelinedRequests; // The maximum number of accepted requests for this service and (approved) capability type, that didn't finish yet. U16 mConcurrentConnections; // The maximum number of allowed concurrent connections to the service of this capability type. @@ -259,7 +265,7 @@ class AIPerService { void added_to_command_queue(AICapabilityType capability_type) { ++mCapabilityType[capability_type].mQueuedCommands; mark_inuse(capability_type); } void removed_from_command_queue(AICapabilityType capability_type) { --mCapabilityType[capability_type].mQueuedCommands; llassert(mCapabilityType[capability_type].mQueuedCommands >= 0); } void added_to_multi_handle(AICapabilityType capability_type); // Called when an easy handle for this service has been added to the multi handle. - void removed_from_multi_handle(AICapabilityType capability_type, bool downloaded_something); // Called when an easy handle for this service is removed again from the multi handle. + void removed_from_multi_handle(AICapabilityType capability_type, bool downloaded_something, bool success); // Called when an easy handle for this service is removed again from the multi handle. void download_started(AICapabilityType capability_type) { ++mCapabilityType[capability_type].mDownloading; } bool throttled(AICapabilityType capability_type) const; // Returns true if the maximum number of allowed requests for this service/capability type have been added to the multi handle. bool nothing_added(AICapabilityType capability_type) const { return mCapabilityType[capability_type].mAdded == 0; } diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 70c4d5a37..f6f971516 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -1647,7 +1647,7 @@ MultiHandle::~MultiHandle() // Curl demands that all handles are removed from the multi session handle before calling curl_multi_cleanup. for(addedEasyRequests_type::iterator iter = mAddedEasyRequests.begin(); iter != mAddedEasyRequests.end(); iter = mAddedEasyRequests.begin()) { - finish_easy_request(*iter, CURLE_OK); // Error code is not used anyway. + finish_easy_request(*iter, CURLE_GOT_NOTHING); // Error code is not used anyway. remove_easy_request(*iter); } delete mWritePollSet; @@ -1848,7 +1848,9 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons res = curl_easy_request_w->remove_handle_from_multi(curl_easy_request_w, mMultiHandle); capability_type = curl_easy_request_w->capability_type(); per_service = curl_easy_request_w->getPerServicePtr(); - PerService_wat(*per_service)->removed_from_multi_handle(capability_type, downloaded_something); // (About to be) removed from mAddedEasyRequests. + CURLcode code; + curl_easy_request_w->getResult(&code, NULL); + PerService_wat(*per_service)->removed_from_multi_handle(capability_type, downloaded_something, code == CURLE_OK); // (About to be) removed from mAddedEasyRequests. #ifdef SHOW_ASSERT curl_easy_request_w->mRemovedPerCommand = as_per_command; #endif @@ -2200,7 +2202,7 @@ void BufferedCurlEasyRequest::update_body_bandwidth(void) mTotalRawBytes = total_raw_bytes; // Note that in some cases (like HTTP_PARTIAL_CONTENT), the output of CURLINFO_SIZE_DOWNLOAD lags // behind and will return 0 the first time, and the value of the previous chunk the next time. - // The last call from MultiHandle::finish_easy_request recorrects this, in that case. + // The last call from MultiHandle::finish_easy_request corrects this, in that case. if (raw_bytes > 0) { U64 const sTime_40ms = curlthread::HTTPTimeout::sTime_10ms >> 2; @@ -2800,7 +2802,7 @@ AIPerService::Approvement* AIPerService::approveHTTPRequestFor(AIPerServicePtr c equal = pipelined_requests_per_capability_type == ct.mMaxPipelinedRequests; increment_threshold = ct.mFlags & ctf_starvation; decrement_threshold = (ct.mFlags & (ctf_empty | ctf_full)) == ctf_full; - ct.mFlags = 0; + ct.mFlags &= ~(ctf_empty|ctf_full|ctf_starvation); if (decrement_threshold) { if ((int)ct.mMaxPipelinedRequests > ct.mConcurrentConnections) diff --git a/indra/newview/aihttpview.cpp b/indra/newview/aihttpview.cpp index 86849575f..60e9fc4e6 100644 --- a/indra/newview/aihttpview.cpp +++ b/indra/newview/aihttpview.cpp @@ -76,7 +76,7 @@ void AIServiceBar::draw() LLFontGL::getFontMonospace()->renderUTF8(mName, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); start += LLFontGL::getFontMonospace()->getWidth(mName); std::string text; - AIPerService::CapabilityType const* cts; + AIPerService::CapabilityType* cts; U32 is_used; U32 is_inuse; int total_added; @@ -94,20 +94,52 @@ void AIServiceBar::draw() for (int col = 0; col < number_of_capability_types; ++col) { AICapabilityType capability_type = static_cast(col); - AIPerService::CapabilityType const& ct(cts[capability_type]); + AIPerService::CapabilityType& ct(cts[capability_type]); start = mHTTPView->updateColumn(col, start); U32 mask = AIPerService::CT2mask(capability_type); if (!(is_used & mask)) { text = " | "; } - else if (col < 2) - { - text = llformat(" | %hu-%hu-%lu,{%hu/%hu,%u}/%u", ct.mApprovedRequests, ct.mQueuedCommands, ct.mQueuedRequests.size(), ct.mAdded, ct.mConcurrentConnections, ct.mDownloading, ct.mMaxPipelinedRequests); - } else { - text = llformat(" | --%hu-%lu,{%hu/%hu,%u}", ct.mQueuedCommands, ct.mQueuedRequests.size(), ct.mAdded, ct.mConcurrentConnections, ct.mDownloading); + if (col < 2) + { + text = llformat(" | %hu-%hu-%lu,{%hu/%hu,%u}/%u", + ct.mApprovedRequests, ct.mQueuedCommands, ct.mQueuedRequests.size(), + ct.mAdded, ct.mConcurrentConnections, ct.mDownloading, + ct.mMaxPipelinedRequests); + } + else + { + text = llformat(" | --%hu-%lu,{%hu/%hu,%u}", + ct.mQueuedCommands, ct.mQueuedRequests.size(), + ct.mAdded, ct.mConcurrentConnections, ct.mDownloading); + } + if (capability_type == cap_texture || capability_type == cap_mesh) + { + if (!(is_inuse & mask)) + { + ct.mFlags |= AIPerService::ctf_grey; + } + else + { + bool show = true; + int progress_counter = (ct.mFlags & AIPerService::ctf_progress_mask) >> AIPerService::ctf_progress_shift; + if ((ct.mFlags & AIPerService::ctf_success)) + { + show = !(ct.mFlags & AIPerService::ctf_grey); + ct.mFlags &= ~(AIPerService::ctf_success|AIPerService::ctf_grey|AIPerService::ctf_progress_mask); + progress_counter = (progress_counter + 1) % 8; + ct.mFlags |= progress_counter << AIPerService::ctf_progress_shift; + } + if (show) + { + static char const* progress_utf8[8] = { " \xe2\xac\x93", " \xe2\xac\x95", " \xe2\x97\xa7", " \xe2\x97\xa9", " \xe2\xac\x92", " \xe2\xac\x94", " \xe2\x97\xa8", " \xe2\x97\xaa" }; + text += progress_utf8[progress_counter]; + } + } + } } LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, ((is_inuse & mask) == 0) ? LLColor4::grey2 : text_color, LLFontGL::LEFT, LLFontGL::TOP); start += LLFontGL::getFontMonospace()->getWidth(text); @@ -174,7 +206,7 @@ void AIGLHTTPHeaderBar::draw(void) // First header line. F32 height = v_offset + sLineHeight * number_of_header_lines; - text = "HTTP console -- [approved]-commandQ-curlQ,{added/max,downloading}[/max]"; + text = "HTTP console -- [approved]-commandQ-curlQ,{added/max,downloading}[/max][ completed]"; LLFontGL::getFontMonospace()->renderUTF8(text, 0, h_offset, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); text = " | Added/Max"; U32 start = mHTTPView->updateColumn(mc_col, 100);