From 0440fe4dccc44c9474c1ee05c506370350b94320 Mon Sep 17 00:00:00 2001
From: Loren Shih <seraph@lindenlab.com>
Date: Wed, 1 Sep 2010 12:02:48 -0400
Subject: [PATCH] VWR-22695 FIXED Adding attachments messaging is inefficient

Single attachment request are now batched up and sent all at once as a single message.
---
 indra/newview/CMakeLists.txt        |   2 +
 indra/newview/llappearancemgr.cpp   |   3 +
 indra/newview/llattachmentsmgr.cpp  | 131 ++++++++++++++++++++++++++++
 indra/newview/llattachmentsmgr.h    |  73 ++++++++++++++++
 indra/newview/llinventorybridge.cpp |  43 +++++----
 5 files changed, 237 insertions(+), 15 deletions(-)
 create mode 100644 indra/newview/llattachmentsmgr.cpp
 create mode 100644 indra/newview/llattachmentsmgr.h

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 630902c48f5..88dfb1a0819 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -82,6 +82,7 @@ set(viewer_SOURCE_FILES
     llappviewerlistener.cpp
     llassetuploadqueue.cpp
     llassetuploadresponders.cpp
+    llattachmentsmgr.cpp
     llaudiosourcevo.cpp
     llavataractions.cpp
     llavatariconctrl.cpp
@@ -604,6 +605,7 @@ set(viewer_HEADER_FILES
     llappviewerlistener.h
     llassetuploadqueue.h
     llassetuploadresponders.h
+    llattachmentsmgr.h
     llaudiosourcevo.h
     llavataractions.h
     llavatariconctrl.h
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 7159d89d21d..ed5e8ceee33 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -31,6 +31,7 @@
 #include "llagentcamera.h"
 #include "llagentwearables.h"
 #include "llappearancemgr.h"
+#include "llattachmentsmgr.h"
 #include "llcommandhandler.h"
 #include "lleventtimer.h"
 #include "llgesturemgr.h"
@@ -2644,6 +2645,8 @@ LLAppearanceMgr::LLAppearanceMgr():
 
 	mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(
 			"OutfitOperationsTimeout")));
+
+	gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL);
 }
 
 LLAppearanceMgr::~LLAppearanceMgr()
diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp
new file mode 100644
index 00000000000..c9543988a68
--- /dev/null
+++ b/indra/newview/llattachmentsmgr.cpp
@@ -0,0 +1,131 @@
+/** 
+ * @file llattachmentsmgr.cpp
+ * @brief Manager for initiating attachments changes on the viewer
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llattachmentsmgr.h"
+
+#include "llagent.h"
+#include "llinventorymodel.h"
+#include "lltooldraganddrop.h" // pack_permissions_slam
+#include "llviewerinventory.h"
+#include "llviewerregion.h"
+#include "message.h"
+
+
+LLAttachmentsMgr::LLAttachmentsMgr()
+{
+}
+
+LLAttachmentsMgr::~LLAttachmentsMgr()
+{
+}
+
+void LLAttachmentsMgr::addAttachment(const LLUUID& item_id,
+									 const U8 attachment_pt,
+									 const BOOL add)
+{
+	AttachmentsInfo attachment;
+	attachment.mItemID = item_id;
+	attachment.mAttachmentPt = attachment_pt;
+	attachment.mAdd = add;
+	mPendingAttachments.push_back(attachment);
+}
+
+// static
+void LLAttachmentsMgr::onIdle(void *)
+{
+	LLAttachmentsMgr::instance().onIdle();
+}
+
+void LLAttachmentsMgr::onIdle()
+{
+	S32 obj_count = mPendingAttachments.size();
+	if (obj_count == 0)
+	{
+		return;
+	}
+	
+	// Limit number of packets to send
+	const S32 MAX_PACKETS_TO_SEND = 10;
+	const S32 OBJECTS_PER_PACKET = 4;
+	const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET;
+	if( obj_count > MAX_OBJECTS_TO_SEND )
+	{
+		obj_count = MAX_OBJECTS_TO_SEND;
+	}
+
+	LLUUID compound_msg_id;
+	compound_msg_id.generate();
+	LLMessageSystem* msg = gMessageSystem;
+
+	
+	S32 i = 0;
+	for (attachments_vec_t::const_iterator iter = mPendingAttachments.begin();
+		 iter != mPendingAttachments.end();
+		 ++iter)
+	{
+		if( 0 == (i % OBJECTS_PER_PACKET) )
+		{
+			// Start a new message chunk
+			msg->newMessageFast(_PREHASH_RezMultipleAttachmentsFromInv);
+			msg->nextBlockFast(_PREHASH_AgentData);
+			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+			msg->nextBlockFast(_PREHASH_HeaderData);
+			msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id );
+			msg->addU8Fast(_PREHASH_TotalObjects, obj_count );
+			msg->addBOOLFast(_PREHASH_FirstDetachAll, false );
+		}
+
+		const AttachmentsInfo &attachment = (*iter);
+		LLViewerInventoryItem* item = gInventory.getItem(attachment.mItemID);
+		if (!item)
+		{
+			llinfos << "Attempted to add non-existant item ID:" << attachment.mItemID << llendl;
+			continue;
+		}
+		S32 attachment_pt = attachment.mAttachmentPt;
+		if (attachment.mAdd) 
+			attachment_pt |= ATTACHMENT_ADD;
+
+		msg->nextBlockFast(_PREHASH_ObjectData );
+		msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
+		msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
+		msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);
+		pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
+		msg->addStringFast(_PREHASH_Name, item->getName());
+		msg->addStringFast(_PREHASH_Description, item->getDescription());
+
+		if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) )
+		{
+			// End of message chunk
+			msg->sendReliable( gAgent.getRegion()->getHost() );
+		}
+		i++;
+	}
+
+	mPendingAttachments.clear();
+}
diff --git a/indra/newview/llattachmentsmgr.h b/indra/newview/llattachmentsmgr.h
new file mode 100644
index 00000000000..1d8ab74dfd9
--- /dev/null
+++ b/indra/newview/llattachmentsmgr.h
@@ -0,0 +1,73 @@
+/** 
+ * @file llattachmentsmgr.h
+ * @brief Batches up attachment requests and sends them all
+ * in one message.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLATTACHMENTSMGR_H
+#define LL_LLATTACHMENTSMGR_H
+
+#include "llsingleton.h"
+
+class LLViewerInventoryItem;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLAttachmentsMgr
+// 
+// The sole purpose of this class is to take attachment
+// requests, queue them up, and send them all at once.
+// This handles situations where the viewer may request
+// a bunch of attachments at once in a short period of
+// time, where each of the requests would normally be
+// sent as a separate message versus being batched into
+// one single message.
+// 
+// The intent of this batching is to reduce viewer->server
+// traffic.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLAttachmentsMgr: public LLSingleton<LLAttachmentsMgr>
+{
+public:
+	LLAttachmentsMgr();
+	virtual ~LLAttachmentsMgr();
+
+	void addAttachment(const LLUUID& item_id,
+					   const U8 attachment_pt,
+					   const BOOL add);
+	static void onIdle(void *);
+protected:
+	void onIdle();
+private:
+	struct AttachmentsInfo
+	{
+		LLUUID mItemID;
+		U8 mAttachmentPt;
+		BOOL mAdd;
+	};
+
+	typedef std::vector<AttachmentsInfo> attachments_vec_t;
+	attachments_vec_t mPendingAttachments;
+};
+
+#endif
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index aff0bc40997..d7a5d4356db 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -34,6 +34,7 @@
 #include "llagentcamera.h"
 #include "llagentwearables.h"
 #include "llappearancemgr.h"
+#include "llattachmentsmgr.h"
 #include "llavataractions.h"
 #include "llfloateropenobject.h"
 #include "llfloaterreg.h"
@@ -4062,22 +4063,34 @@ bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& respon
 
 		if (itemp)
 		{
-			U8 attachment_pt = notification["payload"]["attachment_point"].asInteger();
-			
+			/*
+			{
+				U8 attachment_pt = notification["payload"]["attachment_point"].asInteger();
+				
+				LLMessageSystem* msg = gMessageSystem;
+				msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv);
+				msg->nextBlockFast(_PREHASH_AgentData);
+				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+				msg->nextBlockFast(_PREHASH_ObjectData);
+				msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID());
+				msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner());
+				msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);
+				pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions());
+				msg->addStringFast(_PREHASH_Name, itemp->getName());
+				msg->addStringFast(_PREHASH_Description, itemp->getDescription());
+				msg->sendReliable(gAgent.getRegion()->getHost());
+				return false;
+			}
+			*/
 
-			LLMessageSystem* msg = gMessageSystem;
-			msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv);
-			msg->nextBlockFast(_PREHASH_AgentData);
-			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-			msg->nextBlockFast(_PREHASH_ObjectData);
-			msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID());
-			msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner());
-			msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);
-			pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions());
-			msg->addStringFast(_PREHASH_Name, itemp->getName());
-			msg->addStringFast(_PREHASH_Description, itemp->getDescription());
-			msg->sendReliable(gAgent.getRegion()->getHost());
+			// Queue up attachments to be sent in next idle tick, this way the
+			// attachments are batched up all into one message versus each attachment
+			// being sent in its own separate attachments message.
+			U8 attachment_pt = notification["payload"]["attachment_point"].asInteger();
+			LLAttachmentsMgr::instance().addAttachment(item_id,
+													   attachment_pt,
+													   FALSE);
 		}
 	}
 	return false;
-- 
GitLab