diff options
author | MW | 2007-08-08 18:55:58 +0000 |
---|---|---|
committer | MW | 2007-08-08 18:55:58 +0000 |
commit | be483bc697220effb97338531de4357248f5d71f (patch) | |
tree | 16fd836878477b4db807789e16ad88c4355f5c45 | |
parent | when teleporting to a non-adjacent region, client was not getting new neighbours (diff) | |
download | opensim-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.cs | 118 |
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 | ||
29 | using System; | 29 | using System; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.IO; | ||
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.Threading; | 33 | using System.Threading; |
33 | using libsecondlife; | 34 | using libsecondlife; |
34 | using libsecondlife.Packets; | 35 | using libsecondlife.Packets; |
35 | using OpenSim.Framework.Interfaces; | 36 | using OpenSim.Framework.Interfaces; |
36 | using OpenSim.Framework.Types; | 37 | using OpenSim.Framework.Types; |
38 | using OpenSim.Framework.Utilities; | ||
37 | 39 | ||
38 | namespace OpenSim.Framework.Communications.Caches | 40 | namespace 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 | } |