* 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
This commit is contained in:
Justin Clarke Casey
2008-02-25 23:26:35 +00:00
parent dbb205c181
commit 65862aacea
6 changed files with 203 additions and 55 deletions

View File

@@ -52,7 +52,8 @@ namespace OpenSim.Region.Environment.Modules
/// <summary>
/// There is one queue for all textures waiting to be sent, regardless of the requesting user.
/// </summary>
private readonly BlockingQueue<TextureSender> m_queueSenders = new BlockingQueue<TextureSender>();
private readonly BlockingQueue<ITextureSender> m_queueSenders
= new BlockingQueue<ITextureSender>();
/// <summary>
/// Each user has their own texture download service.
@@ -135,17 +136,19 @@ namespace OpenSim.Region.Environment.Modules
/// <param name="userID"></param>
/// <param name="textureService"></param>
/// <returns>Always returns true, since a service is created if one does not already exist</returns>
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
/// </summary>
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.
/// </summary>
/// <param name="sender"></param>
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);

View File

@@ -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
{
/// <summary>
/// Sends a 'texture not found' packet back to the client
/// </summary>
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;
}
}
}

View File

@@ -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.
/// </summary>
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
/// </summary>
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;
}
/// <summary>
/// Send a texture packet to the client.
/// </summary>
/// <returns>True if the last packet has been sent, false otherwise.</returns>
// 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;
}

View File

@@ -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.
/// </summary>
private readonly BlockingQueue<TextureSender> m_sharedSendersQueue;
private readonly BlockingQueue<ITextureSender> m_sharedSendersQueue;
private readonly Scene m_scene;
private readonly IClientAPI m_client;
public UserTextureDownloadService(Scene scene, BlockingQueue<TextureSender> sharedQueue)
public UserTextureDownloadService(
IClientAPI client, Scene scene, BlockingQueue<ITextureSender> 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.
/// </summary>
/// <param name="client"> </param>
/// <param name="e"></param>
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
/// <param name="texture"></param>
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.
/// </summary>
/// <param name="textureSender"></param>
private void EnqueueTextureSender(TextureSender textureSender)
private void EnqueueTextureSender(ITextureSender textureSender)
{
textureSender.Cancel = false;
textureSender.Sending = true;
textureSender.counter = 0;
if (!m_sharedSendersQueue.Contains(textureSender))
{