From b98bc258f23c3497a5c0605d1be56d44a058be88 Mon Sep 17 00:00:00 2001
From: andreykproductengine <none@none>
Date: Wed, 12 Oct 2016 20:18:05 +0300
Subject: MAINT-6487 Viewer Objects should not queue too many downloads

---
 indra/llmessage/llxfer.cpp        |  2 +-
 indra/llmessage/llxfermanager.cpp | 38 ++++++++++++++++++++++++++++++++------
 indra/llmessage/llxfermanager.h   |  3 ++-
 indra/newview/llviewerobject.cpp  | 39 ++++++++++++++++++++++++++-------------
 indra/newview/llviewerobject.h    | 13 +++++++++++--
 5 files changed, 72 insertions(+), 23 deletions(-)

(limited to 'indra')

diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp
index 4aba5cae72..e0590dfdff 100644
--- a/indra/llmessage/llxfer.cpp
+++ b/indra/llmessage/llxfer.cpp
@@ -294,7 +294,7 @@ S32 LLXfer::processEOF()
 	}
 	else
 	{
-		LL_INFOS() << "xfer from " << mRemoteHost << " failed, code "
+		LL_INFOS() << "xfer from " << mRemoteHost << " failed or aborted, code "
 				<< mCallbackResult << ": " << getFileName() << LL_ENDL;
 	}
 
diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp
index 0ab67b8dda..58d3ee47a1 100644
--- a/indra/llmessage/llxfermanager.cpp
+++ b/indra/llmessage/llxfermanager.cpp
@@ -401,7 +401,7 @@ U64 LLXferManager::registerXfer(const void *datap, const S32 length)
 
 ///////////////////////////////////////////////////////////
 
-void LLXferManager::requestFile(const std::string& local_filename,
+U64 LLXferManager::requestFile(const std::string& local_filename,
 								const std::string& remote_filename,
 								ELLPath remote_path,
 								const LLHost& remote_host,
@@ -424,10 +424,12 @@ void LLXferManager::requestFile(const std::string& local_filename,
 
 		{
 			// cout << "requested a xfer already in progress" << endl;
-			return;
+			return xferp->mID;
 		}
 	}
 
+	U64 xfer_id = 0;
+
 	S32 chunk_size = use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1;
 	xferp = (LLXfer *) new LLXfer_File(chunk_size);
 	if (xferp)
@@ -438,13 +440,15 @@ void LLXferManager::requestFile(const std::string& local_filename,
 		// around.
 		// Note: according to AaronB, this is here to deal with locks on files that were
 		// in transit during a crash,
-		if(delete_remote_on_completion &&
-		   (remote_filename.substr(remote_filename.length()-4) == ".tmp"))
+		if( delete_remote_on_completion
+			&& (remote_filename.substr(remote_filename.length()-4) == ".tmp")
+			&& gDirUtilp->fileExists(local_filename))
 		{
 			LLFile::remove(local_filename);
 		}
+		xfer_id = getNextID();
 		((LLXfer_File *)xferp)->initializeRequest(
-			getNextID(),
+			xfer_id,
 			local_filename,
 			remote_filename,
 			remote_path,
@@ -457,6 +461,7 @@ void LLXferManager::requestFile(const std::string& local_filename,
 	{
 		LL_ERRS() << "Xfer allocation error" << LL_ENDL;
 	}
+	return xfer_id;
 }
 
 void LLXferManager::requestFile(const std::string& remote_filename,
@@ -616,7 +621,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user
 	if (!xferp) 
 	{
 		char U64_BUF[MAX_STRING];		/* Flawfinder : ignore */
-		LL_WARNS() << "received xfer data from " << mesgsys->getSender()
+		LL_INFOS() << "received xfer data from " << mesgsys->getSender()
 			<< " for non-existent xfer id: "
 			<< U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << LL_ENDL;
 		return;
@@ -1103,6 +1108,27 @@ void LLXferManager::retransmitUnackedPackets ()
 	}
 }
 
+///////////////////////////////////////////////////////////
+
+void LLXferManager::abortRequestById(U64 xfer_id, S32 result_code)
+{
+	LLXfer * xferp = findXfer(xfer_id, mReceiveList);
+	if (xferp)
+	{
+		if (xferp->mStatus == e_LL_XFER_IN_PROGRESS)
+		{
+			// causes processAbort();
+			xferp->abort(result_code);
+		}
+		else
+		{
+			xferp->mCallbackResult = result_code;
+			xferp->processEOF(); //should norify requestor
+			removeXfer(xferp, &mReceiveList);
+			startPendingDownloads();
+		}
+	}
+}
 
 ///////////////////////////////////////////////////////////
 
diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h
index b3d110e7a1..d258f0a5ce 100644
--- a/indra/llmessage/llxfermanager.h
+++ b/indra/llmessage/llxfermanager.h
@@ -140,7 +140,7 @@ class LLXferManager
 
 // file requesting routines
 // .. to file
-	virtual void requestFile(const std::string& local_filename,
+	virtual U64 requestFile(const std::string& local_filename,
 							 const std::string& remote_filename,
 							 ELLPath remote_path,
 							 const LLHost& remote_host,
@@ -202,6 +202,7 @@ class LLXferManager
 	virtual void retransmitUnackedPackets ();
 
 // error handling
+	void abortRequestById(U64 xfer_id, S32 result_code);
 	virtual void processAbort (LLMessageSystem *mesgsys, void **user_data);
 };
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 5f4eeaa37b..7964bf1848 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -133,7 +133,6 @@ std::map<std::string, U32> LLViewerObject::sObjectDataMap;
 // JC 3/18/2003
 
 const F32 PHYSICS_TIMESTEP = 1.f / 45.f;
-const F64 INV_REQUEST_EXPIRE_TIME_SEC = 60.f;
 
 static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object");
 
@@ -245,9 +244,10 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
 	mPixelArea(1024.f),
 	mInventory(NULL),
 	mInventorySerialNum(0),
-	mRegionp( regionp ),
-	mInvRequestExpireTime(0.f),
+	mInvRequestState(INVENTORY_REQUEST_STOPPED),
+	mInvRequestXFerId(0),
 	mInventoryDirty(FALSE),
+	mRegionp(regionp),
 	mDead(FALSE),
 	mOrphaned(FALSE),
 	mUserSelected(FALSE),
@@ -2843,11 +2843,7 @@ void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener)
 
 BOOL LLViewerObject::isInventoryPending()
 {
-    if (mInvRequestExpireTime == 0.f || mInvRequestExpireTime < LLFrameTimer::getTotalSeconds())
-    {
-        return FALSE;
-    }
-    return TRUE;
+    return mInvRequestState != INVENTORY_REQUEST_STOPPED;
 }
 
 void LLViewerObject::clearInventoryListeners()
@@ -2888,7 +2884,7 @@ void LLViewerObject::requestInventory()
 
 void LLViewerObject::fetchInventoryFromServer()
 {
-	if (mInvRequestExpireTime == 0.f || mInvRequestExpireTime < LLFrameTimer::getTotalSeconds())
+	if (!isInventoryPending())
 	{
 		delete mInventory;
 		LLMessageSystem* msg = gMessageSystem;
@@ -2901,7 +2897,7 @@ void LLViewerObject::fetchInventoryFromServer()
 		msg->sendReliable(mRegionp->getHost());
 
 		// this will get reset by dirtyInventory or doInventoryCallback
-		mInvRequestExpireTime = LLFrameTimer::getTotalSeconds() + INV_REQUEST_EXPIRE_TIME_SEC;
+		mInvRequestState = INVENTORY_REQUEST_PENDING;
 	}
 }
 
@@ -2962,7 +2958,7 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
 	std::string unclean_filename;
 	msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename);
 	ft->mFilename = LLDir::getScrubbedFileName(unclean_filename);
-	
+
 	if(ft->mFilename.empty())
 	{
 		LL_DEBUGS() << "Task has no inventory" << LL_ENDL;
@@ -2984,13 +2980,27 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
 		delete ft;
 		return;
 	}
-	gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), 
+	U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), 
 								ft->mFilename, LL_PATH_CACHE,
 								object->mRegionp->getHost(),
 								TRUE,
 								&LLViewerObject::processTaskInvFile,
 								(void**)ft,
 								LLXferManager::HIGH_PRIORITY);
+	if (object->mInvRequestState == INVENTORY_XFER)
+	{
+		if (new_id > 0 && new_id != object->mInvRequestXFerId)
+		{
+			// we started new download.
+			gXferManager->abortRequestById(object->mInvRequestXFerId, -1);
+			object->mInvRequestXFerId = new_id;
+		}
+	}
+	else
+	{
+		object->mInvRequestState = INVENTORY_XFER;
+		object->mInvRequestXFerId = new_id;
+	}
 }
 
 void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status)
@@ -3117,7 +3127,10 @@ void LLViewerObject::doInventoryCallback()
 			mInventoryCallbacks.erase(curiter);
 		}
 	}
-	mInvRequestExpireTime = 0.f;
+
+	// release inventory loading state
+	mInvRequestXFerId = 0;
+	mInvRequestState = INVENTORY_REQUEST_STOPPED;
 }
 
 void LLViewerObject::removeInventory(const LLUUID& item_id)
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 804b6c147b..1e8f3f4ec2 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -720,6 +720,7 @@ private:
 	void deleteTEImages(); // correctly deletes list of images
 	
 protected:
+
 	typedef std::map<char *, LLNameValue *> name_value_map_t;
 	name_value_map_t mNameValuePairs;	// Any name-value pairs stored by script
 
@@ -756,9 +757,17 @@ protected:
 	callback_list_t mInventoryCallbacks;
 	S16 mInventorySerialNum;
 
+	enum EInventoryRequestState
+	{
+		INVENTORY_REQUEST_STOPPED,
+		INVENTORY_REQUEST_PENDING,
+		INVENTORY_XFER
+	};
+	EInventoryRequestState	mInvRequestState;
+	U64						mInvRequestXFerId;
+	BOOL					mInventoryDirty;
+
 	LLViewerRegion	*mRegionp;					// Region that this object belongs to.
-	F64				mInvRequestExpireTime;
-	BOOL			mInventoryDirty;
 	BOOL			mDead;
 	BOOL			mOrphaned;					// This is an orphaned child
 	BOOL			mUserSelected;				// Cached user select information
-- 
cgit v1.2.3