From 693492a3f1f495cab879c33a8449ef522a280c60 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 1 Mar 2020 21:45:28 +0000 Subject: [PATCH] several changes to lludp FetchInventoryDescendents --- OpenSim/Framework/IClientAPI.cs | 4 +- .../ClientStack/Linden/UDP/LLClientView.cs | 13 +-- .../Framework/Scenes/Scene.Inventory.cs | 54 ++++++----- .../Framework/Scenes/Scene.PacketHandlers.cs | 93 ++++++++----------- .../OptionalModules/World/NPC/NPCAvatar.cs | 1 + OpenSim/Tests/Common/Mock/TestClient.cs | 1 + 6 files changed, 78 insertions(+), 88 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index cf5c2559ea..cea9f7d5bc 100755 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -1207,8 +1207,8 @@ namespace OpenSim.Framework void FlushPrimUpdates(); void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, - List folders, int version, bool fetchFolders, - bool fetchItems); + List folders, int version, int descendents, + bool fetchFolders, bool fetchItems); void SendInventoryItemDetails(InventoryItemBase[] items); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index e87f6db0c6..780e7c8096 100755 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -2318,7 +2318,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Do we need to send folder information? /// Do we need to send item information? public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, - List folders, int version, + List folders, int version, int descendents, bool fetchFolders, bool fetchItems) { // An inventory descendents packet consists of a single agent section and an inventory details @@ -2339,7 +2339,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Handle empty folders // if (totalItems == 0 && totalFolders == 0) - currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, 0, 0); + currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, descendents, 0, 0); // To preserve SL compatibility, we will NOT combine folders and items in one packet // @@ -2358,7 +2358,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP itemsToSend = MAX_ITEMS_PER_PACKET; } - currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, foldersToSend, itemsToSend); + currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, descendents, foldersToSend, itemsToSend); } if (foldersToSend-- > 0) @@ -10190,9 +10190,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (Fetch.AgentData.SessionID != SessionId || Fetch.AgentData.AgentID != AgentId) return; - OnFetchInventoryDescendents?.Invoke(this, Fetch.InventoryData.FolderID, Fetch.InventoryData.OwnerID, - Fetch.InventoryData.FetchFolders, Fetch.InventoryData.FetchItems, - Fetch.InventoryData.SortOrder); + FetchInventoryDescendentsPacket.InventoryDataBlock data = Fetch.InventoryData; + OnFetchInventoryDescendents?.Invoke(this, data.FolderID, data.OwnerID, + data.FetchFolders, data.FetchItems, + data.SortOrder); } private void HandlePurgeInventoryDescendents(Packet Pack) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index debcad373d..30118be98c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1586,9 +1586,11 @@ namespace OpenSim.Region.Framework.Scenes { if ((fold = LibraryService.LibraryRootFolder.FindFolder(folder.ID)) != null) { + List its = fold.RequestListOfItems(); + List fds = fold.RequestListOfFolders(); client.SendInventoryFolderDetails( - fold.Owner, folder.ID, fold.RequestListOfItems(), - fold.RequestListOfFolders(), fold.Version, fetchFolders, fetchItems); + fold.Owner, folder.ID, its, fds, + fold.Version, its.Count + fds.Count, fetchFolders, fetchItems); return; } } @@ -1602,37 +1604,41 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[AGENT INVENTORY]: Sending inventory folder contents ({0} nodes) for \"{1}\" to {2} {3}", // contents.Folders.Count + contents.Items.Count, containingFolder.Name, client.FirstName, client.LastName); - if (containingFolder != null) + if (containingFolder != null ) { - // If the folder requested contains links, then we need to send those folders first, otherwise the links - // will be broken in the viewer. - HashSet linkedItemFolderIdsToSend = new HashSet(); - foreach (InventoryItemBase item in contents.Items) - { - if (item.AssetType == (int)AssetType.Link) - { - InventoryItemBase linkedItem = InventoryService.GetItem(client.AgentId, item.AssetID); + int descendents = contents.Folders.Count + contents.Items.Count; - // Take care of genuinely broken links where the target doesn't exist - // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, - // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles - // rather than having to keep track of every folder requested in the recursion. - if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) + if(fetchItems && contents.Items.Count > 0) + { + var linksIDs = new HashSet(); + var links = new List(); + for (int i = 0; i < contents.Items.Count; ++i) + { + InventoryItemBase item = contents.Items[i]; + if (item.AssetType == (int)AssetType.Link) { - // We don't need to send the folder if source and destination of the link are in the same - // folder. - if (linkedItem.Folder != containingFolder.ID) - linkedItemFolderIdsToSend.Add(linkedItem.Folder); + UUID linkid = item.AssetID; + if(linksIDs.Contains(linkid)) + continue; + + InventoryItemBase linkedItem = InventoryService.GetItem(item.Owner, linkid); + if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link && linkedItem.AssetType != (int)AssetType.LinkFolder) + { + links.Add(linkedItem); + linksIDs.Add(linkedItem.ID); + } } } + if(links.Count > 0) + { + links.AddRange(contents.Items); + contents.Items = links; + } } - foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) - SendInventoryUpdate(client, new InventoryFolderBase(linkedItemFolderId), false, true); - client.SendInventoryFolderDetails( client.AgentId, folder.ID, contents.Items, contents.Folders, - containingFolder.Version, fetchFolders, fetchItems); + containingFolder.Version, descendents, fetchFolders, fetchItems); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index 2a3285187c..ccbe1627df 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Threading; using OpenMetaverse; using OpenMetaverse.Packets; @@ -504,15 +505,15 @@ namespace OpenSim.Region.Framework.Scenes { public IClientAPI RemoteClient; public UUID FolderID; - public UUID OwnerID; + //public UUID OwnerID; public bool FetchFolders; public bool FetchItems; - public int SortOrder; + //public int SortOrder; } - private Queue m_descendentsRequestQueue = new Queue(); - private Object m_descendentsRequestLock = new Object(); - private bool m_descendentsRequestProcessing = false; + static private ConcurrentQueue m_descendentsRequestQueue = new ConcurrentQueue(); + static private Object m_descendentsRequestLock = new Object(); + static private bool m_descendentsRequestProcessing = false; /// /// Tell the client about the various child items and folders contained in the requested folder. @@ -543,74 +544,54 @@ namespace OpenSim.Region.Framework.Scenes { if ((fold = LibraryService.LibraryRootFolder.FindFolder(folderID)) != null) { + List its = fold.RequestListOfItems(); + List fds = fold.RequestListOfFolders(); remoteClient.SendInventoryFolderDetails( - fold.Owner, folderID, fold.RequestListOfItems(), - fold.RequestListOfFolders(), fold.Version, fetchFolders, fetchItems); + fold.Owner, folderID, its, fds, + fold.Version, its.Count + fds.Count, fetchFolders, fetchItems); return; } } - lock (m_descendentsRequestLock) + DescendentsRequestData req = new DescendentsRequestData(); + req.RemoteClient = remoteClient; + req.FolderID = folderID; + //req.OwnerID = ownerID; + req.FetchFolders = fetchFolders; + req.FetchItems = fetchItems; + //req.SortOrder = sortOrder; + + m_descendentsRequestQueue.Enqueue(req); + + if (Monitor.TryEnter(m_descendentsRequestLock)) { if (!m_descendentsRequestProcessing) { m_descendentsRequestProcessing = true; - - // We're going to send the reply async, because there may be - // an enormous quantity of packets -- basically the entire inventory! - // We don't want to block the client thread while all that is happening. - SendInventoryDelegate d = SendInventoryAsync; - d.BeginInvoke(remoteClient, folderID, ownerID, fetchFolders, fetchItems, sortOrder, SendInventoryComplete, d); - - return; + Util.FireAndForget(x => SendInventoryAsync()); } - - DescendentsRequestData req = new DescendentsRequestData(); - req.RemoteClient = remoteClient; - req.FolderID = folderID; - req.OwnerID = ownerID; - req.FetchFolders = fetchFolders; - req.FetchItems = fetchItems; - req.SortOrder = sortOrder; - - m_descendentsRequestQueue.Enqueue(req); + Monitor.Exit(m_descendentsRequestLock); } } - delegate void SendInventoryDelegate(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder); - - void SendInventoryAsync(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder) + void SendInventoryAsync() { - try + lock(m_descendentsRequestLock) { - SendInventoryUpdate(remoteClient, new InventoryFolderBase(folderID), fetchFolders, fetchItems); - } - catch (Exception e) - { - m_log.Error( - string.Format( - "[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e, folderID)); - } - Thread.Sleep(20); - } - - void SendInventoryComplete(IAsyncResult iar) - { - SendInventoryDelegate d = (SendInventoryDelegate)iar.AsyncState; - d.EndInvoke(iar); - - lock (m_descendentsRequestLock) - { - if (m_descendentsRequestQueue.Count > 0) + try { - DescendentsRequestData req = m_descendentsRequestQueue.Dequeue(); - - d = SendInventoryAsync; - d.BeginInvoke(req.RemoteClient, req.FolderID, req.OwnerID, req.FetchFolders, req.FetchItems, req.SortOrder, SendInventoryComplete, d); - - return; + while(m_descendentsRequestQueue.TryDequeue(out DescendentsRequestData req)) + { + if(!req.RemoteClient.IsActive) + continue; + SendInventoryUpdate(req.RemoteClient, new InventoryFolderBase(req.FolderID), req.FetchFolders, req.FetchItems); + Thread.Sleep(50); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[AGENT INVENTORY]: Error in SendInventoryAsync(). Exception {0}", e); } - m_descendentsRequestProcessing = false; } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 18f04e8ac3..daad4e7ba7 100755 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -842,6 +842,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC List items, List folders, int version, + int descendents, bool fetchFolders, bool fetchItems) { diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index bc74ccfa74..8c4c5413e0 100755 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -791,6 +791,7 @@ namespace OpenSim.Tests.Common List items, List folders, int version, + int descendents, bool fetchFolders, bool fetchItems) {