After seeing sdague do his happy dance over trunk working "the best he has ever seen". I'm not sure I should be doing this commit, but oh well.

So anyway, it moves the Asset downloading (packet sending) to a module (AssetDownloadModule). 
So now at last, AssetCache should be just dealing with fetching assets from the asset server and caching them.
0.6.0-stable
MW 2008-02-27 21:11:01 +00:00
parent 34073607a2
commit e978d00914
5 changed files with 367 additions and 89 deletions

View File

@ -69,12 +69,12 @@ namespace OpenSim.Framework.Communications.Cache
///
/// Assets requests which are waiting for asset server data. This includes texture requests
/// </summary>
private Dictionary<LLUUID, AssetRequest> RequestedAssets;
// private Dictionary<LLUUID, AssetRequest> RequestedAssets;
/// <summary>
/// Asset requests with data which are ready to be sent back to requesters. This includes textures.
/// </summary>
private List<AssetRequest> AssetRequests;
// private List<AssetRequest> AssetRequests;
/// <summary>
@ -84,7 +84,7 @@ namespace OpenSim.Framework.Communications.Cache
private readonly IAssetServer m_assetServer;
private readonly Thread m_assetCacheThread;
// private readonly Thread m_assetCacheThread;
/// <summary>
/// Report statistical data.
@ -94,8 +94,8 @@ namespace OpenSim.Framework.Communications.Cache
m_log.InfoFormat("Assets:{0} Textures:{1} AssetRequests:{2} RequestedAssets:{3} RequestLists:{4}",
Assets.Count,
Textures.Count,
AssetRequests.Count,
RequestedAssets.Count,
// AssetRequests.Count,
// RequestedAssets.Count,
RequestLists.Count);
int temporaryImages = 0;
@ -150,9 +150,9 @@ namespace OpenSim.Framework.Communications.Cache
{
Assets = new Dictionary<LLUUID, AssetInfo>();
Textures = new Dictionary<LLUUID, TextureImage>();
AssetRequests = new List<AssetRequest>();
// AssetRequests = new List<AssetRequest>();
RequestedAssets = new Dictionary<LLUUID, AssetRequest>();
// RequestedAssets = new Dictionary<LLUUID, AssetRequest>();
RequestLists = new Dictionary<LLUUID, AssetRequestsList>();
}
@ -168,18 +168,18 @@ namespace OpenSim.Framework.Communications.Cache
m_assetServer = assetServer;
m_assetServer.SetReceiver(this);
m_assetCacheThread = new Thread(new ThreadStart(RunAssetManager));
m_assetCacheThread.Name = "AssetCacheThread";
m_assetCacheThread.IsBackground = true;
m_assetCacheThread.Start();
OpenSim.Framework.ThreadTracker.Add(m_assetCacheThread);
// m_assetCacheThread = new Thread(new ThreadStart(RunAssetManager));
// m_assetCacheThread.Name = "AssetCacheThread";
// m_assetCacheThread.IsBackground = true;
// m_assetCacheThread.Start();
// OpenSim.Framework.ThreadTracker.Add(m_assetCacheThread);
}
/// <summary>
/// Process the asset queue which holds data which is packeted up and sent
/// directly back to the client.
/// </summary>
public void RunAssetManager()
/* public void RunAssetManager()
{
while (true)
{
@ -193,7 +193,7 @@ namespace OpenSim.Framework.Communications.Cache
m_log.Error("[ASSET CACHE]: " + e.ToString());
}
}
}
}*/
/// <summary>
/// Only get an asset if we already have it in the cache.
@ -449,7 +449,7 @@ namespace OpenSim.Framework.Communications.Cache
StatsManager.SimExtraStats.AddAsset(assetInf);
}
if (RequestedAssets.ContainsKey(assetInf.FullID))
/* if (RequestedAssets.ContainsKey(assetInf.FullID))
{
#if DEBUG
//m_log.DebugFormat("[ASSET CACHE]: Moving {0} from RequestedAssets to AssetRequests", asset.FullID);
@ -461,7 +461,7 @@ namespace OpenSim.Framework.Communications.Cache
RequestedAssets.Remove(assetInf.FullID);
AssetRequests.Add(req);
}
}*/
}
}
@ -541,6 +541,7 @@ namespace OpenSim.Framework.Communications.Cache
}
/*
/// <summary>
/// Calculate the number of packets required to send the asset to the client.
/// </summary>
@ -734,7 +735,7 @@ namespace OpenSim.Framework.Communications.Cache
{
}
}
*/
public class AssetInfo : AssetBase
{

View File

@ -390,6 +390,8 @@ namespace OpenSim.Framework
public delegate void RemoveInventoryFolder(
IClientAPI remoteClient, LLUUID folderID);
public delegate void RequestAsset(IClientAPI remoteClient, TransferRequestPacket transferRequest);
public delegate void RezScript(IClientAPI remoteClient, LLUUID itemID, uint localID);
public delegate void UpdateTaskInventory(IClientAPI remoteClient, LLUUID itemID, LLUUID folderID, uint localID);
@ -503,6 +505,7 @@ namespace OpenSim.Framework
event RezScript OnRezScript;
event UpdateTaskInventory OnUpdateTaskInventory;
event RemoveTaskInventory OnRemoveTaskItem;
event RequestAsset OnRequestAsset;
event UUIDNameRequest OnNameFromUUIDRequest;

View File

@ -51,10 +51,10 @@ namespace OpenSim.Region.ClientStack
/// </summary>
public class ClientView : IClientAPI
{
// ~ClientView()
// {
// System.Console.WriteLine("[CLIENTVIEW]: Destructor called");
// }
// ~ClientView()
// {
// System.Console.WriteLine("[CLIENTVIEW]: Destructor called");
// }
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
@ -214,7 +214,8 @@ namespace OpenSim.Region.ClientStack
private UpdateVector handler089 = null; //OnUpdatePrimGroupPosition;
private UpdatePrimRotation handler090 = null; //OnUpdatePrimGroupRotation;
private UpdatePrimGroupRotation handler091 = null; //OnUpdatePrimGroupMouseRotation;
private PacketStats handler093 = null; // OnPacketStats;
private PacketStats handler093 = null; // OnPacketStats;#
private RequestAsset handler094 = null; // OnRequestAsset;
/* Properties */
@ -502,7 +503,7 @@ namespace OpenSim.Region.ClientStack
protected virtual void ClientLoop()
{
m_log.Info("[CLIENT]: Entered loop");
while( true )
while (true)
{
QueItem nextPacket = m_packetQueue.Dequeue();
if (nextPacket.Incoming)
@ -690,6 +691,7 @@ namespace OpenSim.Region.ClientStack
public event RezScript OnRezScript;
public event UpdateTaskInventory OnUpdateTaskInventory;
public event RemoveTaskInventory OnRemoveTaskItem;
public event RequestAsset OnRequestAsset;
public event UUIDNameRequest OnNameFromUUIDRequest;
@ -1410,7 +1412,7 @@ namespace OpenSim.Region.ClientStack
OutPacket(replyPacket, ThrottleOutPacketType.Task);
}
public void SendAgentDataUpdate(LLUUID agentid, LLUUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname,string grouptitle)
public void SendAgentDataUpdate(LLUUID agentid, LLUUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle)
{
AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate);
sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid;
@ -1420,7 +1422,7 @@ namespace OpenSim.Region.ClientStack
sendAgentDataUpdate.AgentData.GroupPowers = grouppowers;
sendAgentDataUpdate.AgentData.GroupTitle = Helpers.StringToField(grouptitle);
sendAgentDataUpdate.AgentData.LastName = Helpers.StringToField(lastname);
OutPacket(sendAgentDataUpdate,ThrottleOutPacketType.Task);
OutPacket(sendAgentDataUpdate, ThrottleOutPacketType.Task);
}
/// <summary>
@ -3102,7 +3104,7 @@ namespace OpenSim.Region.ClientStack
handler015 = OnRezSingleAttachmentFromInv;
if (handler015 != null)
{
RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket) Pack;
RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket)Pack;
handler015(this, rez.ObjectData.ItemID,
rez.ObjectData.AttachmentPt, rez.ObjectData.ItemFlags, rez.ObjectData.NextOwnerMask);
}
@ -3562,7 +3564,12 @@ namespace OpenSim.Region.ClientStack
case PacketType.TransferRequest:
//Console.WriteLine("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
TransferRequestPacket transfer = (TransferRequestPacket)Pack;
m_assetCache.AddAssetRequest(this, transfer);
// m_assetCache.AddAssetRequest(this, transfer);
handler094 = OnRequestAsset;
if (handler094 != null)
{
handler094(this, transfer);
}
break;
case PacketType.AssetUploadRequest:
AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;

View File

@ -26,25 +26,57 @@
*
*/
using System;
using System.Collections.Generic;
using System.Threading;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
using libsecondlife;
using libsecondlife.Packets;
namespace OpenSim.Region.Environment.Modules
{
public class AssetDownloadModule : IRegionModule
{
private Scene m_scene;
private Dictionary<LLUUID, Scene> RegisteredScenes = new Dictionary<LLUUID, Scene>();
///
/// Assets requests (for each user) which are waiting for asset server data. This includes texture requests
/// </summary>
private Dictionary<LLUUID, Dictionary<LLUUID,AssetRequest>> RequestedAssets;
/// <summary>
/// Asset requests with data which are ready to be sent back to requesters. This includes textures.
/// </summary>
private List<AssetRequest> AssetRequests;
private Thread m_thread;
public AssetDownloadModule()
{
RequestedAssets = new Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>>();
AssetRequests = new List<AssetRequest>();
}
public void Initialise(Scene scene, IConfigSource config)
{
if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
{
RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
scene.EventManager.OnNewClient += NewClient;
}
if (m_scene == null)
{
m_scene = scene;
m_scene.EventManager.OnNewClient += NewClient;
m_thread = new Thread(new ThreadStart(RunAssetQueue));
m_thread.Name = "AssetDownloadQueueThread";
m_thread.IsBackground = true;
m_thread.Start();
OpenSim.Framework.ThreadTracker.Add(m_thread);
}
}
public void PostInitialise()
@ -67,6 +99,240 @@ namespace OpenSim.Region.Environment.Modules
public void NewClient(IClientAPI client)
{
client.OnRequestAsset += AddAssetRequest;
}
/// <summary>
/// Make an asset request the result of which will be packeted up and sent directly back to the client.
/// </summary>
/// <param name="userInfo"></param>
/// <param name="transferRequest"></param>
public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest)
{
LLUUID requestID = null;
byte source = 2;
if (transferRequest.TransferInfo.SourceType == 2)
{
//direct asset request
requestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
}
else if (transferRequest.TransferInfo.SourceType == 3)
{
//inventory asset request
requestID = new LLUUID(transferRequest.TransferInfo.Params, 80);
source = 3;
//Console.WriteLine("asset request " + requestID);
}
//not found asset
// so request from asset server
Dictionary<LLUUID, AssetRequest> userRequests = null;
if (RequestedAssets.TryGetValue(userInfo.AgentId, out userRequests))
{
if (!userRequests.ContainsKey(requestID))
{
AssetRequest request = new AssetRequest();
request.RequestUser = userInfo;
request.RequestAssetID = requestID;
request.TransferRequestID = transferRequest.TransferInfo.TransferID;
request.AssetRequestSource = source;
request.Params = transferRequest.TransferInfo.Params;
userRequests[requestID] = request;
m_scene.AssetCache.GetAsset(requestID, AssetCallback, false);
}
}
else
{
userRequests = new Dictionary<LLUUID, AssetRequest>();
AssetRequest request = new AssetRequest();
request.RequestUser = userInfo;
request.RequestAssetID = requestID;
request.TransferRequestID = transferRequest.TransferInfo.TransferID;
request.AssetRequestSource = source;
request.Params = transferRequest.TransferInfo.Params;
userRequests.Add(requestID, request);
RequestedAssets[userInfo.AgentId] = userRequests;
m_scene.AssetCache.GetAsset(requestID, AssetCallback, false);
}
return;
}
public void AssetCallback(LLUUID assetID, AssetBase asset)
{
if (asset != null)
{
foreach (Dictionary<LLUUID, AssetRequest> userRequests in RequestedAssets.Values)
{
if (userRequests.ContainsKey(assetID))
{
AssetRequest req = userRequests[assetID];
if (req != null)
{
req.AssetInf = asset;
req.NumPackets = CalculateNumPackets(asset.Data);
userRequests.Remove(assetID);
AssetRequests.Add(req);
}
}
}
}
}
private void RunAssetQueue()
{
while (true)
{
try
{
ProcessAssetQueue();
Thread.Sleep(500);
}
catch (Exception e)
{
// m_log.Error("[ASSET CACHE]: " + e.ToString());
}
}
}
/// <summary>
/// Process the asset queue which sends packets directly back to the client.
/// </summary>
private void ProcessAssetQueue()
{
//should move the asset downloading to a module, like has been done with texture downloading
if (AssetRequests.Count == 0)
{
//no requests waiting
return;
}
// if less than 5, do all of them
int num = Math.Min(5, AssetRequests.Count);
AssetRequest req;
for (int i = 0; i < num; i++)
{
req = (AssetRequest)AssetRequests[i];
//Console.WriteLine("sending asset " + req.RequestAssetID);
TransferInfoPacket Transfer = new TransferInfoPacket();
Transfer.TransferInfo.ChannelType = 2;
Transfer.TransferInfo.Status = 0;
Transfer.TransferInfo.TargetType = 0;
if (req.AssetRequestSource == 2)
{
Transfer.TransferInfo.Params = new byte[20];
Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
int assType = (int)req.AssetInf.Type;
Array.Copy(Helpers.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4);
}
else if (req.AssetRequestSource == 3)
{
Transfer.TransferInfo.Params = req.Params;
// 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);
}
Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length;
Transfer.TransferInfo.TransferID = req.TransferRequestID;
req.RequestUser.OutPacket(Transfer, ThrottleOutPacketType.Asset);
if (req.NumPackets == 1)
{
TransferPacketPacket TransferPacket = new TransferPacketPacket();
TransferPacket.TransferData.Packet = 0;
TransferPacket.TransferData.ChannelType = 2;
TransferPacket.TransferData.TransferID = req.TransferRequestID;
TransferPacket.TransferData.Data = req.AssetInf.Data;
TransferPacket.TransferData.Status = 1;
req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
}
else
{
int processedLength = 0;
// libsecondlife hardcodes 1500 as the maximum data chunk size
int maxChunkSize = 1250;
int packetNumber = 0;
while (processedLength < req.AssetInf.Data.Length)
{
TransferPacketPacket TransferPacket = new TransferPacketPacket();
TransferPacket.TransferData.Packet = packetNumber;
TransferPacket.TransferData.ChannelType = 2;
TransferPacket.TransferData.TransferID = req.TransferRequestID;
int chunkSize = Math.Min(req.AssetInf.Data.Length - processedLength, maxChunkSize);
byte[] chunk = new byte[chunkSize];
Array.Copy(req.AssetInf.Data, processedLength, chunk, 0, chunk.Length);
TransferPacket.TransferData.Data = chunk;
// 0 indicates more packets to come, 1 indicates last packet
if (req.AssetInf.Data.Length - processedLength > maxChunkSize)
{
TransferPacket.TransferData.Status = 0;
}
else
{
TransferPacket.TransferData.Status = 1;
}
req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
processedLength += chunkSize;
packetNumber++;
}
}
}
//remove requests that have been completed
for (int i = 0; i < num; i++)
{
AssetRequests.RemoveAt(0);
}
}
/// <summary>
/// Calculate the number of packets required to send the asset to the client.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private int CalculateNumPackets(byte[] data)
{
const uint m_maxPacketSize = 600;
int numPackets = 1;
if (data.LongLength > m_maxPacketSize)
{
// over max number of bytes so split up file
long restData = data.LongLength - m_maxPacketSize;
int restPackets = (int)((restData + m_maxPacketSize - 1) / m_maxPacketSize);
numPackets += restPackets;
}
return numPackets;
}
public class AssetRequest
{
public IClientAPI RequestUser;
public LLUUID RequestAssetID;
public AssetBase AssetInf;
public AssetBase ImageInfo;
public LLUUID TransferRequestID;
public long DataPointer = 0;
public int NumPackets = 0;
public int PacketCounter = 0;
public bool IsTextureRequest;
public byte AssetRequestSource = 2;
public byte[] Params = null;
//public bool AssetInCache;
//public int TimeRequested;
public int DiscardLevel = -1;
public AssetRequest()
{
}
}
}
}

View File

@ -131,6 +131,7 @@ namespace SimpleApp
public event RezScript OnRezScript;
public event UpdateTaskInventory OnUpdateTaskInventory;
public event RemoveTaskInventory OnRemoveTaskItem;
public event RequestAsset OnRequestAsset;
public event UUIDNameRequest OnNameFromUUIDRequest;