* Add documentation

* The reason why pending downloads tick ever upwards is because missing assets are never signalled to the TextureSender
* Rectifying this is not straightfoward, but this will constitute the next patch.
* This does not explain the memory leak.
ThreadPoolClientBranch
Justin Clarke Casey 2008-02-19 23:42:30 +00:00
parent 9a8c19d67b
commit 48e085c774
3 changed files with 112 additions and 16 deletions

View File

@ -49,8 +49,14 @@ namespace OpenSim.Region.Environment.Modules
private Scene m_scene;
private List<Scene> m_scenes = new List<Scene>();
/// <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>();
/// <summary>
/// Each user has their own texture download queue.
/// </summary>
private readonly Dictionary<LLUUID, UserTextureDownloadService> m_userTextureServices =
new Dictionary<LLUUID, UserTextureDownloadService>();
@ -80,13 +86,17 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Cleanup the texture service related objects for the removed presence.
/// </summary>
/// <param name="agentId"> </param>
private void EventManager_OnRemovePresence(LLUUID agentId)
{
UserTextureDownloadService textureService;
lock (m_userTextureServices)
{
if( m_userTextureServices.TryGetValue( agentId, out textureService ))
if (m_userTextureServices.TryGetValue(agentId, out textureService))
{
textureService.Close();
@ -118,6 +128,12 @@ namespace OpenSim.Region.Environment.Modules
client.OnRequestTexture += TextureRequest;
}
/// <summary>
/// Does this user have a registered texture download service?
/// </summary>
/// <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)
{
lock (m_userTextureServices)
@ -133,6 +149,11 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Start the process of requesting a given texture.
/// </summary>
/// <param name="sender"> </param>
/// <param name="e"></param>
public void TextureRequest(Object sender, TextureRequestArgs e)
{
IClientAPI client = (IClientAPI) sender;
@ -141,10 +162,12 @@ namespace OpenSim.Region.Environment.Modules
{
textureService.HandleTextureRequest(client, e);
m_scene.AddPendingDownloads(1);
}
}
}
/// <summary>
/// Entry point for the thread dedicated to processing the texture queue.
/// </summary>
public void ProcessTextureSenders()
{
TextureSender sender = null;
@ -179,11 +202,14 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Called when the texture has finished sending.
/// </summary>
/// <param name="sender"></param>
private void TextureSent(TextureSender sender)
{
sender.Sending = false;
m_scene.AddPendingDownloads(-1);
}
}
}

View File

@ -34,36 +34,59 @@ using OpenSim.Framework.Console;
namespace OpenSim.Region.Environment.Modules
{
/// <summary>
/// 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
{
private static readonly log4net.ILog m_log
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Records the number of times texture send has been called.
/// </summary>
public int counter = 0;
/// <summary>
/// Holds the texture asset to send.
/// </summary>
private AssetBase m_asset;
public long DataPointer = 0;
public int NumPackets = 0;
public int PacketCounter = 0;
/// <summary>
/// This is actually the number of extra packets required to send the texture data! We always assume
/// at least one is required.
/// </summary>
private int NumPackets = 0;
/// <summary>
/// Holds the packet number to send next. In this case, each packet is 1000 bytes long and starts
/// at the 600th byte (0th indexed).
/// </summary>
private int PacketCounter = 0;
public bool Cancel = false;
public bool ImageLoaded = false;
public bool Sending = false;
public IClientAPI RequestUser;
public LLUUID RequestedAssetID;
public int RequestedDiscardLevel = -1;
public uint StartPacketNumber = 0;
private IClientAPI RequestUser;
// private int m_sentDiscardLevel = -1;
private int RequestedDiscardLevel = -1;
private uint StartPacketNumber = 0;
public TextureSender(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber)
public TextureSender(IClientAPI client, int discardLevel, uint packetNumber)
{
RequestUser = client;
RequestedAssetID = textureID;
RequestedDiscardLevel = discardLevel;
StartPacketNumber = packetNumber;
}
/// <summary>
/// Load up the texture data to send.
/// </summary>
/// <param name="asset">
/// A <see cref="AssetBase"/>
/// </param>
public void TextureReceived(AssetBase asset)
{
m_asset = asset;
@ -79,6 +102,10 @@ 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>
public bool SendTexturePacket()
{
SendPacket();
@ -91,6 +118,9 @@ namespace OpenSim.Region.Environment.Modules
return false;
}
/// <summary>
/// Sends a texture packet to the client.
/// </summary>
private void SendPacket()
{
if (PacketCounter <= NumPackets)
@ -148,6 +178,12 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Calculate the number of packets that will be required to send the texture loaded into this sender
/// This is actually the number of 1000 byte packets not including an initial 600 byte packet...
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
private int CalculateNumPackets(int length)
{
int numPackets = 0;

View File

@ -35,13 +35,27 @@ using OpenSim.Region.Environment.Scenes;
namespace OpenSim.Region.Environment.Modules
{
/// <summary>
/// This module sets up texture senders in response to client texture requests, and places them on a
/// processing queue once those senders have the appropriate data (i.e. a texture retrieved from the
/// asset cache).
/// </summary>
public class UserTextureDownloadService
{
private static readonly log4net.ILog m_log
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Holds texture senders before they have received the appropriate texture from the asset cache.
/// </summary>
private readonly Dictionary<LLUUID, TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender>();
/// <summary>
/// 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 Scene m_scene;
public UserTextureDownloadService(Scene scene, BlockingQueue<TextureSender> sharedQueue)
@ -50,6 +64,12 @@ namespace OpenSim.Region.Environment.Modules
m_sharedSendersQueue = sharedQueue;
}
/// <summary>
/// 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)
{
TextureSender textureSender;
@ -72,8 +92,9 @@ namespace OpenSim.Region.Environment.Modules
else
{
TextureSender requestHandler =
new TextureSender(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber);
new TextureSender(client, e.DiscardLevel, e.PacketNumber);
m_textureSenders.Add(e.RequestedAssetID, requestHandler);
m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback);
}
}
@ -90,6 +111,12 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// The callback for the asset cache when a texture has been retrieved. This method queues the
/// texture sender for processing.
/// </summary>
/// <param name="textureID"></param>
/// <param name="asset"></param>
public void TextureCallback(LLUUID textureID, AssetBase asset)
{
lock (m_textureSenders)
@ -115,6 +142,10 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Place a ready texture sender on the processing queue.
/// </summary>
/// <param name="textureSender"></param>
private void EnqueueTextureSender(TextureSender textureSender)
{
textureSender.Cancel = false;
@ -127,6 +158,9 @@ namespace OpenSim.Region.Environment.Modules
}
}
/// <summary>
/// Close this module.
/// </summary>
internal void Close()
{
lock (m_textureSenders)