diff options
author | MW | 2008-02-27 16:20:45 +0000 |
---|---|---|
committer | MW | 2008-02-27 16:20:45 +0000 |
commit | aac7c1dda57bf237abba4dd02bc1a25422d03a35 (patch) | |
tree | 5835b88a41ccf83949921bb489d9766db4a547ec | |
parent | Update svn properties. (diff) | |
download | opensim-SC-aac7c1dda57bf237abba4dd02bc1a25422d03a35.zip opensim-SC-aac7c1dda57bf237abba4dd02bc1a25422d03a35.tar.gz opensim-SC-aac7c1dda57bf237abba4dd02bc1a25422d03a35.tar.bz2 opensim-SC-aac7c1dda57bf237abba4dd02bc1a25422d03a35.tar.xz |
another attempt at fixing asset lockups
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/Communications/Cache/AssetCache.cs | 471 |
1 files changed, 247 insertions, 224 deletions
diff --git a/OpenSim/Framework/Communications/Cache/AssetCache.cs b/OpenSim/Framework/Communications/Cache/AssetCache.cs index 3bd8f5b..061b857 100644 --- a/OpenSim/Framework/Communications/Cache/AssetCache.cs +++ b/OpenSim/Framework/Communications/Cache/AssetCache.cs | |||
@@ -69,12 +69,12 @@ namespace OpenSim.Framework.Communications.Cache | |||
69 | /// | 69 | /// |
70 | /// Assets requests which are waiting for asset server data. This includes texture requests | 70 | /// Assets requests which are waiting for asset server data. This includes texture requests |
71 | /// </summary> | 71 | /// </summary> |
72 | private Dictionary<LLUUID, AssetRequest> RequestedAssets; | 72 | private Dictionary<LLUUID, AssetRequest> RequestedAssets; |
73 | 73 | ||
74 | /// <summary> | 74 | /// <summary> |
75 | /// Asset requests with data which are ready to be sent back to requesters. This includes textures. | 75 | /// Asset requests with data which are ready to be sent back to requesters. This includes textures. |
76 | /// </summary> | 76 | /// </summary> |
77 | private List<AssetRequest> AssetRequests; | 77 | private List<AssetRequest> AssetRequests; |
78 | 78 | ||
79 | 79 | ||
80 | /// <summary> | 80 | /// <summary> |
@@ -94,8 +94,8 @@ namespace OpenSim.Framework.Communications.Cache | |||
94 | m_log.InfoFormat("Assets:{0} Textures:{1} AssetRequests:{2} RequestedAssets:{3} RequestLists:{4}", | 94 | m_log.InfoFormat("Assets:{0} Textures:{1} AssetRequests:{2} RequestedAssets:{3} RequestLists:{4}", |
95 | Assets.Count, | 95 | Assets.Count, |
96 | Textures.Count, | 96 | Textures.Count, |
97 | AssetRequests.Count, | 97 | AssetRequests.Count, |
98 | RequestedAssets.Count, | 98 | RequestedAssets.Count, |
99 | RequestLists.Count); | 99 | RequestLists.Count); |
100 | 100 | ||
101 | int temporaryImages = 0; | 101 | int temporaryImages = 0; |
@@ -150,9 +150,9 @@ namespace OpenSim.Framework.Communications.Cache | |||
150 | { | 150 | { |
151 | Assets = new Dictionary<LLUUID, AssetInfo>(); | 151 | Assets = new Dictionary<LLUUID, AssetInfo>(); |
152 | Textures = new Dictionary<LLUUID, TextureImage>(); | 152 | Textures = new Dictionary<LLUUID, TextureImage>(); |
153 | AssetRequests = new List<AssetRequest>(); | 153 | AssetRequests = new List<AssetRequest>(); |
154 | 154 | ||
155 | RequestedAssets = new Dictionary<LLUUID, AssetRequest>(); | 155 | RequestedAssets = new Dictionary<LLUUID, AssetRequest>(); |
156 | RequestLists = new Dictionary<LLUUID, AssetRequestsList>(); | 156 | RequestLists = new Dictionary<LLUUID, AssetRequestsList>(); |
157 | } | 157 | } |
158 | 158 | ||
@@ -168,32 +168,32 @@ namespace OpenSim.Framework.Communications.Cache | |||
168 | m_assetServer = assetServer; | 168 | m_assetServer = assetServer; |
169 | m_assetServer.SetReceiver(this); | 169 | m_assetServer.SetReceiver(this); |
170 | 170 | ||
171 | m_assetCacheThread = new Thread(new ThreadStart(RunAssetManager)); | 171 | m_assetCacheThread = new Thread(new ThreadStart(RunAssetManager)); |
172 | m_assetCacheThread.Name = "AssetCacheThread"; | 172 | m_assetCacheThread.Name = "AssetCacheThread"; |
173 | m_assetCacheThread.IsBackground = true; | 173 | m_assetCacheThread.IsBackground = true; |
174 | m_assetCacheThread.Start(); | 174 | m_assetCacheThread.Start(); |
175 | OpenSim.Framework.ThreadTracker.Add(m_assetCacheThread); | 175 | OpenSim.Framework.ThreadTracker.Add(m_assetCacheThread); |
176 | } | 176 | } |
177 | 177 | ||
178 | /// <summary> | 178 | /// <summary> |
179 | /// Process the asset queue which holds data which is packeted up and sent | 179 | /// Process the asset queue which holds data which is packeted up and sent |
180 | /// directly back to the client. | 180 | /// directly back to the client. |
181 | /// </summary> | 181 | /// </summary> |
182 | public void RunAssetManager() | 182 | public void RunAssetManager() |
183 | { | ||
184 | while (true) | ||
185 | { | 183 | { |
186 | try | 184 | while (true) |
187 | { | ||
188 | ProcessAssetQueue(); | ||
189 | Thread.Sleep(500); | ||
190 | } | ||
191 | catch (Exception e) | ||
192 | { | 185 | { |
193 | m_log.Error("[ASSET CACHE]: " + e.ToString()); | 186 | try |
187 | { | ||
188 | ProcessAssetQueue(); | ||
189 | Thread.Sleep(500); | ||
190 | } | ||
191 | catch (Exception e) | ||
192 | { | ||
193 | m_log.Error("[ASSET CACHE]: " + e.ToString()); | ||
194 | } | ||
194 | } | 195 | } |
195 | } | 196 | } |
196 | } | ||
197 | 197 | ||
198 | /// <summary> | 198 | /// <summary> |
199 | /// Only get an asset if we already have it in the cache. | 199 | /// Only get an asset if we already have it in the cache. |
@@ -265,6 +265,7 @@ namespace OpenSim.Framework.Communications.Cache | |||
265 | AssetRequestsList requestList; | 265 | AssetRequestsList requestList; |
266 | lock (RequestLists) | 266 | lock (RequestLists) |
267 | { | 267 | { |
268 | // m_log.Info("AssetCache: Lock taken on requestLists (GetAsset)"); | ||
268 | if (RequestLists.TryGetValue(assetId, out requestList)) | 269 | if (RequestLists.TryGetValue(assetId, out requestList)) |
269 | { | 270 | { |
270 | } | 271 | } |
@@ -274,6 +275,7 @@ namespace OpenSim.Framework.Communications.Cache | |||
274 | RequestLists.Add(assetId, requestList); | 275 | RequestLists.Add(assetId, requestList); |
275 | } | 276 | } |
276 | } | 277 | } |
278 | // m_log.Info("AssetCache: Lock released on requestLists (GetAsset)"); | ||
277 | 279 | ||
278 | requestList.Requests.Add(req); | 280 | requestList.Requests.Add(req); |
279 | 281 | ||
@@ -447,19 +449,19 @@ namespace OpenSim.Framework.Communications.Cache | |||
447 | StatsManager.SimExtraStats.AddAsset(assetInf); | 449 | StatsManager.SimExtraStats.AddAsset(assetInf); |
448 | } | 450 | } |
449 | 451 | ||
450 | if (RequestedAssets.ContainsKey(assetInf.FullID)) | 452 | if (RequestedAssets.ContainsKey(assetInf.FullID)) |
451 | { | 453 | { |
452 | #if DEBUG | 454 | #if DEBUG |
453 | //m_log.DebugFormat("[ASSET CACHE]: Moving {0} from RequestedAssets to AssetRequests", asset.FullID); | 455 | //m_log.DebugFormat("[ASSET CACHE]: Moving {0} from RequestedAssets to AssetRequests", asset.FullID); |
454 | #endif | 456 | #endif |
455 | 457 | ||
456 | AssetRequest req = RequestedAssets[assetInf.FullID]; | 458 | AssetRequest req = RequestedAssets[assetInf.FullID]; |
457 | req.AssetInf = assetInf; | 459 | req.AssetInf = assetInf; |
458 | req.NumPackets = CalculateNumPackets(assetInf.Data); | 460 | req.NumPackets = CalculateNumPackets(assetInf.Data); |
459 | 461 | ||
460 | RequestedAssets.Remove(assetInf.FullID); | 462 | RequestedAssets.Remove(assetInf.FullID); |
461 | AssetRequests.Add(req); | 463 | AssetRequests.Add(req); |
462 | } | 464 | } |
463 | } | 465 | } |
464 | } | 466 | } |
465 | 467 | ||
@@ -469,9 +471,11 @@ namespace OpenSim.Framework.Communications.Cache | |||
469 | AssetRequestsList reqList = null; | 471 | AssetRequestsList reqList = null; |
470 | lock (RequestLists) | 472 | lock (RequestLists) |
471 | { | 473 | { |
474 | //m_log.Info("AssetCache: Lock taken on requestLists (AssetReceived #1)"); | ||
472 | reqList = RequestLists[asset.FullID]; | 475 | reqList = RequestLists[asset.FullID]; |
473 | 476 | ||
474 | } | 477 | } |
478 | //m_log.Info("AssetCache: Lock released on requestLists (AssetReceived #1)"); | ||
475 | if (reqList != null) | 479 | if (reqList != null) |
476 | { | 480 | { |
477 | //making a copy of the list is not ideal | 481 | //making a copy of the list is not ideal |
@@ -486,8 +490,10 @@ namespace OpenSim.Framework.Communications.Cache | |||
486 | 490 | ||
487 | lock (RequestLists) | 491 | lock (RequestLists) |
488 | { | 492 | { |
493 | // m_log.Info("AssetCache: Lock taken on requestLists (AssetReceived #2)"); | ||
489 | RequestLists.Remove(asset.FullID); | 494 | RequestLists.Remove(asset.FullID); |
490 | } | 495 | } |
496 | //m_log.Info("AssetCache: Lock released on requestLists (AssetReceived #2)"); | ||
491 | 497 | ||
492 | foreach (NewAssetRequest req in theseRequests) | 498 | foreach (NewAssetRequest req in theseRequests) |
493 | { | 499 | { |
@@ -501,217 +507,234 @@ namespace OpenSim.Framework.Communications.Cache | |||
501 | // See IAssetReceiver | 507 | // See IAssetReceiver |
502 | public void AssetNotFound(LLUUID assetID) | 508 | public void AssetNotFound(LLUUID assetID) |
503 | { | 509 | { |
504 | m_log.WarnFormat("[ASSET CACHE]: AssetNotFound for {0}", assetID); | 510 | // m_log.WarnFormat("[ASSET CACHE]: AssetNotFound for {0}", assetID); |
505 | 511 | ||
506 | // Notify requesters for this asset | 512 | // Notify requesters for this asset |
513 | AssetRequestsList reqList = null; | ||
507 | lock (RequestLists) | 514 | lock (RequestLists) |
508 | { | 515 | { |
516 | // m_log.Info("AssetCache: Lock taken on requestLists (AssetNotFound #1)"); | ||
509 | if (RequestLists.ContainsKey(assetID)) | 517 | if (RequestLists.ContainsKey(assetID)) |
510 | { | 518 | { |
511 | AssetRequestsList reqList = RequestLists[assetID]; | 519 | reqList = RequestLists[assetID]; |
512 | foreach (NewAssetRequest req in reqList.Requests) | ||
513 | { | ||
514 | req.Callback(assetID, null); | ||
515 | } | ||
516 | |||
517 | RequestLists.Remove(assetID); | ||
518 | } | 520 | } |
519 | } | 521 | } |
520 | } | 522 | // m_log.Info("AssetCache: Lock released on requestLists (AssetNotFound #1)"); |
521 | |||
522 | /// <summary> | ||
523 | /// Calculate the number of packets required to send the asset to the client. | ||
524 | /// </summary> | ||
525 | /// <param name="data"></param> | ||
526 | /// <returns></returns> | ||
527 | private int CalculateNumPackets(byte[] data) | ||
528 | { | ||
529 | const uint m_maxPacketSize = 600; | ||
530 | int numPackets = 1; | ||
531 | 523 | ||
532 | if (data.LongLength > m_maxPacketSize) | 524 | if (reqList != null) |
533 | { | 525 | { |
534 | // over max number of bytes so split up file | 526 | List<NewAssetRequest> theseRequests = new List<NewAssetRequest>(reqList.Requests); |
535 | long restData = data.LongLength - m_maxPacketSize; | 527 | reqList.Requests.Clear(); |
536 | int restPackets = (int)((restData + m_maxPacketSize - 1) / m_maxPacketSize); | ||
537 | numPackets += restPackets; | ||
538 | } | ||
539 | 528 | ||
540 | return numPackets; | 529 | lock (RequestLists) |
541 | } | ||
542 | |||
543 | /// <summary> | ||
544 | /// Make an asset request the result of which will be packeted up and sent directly back to the client. | ||
545 | /// </summary> | ||
546 | /// <param name="userInfo"></param> | ||
547 | /// <param name="transferRequest"></param> | ||
548 | public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest) | ||
549 | { | ||
550 | LLUUID requestID = null; | ||
551 | byte source = 2; | ||
552 | if (transferRequest.TransferInfo.SourceType == 2) | ||
553 | { | ||
554 | //direct asset request | ||
555 | requestID = new LLUUID(transferRequest.TransferInfo.Params, 0); | ||
556 | } | ||
557 | else if (transferRequest.TransferInfo.SourceType == 3) | ||
558 | { | ||
559 | //inventory asset request | ||
560 | requestID = new LLUUID(transferRequest.TransferInfo.Params, 80); | ||
561 | source = 3; | ||
562 | //Console.WriteLine("asset request " + requestID); | ||
563 | } | ||
564 | //check to see if asset is in local cache, if not we need to request it from asset server. | ||
565 | //Console.WriteLine("asset request " + requestID); | ||
566 | if (!Assets.ContainsKey(requestID)) | ||
567 | { | ||
568 | //not found asset | ||
569 | // so request from asset server | ||
570 | if (!RequestedAssets.ContainsKey(requestID)) | ||
571 | { | ||
572 | AssetRequest request = new AssetRequest(); | ||
573 | request.RequestUser = userInfo; | ||
574 | request.RequestAssetID = requestID; | ||
575 | request.TransferRequestID = transferRequest.TransferInfo.TransferID; | ||
576 | request.AssetRequestSource = source; | ||
577 | request.Params = transferRequest.TransferInfo.Params; | ||
578 | RequestedAssets.Add(requestID, request); | ||
579 | m_assetServer.RequestAsset(requestID, false); | ||
580 | } | ||
581 | return; | ||
582 | } | ||
583 | //it is in our cache | ||
584 | AssetInfo asset = Assets[requestID]; | ||
585 | |||
586 | // add to the AssetRequests list | ||
587 | AssetRequest req = new AssetRequest(); | ||
588 | req.RequestUser = userInfo; | ||
589 | req.RequestAssetID = requestID; | ||
590 | req.TransferRequestID = transferRequest.TransferInfo.TransferID; | ||
591 | req.AssetRequestSource = source; | ||
592 | req.Params = transferRequest.TransferInfo.Params; | ||
593 | req.AssetInf = asset; | ||
594 | req.NumPackets = CalculateNumPackets(asset.Data); | ||
595 | AssetRequests.Add(req); | ||
596 | } | ||
597 | |||
598 | /// <summary> | ||
599 | /// Process the asset queue which sends packets directly back to the client. | ||
600 | /// </summary> | ||
601 | private void ProcessAssetQueue() | ||
602 | { | ||
603 | //should move the asset downloading to a module, like has been done with texture downloading | ||
604 | if (AssetRequests.Count == 0) | ||
605 | { | ||
606 | //no requests waiting | ||
607 | return; | ||
608 | } | ||
609 | // if less than 5, do all of them | ||
610 | int num = Math.Min(5, AssetRequests.Count); | ||
611 | |||
612 | AssetRequest req; | ||
613 | for (int i = 0; i < num; i++) | ||
614 | { | ||
615 | req = (AssetRequest)AssetRequests[i]; | ||
616 | //Console.WriteLine("sending asset " + req.RequestAssetID); | ||
617 | TransferInfoPacket Transfer = new TransferInfoPacket(); | ||
618 | Transfer.TransferInfo.ChannelType = 2; | ||
619 | Transfer.TransferInfo.Status = 0; | ||
620 | Transfer.TransferInfo.TargetType = 0; | ||
621 | if (req.AssetRequestSource == 2) | ||
622 | { | ||
623 | Transfer.TransferInfo.Params = new byte[20]; | ||
624 | Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); | ||
625 | int assType = (int)req.AssetInf.Type; | ||
626 | Array.Copy(Helpers.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4); | ||
627 | } | ||
628 | else if (req.AssetRequestSource == 3) | ||
629 | { | 530 | { |
630 | Transfer.TransferInfo.Params = req.Params; | 531 | // m_log.Info("AssetCache: Lock taken on requestLists (AssetNotFound #2)"); |
631 | // Transfer.TransferInfo.Params = new byte[100]; | 532 | RequestLists.Remove(assetID); |
632 | //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); | ||
633 | //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16); | ||
634 | } | 533 | } |
635 | Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length; | 534 | // m_log.Info("AssetCache: Lock released on requestLists (AssetNotFound #2)"); |
636 | Transfer.TransferInfo.TransferID = req.TransferRequestID; | ||
637 | req.RequestUser.OutPacket(Transfer, ThrottleOutPacketType.Asset); | ||
638 | 535 | ||
639 | if (req.NumPackets == 1) | 536 | foreach (NewAssetRequest req in theseRequests) |
640 | { | 537 | { |
641 | TransferPacketPacket TransferPacket = new TransferPacketPacket(); | 538 | req.Callback(assetID, null); |
642 | TransferPacket.TransferData.Packet = 0; | ||
643 | TransferPacket.TransferData.ChannelType = 2; | ||
644 | TransferPacket.TransferData.TransferID = req.TransferRequestID; | ||
645 | TransferPacket.TransferData.Data = req.AssetInf.Data; | ||
646 | TransferPacket.TransferData.Status = 1; | ||
647 | req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset); | ||
648 | } | ||
649 | else | ||
650 | { | ||
651 | int processedLength = 0; | ||
652 | // libsecondlife hardcodes 1500 as the maximum data chunk size | ||
653 | int maxChunkSize = 1250; | ||
654 | int packetNumber = 0; | ||
655 | |||
656 | while (processedLength < req.AssetInf.Data.Length) | ||
657 | { | ||
658 | TransferPacketPacket TransferPacket = new TransferPacketPacket(); | ||
659 | TransferPacket.TransferData.Packet = packetNumber; | ||
660 | TransferPacket.TransferData.ChannelType = 2; | ||
661 | TransferPacket.TransferData.TransferID = req.TransferRequestID; | ||
662 | |||
663 | int chunkSize = Math.Min(req.AssetInf.Data.Length - processedLength, maxChunkSize); | ||
664 | byte[] chunk = new byte[chunkSize]; | ||
665 | Array.Copy(req.AssetInf.Data, processedLength, chunk, 0, chunk.Length); | ||
666 | |||
667 | TransferPacket.TransferData.Data = chunk; | ||
668 | |||
669 | // 0 indicates more packets to come, 1 indicates last packet | ||
670 | if (req.AssetInf.Data.Length - processedLength > maxChunkSize) | ||
671 | { | ||
672 | TransferPacket.TransferData.Status = 0; | ||
673 | } | ||
674 | else | ||
675 | { | ||
676 | TransferPacket.TransferData.Status = 1; | ||
677 | } | ||
678 | |||
679 | req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset); | ||
680 | |||
681 | processedLength += chunkSize; | ||
682 | packetNumber++; | ||
683 | } | ||
684 | } | 539 | } |
685 | } | 540 | } |
686 | 541 | ||
687 | //remove requests that have been completed | ||
688 | for (int i = 0; i < num; i++) | ||
689 | { | ||
690 | AssetRequests.RemoveAt(0); | ||
691 | } | ||
692 | } | 542 | } |
693 | 543 | ||
694 | public class AssetRequest | 544 | /// <summary> |
695 | { | 545 | /// Calculate the number of packets required to send the asset to the client. |
696 | public IClientAPI RequestUser; | 546 | /// </summary> |
697 | public LLUUID RequestAssetID; | 547 | /// <param name="data"></param> |
698 | public AssetInfo AssetInf; | 548 | /// <returns></returns> |
699 | public TextureImage ImageInfo; | 549 | private int CalculateNumPackets(byte[] data) |
700 | public LLUUID TransferRequestID; | 550 | { |
701 | public long DataPointer = 0; | 551 | const uint m_maxPacketSize = 600; |
702 | public int NumPackets = 0; | 552 | int numPackets = 1; |
703 | public int PacketCounter = 0; | 553 | |
704 | public bool IsTextureRequest; | 554 | if (data.LongLength > m_maxPacketSize) |
705 | public byte AssetRequestSource = 2; | 555 | { |
706 | public byte[] Params = null; | 556 | // over max number of bytes so split up file |
707 | //public bool AssetInCache; | 557 | long restData = data.LongLength - m_maxPacketSize; |
708 | //public int TimeRequested; | 558 | int restPackets = (int)((restData + m_maxPacketSize - 1) / m_maxPacketSize); |
709 | public int DiscardLevel = -1; | 559 | numPackets += restPackets; |
710 | 560 | } | |
711 | public AssetRequest() | 561 | |
712 | { | 562 | return numPackets; |
713 | } | 563 | } |
714 | } | 564 | |
565 | /// <summary> | ||
566 | /// Make an asset request the result of which will be packeted up and sent directly back to the client. | ||
567 | /// </summary> | ||
568 | /// <param name="userInfo"></param> | ||
569 | /// <param name="transferRequest"></param> | ||
570 | public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest) | ||
571 | { | ||
572 | LLUUID requestID = null; | ||
573 | byte source = 2; | ||
574 | if (transferRequest.TransferInfo.SourceType == 2) | ||
575 | { | ||
576 | //direct asset request | ||
577 | requestID = new LLUUID(transferRequest.TransferInfo.Params, 0); | ||
578 | } | ||
579 | else if (transferRequest.TransferInfo.SourceType == 3) | ||
580 | { | ||
581 | //inventory asset request | ||
582 | requestID = new LLUUID(transferRequest.TransferInfo.Params, 80); | ||
583 | source = 3; | ||
584 | //Console.WriteLine("asset request " + requestID); | ||
585 | } | ||
586 | //check to see if asset is in local cache, if not we need to request it from asset server. | ||
587 | //Console.WriteLine("asset request " + requestID); | ||
588 | if (!Assets.ContainsKey(requestID)) | ||
589 | { | ||
590 | //not found asset | ||
591 | // so request from asset server | ||
592 | if (!RequestedAssets.ContainsKey(requestID)) | ||
593 | { | ||
594 | AssetRequest request = new AssetRequest(); | ||
595 | request.RequestUser = userInfo; | ||
596 | request.RequestAssetID = requestID; | ||
597 | request.TransferRequestID = transferRequest.TransferInfo.TransferID; | ||
598 | request.AssetRequestSource = source; | ||
599 | request.Params = transferRequest.TransferInfo.Params; | ||
600 | RequestedAssets.Add(requestID, request); | ||
601 | m_assetServer.RequestAsset(requestID, false); | ||
602 | } | ||
603 | return; | ||
604 | } | ||
605 | //it is in our cache | ||
606 | AssetInfo asset = Assets[requestID]; | ||
607 | |||
608 | // add to the AssetRequests list | ||
609 | AssetRequest req = new AssetRequest(); | ||
610 | req.RequestUser = userInfo; | ||
611 | req.RequestAssetID = requestID; | ||
612 | req.TransferRequestID = transferRequest.TransferInfo.TransferID; | ||
613 | req.AssetRequestSource = source; | ||
614 | req.Params = transferRequest.TransferInfo.Params; | ||
615 | req.AssetInf = asset; | ||
616 | req.NumPackets = CalculateNumPackets(asset.Data); | ||
617 | AssetRequests.Add(req); | ||
618 | } | ||
619 | |||
620 | /// <summary> | ||
621 | /// Process the asset queue which sends packets directly back to the client. | ||
622 | /// </summary> | ||
623 | private void ProcessAssetQueue() | ||
624 | { | ||
625 | //should move the asset downloading to a module, like has been done with texture downloading | ||
626 | if (AssetRequests.Count == 0) | ||
627 | { | ||
628 | //no requests waiting | ||
629 | return; | ||
630 | } | ||
631 | // if less than 5, do all of them | ||
632 | int num = Math.Min(5, AssetRequests.Count); | ||
633 | |||
634 | AssetRequest req; | ||
635 | for (int i = 0; i < num; i++) | ||
636 | { | ||
637 | req = (AssetRequest)AssetRequests[i]; | ||
638 | //Console.WriteLine("sending asset " + req.RequestAssetID); | ||
639 | TransferInfoPacket Transfer = new TransferInfoPacket(); | ||
640 | Transfer.TransferInfo.ChannelType = 2; | ||
641 | Transfer.TransferInfo.Status = 0; | ||
642 | Transfer.TransferInfo.TargetType = 0; | ||
643 | if (req.AssetRequestSource == 2) | ||
644 | { | ||
645 | Transfer.TransferInfo.Params = new byte[20]; | ||
646 | Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); | ||
647 | int assType = (int)req.AssetInf.Type; | ||
648 | Array.Copy(Helpers.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4); | ||
649 | } | ||
650 | else if (req.AssetRequestSource == 3) | ||
651 | { | ||
652 | Transfer.TransferInfo.Params = req.Params; | ||
653 | // Transfer.TransferInfo.Params = new byte[100]; | ||
654 | //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); | ||
655 | //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16); | ||
656 | } | ||
657 | Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length; | ||
658 | Transfer.TransferInfo.TransferID = req.TransferRequestID; | ||
659 | req.RequestUser.OutPacket(Transfer, ThrottleOutPacketType.Asset); | ||
660 | |||
661 | if (req.NumPackets == 1) | ||
662 | { | ||
663 | TransferPacketPacket TransferPacket = new TransferPacketPacket(); | ||
664 | TransferPacket.TransferData.Packet = 0; | ||
665 | TransferPacket.TransferData.ChannelType = 2; | ||
666 | TransferPacket.TransferData.TransferID = req.TransferRequestID; | ||
667 | TransferPacket.TransferData.Data = req.AssetInf.Data; | ||
668 | TransferPacket.TransferData.Status = 1; | ||
669 | req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset); | ||
670 | } | ||
671 | else | ||
672 | { | ||
673 | int processedLength = 0; | ||
674 | // libsecondlife hardcodes 1500 as the maximum data chunk size | ||
675 | int maxChunkSize = 1250; | ||
676 | int packetNumber = 0; | ||
677 | |||
678 | while (processedLength < req.AssetInf.Data.Length) | ||
679 | { | ||
680 | TransferPacketPacket TransferPacket = new TransferPacketPacket(); | ||
681 | TransferPacket.TransferData.Packet = packetNumber; | ||
682 | TransferPacket.TransferData.ChannelType = 2; | ||
683 | TransferPacket.TransferData.TransferID = req.TransferRequestID; | ||
684 | |||
685 | int chunkSize = Math.Min(req.AssetInf.Data.Length - processedLength, maxChunkSize); | ||
686 | byte[] chunk = new byte[chunkSize]; | ||
687 | Array.Copy(req.AssetInf.Data, processedLength, chunk, 0, chunk.Length); | ||
688 | |||
689 | TransferPacket.TransferData.Data = chunk; | ||
690 | |||
691 | // 0 indicates more packets to come, 1 indicates last packet | ||
692 | if (req.AssetInf.Data.Length - processedLength > maxChunkSize) | ||
693 | { | ||
694 | TransferPacket.TransferData.Status = 0; | ||
695 | } | ||
696 | else | ||
697 | { | ||
698 | TransferPacket.TransferData.Status = 1; | ||
699 | } | ||
700 | |||
701 | req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset); | ||
702 | |||
703 | processedLength += chunkSize; | ||
704 | packetNumber++; | ||
705 | } | ||
706 | } | ||
707 | } | ||
708 | |||
709 | //remove requests that have been completed | ||
710 | for (int i = 0; i < num; i++) | ||
711 | { | ||
712 | AssetRequests.RemoveAt(0); | ||
713 | } | ||
714 | } | ||
715 | |||
716 | public class AssetRequest | ||
717 | { | ||
718 | public IClientAPI RequestUser; | ||
719 | public LLUUID RequestAssetID; | ||
720 | public AssetInfo AssetInf; | ||
721 | public TextureImage ImageInfo; | ||
722 | public LLUUID TransferRequestID; | ||
723 | public long DataPointer = 0; | ||
724 | public int NumPackets = 0; | ||
725 | public int PacketCounter = 0; | ||
726 | public bool IsTextureRequest; | ||
727 | public byte AssetRequestSource = 2; | ||
728 | public byte[] Params = null; | ||
729 | //public bool AssetInCache; | ||
730 | //public int TimeRequested; | ||
731 | public int DiscardLevel = -1; | ||
732 | |||
733 | public AssetRequest() | ||
734 | { | ||
735 | } | ||
736 | } | ||
737 | |||
715 | 738 | ||
716 | public class AssetInfo : AssetBase | 739 | public class AssetInfo : AssetBase |
717 | { | 740 | { |