* Moves sending items to inventory via a delete into a seperate thread (this thread can be expanded to support all sends to inventory from inworld easily enough). Thread is temporary and only exists while items are being returned.

* This should remove the "lag" caused by deleting many objects.
* Patch brought to you by Joshua Nightshade's bitching at me to fix it.
0.6.0-stable
Adam Frisby 2008-07-06 02:27:10 +00:00
parent fd69251bcd
commit 55dda82180
1 changed files with 175 additions and 95 deletions

View File

@ -29,6 +29,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Timers;
using libsecondlife; using libsecondlife;
using libsecondlife.Packets; using libsecondlife.Packets;
using log4net; using log4net;
@ -38,8 +39,20 @@ using OpenSim.Region.Environment.Interfaces;
namespace OpenSim.Region.Environment.Scenes namespace OpenSim.Region.Environment.Scenes
{ {
class DeleteToInventoryHolder
{
public DeRezObjectPacket DeRezPacket;
public EntityBase selectedEnt;
public IClientAPI remoteClient;
public SceneObjectGroup objectGroup;
public LLUUID folderID;
}
public partial class Scene public partial class Scene
{ {
private Timer m_inventoryTicker;
private readonly Queue<DeleteToInventoryHolder> m_inventoryDeletes = new Queue<DeleteToInventoryHolder>();
private static readonly ILog m_log private static readonly ILog m_log
= LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@ -1395,7 +1408,7 @@ namespace OpenSim.Region.Environment.Scenes
/// Called when an object is removed from the environment into inventory. /// Called when an object is removed from the environment into inventory.
/// </summary> /// </summary>
/// <param name="packet"></param> /// <param name="packet"></param>
/// <param name="simClient"></param> /// <param name="remoteClient"></param>
public virtual void DeRezObject(Packet packet, IClientAPI remoteClient) public virtual void DeRezObject(Packet packet, IClientAPI remoteClient)
{ {
DeRezObjectPacket DeRezPacket = (DeRezObjectPacket) packet; DeRezObjectPacket DeRezPacket = (DeRezObjectPacket) packet;
@ -1453,12 +1466,84 @@ namespace OpenSim.Region.Environment.Scenes
if (permissionToTake) if (permissionToTake)
{ {
string sceneObjectXml = objectGroup.ToXmlString(); if (m_inventoryTicker != null)
CachedUserInfo userInfo =
CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
if (userInfo != null)
{ {
m_inventoryTicker.Stop();
}
else
{
m_inventoryTicker = new Timer(2000);
m_inventoryTicker.AutoReset = false;
m_inventoryTicker.Elapsed += InventoryRunDeleteTimer;
}
lock(m_inventoryDeletes)
{
DeleteToInventoryHolder dtis = new DeleteToInventoryHolder();
dtis.DeRezPacket = DeRezPacket;
dtis.folderID = folderID;
dtis.objectGroup = objectGroup;
dtis.remoteClient = remoteClient;
dtis.selectedEnt = selectedEnt;
m_inventoryDeletes.Enqueue(dtis);
}
m_inventoryTicker.Start();
// Visually remove it, even if it isnt really gone yet.
objectGroup.FakeDeleteGroup();
}
else if (permissionToDelete)
{
DeleteSceneObject(objectGroup);
}
}
}
}
void InventoryRunDeleteTimer(object sender, ElapsedEventArgs e)
{
m_log.Info("Starting inventory send loop");
while (InventoryDeQueueAndDelete() == true)
{
m_log.Info("Returned item successfully, continuing...");
}
}
private bool InventoryDeQueueAndDelete()
{
DeleteToInventoryHolder x;
try
{
lock (m_inventoryDeletes)
{
int left = m_inventoryDeletes.Count;
if (left > 0)
{
m_log.InfoFormat("Sending deleted object to user's inventory, {0} item(s) remaining.", left);
x = m_inventoryDeletes.Dequeue();
DeleteToInventory(x.DeRezPacket, x.selectedEnt, x.remoteClient, x.objectGroup, x.folderID);
return true;
}
}
} catch(Exception e)
{
m_log.Error(e.ToString());
}
m_log.Info("No objects left in inventory delete queue.");
return false;
}
private void DeleteToInventory(DeRezObjectPacket DeRezPacket, EntityBase selectedEnt, IClientAPI remoteClient, SceneObjectGroup objectGroup, LLUUID folderID)
{
string sceneObjectXml = objectGroup.ToXmlString();
CachedUserInfo userInfo =
CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
if (userInfo != null)
{
// string searchFolder = ""; // string searchFolder = "";
// if (DeRezPacket.AgentBlock.Destination == 6) // if (DeRezPacket.AgentBlock.Destination == 6)
@ -1466,103 +1551,98 @@ namespace OpenSim.Region.Environment.Scenes
// else if (DeRezPacket.AgentBlock.Destination == 9) // else if (DeRezPacket.AgentBlock.Destination == 9)
// searchFolder = "Lost And Found"; // searchFolder = "Lost And Found";
// If we're deleting someone else's item, it goes back to their deleted items folder // If we're deleting someone else's item, it goes back to their deleted items folder
// If we're returning someone's item, it goes back to the owner's Lost And Found folder. // If we're returning someone's item, it goes back to the owner's Lost And Found folder.
if (DeRezPacket.AgentBlock.DestinationID == LLUUID.Zero || (DeRezPacket.AgentBlock.Destination == 6 && objectGroup.OwnerID != remoteClient.AgentId)) if (DeRezPacket.AgentBlock.DestinationID == LLUUID.Zero || (DeRezPacket.AgentBlock.Destination == 6 && objectGroup.OwnerID != remoteClient.AgentId))
{ {
List<InventoryFolderBase> subrootfolders = userInfo.RootFolder.RequestListOfFolders(); List<InventoryFolderBase> subrootfolders = userInfo.RootFolder.RequestListOfFolders();
foreach (InventoryFolderBase flder in subrootfolders) foreach (InventoryFolderBase flder in subrootfolders)
{ {
if (flder.Name == "Lost And Found") if (flder.Name == "Lost And Found")
{ {
folderID = flder.ID; folderID = flder.ID;
break; break;
}
}
if (folderID == LLUUID.Zero)
{
folderID = userInfo.RootFolder.ID;
}
//currently following code not used (or don't know of any case of destination being zero
}
else
{
folderID = DeRezPacket.AgentBlock.DestinationID;
}
AssetBase asset = CreateAsset(
((SceneObjectGroup) selectedEnt).GetPartName(selectedEnt.LocalId),
((SceneObjectGroup) selectedEnt).GetPartDescription(selectedEnt.LocalId),
(sbyte)AssetType.Object,
Helpers.StringToField(sceneObjectXml));
AssetCache.AddAsset(asset);
InventoryItemBase item = new InventoryItemBase();
item.Creator = objectGroup.RootPart.CreatorID;
if (DeRezPacket.AgentBlock.Destination == 1 || DeRezPacket.AgentBlock.Destination == 4)// Take / Copy
item.Owner = remoteClient.AgentId;
else // Delete / Return
item.Owner = objectGroup.OwnerID;
item.ID = LLUUID.Random();
item.AssetID = asset.FullID;
item.Description = asset.Description;
item.Name = asset.Name;
item.AssetType = asset.Type;
item.InvType = (int)InventoryType.Object;
item.Folder = folderID;
if ((remoteClient.AgentId != objectGroup.RootPart.OwnerID) && ExternalChecks.ExternalChecksPropagatePermissions())
{
uint perms=objectGroup.GetEffectivePermissions();
uint nextPerms=(perms & 7) << 13;
if ((nextPerms & (uint)PermissionMask.Copy) == 0)
perms &= ~(uint)PermissionMask.Copy;
if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
perms &= ~(uint)PermissionMask.Transfer;
if ((nextPerms & (uint)PermissionMask.Modify) == 0)
perms &= ~(uint)PermissionMask.Modify;
item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask;
item.CurrentPermissions = item.BasePermissions;
item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask;
item.CurrentPermissions |= 8; // Slam!
}
else
{
item.BasePermissions = objectGroup.GetEffectivePermissions();
item.CurrentPermissions = objectGroup.GetEffectivePermissions();
item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask;
}
// TODO: add the new fields (Flags, Sale info, etc)
userInfo.AddItem(item);
if (item.Owner == remoteClient.AgentId)
{
remoteClient.SendInventoryItemCreateUpdate(item);
}
else
{
ScenePresence notifyUser = GetScenePresence(item.Owner);
if (notifyUser != null)
{
notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item);
}
}
} }
} }
if (permissionToDelete) if (folderID == LLUUID.Zero)
{ {
DeleteSceneObject(objectGroup); folderID = userInfo.RootFolder.ID;
}
//currently following code not used (or don't know of any case of destination being zero
}
else
{
folderID = DeRezPacket.AgentBlock.DestinationID;
}
AssetBase asset = CreateAsset(
((SceneObjectGroup) selectedEnt).GetPartName(selectedEnt.LocalId),
((SceneObjectGroup) selectedEnt).GetPartDescription(selectedEnt.LocalId),
(sbyte)AssetType.Object,
Helpers.StringToField(sceneObjectXml));
AssetCache.AddAsset(asset);
InventoryItemBase item = new InventoryItemBase();
item.Creator = objectGroup.RootPart.CreatorID;
if (DeRezPacket.AgentBlock.Destination == 1 || DeRezPacket.AgentBlock.Destination == 4)// Take / Copy
item.Owner = remoteClient.AgentId;
else // Delete / Return
item.Owner = objectGroup.OwnerID;
item.ID = LLUUID.Random();
item.AssetID = asset.FullID;
item.Description = asset.Description;
item.Name = asset.Name;
item.AssetType = asset.Type;
item.InvType = (int)InventoryType.Object;
item.Folder = folderID;
if ((remoteClient.AgentId != objectGroup.RootPart.OwnerID) && ExternalChecks.ExternalChecksPropagatePermissions())
{
uint perms=objectGroup.GetEffectivePermissions();
uint nextPerms=(perms & 7) << 13;
if ((nextPerms & (uint)PermissionMask.Copy) == 0)
perms &= ~(uint)PermissionMask.Copy;
if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
perms &= ~(uint)PermissionMask.Transfer;
if ((nextPerms & (uint)PermissionMask.Modify) == 0)
perms &= ~(uint)PermissionMask.Modify;
item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask;
item.CurrentPermissions = item.BasePermissions;
item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask;
item.CurrentPermissions |= 8; // Slam!
}
else
{
item.BasePermissions = objectGroup.GetEffectivePermissions();
item.CurrentPermissions = objectGroup.GetEffectivePermissions();
item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask;
}
// TODO: add the new fields (Flags, Sale info, etc)
userInfo.AddItem(item);
if (item.Owner == remoteClient.AgentId)
{
remoteClient.SendInventoryItemCreateUpdate(item);
}
else
{
ScenePresence notifyUser = GetScenePresence(item.Owner);
if (notifyUser != null)
{
notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item);
} }
} }
} }
// Finally remove the item, for reals this time.
DeleteSceneObject(objectGroup);
} }
public void updateKnownAsset(IClientAPI remoteClient, SceneObjectGroup grp, LLUUID assetID, LLUUID agentID) public void updateKnownAsset(IClientAPI remoteClient, SceneObjectGroup grp, LLUUID assetID, LLUUID agentID)