aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorMW2007-08-08 18:55:58 +0000
committerMW2007-08-08 18:55:58 +0000
commitbe483bc697220effb97338531de4357248f5d71f (patch)
tree16fd836878477b4db807789e16ad88c4355f5c45
parentwhen teleporting to a non-adjacent region, client was not getting new neighbours (diff)
downloadopensim-SC-be483bc697220effb97338531de4357248f5d71f.zip
opensim-SC-be483bc697220effb97338531de4357248f5d71f.tar.gz
opensim-SC-be483bc697220effb97338531de4357248f5d71f.tar.bz2
opensim-SC-be483bc697220effb97338531de4357248f5d71f.tar.xz
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.
-rw-r--r--OpenSim/Framework/Communications/Cache/AssetCache.cs118
1 files changed, 83 insertions, 35 deletions
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 @@
28 28
29using System; 29using System;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.IO;
31using System.Reflection; 32using System.Reflection;
32using System.Threading; 33using System.Threading;
33using libsecondlife; 34using libsecondlife;
34using libsecondlife.Packets; 35using libsecondlife.Packets;
35using OpenSim.Framework.Interfaces; 36using OpenSim.Framework.Interfaces;
36using OpenSim.Framework.Types; 37using OpenSim.Framework.Types;
38using OpenSim.Framework.Utilities;
37 39
38namespace OpenSim.Framework.Communications.Caches 40namespace OpenSim.Framework.Communications.Caches
39{ 41{
@@ -54,9 +56,15 @@ namespace OpenSim.Framework.Communications.Caches
54 public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>(); //Textures requested from the asset server 56 public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>(); //Textures requested from the asset server
55 57
56 public Dictionary<LLUUID, TextureSender> SendingTextures = new Dictionary<LLUUID, TextureSender>(); 58 public Dictionary<LLUUID, TextureSender> SendingTextures = new Dictionary<LLUUID, TextureSender>();
59 private BlockingQueue<TextureSender> QueueTextures = new BlockingQueue<TextureSender>();
60
61 private Dictionary<LLUUID, List<LLUUID>> AvatarRecievedTextures = new Dictionary<LLUUID,List<LLUUID>>();
62
57 private IAssetServer _assetServer; 63 private IAssetServer _assetServer;
58 private Thread _assetCacheThread; 64 private Thread _assetCacheThread;
59 65
66 private Thread TextureSenderThread;
67
60 /// <summary> 68 /// <summary>
61 /// 69 ///
62 /// </summary> 70 /// </summary>
@@ -71,6 +79,10 @@ namespace OpenSim.Framework.Communications.Caches
71 this._assetCacheThread.IsBackground = true; 79 this._assetCacheThread.IsBackground = true;
72 this._assetCacheThread.Start(); 80 this._assetCacheThread.Start();
73 81
82 this.TextureSenderThread = new Thread(new ThreadStart(this.ProcessTextureSenders));
83 this.TextureSenderThread.IsBackground = true;
84 this.TextureSenderThread.Start();
85
74 } 86 }
75 87
76 public AssetCache(string assetServerDLLName, string assetServerURL, string assetServerKey) 88 public AssetCache(string assetServerDLLName, string assetServerURL, string assetServerKey)
@@ -85,6 +97,9 @@ namespace OpenSim.Framework.Communications.Caches
85 this._assetCacheThread.IsBackground = true; 97 this._assetCacheThread.IsBackground = true;
86 this._assetCacheThread.Start(); 98 this._assetCacheThread.Start();
87 99
100 this.TextureSenderThread = new Thread(new ThreadStart(this.ProcessTextureSenders));
101 this.TextureSenderThread.IsBackground = true;
102 this.TextureSenderThread.Start();
88 } 103 }
89 104
90 /// <summary> 105 /// <summary>
@@ -165,12 +180,14 @@ namespace OpenSim.Framework.Communications.Caches
165 req = (AssetRequest)this.TextureRequests[i]; 180 req = (AssetRequest)this.TextureRequests[i];
166 if (!this.SendingTextures.ContainsKey(req.ImageInfo.FullID)) 181 if (!this.SendingTextures.ContainsKey(req.ImageInfo.FullID))
167 { 182 {
183 //Console.WriteLine("new texture to send");
168 TextureSender sender = new TextureSender(req); 184 TextureSender sender = new TextureSender(req);
169 sender.OnComplete += this.TextureSent; 185 //sender.OnComplete += this.TextureSent;
170 lock (this.SendingTextures) 186 lock (this.SendingTextures)
171 { 187 {
172 this.SendingTextures.Add(req.ImageInfo.FullID, sender); 188 this.SendingTextures.Add(req.ImageInfo.FullID, sender);
173 } 189 }
190 this.QueueTextures.Enqueue(sender);
174 } 191 }
175 192
176 } 193 }
@@ -178,6 +195,25 @@ namespace OpenSim.Framework.Communications.Caches
178 this.TextureRequests.Clear(); 195 this.TextureRequests.Clear();
179 } 196 }
180 197
198 public void ProcessTextureSenders()
199 {
200 while (true)
201 {
202 TextureSender sender = this.QueueTextures.Dequeue();
203 bool finished = sender.SendTexture();
204 if (finished)
205 {
206 this.TextureSent(sender);
207 }
208 else
209 {
210 // Console.WriteLine("readding texture");
211 this.QueueTextures.Enqueue(sender);
212 }
213 }
214
215 }
216
181 /// <summary> 217 /// <summary>
182 /// Event handler, called by a TextureSender object to say that texture has been sent 218 /// Event handler, called by a TextureSender object to say that texture has been sent
183 /// </summary> 219 /// </summary>
@@ -189,6 +225,7 @@ namespace OpenSim.Framework.Communications.Caches
189 lock (this.SendingTextures) 225 lock (this.SendingTextures)
190 { 226 {
191 this.SendingTextures.Remove(sender.request.ImageInfo.FullID); 227 this.SendingTextures.Remove(sender.request.ImageInfo.FullID);
228 this.AvatarRecievedTextures[sender.request.RequestUser.AgentId].Add(sender.request.ImageInfo.FullID);
192 } 229 }
193 } 230 }
194 } 231 }
@@ -201,8 +238,10 @@ namespace OpenSim.Framework.Communications.Caches
201 //then add to the correct cache list 238 //then add to the correct cache list
202 //then check for waiting requests for this asset/texture (in the Requested lists) 239 //then check for waiting requests for this asset/texture (in the Requested lists)
203 //and move those requests into the Requests list. 240 //and move those requests into the Requests list.
241
204 if (IsTexture) 242 if (IsTexture)
205 { 243 {
244 // Console.WriteLine("asset recieved from asset server");
206 TextureImage image = new TextureImage(asset); 245 TextureImage image = new TextureImage(asset);
207 this.Textures.Add(image.FullID, image); 246 this.Textures.Add(image.FullID, image);
208 if (this.RequestedTextures.ContainsKey(image.FullID)) 247 if (this.RequestedTextures.ContainsKey(image.FullID))
@@ -212,7 +251,7 @@ namespace OpenSim.Framework.Communications.Caches
212 if (image.Data.LongLength > 600) 251 if (image.Data.LongLength > 600)
213 { 252 {
214 //over 600 bytes so split up file 253 //over 600 bytes so split up file
215 req.NumPackets = 1 + (int)(image.Data.Length - 600 + 999) / 1000; 254 req.NumPackets = 1 + (int)(image.Data.Length - 600 ) / 1000;
216 } 255 }
217 else 256 else
218 { 257 {
@@ -260,7 +299,7 @@ namespace OpenSim.Framework.Communications.Caches
260 /// <param name="transferRequest"></param> 299 /// <param name="transferRequest"></param>
261 public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest) 300 public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest)
262 { 301 {
263 LLUUID requestID = null; 302 LLUUID requestID = null;
264 byte source = 2; 303 byte source = 2;
265 if (transferRequest.TransferInfo.SourceType == 2) 304 if (transferRequest.TransferInfo.SourceType == 2)
266 { 305 {
@@ -359,7 +398,7 @@ namespace OpenSim.Framework.Communications.Caches
359 else if (req.AssetRequestSource == 3) 398 else if (req.AssetRequestSource == 3)
360 { 399 {
361 Transfer.TransferInfo.Params = req.Params; 400 Transfer.TransferInfo.Params = req.Params;
362 // Transfer.TransferInfo.Params = new byte[100]; 401 // Transfer.TransferInfo.Params = new byte[100];
363 //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); 402 //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
364 //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16); 403 //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16);
365 } 404 }
@@ -411,7 +450,7 @@ namespace OpenSim.Framework.Communications.Caches
411 TransferPacket.TransferData.Data = chunk1; 450 TransferPacket.TransferData.Data = chunk1;
412 TransferPacket.TransferData.Status = 1; 451 TransferPacket.TransferData.Status = 1;
413 req.RequestUser.OutPacket(TransferPacket); 452 req.RequestUser.OutPacket(TransferPacket);
414 } 453 }
415 } 454 }
416 455
417 } 456 }
@@ -444,8 +483,17 @@ namespace OpenSim.Framework.Communications.Caches
444 /// <param name="imageID"></param> 483 /// <param name="imageID"></param>
445 public void AddTextureRequest(IClientAPI userInfo, LLUUID imageID) 484 public void AddTextureRequest(IClientAPI userInfo, LLUUID imageID)
446 { 485 {
447 //Console.WriteLine("texture request for " + imageID.ToStringHyphenated()); 486 // Console.WriteLine("texture request for " + imageID.ToStringHyphenated());
448 //check to see if texture is in local cache, if not request from asset server 487 //check to see if texture is in local cache, if not request from asset server
488 if(!this.AvatarRecievedTextures.ContainsKey(userInfo.AgentId))
489 {
490 this.AvatarRecievedTextures.Add(userInfo.AgentId, new List<LLUUID>());
491 }
492 if(this.AvatarRecievedTextures[userInfo.AgentId].Contains(imageID))
493 {
494 //Console.WriteLine(userInfo.AgentId +" is requesting a image( "+ imageID+" that has already been sent to them");
495 return;
496 }
449 if (!this.Textures.ContainsKey(imageID)) 497 if (!this.Textures.ContainsKey(imageID))
450 { 498 {
451 if (!this.RequestedTextures.ContainsKey(imageID)) 499 if (!this.RequestedTextures.ContainsKey(imageID))
@@ -472,7 +520,8 @@ namespace OpenSim.Framework.Communications.Caches
472 if (imag.Data.LongLength > 600) 520 if (imag.Data.LongLength > 600)
473 { 521 {
474 //over 600 bytes so split up file 522 //over 600 bytes so split up file
475 req.NumPackets = 1 + (int)(imag.Data.Length - 600 + 999) / 1000; 523 req.NumPackets = 1 + (int)(imag.Data.Length - 600 ) / 1000;
524 //Console.WriteLine("texture is " + imag.Data.Length + " which we will send in " +req.NumPackets +" packets");
476 } 525 }
477 else 526 else
478 { 527 {
@@ -582,37 +631,22 @@ namespace OpenSim.Framework.Communications.Caches
582 public class TextureSender 631 public class TextureSender
583 { 632 {
584 public AssetRequest request; 633 public AssetRequest request;
585 public event DownloadComplete OnComplete; 634
586 Thread m_thread;
587 public TextureSender(AssetRequest req) 635 public TextureSender(AssetRequest req)
588 { 636 {
589 request = req; 637 request = req;
590 //Console.WriteLine("creating worker thread for texture " + req.ImageInfo.FullID.ToStringHyphenated()); 638
591 //Console.WriteLine("texture data length is " + req.ImageInfo.Data.Length);
592 // Console.WriteLine("in " + req.NumPackets + " packets");
593 //ThreadPool.QueueUserWorkItem(new WaitCallback(SendTexture), new object());
594
595 //need some sort of custom threadpool here, as using the .net one, overloads it and stops the handling of incoming packets etc
596 //but don't really want to create a thread for every texture download
597 m_thread = new Thread(new ThreadStart(SendTexture));
598 m_thread.IsBackground = true;
599 m_thread.Start();
600 } 639 }
601 640
602 public void SendTexture() 641 public bool SendTexture()
603 { 642 {
604 //Console.WriteLine("starting to send sending texture " + request.ImageInfo.FullID.ToStringHyphenated()); 643 SendPacket();
605 while (request.PacketCounter != request.NumPackets) 644
645 if ((request.PacketCounter > request.NumPackets) |(request.NumPackets ==1))
606 { 646 {
607 SendPacket(); 647 return true;
608 Thread.Sleep(500);
609 }
610
611 //Console.WriteLine("finished sending texture " + request.ImageInfo.FullID.ToStringHyphenated());
612 if (OnComplete != null)
613 {
614 OnComplete(this);
615 } 648 }
649 return false;
616 } 650 }
617 651
618 public void SendPacket() 652 public void SendPacket()
@@ -643,13 +677,14 @@ namespace OpenSim.Framework.Communications.Caches
643 { 677 {
644 //more than one packet so split file up 678 //more than one packet so split file up
645 ImageDataPacket im = new ImageDataPacket(); 679 ImageDataPacket im = new ImageDataPacket();
646 im.ImageID.Packets = (ushort)req.NumPackets; 680 im.ImageID.Packets = (ushort)(req.NumPackets);
647 im.ImageID.ID = req.ImageInfo.FullID; 681 im.ImageID.ID = req.ImageInfo.FullID;
648 im.ImageID.Size = (uint)req.ImageInfo.Data.Length; 682 im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
649 im.ImageData.Data = new byte[600]; 683 im.ImageData.Data = new byte[600];
650 Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600); 684 Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600);
651 im.ImageID.Codec = 2; 685 im.ImageID.Codec = 2;
652 req.RequestUser.OutPacket(im); 686 req.RequestUser.OutPacket(im);
687 //this.SaveAssetToFile("packetheader.dat", im.ImageData.Data);
653 req.PacketCounter++; 688 req.PacketCounter++;
654 //req.ImageInfo.last_used = time; 689 //req.ImageInfo.last_used = time;
655 //System.Console.WriteLine("sent first packet of texture: 690 //System.Console.WriteLine("sent first packet of texture:
@@ -658,23 +693,36 @@ namespace OpenSim.Framework.Communications.Caches
658 } 693 }
659 else 694 else
660 { 695 {
661 //Console.WriteLine("sending packet" + req.PacketCounter + "for " + req.ImageInfo.FullID.ToStringHyphenated()); 696 // Console.WriteLine("sending packet" + req.PacketCounter + "for " + req.ImageInfo.FullID.ToStringHyphenated());
662 //send imagepacket 697 //send imagepacket
663 //more than one packet so split file up 698 //more than one packet so split file up
664 ImagePacketPacket im = new ImagePacketPacket(); 699 ImagePacketPacket im = new ImagePacketPacket();
665 im.ImageID.Packet = (ushort)req.PacketCounter; 700 im.ImageID.Packet = (ushort)(req.PacketCounter);
666 im.ImageID.ID = req.ImageInfo.FullID; 701 im.ImageID.ID = req.ImageInfo.FullID;
667 int size = req.ImageInfo.Data.Length - 600 - 1000 * (req.PacketCounter - 1); 702 int size = req.ImageInfo.Data.Length - 600 - (1000 * (req.PacketCounter - 1));
668 if (size > 1000) size = 1000; 703 if (size > 1000) size = 1000;
669 im.ImageData.Data = new byte[size]; 704 im.ImageData.Data = new byte[size];
670 Array.Copy(req.ImageInfo.Data, 600 + 1000 * (req.PacketCounter - 1), im.ImageData.Data, 0, size); 705 Array.Copy(req.ImageInfo.Data, 600 + (1000 * (req.PacketCounter - 1)), im.ImageData.Data, 0, size);
671 req.RequestUser.OutPacket(im); 706 req.RequestUser.OutPacket(im);
707 //if (req.PacketCounter == req.NumPackets)
708 // {
709 // this.SaveAssetToFile("packet"+req.PacketCounter+".dat", im.ImageData.Data);
710 //}
672 req.PacketCounter++; 711 req.PacketCounter++;
673 //req.ImageInfo.last_used = time; 712 //req.ImageInfo.last_used = time;
674 //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID); 713 //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID);
675 } 714 }
676 715
677 } 716 }
717
718 private void SaveAssetToFile(string filename, byte[] data)
719 {
720 FileStream fs = File.Create(filename);
721 BinaryWriter bw = new BinaryWriter(fs);
722 bw.Write(data);
723 bw.Close();
724 fs.Close();
725 }
678 } 726 }
679 } 727 }
680} 728}