From be483bc697220effb97338531de4357248f5d71f Mon Sep 17 00:00:00 2001 From: MW Date: Wed, 8 Aug 2007 18:55:58 +0000 Subject: Hopefully improved texture downloading (including the speed at which they download), but still a few problems, it seems that the client has a quite short timeout for receiving a texture and if the whole texture isn't sent within this time, the client will request the texture again, With quite small textures this is fine, but it seems that with larger textures we can't send them fast enough and a infinite loop develops where the client keeps requesting a texture and we keep trying to send it, but are never fast enough. So I've for now put code in that so that the server will try to send a texture only once and then after that will ignore future requests from that client for that texture. --- .../Framework/Communications/Cache/AssetCache.cs | 118 +++++++++++++++------ 1 file changed, 83 insertions(+), 35 deletions(-) (limited to 'OpenSim/Framework/Communications') diff --git a/OpenSim/Framework/Communications/Cache/AssetCache.cs b/OpenSim/Framework/Communications/Cache/AssetCache.cs index e4c01b3..ca74724 100644 --- a/OpenSim/Framework/Communications/Cache/AssetCache.cs +++ b/OpenSim/Framework/Communications/Cache/AssetCache.cs @@ -28,12 +28,14 @@ using System; using System.Collections.Generic; +using System.IO; using System.Reflection; using System.Threading; using libsecondlife; using libsecondlife.Packets; using OpenSim.Framework.Interfaces; using OpenSim.Framework.Types; +using OpenSim.Framework.Utilities; namespace OpenSim.Framework.Communications.Caches { @@ -54,9 +56,15 @@ namespace OpenSim.Framework.Communications.Caches public Dictionary RequestedTextures = new Dictionary(); //Textures requested from the asset server public Dictionary SendingTextures = new Dictionary(); + private BlockingQueue QueueTextures = new BlockingQueue(); + + private Dictionary> AvatarRecievedTextures = new Dictionary>(); + private IAssetServer _assetServer; private Thread _assetCacheThread; + private Thread TextureSenderThread; + /// /// /// @@ -71,6 +79,10 @@ namespace OpenSim.Framework.Communications.Caches this._assetCacheThread.IsBackground = true; this._assetCacheThread.Start(); + this.TextureSenderThread = new Thread(new ThreadStart(this.ProcessTextureSenders)); + this.TextureSenderThread.IsBackground = true; + this.TextureSenderThread.Start(); + } public AssetCache(string assetServerDLLName, string assetServerURL, string assetServerKey) @@ -85,6 +97,9 @@ namespace OpenSim.Framework.Communications.Caches this._assetCacheThread.IsBackground = true; this._assetCacheThread.Start(); + this.TextureSenderThread = new Thread(new ThreadStart(this.ProcessTextureSenders)); + this.TextureSenderThread.IsBackground = true; + this.TextureSenderThread.Start(); } /// @@ -165,12 +180,14 @@ namespace OpenSim.Framework.Communications.Caches req = (AssetRequest)this.TextureRequests[i]; if (!this.SendingTextures.ContainsKey(req.ImageInfo.FullID)) { + //Console.WriteLine("new texture to send"); TextureSender sender = new TextureSender(req); - sender.OnComplete += this.TextureSent; + //sender.OnComplete += this.TextureSent; lock (this.SendingTextures) { this.SendingTextures.Add(req.ImageInfo.FullID, sender); } + this.QueueTextures.Enqueue(sender); } } @@ -178,6 +195,25 @@ namespace OpenSim.Framework.Communications.Caches this.TextureRequests.Clear(); } + public void ProcessTextureSenders() + { + while (true) + { + TextureSender sender = this.QueueTextures.Dequeue(); + bool finished = sender.SendTexture(); + if (finished) + { + this.TextureSent(sender); + } + else + { + // Console.WriteLine("readding texture"); + this.QueueTextures.Enqueue(sender); + } + } + + } + /// /// Event handler, called by a TextureSender object to say that texture has been sent /// @@ -189,6 +225,7 @@ namespace OpenSim.Framework.Communications.Caches lock (this.SendingTextures) { this.SendingTextures.Remove(sender.request.ImageInfo.FullID); + this.AvatarRecievedTextures[sender.request.RequestUser.AgentId].Add(sender.request.ImageInfo.FullID); } } } @@ -201,8 +238,10 @@ namespace OpenSim.Framework.Communications.Caches //then add to the correct cache list //then check for waiting requests for this asset/texture (in the Requested lists) //and move those requests into the Requests list. + if (IsTexture) { + // Console.WriteLine("asset recieved from asset server"); TextureImage image = new TextureImage(asset); this.Textures.Add(image.FullID, image); if (this.RequestedTextures.ContainsKey(image.FullID)) @@ -212,7 +251,7 @@ namespace OpenSim.Framework.Communications.Caches if (image.Data.LongLength > 600) { //over 600 bytes so split up file - req.NumPackets = 1 + (int)(image.Data.Length - 600 + 999) / 1000; + req.NumPackets = 1 + (int)(image.Data.Length - 600 ) / 1000; } else { @@ -260,7 +299,7 @@ namespace OpenSim.Framework.Communications.Caches /// public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest) { - LLUUID requestID = null; + LLUUID requestID = null; byte source = 2; if (transferRequest.TransferInfo.SourceType == 2) { @@ -359,7 +398,7 @@ namespace OpenSim.Framework.Communications.Caches else if (req.AssetRequestSource == 3) { Transfer.TransferInfo.Params = req.Params; - // Transfer.TransferInfo.Params = new byte[100]; + // Transfer.TransferInfo.Params = new byte[100]; //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16); } @@ -411,7 +450,7 @@ namespace OpenSim.Framework.Communications.Caches TransferPacket.TransferData.Data = chunk1; TransferPacket.TransferData.Status = 1; req.RequestUser.OutPacket(TransferPacket); - } + } } } @@ -444,8 +483,17 @@ namespace OpenSim.Framework.Communications.Caches /// public void AddTextureRequest(IClientAPI userInfo, LLUUID imageID) { - //Console.WriteLine("texture request for " + imageID.ToStringHyphenated()); + // Console.WriteLine("texture request for " + imageID.ToStringHyphenated()); //check to see if texture is in local cache, if not request from asset server + if(!this.AvatarRecievedTextures.ContainsKey(userInfo.AgentId)) + { + this.AvatarRecievedTextures.Add(userInfo.AgentId, new List()); + } + if(this.AvatarRecievedTextures[userInfo.AgentId].Contains(imageID)) + { + //Console.WriteLine(userInfo.AgentId +" is requesting a image( "+ imageID+" that has already been sent to them"); + return; + } if (!this.Textures.ContainsKey(imageID)) { if (!this.RequestedTextures.ContainsKey(imageID)) @@ -472,7 +520,8 @@ namespace OpenSim.Framework.Communications.Caches if (imag.Data.LongLength > 600) { //over 600 bytes so split up file - req.NumPackets = 1 + (int)(imag.Data.Length - 600 + 999) / 1000; + req.NumPackets = 1 + (int)(imag.Data.Length - 600 ) / 1000; + //Console.WriteLine("texture is " + imag.Data.Length + " which we will send in " +req.NumPackets +" packets"); } else { @@ -582,37 +631,22 @@ namespace OpenSim.Framework.Communications.Caches public class TextureSender { public AssetRequest request; - public event DownloadComplete OnComplete; - Thread m_thread; + public TextureSender(AssetRequest req) { request = req; - //Console.WriteLine("creating worker thread for texture " + req.ImageInfo.FullID.ToStringHyphenated()); - //Console.WriteLine("texture data length is " + req.ImageInfo.Data.Length); - // Console.WriteLine("in " + req.NumPackets + " packets"); - //ThreadPool.QueueUserWorkItem(new WaitCallback(SendTexture), new object()); - - //need some sort of custom threadpool here, as using the .net one, overloads it and stops the handling of incoming packets etc - //but don't really want to create a thread for every texture download - m_thread = new Thread(new ThreadStart(SendTexture)); - m_thread.IsBackground = true; - m_thread.Start(); + } - public void SendTexture() + public bool SendTexture() { - //Console.WriteLine("starting to send sending texture " + request.ImageInfo.FullID.ToStringHyphenated()); - while (request.PacketCounter != request.NumPackets) + SendPacket(); + + if ((request.PacketCounter > request.NumPackets) |(request.NumPackets ==1)) { - SendPacket(); - Thread.Sleep(500); - } - - //Console.WriteLine("finished sending texture " + request.ImageInfo.FullID.ToStringHyphenated()); - if (OnComplete != null) - { - OnComplete(this); + return true; } + return false; } public void SendPacket() @@ -643,13 +677,14 @@ namespace OpenSim.Framework.Communications.Caches { //more than one packet so split file up ImageDataPacket im = new ImageDataPacket(); - im.ImageID.Packets = (ushort)req.NumPackets; + im.ImageID.Packets = (ushort)(req.NumPackets); im.ImageID.ID = req.ImageInfo.FullID; im.ImageID.Size = (uint)req.ImageInfo.Data.Length; im.ImageData.Data = new byte[600]; Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600); im.ImageID.Codec = 2; req.RequestUser.OutPacket(im); + //this.SaveAssetToFile("packetheader.dat", im.ImageData.Data); req.PacketCounter++; //req.ImageInfo.last_used = time; //System.Console.WriteLine("sent first packet of texture: @@ -658,23 +693,36 @@ namespace OpenSim.Framework.Communications.Caches } else { - //Console.WriteLine("sending packet" + req.PacketCounter + "for " + req.ImageInfo.FullID.ToStringHyphenated()); + // Console.WriteLine("sending packet" + req.PacketCounter + "for " + req.ImageInfo.FullID.ToStringHyphenated()); //send imagepacket //more than one packet so split file up ImagePacketPacket im = new ImagePacketPacket(); - im.ImageID.Packet = (ushort)req.PacketCounter; + im.ImageID.Packet = (ushort)(req.PacketCounter); im.ImageID.ID = req.ImageInfo.FullID; - int size = req.ImageInfo.Data.Length - 600 - 1000 * (req.PacketCounter - 1); + int size = req.ImageInfo.Data.Length - 600 - (1000 * (req.PacketCounter - 1)); if (size > 1000) size = 1000; im.ImageData.Data = new byte[size]; - Array.Copy(req.ImageInfo.Data, 600 + 1000 * (req.PacketCounter - 1), im.ImageData.Data, 0, size); + Array.Copy(req.ImageInfo.Data, 600 + (1000 * (req.PacketCounter - 1)), im.ImageData.Data, 0, size); req.RequestUser.OutPacket(im); + //if (req.PacketCounter == req.NumPackets) + // { + // this.SaveAssetToFile("packet"+req.PacketCounter+".dat", im.ImageData.Data); + //} req.PacketCounter++; //req.ImageInfo.last_used = time; //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID); } } + + private void SaveAssetToFile(string filename, byte[] data) + { + FileStream fs = File.Create(filename); + BinaryWriter bw = new BinaryWriter(fs); + bw.Write(data); + bw.Close(); + fs.Close(); + } } } } -- cgit v1.1