Merge branch 'master' into careminster-presence-refactor

avinationmerge
Melanie 2011-04-18 20:17:29 +01:00
commit d1913f2429
14 changed files with 550 additions and 424 deletions

View File

@ -1352,12 +1352,12 @@ namespace OpenSim.Client.MXP.ClientStack
// Need to translate to MXP somehow
}
public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description)
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
{
//throw new System.NotImplementedException();
}
public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice)
public void SendObjectPropertiesReply(ISceneEntity entity)
{
//throw new System.NotImplementedException();
}

View File

@ -890,12 +890,12 @@ namespace OpenSim.Client.VWoHTTP.ClientStack
throw new System.NotImplementedException();
}
public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description)
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
{
throw new System.NotImplementedException();
}
public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice)
public void SendObjectPropertiesReply(ISceneEntity entity)
{
throw new System.NotImplementedException();
}

View File

@ -574,16 +574,35 @@ namespace OpenSim.Framework
public float dwell;
}
public class EntityUpdate
public class IEntityUpdate
{
public ISceneEntity Entity;
public PrimUpdateFlags Flags;
public float TimeDilation;
public uint Flags;
public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation)
public virtual void Update(IEntityUpdate update)
{
this.Flags |= update.Flags;
}
public IEntityUpdate(ISceneEntity entity, uint flags)
{
Entity = entity;
Flags = flags;
}
}
public class EntityUpdate : IEntityUpdate
{
// public ISceneEntity Entity;
// public PrimUpdateFlags Flags;
public float TimeDilation;
public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation)
: base(entity,(uint)flags)
{
//Entity = entity;
// Flags = flags;
TimeDilation = timedilation;
}
}
@ -1217,20 +1236,9 @@ namespace OpenSim.Framework
/// <param name="stats"></param>
void SendSimStats(SimStats stats);
void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID,
uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask,
uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice,
uint Category,
UUID LastOwnerID, string ObjectName, string Description);
void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags);
void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID,
UUID FromTaskUUID,
UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID,
UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle,
string ItemName,
string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask,
uint EveryoneMask,
uint BaseMask, byte saleType, int salePrice);
void SendObjectPropertiesReply(ISceneEntity Entity);
void SendAgentOffline(UUID[] agentIDs);

View File

@ -301,77 +301,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Used to adjust Sun Orbit values so Linden based viewers properly position sun</summary>
private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
// First log file or time has expired, start writing to a new log file
//<MIC>
// -----------------------------------------------------------------
// -----------------------------------------------------------------
// THIS IS DEBUGGING CODE & SHOULD BE REMOVED
// -----------------------------------------------------------------
// -----------------------------------------------------------------
public class QueueLogger
{
public Int32 start = 0;
public StreamWriter Log = null;
private Dictionary<UUID,int> m_idMap = new Dictionary<UUID,int>();
public QueueLogger()
{
DateTime now = DateTime.Now;
String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss"));
Log = new StreamWriter(fname);
start = Util.EnvironmentTickCount();
}
public int LookupID(UUID uuid)
{
int localid;
if (! m_idMap.TryGetValue(uuid,out localid))
{
localid = m_idMap.Count + 1;
m_idMap[uuid] = localid;
}
return localid;
}
}
public static QueueLogger QueueLog = null;
// -----------------------------------------------------------------
public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue)
{
if (QueueLog == null)
QueueLog = new QueueLogger();
Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
lock(QueueLog)
{
int cid = QueueLog.LookupID(client);
int aid = QueueLog.LookupID(avatar);
QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue);
}
}
// -----------------------------------------------------------------
public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup)
{
if (QueueLog == null)
QueueLog = new QueueLogger();
Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
lock(QueueLog)
{
int cid = QueueLog.LookupID(client);
QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString());
}
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
// -----------------------------------------------------------------
// -----------------------------------------------------------------
//</MIC>
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
@ -387,6 +316,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private int m_cachedTextureSerial;
private PriorityQueue m_entityUpdates;
private PriorityQueue m_entityProps;
private Prioritizer m_prioritizer;
private bool m_disableFacelights = false;
@ -435,9 +365,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected IAssetService m_assetService;
private const bool m_checkPackets = true;
private Timer m_propertiesPacketTimer;
private List<ObjectPropertiesPacket.ObjectDataBlock> m_propertiesBlocks = new List<ObjectPropertiesPacket.ObjectDataBlock>();
#endregion Class Members
#region Properties
@ -521,6 +448,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_scene = scene;
m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
m_entityProps = new PriorityQueue(m_scene.Entities.Count);
m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
m_killRecord = new HashSet<uint>();
// m_attachmentsSent = new HashSet<uint>();
@ -544,9 +472,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_udpClient.OnQueueEmpty += HandleQueueEmpty;
m_udpClient.OnPacketStats += PopulateStats;
m_propertiesPacketTimer = new Timer(100);
m_propertiesPacketTimer.Elapsed += ProcessObjectPropertiesPacket;
m_prioritizer = new Prioritizer(m_scene);
RegisterLocalPacketHandlers();
@ -2468,7 +2393,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
packet.Effect = effectBlocks;
OutPacket(packet, ThrottleOutPacketType.State);
// OutPacket(packet, ThrottleOutPacketType.State);
OutPacket(packet, ThrottleOutPacketType.Task);
}
public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember,
@ -3670,9 +3596,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
}
private Int32 m_LastQueueFill = 0;
private uint m_maxUpdates = 0;
private void ProcessEntityUpdates(int maxUpdates)
{
OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@ -3680,41 +3603,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
// Check to see if this is a flush
if (maxUpdates <= 0)
{
m_maxUpdates = Int32.MaxValue;
maxUpdates = Int32.MaxValue;
}
else
{
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
{
m_maxUpdates = (uint)maxUpdates;
}
else
{
if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200)
m_maxUpdates += 5;
else
m_maxUpdates = m_maxUpdates >> 1;
}
m_maxUpdates = Util.Clamp<uint>(m_maxUpdates,10,500);
}
m_LastQueueFill = Util.EnvironmentTickCount();
int updatesThisCall = 0;
// We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
// condition where a kill can be processed before an out-of-date update for the same object.
float avgTimeDilation = 1.0f;
EntityUpdate update;
IEntityUpdate iupdate;
Int32 timeinqueue; // this is just debugging code & can be dropped later
while (updatesThisCall < m_maxUpdates)
while (updatesThisCall < maxUpdates)
{
lock (m_entityUpdates.SyncRoot)
if (!m_entityUpdates.TryDequeue(out update, out timeinqueue))
if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
break;
EntityUpdate update = (EntityUpdate)iupdate;
avgTimeDilation += update.TimeDilation;
avgTimeDilation *= 0.5f;
@ -3770,7 +3680,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!found)
continue;
}
if (part.ParentGroup.IsAttachment && m_disableFacelights)
{
if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
@ -3785,7 +3694,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region UpdateFlags to packet type conversion
PrimUpdateFlags updateFlags = update.Flags;
PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
bool canUseCompressed = true;
bool canUseImproved = true;
@ -3960,12 +3869,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion Primitive Packet/Data Sending Methods
// These are used to implement an adaptive backoff in the number
// of updates converted to packets. Since we don't want packets
// to sit in the queue with old data, only convert enough updates
// to packets that can be sent in 200ms.
private Int32 m_LastQueueFill = 0;
private Int32 m_maxUpdates = 0;
void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
{
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
{
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
{
m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
}
else
{
if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200)
m_maxUpdates += 5;
else
m_maxUpdates = m_maxUpdates >> 1;
}
m_maxUpdates = Util.Clamp<Int32>(m_maxUpdates,10,500);
m_LastQueueFill = Util.EnvironmentTickCount();
if (m_entityUpdates.Count > 0)
ProcessEntityUpdates(m_udpServer.PrimUpdatesPerCallback);
ProcessEntityUpdates(m_maxUpdates);
if (m_entityProps.Count > 0)
ProcessEntityPropertyRequests(m_maxUpdates);
}
if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
@ -4079,47 +4012,167 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(pack, ThrottleOutPacketType.Task);
}
public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID,
uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask,
uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category,
UUID LastOwnerID, string ObjectName, string Description)
private class ObjectPropertyUpdate : IEntityUpdate
{
ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
// TODO: don't create new blocks if recycling an old packet
internal bool SendFamilyProps;
internal bool SendObjectProps;
ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock();
objPropDB.RequestFlags = RequestFlags;
objPropDB.ObjectID = ObjectUUID;
if (OwnerID == GroupID)
objPropDB.OwnerID = UUID.Zero;
else
objPropDB.OwnerID = OwnerID;
objPropDB.GroupID = GroupID;
objPropDB.BaseMask = BaseMask;
objPropDB.OwnerMask = OwnerMask;
objPropDB.GroupMask = GroupMask;
objPropDB.EveryoneMask = EveryoneMask;
objPropDB.NextOwnerMask = NextOwnerMask;
// TODO: More properties are needed in SceneObjectPart!
objPropDB.OwnershipCost = OwnershipCost;
objPropDB.SaleType = SaleType;
objPropDB.SalePrice = SalePrice;
objPropDB.Category = Category;
objPropDB.LastOwnerID = LastOwnerID;
objPropDB.Name = Util.StringToBytes256(ObjectName);
objPropDB.Description = Util.StringToBytes256(Description);
objPropFamilyPack.ObjectData = objPropDB;
objPropFamilyPack.Header.Zerocoded = true;
OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task);
public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj)
: base(entity,flags)
{
SendFamilyProps = sendfam;
SendObjectProps = sendobj;
}
public void Update(ObjectPropertyUpdate update)
{
SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
SendObjectProps = SendObjectProps || update.SendObjectProps;
Flags |= update.Flags;
}
}
public void SendObjectPropertiesReply(
UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID,
UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID,
UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName,
string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask,
uint BaseMask, byte saleType, int salePrice)
public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags)
{
uint priority = 0; // time based ordering only
lock (m_entityProps.SyncRoot)
m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
}
public void SendObjectPropertiesReply(ISceneEntity entity)
{
uint priority = 0; // time based ordering only
lock (m_entityProps.SyncRoot)
m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true));
}
private void ProcessEntityPropertyRequests(int maxUpdates)
{
OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>> objectFamilyBlocks =
new OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>>();
OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks =
new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>();
IEntityUpdate iupdate;
Int32 timeinqueue; // this is just debugging code & can be dropped later
int updatesThisCall = 0;
while (updatesThisCall < m_maxUpdates)
{
lock (m_entityProps.SyncRoot)
if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue))
break;
ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate;
if (update.SendFamilyProps)
{
if (update.Entity is SceneObjectPart)
{
SceneObjectPart sop = (SceneObjectPart)update.Entity;
ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
objectFamilyBlocks.Value.Add(objPropDB);
}
}
if (update.SendObjectProps)
{
if (update.Entity is SceneObjectPart)
{
SceneObjectPart sop = (SceneObjectPart)update.Entity;
ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
objectPropertiesBlocks.Value.Add(objPropDB);
}
}
updatesThisCall++;
}
Int32 ppcnt = 0;
Int32 pbcnt = 0;
if (objectPropertiesBlocks.IsValueCreated)
{
List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value;
ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count];
for (int i = 0; i < blocks.Count; i++)
packet.ObjectData[i] = blocks[i];
packet.Header.Zerocoded = true;
OutPacket(packet, ThrottleOutPacketType.Task, true);
pbcnt += blocks.Count;
ppcnt++;
}
Int32 fpcnt = 0;
Int32 fbcnt = 0;
if (objectFamilyBlocks.IsValueCreated)
{
List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value;
// ObjectPropertiesFamilyPacket objPropFamilyPack =
// (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
//
// objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count];
// for (int i = 0; i < blocks.Count; i++)
// objPropFamilyPack.ObjectData[i] = blocks[i];
//
// OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true);
// one packet per object block... uggh...
for (int i = 0; i < blocks.Count; i++)
{
ObjectPropertiesFamilyPacket packet =
(ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
packet.ObjectData = blocks[i];
packet.Header.Zerocoded = true;
OutPacket(packet, ThrottleOutPacketType.Task);
fpcnt++;
fbcnt++;
}
}
// m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt);
// m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt);
}
private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags)
{
ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock();
block.RequestFlags = requestFlags;
block.ObjectID = sop.UUID;
if (sop.OwnerID == sop.GroupID)
block.OwnerID = UUID.Zero;
else
block.OwnerID = sop.OwnerID;
block.GroupID = sop.GroupID;
block.BaseMask = sop.BaseMask;
block.OwnerMask = sop.OwnerMask;
block.GroupMask = sop.GroupMask;
block.EveryoneMask = sop.EveryoneMask;
block.NextOwnerMask = sop.NextOwnerMask;
// TODO: More properties are needed in SceneObjectPart!
block.OwnershipCost = sop.OwnershipCost;
block.SaleType = sop.ObjectSaleType;
block.SalePrice = sop.SalePrice;
block.Category = sop.Category;
block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right?
block.Name = Util.StringToBytes256(sop.Name);
block.Description = Util.StringToBytes256(sop.Description);
return block;
}
private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop)
{
//ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
// TODO: don't create new blocks if recycling an old packet
@ -4127,87 +4180,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ObjectPropertiesPacket.ObjectDataBlock block =
new ObjectPropertiesPacket.ObjectDataBlock();
block.ItemID = ItemID;
block.CreationDate = CreationDate;
block.CreatorID = CreatorUUID;
block.FolderID = FolderUUID;
block.FromTaskID = FromTaskUUID;
block.GroupID = GroupUUID;
block.InventorySerial = InventorySerial;
block.ObjectID = sop.UUID;
block.Name = Util.StringToBytes256(sop.Name);
block.Description = Util.StringToBytes256(sop.Description);
block.LastOwnerID = LastOwnerUUID;
// proper.ObjectData[0].LastOwnerID = UUID.Zero;
block.ObjectID = ObjectUUID;
if (OwnerUUID == GroupUUID)
block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds
block.CreatorID = sop.CreatorID;
block.GroupID = sop.GroupID;
block.LastOwnerID = sop.LastOwnerID;
if (sop.OwnerID == sop.GroupID)
block.OwnerID = UUID.Zero;
else
block.OwnerID = OwnerUUID;
block.TouchName = Util.StringToBytes256(TouchTitle);
block.TextureID = TextureID;
block.SitName = Util.StringToBytes256(SitTitle);
block.Name = Util.StringToBytes256(ItemName);
block.Description = Util.StringToBytes256(ItemDescription);
block.OwnerMask = OwnerMask;
block.NextOwnerMask = NextOwnerMask;
block.GroupMask = GroupMask;
block.EveryoneMask = EveryoneMask;
block.BaseMask = BaseMask;
// proper.ObjectData[0].AggregatePerms = 53;
// proper.ObjectData[0].AggregatePermTextures = 0;
// proper.ObjectData[0].AggregatePermTexturesOwner = 0;
block.SaleType = saleType;
block.SalePrice = salePrice;
block.OwnerID = sop.OwnerID;
lock (m_propertiesPacketTimer)
{
m_propertiesBlocks.Add(block);
block.ItemID = sop.FromUserInventoryItemID;
block.FolderID = UUID.Zero; // sop.FromFolderID ??
block.FromTaskID = UUID.Zero; // ???
block.InventorySerial = (short)sop.InventorySerial;
int length = 0;
foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks)
{
length += b.Length;
}
if (length > 1100) // FIXME: use real MTU
{
ProcessObjectPropertiesPacket(null, null);
m_propertiesPacketTimer.Stop();
return;
}
SceneObjectPart root = sop.ParentGroup.RootPart;
m_propertiesPacketTimer.Stop();
m_propertiesPacketTimer.Start();
}
block.TouchName = Util.StringToBytes256(root.TouchName);
block.TextureID = new byte[0]; // TextureID ???
block.SitName = Util.StringToBytes256(root.SitName);
block.OwnerMask = root.OwnerMask;
block.NextOwnerMask = root.NextOwnerMask;
block.GroupMask = root.GroupMask;
block.EveryoneMask = root.EveryoneMask;
block.BaseMask = root.BaseMask;
block.SaleType = root.ObjectSaleType;
block.SalePrice = root.SalePrice;
//proper.Header.Zerocoded = true;
//OutPacket(proper, ThrottleOutPacketType.Task);
}
private void ProcessObjectPropertiesPacket(Object sender, ElapsedEventArgs e)
{
ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
lock (m_propertiesPacketTimer)
{
m_propertiesPacketTimer.Stop();
if (m_propertiesBlocks.Count == 0)
return;
proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count];
int index = 0;
foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks)
{
proper.ObjectData[index++] = b;
}
m_propertiesBlocks.Clear();
}
proper.Header.Zerocoded = true;
OutPacket(proper, ThrottleOutPacketType.Task);
return block;
}
#region Estate Data Sending Methods
@ -4548,6 +4552,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void SendForceClientSelectObjects(List<uint> ObjectIDs)
{
m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
bool firstCall = true;
const int MAX_OBJECTS_PER_PACKET = 251;
ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect);

View File

@ -135,7 +135,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private int m_nextOnQueueEmpty = 1;
/// <summary>Throttle bucket for this agent's connection</summary>
private readonly TokenBucket m_throttle;
private readonly TokenBucket m_throttleClient;
/// <summary>Throttle bucket for this agent's connection</summary>
private readonly TokenBucket m_throttleCategory;
/// <summary>Throttle buckets for each packet category</summary>
private readonly TokenBucket[] m_throttleCategories;
/// <summary>Outgoing queues for throttled packets</summary>
@ -175,7 +177,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_maxRTO = maxRTO;
// Create a token bucket throttle for this client that has the scene token bucket as a parent
m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total);
m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit);
// Create a token bucket throttle for the total categary with the client bucket as a throttle
m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit);
// Create an array of token buckets for this clients different throttle categories
m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
@ -186,7 +190,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Initialize the packet outboxes, where packets sit while they are waiting for tokens
m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
// Initialize the token buckets that control the throttling for each category
m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type));
m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type));
}
// Default the retransmission timeout to three seconds
@ -207,6 +211,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_packetOutboxes[i].Clear();
m_nextPackets[i] = null;
}
// pull the throttle out of the scene throttle
m_throttleClient.Parent.UnregisterRequest(m_throttleClient);
OnPacketStats = null;
OnQueueEmpty = null;
}
@ -217,6 +224,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <returns>Information about the client connection</returns>
public ClientInfo GetClientInfo()
{
///<mic>
TokenBucket tb;
tb = m_throttleClient.Parent;
m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT");
tb = m_throttleClient;
m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT");
tb = m_throttleCategory;
m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY");
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
{
tb = m_throttleCategories[i];
m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET");
}
///</mic>
// TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
// of pending and needed ACKs for every client every time some method wants information about
// this connection is a recipe for poor performance
@ -224,13 +251,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
info.pendingAcks = new Dictionary<uint, uint>();
info.needAck = new Dictionary<uint, byte[]>();
info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
// info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle +
info.taskThrottle + info.assetThrottle + info.textureThrottle;
@ -318,8 +346,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
// State is a subcategory of task that we allocate a percentage to
int state = (int)((float)task * STATE_TASK_PERCENTAGE);
task -= state;
int state = 0;
// int state = (int)((float)task * STATE_TASK_PERCENTAGE);
// task -= state;
// Make sure none of the throttles are set below our packet MTU,
// otherwise a throttle could become permanently clogged
@ -340,40 +369,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Update the token buckets with new throttle values
TokenBucket bucket;
bucket = m_throttle;
bucket.MaxBurst = total;
bucket = m_throttleCategory;
bucket.RequestedDripRate = total;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
bucket.DripRate = resend;
bucket.MaxBurst = resend;
bucket.RequestedDripRate = resend;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
bucket.DripRate = land;
bucket.MaxBurst = land;
bucket.RequestedDripRate = land;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
bucket.DripRate = wind;
bucket.MaxBurst = wind;
bucket.RequestedDripRate = wind;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
bucket.DripRate = cloud;
bucket.MaxBurst = cloud;
bucket.RequestedDripRate = cloud;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
bucket.DripRate = asset;
bucket.MaxBurst = asset;
bucket.RequestedDripRate = asset;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
bucket.DripRate = task + state;
bucket.MaxBurst = task + state;
bucket.RequestedDripRate = task;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.State];
bucket.DripRate = state;
bucket.MaxBurst = state;
bucket.RequestedDripRate = state;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
bucket.DripRate = texture;
bucket.MaxBurst = texture;
bucket.RequestedDripRate = texture;
// Reset the packed throttles cached data
m_packedThrottles = null;
@ -388,14 +409,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
data = new byte[7 * 4];
int i = 0;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) +
m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4;
m_packedThrottles = data;
}
@ -428,6 +448,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
TokenBucket bucket = m_throttleCategories[category];
// Don't send this packet if there is already a packet waiting in the queue
// even if we have the tokens to send it, tokens should go to the already
// queued packets
if (queue.Count > 0)
{
queue.Enqueue(packet);
return true;
}
if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
{
// Enough tokens were removed from the bucket, the packet will not be queued

View File

@ -228,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
#endregion BinaryStats
m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps);
m_throttle = new TokenBucket(null, sceneThrottleBps);
ThrottleRates = new ThrottleRates(configSource);
}

View File

@ -78,7 +78,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
public bool Enqueue(uint pqueue, EntityUpdate value)
public bool Enqueue(uint pqueue, IEntityUpdate value)
{
LookupItem lookup;
@ -87,7 +87,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (m_lookupTable.TryGetValue(localid, out lookup))
{
entry = lookup.Heap[lookup.Handle].EntryOrder;
value.Flags |= lookup.Heap[lookup.Handle].Value.Flags;
value.Update(lookup.Heap[lookup.Handle].Value);
lookup.Heap.Remove(lookup.Handle);
}
@ -99,7 +99,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return true;
}
internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue)
internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
{
for (int i = 0; i < m_numberOfQueues; ++i)
{
@ -122,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
timeinqueue = 0;
value = default(EntityUpdate);
value = default(IEntityUpdate);
return false;
}
@ -175,8 +175,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region MinHeapItem
private struct MinHeapItem : IComparable<MinHeapItem>
{
private EntityUpdate value;
internal EntityUpdate Value {
private IEntityUpdate value;
internal IEntityUpdate Value {
get {
return this.value;
}
@ -212,7 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
this.pqueue = pqueue;
}
internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value)
internal MinHeapItem(uint pqueue, UInt64 entryorder, IEntityUpdate value)
{
this.entrytime = Util.EnvironmentTickCount();
this.entryorder = entryorder;

View File

@ -26,6 +26,10 @@
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using log4net;
namespace OpenSim.Region.ClientStack.LindenUDP
{
@ -35,89 +39,126 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary>
public class TokenBucket
{
/// <summary>Parent bucket to this bucket, or null if this is a root
/// bucket</summary>
TokenBucket parent;
/// <summary>Size of the bucket in bytes. If zero, the bucket has
/// infinite capacity</summary>
int maxBurst;
/// <summary>Rate that the bucket fills, in bytes per millisecond. If
/// zero, the bucket always remains full</summary>
int tokensPerMS;
/// <summary>Number of tokens currently in the bucket</summary>
int content;
/// <summary>Time of the last drip, in system ticks</summary>
int lastDrip;
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static Int32 m_counter = 0;
#region Properties
private Int32 m_identifier;
/// <summary>
/// Number of ticks (ms) per quantum, drip rate and max burst
/// are defined over this interval.
/// </summary>
private const Int32 m_ticksPerQuantum = 1000;
/// <summary>
/// This is the number of quantums worth of packets that can
/// be accommodated during a burst
/// </summary>
private const Double m_quantumsPerBurst = 1.5;
/// <summary>
/// </summary>
private const Int32 m_minimumDripRate = 1400;
/// <summary>Time of the last drip, in system ticks</summary>
private Int32 m_lastDrip;
/// <summary>
/// The number of bytes that can be sent at this moment. This is the
/// current number of tokens in the bucket
/// </summary>
private Int64 m_tokenCount;
/// <summary>
/// Map of children buckets and their requested maximum burst rate
/// </summary>
private Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
#region Properties
/// <summary>
/// The parent bucket of this bucket, or null if this bucket has no
/// parent. The parent bucket will limit the aggregate bandwidth of all
/// of its children buckets
/// </summary>
private TokenBucket m_parent;
public TokenBucket Parent
{
get { return parent; }
get { return m_parent; }
set { m_parent = value; }
}
/// <summary>
/// Maximum burst rate in bytes per second. This is the maximum number
/// of tokens that can accumulate in the bucket at any one time
/// of tokens that can accumulate in the bucket at any one time. This
/// also sets the total request for leaf nodes
/// </summary>
public int MaxBurst
private Int64 m_burstRate;
public Int64 RequestedBurstRate
{
get { return maxBurst; }
set { maxBurst = (value >= 0 ? value : 0); }
get { return m_burstRate; }
set { m_burstRate = (value < 0 ? 0 : value); }
}
/// <summary>
/// The speed limit of this bucket in bytes per second. This is the
/// number of tokens that are added to the bucket per second
/// </summary>
/// <remarks>Tokens are added to the bucket any time
/// <seealso cref="RemoveTokens"/> is called, at the granularity of
/// the system tick interval (typically around 15-22ms)</remarks>
public int DripRate
public Int64 BurstRate
{
get { return tokensPerMS * 1000; }
set
{
if (value == 0)
tokensPerMS = 0;
else
{
int bpms = (int)((float)value / 1000.0f);
get {
double rate = RequestedBurstRate * BurstRateModifier();
if (rate < m_minimumDripRate * m_quantumsPerBurst)
rate = m_minimumDripRate * m_quantumsPerBurst;
if (bpms <= 0)
tokensPerMS = 1; // 1 byte/ms is the minimum granularity
else
tokensPerMS = bpms;
}
return (Int64) rate;
}
}
/// <summary>
/// The speed limit of this bucket in bytes per millisecond
/// The speed limit of this bucket in bytes per second. This is the
/// number of tokens that are added to the bucket per quantum
/// </summary>
public int DripPerMS
/// <remarks>Tokens are added to the bucket any time
/// <seealso cref="RemoveTokens"/> is called, at the granularity of
/// the system tick interval (typically around 15-22ms)</remarks>
private Int64 m_dripRate;
public Int64 RequestedDripRate
{
get { return tokensPerMS; }
get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
set {
m_dripRate = (value < 0 ? 0 : value);
m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
m_totalDripRequest = m_dripRate;
if (m_parent != null)
m_parent.RegisterRequest(this,m_dripRate);
}
}
public Int64 DripRate
{
get {
if (m_parent == null)
return Math.Min(RequestedDripRate,TotalDripRequest);
double rate = (double)RequestedDripRate * m_parent.DripRateModifier();
if (rate < m_minimumDripRate)
rate = m_minimumDripRate;
return (Int64)rate;
}
}
/// <summary>
/// The number of bytes that can be sent at this moment. This is the
/// current number of tokens in the bucket
/// <remarks>If this bucket has a parent bucket that does not have
/// enough tokens for a request, <seealso cref="RemoveTokens"/> will
/// return false regardless of the content of this bucket</remarks>
/// The current total of the requested maximum burst rates of
/// this bucket's children buckets.
/// </summary>
public int Content
{
get { return content; }
}
private Int64 m_totalDripRequest;
public Int64 TotalDripRequest
{
get { return m_totalDripRequest; }
set { m_totalDripRequest = value; }
}
#endregion Properties
#endregion Properties
#region Constructor
/// <summary>
/// Default constructor
@ -128,12 +169,76 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// zero if this bucket has no maximum capacity</param>
/// <param name="dripRate">Rate that the bucket fills, in bytes per
/// second. If zero, the bucket always remains full</param>
public TokenBucket(TokenBucket parent, int maxBurst, int dripRate)
public TokenBucket(TokenBucket parent, Int64 dripRate)
{
this.parent = parent;
MaxBurst = maxBurst;
DripRate = dripRate;
lastDrip = Environment.TickCount;
m_identifier = m_counter++;
Parent = parent;
RequestedDripRate = dripRate;
// TotalDripRequest = dripRate; // this will be overwritten when a child node registers
// MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
m_lastDrip = Environment.TickCount & Int32.MaxValue;
}
#endregion Constructor
/// <summary>
/// Compute a modifier for the MaxBurst rate. This is 1.0, meaning
/// no modification if the requested bandwidth is less than the
/// max burst bandwidth all the way to the root of the throttle
/// hierarchy. However, if any of the parents is over-booked, then
/// the modifier will be less than 1.
/// </summary>
private double DripRateModifier()
{
Int64 driprate = DripRate;
return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
}
/// <summary>
/// </summary>
private double BurstRateModifier()
{
// for now... burst rate is always m_quantumsPerBurst (constant)
// larger than drip rate so the ratio of burst requests is the
// same as the drip ratio
return DripRateModifier();
}
/// <summary>
/// Register drip rate requested by a child of this throttle. Pass the
/// changes up the hierarchy.
/// </summary>
public void RegisterRequest(TokenBucket child, Int64 request)
{
m_children[child] = request;
// m_totalDripRequest = m_children.Values.Sum();
m_totalDripRequest = 0;
foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
m_totalDripRequest += cref.Value;
// Pass the new values up to the parent
if (m_parent != null)
m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
}
/// <summary>
/// Remove the rate requested by a child of this throttle. Pass the
/// changes up the hierarchy.
/// </summary>
public void UnregisterRequest(TokenBucket child)
{
m_children.Remove(child);
// m_totalDripRequest = m_children.Values.Sum();
m_totalDripRequest = 0;
foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
m_totalDripRequest += cref.Value;
// Pass the new values up to the parent
if (m_parent != null)
m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
}
/// <summary>
@ -142,32 +247,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <param name="amount">Number of tokens to remove from the bucket</param>
/// <returns>True if the requested number of tokens were removed from
/// the bucket, otherwise false</returns>
public bool RemoveTokens(int amount)
public bool RemoveTokens(Int64 amount)
{
if (maxBurst == 0)
// Deposit tokens for this interval
Drip();
// If we have enough tokens then remove them and return
if (m_tokenCount - amount >= 0)
{
// we don't have to remove from the parent, the drip rate is already
// reflective of the drip rate limits in the parent
m_tokenCount -= amount;
return true;
}
if (amount > maxBurst)
{
throw new Exception("amount " + amount + " exceeds maxBurst " + maxBurst);
}
return false;
}
Drip();
/// <summary>
/// Deposit tokens into the bucket from a child bucket that did
/// not use all of its available tokens
/// </summary>
private void Deposit(Int64 count)
{
m_tokenCount += count;
if (content < amount)
{
return false;
}
if (parent != null && !parent.RemoveTokens(amount))
{
return false;
}
content -= amount;
return true;
// Deposit the overflow in the parent bucket, this is how we share
// unused bandwidth
Int64 burstrate = BurstRate;
if (m_tokenCount > burstrate)
m_tokenCount = burstrate;
}
/// <summary>
@ -176,30 +285,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// call to Drip
/// </summary>
/// <returns>True if tokens were added to the bucket, otherwise false</returns>
public bool Drip()
private void Drip()
{
if (tokensPerMS == 0)
// This should never happen... means we are a leaf node and were created
// with no drip rate...
if (DripRate == 0)
{
content = maxBurst;
return true;
m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0");
return;
}
int now = Environment.TickCount;
int deltaMS = now - lastDrip;
lastDrip = now;
// Determine the interval over which we are adding tokens, never add
// more than a single quantum of tokens
Int32 now = Environment.TickCount & Int32.MaxValue;
Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum);
m_lastDrip = now;
// This can be 0 in the very unusual case that the timer wrapped
// It can be 0 if we try add tokens at a sub-tick rate
if (deltaMS <= 0)
{
return false;
}
return;
long dripAmount = (long)deltaMS * (long)tokensPerMS + (long)content;
if (dripAmount > maxBurst)
{
dripAmount = maxBurst;
}
content = (int)dripAmount;
return true;
Deposit(deltaMS * DripRate / m_ticksPerQuantum);
}
}
}

View File

@ -702,18 +702,12 @@ namespace OpenSim.Region.Examples.SimpleModule
{
}
public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID,
uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask,
uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category,
UUID LastOwnerID, string ObjectName, string Description)
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
{
}
public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID,
UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID,
UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName,
string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask,
uint BaseMask, byte saleType, int salePrice)
public void SendObjectPropertiesReply(ISceneEntity entity)
{
}

View File

@ -2111,10 +2111,12 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="part"></param>
public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
{
remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask,
RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
RootPart.CreatorID, RootPart.Name, RootPart.Description);
remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags);
// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask,
// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
// RootPart.CreatorID, RootPart.Name, RootPart.Description);
}
public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)

View File

@ -2093,15 +2093,7 @@ namespace OpenSim.Region.Framework.Scenes
public void GetProperties(IClientAPI client)
{
//Viewer wants date in microseconds so multiply it by 1,000,000.
client.SendObjectPropertiesReply(
m_fromUserInventoryItemID, (ulong)_creationDate*(ulong)1e6, _creatorID, UUID.Zero, UUID.Zero,
_groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID,
ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description,
ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask,
ParentGroup.RootPart._baseMask,
ParentGroup.RootPart.ObjectSaleType,
ParentGroup.RootPart.SalePrice);
client.SendObjectPropertiesReply(this);
}
public UUID GetRootPartUUID()

View File

@ -1338,14 +1338,13 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
}
public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description)
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
{
}
public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice)
public void SendObjectPropertiesReply(ISceneEntity entity)
{
}
public void SendAgentOffline(UUID[] agentIDs)

View File

@ -786,18 +786,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC
{
}
public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID,
uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask,
uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category,
UUID LastOwnerID, string ObjectName, string Description)
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
{
}
public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID,
UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID,
UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName,
string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask,
uint BaseMask, byte saleType, int salePrice)
public void SendObjectPropertiesReply(ISceneEntity entity)
{
}

View File

@ -816,18 +816,11 @@ namespace OpenSim.Tests.Common.Mock
{
}
public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID,
uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask,
uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category,
UUID LastOwnerID, string ObjectName, string Description)
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
{
}
public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID,
UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID,
UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName,
string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask,
uint BaseMask, byte saleType, int salePrice)
public void SendObjectPropertiesReply(ISceneEntity entity)
{
}