From 65862aaceadc69218895e07b5d547266b12916a9 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Mon, 25 Feb 2008 23:26:35 +0000 Subject: * Start sending "ImageNotFound" packet back to the client if we can't find an image * This might stop some client's constant requests for unfound textures, which is a candidate for the memory leak * If a texture is not found then the "Image not found" texture will now be displayed clientside * If it works, this should resolve mantis 676 * Non texture image requests do not receive this packet yet * This will require a prebuild --- .../Environment/Interfaces/ITextureSender.cs | 61 ++++++++++++++++++ .../Environment/Modules/TextureDownloadModule.cs | 22 ++++--- .../Environment/Modules/TextureNotFoundSender.cs | 75 ++++++++++++++++++++++ .../Region/Environment/Modules/TextureSender.cs | 33 +++++++--- .../Modules/UserTextureDownloadService.cs | 35 ++++++---- 5 files changed, 195 insertions(+), 31 deletions(-) create mode 100644 OpenSim/Region/Environment/Interfaces/ITextureSender.cs create mode 100644 OpenSim/Region/Environment/Modules/TextureNotFoundSender.cs (limited to 'OpenSim/Region/Environment') diff --git a/OpenSim/Region/Environment/Interfaces/ITextureSender.cs b/OpenSim/Region/Environment/Interfaces/ITextureSender.cs new file mode 100644 index 0000000..6ea08d0 --- /dev/null +++ b/OpenSim/Region/Environment/Interfaces/ITextureSender.cs @@ -0,0 +1,61 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +using System; + +namespace OpenSim.Region.Environment.Interfaces +{ + /// + /// Interface for an object which can send texture information to a client + /// + public interface ITextureSender + { + /// + /// Are we in the process of sending the texture? + /// + bool Sending { get; set; } + + /// + /// Has the texture send been cancelled? + /// + bool Cancel { get; set; } + + /// + /// Update the non data properties of a texture request + /// + /// + /// + void UpdateRequest(int discardLevel, uint packetNumber); + + /// + /// Send a texture packet to the client. + /// + /// True if the last packet has been sent, false otherwise. + bool SendTexturePacket(); + } +} diff --git a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs index c773f9e..2b2ac42 100644 --- a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs +++ b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs @@ -52,7 +52,8 @@ namespace OpenSim.Region.Environment.Modules /// /// There is one queue for all textures waiting to be sent, regardless of the requesting user. /// - private readonly BlockingQueue m_queueSenders = new BlockingQueue(); + private readonly BlockingQueue m_queueSenders + = new BlockingQueue(); /// /// Each user has their own texture download service. @@ -135,17 +136,19 @@ namespace OpenSim.Region.Environment.Modules /// /// /// Always returns true, since a service is created if one does not already exist - private bool TryGetUserTextureService(LLUUID userID, out UserTextureDownloadService textureService) + private bool TryGetUserTextureService( + IClientAPI client, out UserTextureDownloadService textureService) { lock (m_userTextureServices) { - if (m_userTextureServices.TryGetValue(userID, out textureService)) + if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) { return true; } - textureService = new UserTextureDownloadService(m_scene, m_queueSenders); - m_userTextureServices.Add(userID, textureService); + textureService = new UserTextureDownloadService(client, m_scene, m_queueSenders); + m_userTextureServices.Add(client.AgentId, textureService); + return true; } } @@ -159,9 +162,10 @@ namespace OpenSim.Region.Environment.Modules { IClientAPI client = (IClientAPI) sender; UserTextureDownloadService textureService; - if (TryGetUserTextureService(client.AgentId, out textureService)) + + if (TryGetUserTextureService(client, out textureService)) { - textureService.HandleTextureRequest(client, e); + textureService.HandleTextureRequest(e); } } @@ -170,7 +174,7 @@ namespace OpenSim.Region.Environment.Modules /// public void ProcessTextureSenders() { - TextureSender sender = null; + ITextureSender sender = null; while (true) { @@ -206,7 +210,7 @@ namespace OpenSim.Region.Environment.Modules /// Called when the texture has finished sending. /// /// - private void TextureSent(TextureSender sender) + private void TextureSent(ITextureSender sender) { sender.Sending = false; //m_log.DebugFormat("[TEXTURE DOWNLOAD]: Removing download stat for {0}", sender.assetID); diff --git a/OpenSim/Region/Environment/Modules/TextureNotFoundSender.cs b/OpenSim/Region/Environment/Modules/TextureNotFoundSender.cs new file mode 100644 index 0000000..f85e900 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/TextureNotFoundSender.cs @@ -0,0 +1,75 @@ +/* + * Created by SharpDevelop. + * User: caseyj + * Date: 25/02/2008 + * Time: 21:30 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System; + +using libsecondlife; +using libsecondlife.Packets; + +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; + +namespace OpenSim.Region.Environment.Modules +{ + /// + /// Sends a 'texture not found' packet back to the client + /// + public class TextureNotFoundSender : ITextureSender + { + //private static readonly log4net.ILog m_log + // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private LLUUID m_textureId; + private IClientAPI m_client; + + // See ITextureSender + public bool Sending + { + get { return false; } + set { m_sending = value; } + } + + private bool m_sending = false; + + // See ITextureSender + public bool Cancel + { + get { return false; } + set { m_cancel = value; } + } + + private bool m_cancel = false; + + public TextureNotFoundSender(IClientAPI client, LLUUID textureID) + { + m_client = client; + m_textureId = textureID; + } + + // See ITextureSender + public void UpdateRequest(int discardLevel, uint packetNumber) + { + // Not need to implement since priority changes don't affect this operation + } + + // See ITextureSender + public bool SendTexturePacket() + { + //m_log.InfoFormat( + // "[TEXTURE NOT FOUND SENDER]: Informing the client that texture {0} cannot be found", + // m_textureId); + + ImageNotInDatabasePacket notFound = new ImageNotInDatabasePacket(); + notFound.ImageID.ID = m_textureId; + m_client.OutPacket(notFound, ThrottleOutPacketType.Unknown); + + return true; + } + } +} diff --git a/OpenSim/Region/Environment/Modules/TextureSender.cs b/OpenSim/Region/Environment/Modules/TextureSender.cs index 056b8e1..3d097c8 100644 --- a/OpenSim/Region/Environment/Modules/TextureSender.cs +++ b/OpenSim/Region/Environment/Modules/TextureSender.cs @@ -31,6 +31,7 @@ using libsecondlife; using libsecondlife.Packets; using OpenSim.Framework; using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; namespace OpenSim.Region.Environment.Modules { @@ -38,7 +39,7 @@ namespace OpenSim.Region.Environment.Modules /// A TextureSender handles the process of receiving a texture requested by the client from the /// AssetCache, and then sending that texture back to the client. /// - public class TextureSender + public class TextureSender : ITextureSender { private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); @@ -67,9 +68,25 @@ namespace OpenSim.Region.Environment.Modules /// private int PacketCounter = 0; - public bool Cancel = false; + // See ITextureSender + public bool Cancel + { + get { return false; } + set { m_cancel = value; } + } + + private bool m_cancel = false; + + // See ITextureSender + public bool Sending + { + get { return false; } + set { m_sending = value; } + } + + private bool m_sending = false; + public bool ImageLoaded = false; - public bool Sending = false; private IClientAPI RequestUser; @@ -97,6 +114,7 @@ namespace OpenSim.Region.Environment.Modules ImageLoaded = true; } + // See ITextureSender public void UpdateRequest(int discardLevel, uint packetNumber) { RequestedDiscardLevel = discardLevel; @@ -104,12 +122,11 @@ namespace OpenSim.Region.Environment.Modules PacketCounter = (int) StartPacketNumber; } - /// - /// Send a texture packet to the client. - /// - /// True if the last packet has been sent, false otherwise. + // See ITextureSender public bool SendTexturePacket() { + //m_log.DebugFormat("[TEXTURE SENDER]: Sending packet for {0}", m_asset.FullID); + SendPacket(); counter++; if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || @@ -170,7 +187,7 @@ namespace OpenSim.Region.Environment.Modules } catch (ArgumentOutOfRangeException) { - m_log.Error("[TEXTURE]: Unable to separate texture into multiple packets: Array bounds failure on asset:" + + m_log.Error("[TEXTURE SENDER]: Unable to separate texture into multiple packets: Array bounds failure on asset:" + m_asset.FullID.ToString() ); return; } diff --git a/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs b/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs index 8987a19..77829f0 100644 --- a/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs +++ b/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs @@ -28,9 +28,13 @@ using System; using System.Collections.Generic; + using libsecondlife; +using libsecondlife.Packets; + using OpenSim.Framework; using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Scenes; namespace OpenSim.Region.Environment.Modules @@ -54,12 +58,16 @@ namespace OpenSim.Region.Environment.Modules /// Texture Senders are placed in this queue once they have received their texture from the asset /// cache. Another module actually invokes the send. /// - private readonly BlockingQueue m_sharedSendersQueue; + private readonly BlockingQueue m_sharedSendersQueue; private readonly Scene m_scene; + + private readonly IClientAPI m_client; - public UserTextureDownloadService(Scene scene, BlockingQueue sharedQueue) + public UserTextureDownloadService( + IClientAPI client, Scene scene, BlockingQueue sharedQueue) { + m_client = client; m_scene = scene; m_sharedSendersQueue = sharedQueue; } @@ -68,9 +76,8 @@ namespace OpenSim.Region.Environment.Modules /// Handle a texture request. This involves creating a texture sender and placing it on the /// previously passed in shared queue. /// - /// /// - public void HandleTextureRequest(IClientAPI client, TextureRequestArgs e) + public void HandleTextureRequest(TextureRequestArgs e) { TextureSender textureSender; @@ -91,7 +98,7 @@ namespace OpenSim.Region.Environment.Modules m_scene.AddPendingDownloads(1); TextureSender requestHandler = - new TextureSender(client, e.DiscardLevel, e.PacketNumber); + new TextureSender(m_client, e.DiscardLevel, e.PacketNumber); m_textureSenders.Add(e.RequestedAssetID, requestHandler); m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback, true); @@ -118,6 +125,8 @@ namespace OpenSim.Region.Environment.Modules /// public void TextureCallback(LLUUID textureID, AssetBase texture) { + //m_log.DebugFormat("[USER TEXTURE DOWNLOAD SERVICE]: Calling TextureCallback with {0}, texture == null is {1}", textureID, (texture == null ? true : false)); + lock (m_textureSenders) { TextureSender textureSender; @@ -129,13 +138,12 @@ namespace OpenSim.Region.Environment.Modules // Needs investigation. if (texture == null || texture.Data == null) { - // Right now, leaving it up to lower level asset server code to post the fact that - // this texture could not be found - - // TODO Send packet back to the client telling it not to expect the texture - - //m_log.DebugFormat("[USER TEXTURE DOWNLOAD]: Removing download stat for {0}", textureID); - m_scene.AddPendingDownloads(-1); + m_log.DebugFormat( + "[USER TEXTURE DOWNLOAD SERVICE]: Queueing TextureNotFoundSender for {0}", + textureID); + + ITextureSender textureNotFoundSender = new TextureNotFoundSender(m_client, textureID); + EnqueueTextureSender(textureNotFoundSender); } else { @@ -163,11 +171,10 @@ namespace OpenSim.Region.Environment.Modules /// Place a ready texture sender on the processing queue. /// /// - private void EnqueueTextureSender(TextureSender textureSender) + private void EnqueueTextureSender(ITextureSender textureSender) { textureSender.Cancel = false; textureSender.Sending = true; - textureSender.counter = 0; if (!m_sharedSendersQueue.Contains(textureSender)) { -- cgit v1.1