diff --git a/LibreMetaverse.StructuredData/JSON/JsonMapper.cs b/LibreMetaverse.StructuredData/JSON/JsonMapper.cs index 4b6bd08e..b5b7915f 100644 --- a/LibreMetaverse.StructuredData/JSON/JsonMapper.cs +++ b/LibreMetaverse.StructuredData/JSON/JsonMapper.cs @@ -281,16 +281,16 @@ namespace LitJson private static MethodInfo GetConvOp (Type t1, Type t2) { - lock (conv_ops_lock) { - if (! conv_ops.ContainsKey (t1)) - conv_ops.Add (t1, new Dictionary ()); + lock (conv_ops_lock) + { + if (!conv_ops.ContainsKey(t1)) + conv_ops.Add(t1, new Dictionary()); + + if (conv_ops[t1].ContainsKey(t2)) + return conv_ops[t1][t2]; } - if (conv_ops[t1].ContainsKey (t2)) - return conv_ops[t1][t2]; - - MethodInfo op = t1.GetMethod ( - "op_Implicit", new Type[] { t2 }); + var op = t1.GetMethod("op_Implicit", new[] { t2 }); lock (conv_ops_lock) { try { diff --git a/LibreMetaverse/AssetManager.cs b/LibreMetaverse/AssetManager.cs index 1ea43af6..407c0e33 100644 --- a/LibreMetaverse/AssetManager.cs +++ b/LibreMetaverse/AssetManager.cs @@ -444,7 +444,7 @@ namespace OpenMetaverse private GridClient Client; - private Dictionary Transfers = new Dictionary(); + private readonly Dictionary Transfers = new Dictionary(); private AssetUpload PendingUpload; private object PendingUploadLock = new object(); @@ -1038,7 +1038,7 @@ namespace OpenMetaverse String.Format("Beginning asset upload [Single Packet], ID: {0}, AssetID: {1}, Size: {2}", upload.ID.ToString(), upload.AssetID.ToString(), upload.Size), Helpers.LogLevel.Info, Client); - Transfers[upload.ID] = upload; + lock (Transfers) Transfers[upload.ID] = upload; // The whole asset will fit in this packet, makes things easy request.AssetBlock.AssetData = data; @@ -1664,13 +1664,15 @@ namespace OpenMetaverse /// The EventArgs object containing the packet data protected void TransferInfoHandler(object sender, PacketReceivedEventArgs e) { - TransferInfoPacket info = (TransferInfoPacket)e.Packet; + var info = (TransferInfoPacket)e.Packet; Transfer transfer; - AssetDownload download; - if (Transfers.TryGetValue(info.TransferInfo.TransferID, out transfer)) + bool success; + lock (Transfers) success = Transfers.TryGetValue(info.TransferInfo.TransferID, out transfer); + + if (success) { - download = (AssetDownload)transfer; + var download = (AssetDownload)transfer; if (download.Callback == null) return; @@ -1745,89 +1747,91 @@ namespace OpenMetaverse TransferPacketPacket asset = (TransferPacketPacket)e.Packet; Transfer transfer; - if (Transfers.TryGetValue(asset.TransferData.TransferID, out transfer)) + bool success; + lock (Transfers) success = Transfers.TryGetValue(asset.TransferData.TransferID, out transfer); + + // skip if we couldn't find the transfer + if (!success) return; + + var download = (AssetDownload)transfer; + if (download.Size == 0) { - AssetDownload download = (AssetDownload)transfer; + Logger.DebugLog("TransferPacket received ahead of the transfer header, blocking...", Client); + + // We haven't received the header yet, block until it's received or times out + download.HeaderReceivedEvent.WaitOne(TRANSFER_HEADER_TIMEOUT, false); if (download.Size == 0) { - Logger.DebugLog("TransferPacket received ahead of the transfer header, blocking...", Client); + Logger.Log("Timed out while waiting for the asset header to download for " + + download.ID.ToString(), Helpers.LogLevel.Warning, Client); - // We haven't received the header yet, block until it's received or times out - download.HeaderReceivedEvent.WaitOne(TRANSFER_HEADER_TIMEOUT, false); + // Abort the transfer + TransferAbortPacket abort = new TransferAbortPacket(); + abort.TransferInfo.ChannelType = (int)download.Channel; + abort.TransferInfo.TransferID = download.ID; + Client.Network.SendPacket(abort, download.Simulator); - if (download.Size == 0) - { - Logger.Log("Timed out while waiting for the asset header to download for " + - download.ID.ToString(), Helpers.LogLevel.Warning, Client); - - // Abort the transfer - TransferAbortPacket abort = new TransferAbortPacket(); - abort.TransferInfo.ChannelType = (int)download.Channel; - abort.TransferInfo.TransferID = download.ID; - Client.Network.SendPacket(abort, download.Simulator); - - download.Success = false; - lock (Transfers) Transfers.Remove(download.ID); - - // Fire the event with our transfer that contains Success = false - if (download.Callback != null) - { - try { download.Callback(download, null); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } - } - - return; - } - } - - // If packets arrive out of order, we add them to the out of order packet directory - // until all previous packets have arrived - try - { - if (download.nextPacket == asset.TransferData.Packet) - { - byte[] data = asset.TransferData.Data; - do - { - Buffer.BlockCopy(data, 0, download.AssetData, download.Transferred, data.Length); - download.Transferred += data.Length; - download.nextPacket++; - } while (download.outOfOrderPackets.TryGetValue(download.nextPacket, out data)); - } - else - { - //Logger.Log(string.Format("Fixing out of order packet {0} when expecting {1}!", asset.TransferData.Packet, download.nextPacket), Helpers.LogLevel.Debug); - download.outOfOrderPackets.Add(asset.TransferData.Packet, asset.TransferData.Data); - } - } - catch (ArgumentException) - { - Logger.Log(String.Format("TransferPacket handling failed. TransferData.Data.Length={0}, AssetData.Length={1}, TransferData.Packet={2}", - asset.TransferData.Data.Length, download.AssetData.Length, asset.TransferData.Packet), Helpers.LogLevel.Error); - return; - } - - //Client.DebugLog(String.Format("Transfer packet {0}, received {1}/{2}/{3} bytes for asset {4}", - // asset.TransferData.Packet, asset.TransferData.Data.Length, transfer.Transferred, transfer.Size, - // transfer.AssetID.ToString())); - - // Check if we downloaded the full asset - if (download.Transferred >= download.Size) - { - Logger.DebugLog("Transfer for asset " + download.AssetID.ToString() + " completed", Client); - - download.Success = true; + download.Success = false; lock (Transfers) Transfers.Remove(download.ID); - // Cache successful asset download - Cache.SaveAssetToCache(download.AssetID, download.AssetData); - + // Fire the event with our transfer that contains Success = false if (download.Callback != null) { - try { download.Callback(download, WrapAsset(download)); } + try { download.Callback(download, null); } catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } + + return; + } + } + + // If packets arrive out of order, we add them to the out of order packet directory + // until all previous packets have arrived + try + { + if (download.nextPacket == asset.TransferData.Packet) + { + byte[] data = asset.TransferData.Data; + do + { + Buffer.BlockCopy(data, 0, download.AssetData, download.Transferred, data.Length); + download.Transferred += data.Length; + download.nextPacket++; + } while (download.outOfOrderPackets.TryGetValue(download.nextPacket, out data)); + } + else + { + //Logger.Log(string.Format("Fixing out of order packet {0} when expecting {1}!", asset.TransferData.Packet, download.nextPacket), Helpers.LogLevel.Debug); + download.outOfOrderPackets.Add(asset.TransferData.Packet, asset.TransferData.Data); + } + } + catch (ArgumentException) + { + Logger.Log(String.Format("TransferPacket handling failed. TransferData.Data.Length={0}, AssetData.Length={1}, TransferData.Packet={2}", + asset.TransferData.Data.Length, download.AssetData.Length, asset.TransferData.Packet), Helpers.LogLevel.Error); + return; + } + + //Client.DebugLog(String.Format("Transfer packet {0}, received {1}/{2}/{3} bytes for asset {4}", + // asset.TransferData.Packet, asset.TransferData.Data.Length, transfer.Transferred, transfer.Size, + // transfer.AssetID.ToString())); + + // Check if we downloaded the full asset + if (download.Transferred >= download.Size) + { + Logger.DebugLog("Transfer for asset " + download.AssetID.ToString() + " completed", Client); + + download.Success = true; + lock (Transfers) Transfers.Remove(download.ID); + + // Cache successful asset download + Cache.SaveAssetToCache(download.AssetID, download.AssetData); + + if (download.Callback != null) + { + try { download.Callback(download, WrapAsset(download)); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } } } @@ -1868,7 +1872,7 @@ namespace OpenMetaverse upload.Type = (AssetType)request.XferID.VFileType; UUID transferID = new UUID(upload.XferID); - Transfers[transferID] = upload; + lock (Transfers) Transfers[transferID] = upload; // Send the first packet containing actual asset data SendNextUploadPacket(upload); @@ -1880,27 +1884,28 @@ namespace OpenMetaverse /// The EventArgs object containing the packet data protected void ConfirmXferPacketHandler(object sender, PacketReceivedEventArgs e) { - ConfirmXferPacketPacket confirm = (ConfirmXferPacketPacket)e.Packet; + var confirm = (ConfirmXferPacketPacket)e.Packet; // Building a new UUID every time an ACK is received for an upload is a horrible // thing, but this whole Xfer system is horrible UUID transferID = new UUID(confirm.XferID.ID); Transfer transfer; - AssetUpload upload = null; - if (Transfers.TryGetValue(transferID, out transfer)) - { - upload = (AssetUpload)transfer; + bool success; + lock (Transfers) success = Transfers.TryGetValue(transferID, out transfer); - //Client.DebugLog(String.Format("ACK for upload {0} of asset type {1} ({2}/{3})", - // upload.AssetID.ToString(), upload.Type, upload.Transferred, upload.Size)); + // skip if we couldn't find the transfer + if (!success) return; + var upload = (AssetUpload)transfer; - try { OnUploadProgress(new AssetUploadEventArgs(upload)); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + //Client.DebugLog(String.Format("ACK for upload {0} of asset type {1} ({2}/{3})", + // upload.AssetID.ToString(), upload.Type, upload.Transferred, upload.Size)); - if (upload.Transferred < upload.Size) - SendNextUploadPacket(upload); - } + try { OnUploadProgress(new AssetUploadEventArgs(upload)); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + + if (upload.Transferred < upload.Size) + SendNextUploadPacket(upload); } /// Process an incoming packet and raise the appropriate events @@ -1916,13 +1921,13 @@ namespace OpenMetaverse if (m_AssetUploadedEvent != null) { - bool found = false; - KeyValuePair foundTransfer = new KeyValuePair(); + var found = false; + var foundTransfer = new KeyValuePair(); // Xfer system sucks really really bad. Where is the damn XferID? lock (Transfers) { - foreach (KeyValuePair transfer in Transfers) + foreach (var transfer in Transfers) { if (transfer.Value.GetType() == typeof(AssetUpload)) { @@ -1962,78 +1967,80 @@ namespace OpenMetaverse /// The EventArgs object containing the packet data protected void SendXferPacketHandler(object sender, PacketReceivedEventArgs e) { - SendXferPacketPacket xfer = (SendXferPacketPacket)e.Packet; + var xfer = (SendXferPacketPacket)e.Packet; // Lame ulong to UUID conversion, please go away Xfer system UUID transferID = new UUID(xfer.XferID.ID); Transfer transfer; - XferDownload download = null; - if (Transfers.TryGetValue(transferID, out transfer)) + bool success; + lock (Transfers) success = Transfers.TryGetValue(transferID, out transfer); + + // skip if we couldn't find the transfer + if (!success) return; + + var download = (XferDownload)transfer; + + // Apply a mask to get rid of the "end of transfer" bit + uint packetNum = xfer.XferID.Packet & 0x0FFFFFFF; + + // Check for out of order packets, possibly indicating a resend + if (packetNum != download.PacketNum) { - download = (XferDownload)transfer; - - // Apply a mask to get rid of the "end of transfer" bit - uint packetNum = xfer.XferID.Packet & 0x0FFFFFFF; - - // Check for out of order packets, possibly indicating a resend - if (packetNum != download.PacketNum) + if (packetNum == download.PacketNum - 1) { - if (packetNum == download.PacketNum - 1) - { - Logger.DebugLog("Resending Xfer download confirmation for packet " + packetNum, Client); - SendConfirmXferPacket(download.XferID, packetNum); - } - else - { - Logger.Log("Out of order Xfer packet in a download, got " + packetNum + " expecting " + download.PacketNum, - Helpers.LogLevel.Warning, Client); - // Re-confirm the last packet we actually received - SendConfirmXferPacket(download.XferID, download.PacketNum - 1); - } - - return; - } - - if (packetNum == 0) - { - // This is the first packet received in the download, the first four bytes are a size integer - // in little endian ordering - byte[] bytes = xfer.DataPacket.Data; - download.Size = (bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24)); - download.AssetData = new byte[download.Size]; - - Logger.DebugLog("Received first packet in an Xfer download of size " + download.Size); - - Buffer.BlockCopy(xfer.DataPacket.Data, 4, download.AssetData, 0, xfer.DataPacket.Data.Length - 4); - download.Transferred += xfer.DataPacket.Data.Length - 4; + Logger.DebugLog("Resending Xfer download confirmation for packet " + packetNum, Client); + SendConfirmXferPacket(download.XferID, packetNum); } else { - Buffer.BlockCopy(xfer.DataPacket.Data, 0, download.AssetData, 1000 * (int)packetNum, xfer.DataPacket.Data.Length); - download.Transferred += xfer.DataPacket.Data.Length; + Logger.Log("Out of order Xfer packet in a download, got " + packetNum + " expecting " + download.PacketNum, + Helpers.LogLevel.Warning, Client); + // Re-confirm the last packet we actually received + SendConfirmXferPacket(download.XferID, download.PacketNum - 1); } - // Increment the packet number to the packet we are expecting next - download.PacketNum++; + return; + } - // Confirm receiving this packet - SendConfirmXferPacket(download.XferID, packetNum); + if (packetNum == 0) + { + // This is the first packet received in the download, the first four bytes are a size integer + // in little endian ordering + byte[] bytes = xfer.DataPacket.Data; + download.Size = (bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24)); + download.AssetData = new byte[download.Size]; - if ((xfer.XferID.Packet & 0x80000000) != 0) - { - // This is the last packet in the transfer - if (!String.IsNullOrEmpty(download.Filename)) - Logger.DebugLog("Xfer download for asset " + download.Filename + " completed", Client); - else - Logger.DebugLog("Xfer download for asset " + download.VFileID.ToString() + " completed", Client); + Logger.DebugLog("Received first packet in an Xfer download of size " + download.Size); - download.Success = true; - lock (Transfers) Transfers.Remove(download.ID); + Buffer.BlockCopy(xfer.DataPacket.Data, 4, download.AssetData, 0, xfer.DataPacket.Data.Length - 4); + download.Transferred += xfer.DataPacket.Data.Length - 4; + } + else + { + Buffer.BlockCopy(xfer.DataPacket.Data, 0, download.AssetData, 1000 * (int)packetNum, xfer.DataPacket.Data.Length); + download.Transferred += xfer.DataPacket.Data.Length; + } - try { OnXferReceived(new XferReceivedEventArgs(download)); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } - } + // Increment the packet number to the packet we are expecting next + download.PacketNum++; + + // Confirm receiving this packet + SendConfirmXferPacket(download.XferID, packetNum); + + if ((xfer.XferID.Packet & 0x80000000) != 0) + { + // This is the last packet in the transfer + if (!String.IsNullOrEmpty(download.Filename)) + Logger.DebugLog("Xfer download for asset " + download.Filename + " completed", Client); + else + Logger.DebugLog("Xfer download for asset " + download.VFileID.ToString() + " completed", Client); + + download.Success = true; + lock (Transfers) Transfers.Remove(download.ID); + + try { OnXferReceived(new XferReceivedEventArgs(download)); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } } @@ -2050,8 +2057,7 @@ namespace OpenMetaverse lock (Transfers) { - Transfer transfer; - if (Transfers.TryGetValue(transferID, out transfer)) + if (Transfers.TryGetValue(transferID, out var transfer)) { download = (XferDownload)transfer; Transfers.Remove(transferID); diff --git a/LibreMetaverse/InternalDictionary.cs b/LibreMetaverse/InternalDictionary.cs index 40fe5780..a9c1cd40 100644 --- a/LibreMetaverse/InternalDictionary.cs +++ b/LibreMetaverse/InternalDictionary.cs @@ -54,7 +54,7 @@ namespace OpenMetaverse /// /// Gets the number of Key/Value pairs contained in the /// - public int Count { get { return Dictionary.Count; } } + public int Count { get { lock (Dictionary) return Dictionary.Count; } } /// /// Initializes a new instance of the Class @@ -280,7 +280,7 @@ namespace OpenMetaverse /// if found, otherwise public bool ContainsKey(TKey key) { - return Dictionary.ContainsKey(key); + lock (Dictionary) return Dictionary.ContainsKey(key); } /// Check if Value exists in Dictionary @@ -288,7 +288,7 @@ namespace OpenMetaverse /// if found, otherwise public bool ContainsValue(TValue value) { - return Dictionary.ContainsValue(value); + lock (Dictionary) return Dictionary.ContainsValue(value); } /// diff --git a/LibreMetaverse/InventoryNodeDictionary.cs b/LibreMetaverse/InventoryNodeDictionary.cs index e31f15d7..b18e4945 100644 --- a/LibreMetaverse/InventoryNodeDictionary.cs +++ b/LibreMetaverse/InventoryNodeDictionary.cs @@ -31,10 +31,10 @@ namespace OpenMetaverse { public class InventoryNodeDictionary: IComparer { - protected SortedDictionary SDictionary; - protected Dictionary Dictionary = new Dictionary(); + protected readonly SortedDictionary SDictionary; + protected readonly Dictionary Dictionary = new Dictionary(); protected InventoryNode parent; - protected object syncRoot = new object(); + protected readonly object syncRoot = new object(); public int Compare(UUID x, UUID y) { InventoryNode n1 = Get(x); @@ -97,14 +97,14 @@ namespace OpenMetaverse public InventoryNode this[UUID key] { - get => (InventoryNode)this.Dictionary[key]; + get => (InventoryNode)Dictionary[key]; set { value.Parent = parent; lock (syncRoot) { Dictionary[key] = value; - if (Settings.SORT_INVENTORY) this.SDictionary[key] = value; + if (Settings.SORT_INVENTORY) SDictionary[key] = value; } } } @@ -113,7 +113,7 @@ namespace OpenMetaverse { get { - if (Settings.SORT_INVENTORY) return this.SDictionary.Keys; + if (Settings.SORT_INVENTORY) return SDictionary.Keys; return Dictionary.Keys; } } @@ -121,8 +121,8 @@ namespace OpenMetaverse { get { - if (Settings.SORT_INVENTORY) return this.SDictionary.Values; - return this.Dictionary.Values; + if (Settings.SORT_INVENTORY) return SDictionary.Values; + return Dictionary.Values; } } @@ -132,7 +132,7 @@ namespace OpenMetaverse lock (syncRoot) { Dictionary[key] = value; - if (Settings.SORT_INVENTORY) this.SDictionary.Add(key, value); + if (Settings.SORT_INVENTORY) SDictionary.Add(key, value); } } @@ -140,14 +140,14 @@ namespace OpenMetaverse { lock (syncRoot) { - this.Dictionary.Remove(key); - if (Settings.SORT_INVENTORY) this.SDictionary.Remove(key); + Dictionary.Remove(key); + if (Settings.SORT_INVENTORY) SDictionary.Remove(key); } } public bool Contains(UUID key) { - return this.Dictionary.ContainsKey(key); + return Dictionary.ContainsKey(key); } internal void Sort() diff --git a/LibreMetaverse/NetworkManager.cs b/LibreMetaverse/NetworkManager.cs index c5b7811c..1ccd932a 100644 --- a/LibreMetaverse/NetworkManager.cs +++ b/LibreMetaverse/NetworkManager.cs @@ -763,9 +763,14 @@ namespace OpenMetaverse OnSimDisconnected(new SimDisconnectedEventArgs(simulator, DisconnectType.NetworkTimeout)); } - lock (Simulators) Simulators.Remove(simulator); + int simulatorsCount; + lock (Simulators) + { + Simulators.Remove(simulator); + simulatorsCount = Simulators.Count; + } - if (Simulators.Count == 0) Shutdown(DisconnectType.SimShutdown); + if (simulatorsCount == 0) Shutdown(DisconnectType.SimShutdown); } else { diff --git a/LibreMetaverse/Simulator.cs b/LibreMetaverse/Simulator.cs index 9e15e4bf..0b25d0a0 100644 --- a/LibreMetaverse/Simulator.cs +++ b/LibreMetaverse/Simulator.cs @@ -1235,12 +1235,12 @@ namespace OpenMetaverse /// private void ResendUnacked() { - if (NeedAck.Count <= 0) return; - NetworkManager.OutgoingPacket[] array; lock (NeedAck) { + if (NeedAck.Count <= 0) return; + // Create a temporary copy of the outgoing packets array to iterate over array = new NetworkManager.OutgoingPacket[NeedAck.Count]; NeedAck.Values.CopyTo(array, 0); diff --git a/LibreMetaverse/TexturePipeline.cs b/LibreMetaverse/TexturePipeline.cs index 581877b2..9d6f4272 100644 --- a/LibreMetaverse/TexturePipeline.cs +++ b/LibreMetaverse/TexturePipeline.cs @@ -136,7 +136,10 @@ namespace OpenMetaverse private System.Timers.Timer RefreshDownloadsTimer; /// Current number of pending and in-process transfers - public int TransferCount => _Transfers.Count; + public int TransferCount + { + get { lock (_Transfers) return _Transfers.Count; } + } /// /// Default constructor, Instantiates a new copy of the TexturePipeline class diff --git a/LibreMetaverse/UtilizationStatistics.cs b/LibreMetaverse/UtilizationStatistics.cs index 904345fb..90fd3e2f 100644 --- a/LibreMetaverse/UtilizationStatistics.cs +++ b/LibreMetaverse/UtilizationStatistics.cs @@ -24,37 +24,28 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System.Threading; using System.Collections.Generic; +using System.Linq; namespace OpenMetaverse.Stats { public enum Type - { - Packet, - Message - } + { + Packet, + Message + } + public class UtilizationStatistics { - public class Stat { - public Type Type; - public long TxCount; - public long RxCount; - public long TxBytes; - public long RxBytes; - - public Stat(Type type, long txCount, long rxCount, long txBytes, long rxBytes) - { - Type = type; - TxCount = txCount; - RxCount = rxCount; - TxBytes = txBytes; - RxBytes = rxBytes; - } + public Type Type { get; set; } + public long TxCount { get; set; } + public long RxCount { get; set; } + public long TxBytes { get; set; } + public long RxBytes { get; set; } } - + private readonly Dictionary m_StatsCollection; public UtilizationStatistics() @@ -62,40 +53,54 @@ namespace OpenMetaverse.Stats m_StatsCollection = new Dictionary(); } - internal void Update(string key, Type Type, long txBytes, long rxBytes) - { + internal void Update(string key, Type type, long txBytes, long rxBytes) + { lock (m_StatsCollection) { - if(m_StatsCollection.ContainsKey(key)) + Stat stat; + + if (m_StatsCollection.ContainsKey(key)) { - Stat stat = m_StatsCollection[key]; - if (rxBytes > 0) + stat = m_StatsCollection[key]; + } + else + { + stat = new Stat() { - Interlocked.Increment(ref stat.RxCount); - Interlocked.Add(ref stat.RxBytes, rxBytes); - } - - if (txBytes > 0) - { - Interlocked.Increment(ref stat.TxCount); - Interlocked.Add(ref stat.TxBytes, txBytes); - } - - } else { - Stat stat; - stat = txBytes > 0 ? new Stat(Type, 1, 0, txBytes, 0) : new Stat(Type, 0, 1, 0, rxBytes); - + Type = type + }; m_StatsCollection.Add(key, stat); } + + if (rxBytes > 0) + { + stat.RxCount += 1; + stat.RxBytes += rxBytes; + } + + if (txBytes > 0) + { + stat.TxCount += 1; + stat.TxBytes += txBytes; + } } } public Dictionary GetStatistics() { - lock(m_StatsCollection) + lock (m_StatsCollection) { - return new Dictionary(m_StatsCollection); + return m_StatsCollection.ToDictionary( + e => e.Key, + e => new Stat() + { + Type = e.Value.Type, + RxBytes = e.Value.RxBytes, + RxCount = e.Value.RxCount, + TxBytes = e.Value.TxBytes, + TxCount = e.Value.TxCount + }); } } } -} +} \ No newline at end of file diff --git a/LibreMetaverseTypes/DoubleDictionary.cs b/LibreMetaverseTypes/DoubleDictionary.cs index 21326406..f78cc6e7 100644 --- a/LibreMetaverseTypes/DoubleDictionary.cs +++ b/LibreMetaverseTypes/DoubleDictionary.cs @@ -28,66 +28,60 @@ using System; using System.Threading; using System.Collections.Generic; -#if VISUAL_STUDIO -using ReaderWriterLockImpl = System.Threading.ReaderWriterLockSlim; -#else -using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim; -#endif - namespace OpenMetaverse { public class DoubleDictionary { - readonly Dictionary Dictionary1; - readonly Dictionary Dictionary2; - ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl(); + private readonly Dictionary _dictionary1; + private readonly Dictionary _dictionary2; + private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); public DoubleDictionary() { - Dictionary1 = new Dictionary(); - Dictionary2 = new Dictionary(); + _dictionary1 = new Dictionary(); + _dictionary2 = new Dictionary(); } public DoubleDictionary(int capacity) { - Dictionary1 = new Dictionary(capacity); - Dictionary2 = new Dictionary(capacity); + _dictionary1 = new Dictionary(capacity); + _dictionary2 = new Dictionary(capacity); } public void Add(TKey1 key1, TKey2 key2, TValue value) { - rwLock.EnterWriteLock(); + _rwLock.EnterWriteLock(); try { - if (Dictionary1.ContainsKey(key1)) + if (_dictionary1.ContainsKey(key1)) { - if (!Dictionary2.ContainsKey(key2)) + if (!_dictionary2.ContainsKey(key2)) throw new ArgumentException("key1 exists in the dictionary but not key2"); } - else if (Dictionary2.ContainsKey(key2)) + else if (_dictionary2.ContainsKey(key2)) { - if (!Dictionary1.ContainsKey(key1)) + if (!_dictionary1.ContainsKey(key1)) throw new ArgumentException("key2 exists in the dictionary but not key1"); } - Dictionary1[key1] = value; - Dictionary2[key2] = value; + _dictionary1[key1] = value; + _dictionary2[key2] = value; } - finally { rwLock.ExitWriteLock(); } + finally { _rwLock.ExitWriteLock(); } } public bool Remove(TKey1 key1, TKey2 key2) { bool success; - rwLock.EnterWriteLock(); + _rwLock.EnterWriteLock(); try { - Dictionary1.Remove(key1); - success = Dictionary2.Remove(key2); + _dictionary1.Remove(key1); + success = _dictionary2.Remove(key2); } - finally { rwLock.ExitWriteLock(); } + finally { _rwLock.ExitWriteLock(); } return success; } @@ -95,27 +89,27 @@ namespace OpenMetaverse public bool Remove(TKey1 key1) { bool found = false; - rwLock.EnterWriteLock(); + _rwLock.EnterWriteLock(); try { // This is an O(n) operation! TValue value; - if (Dictionary1.TryGetValue(key1, out value)) + if (_dictionary1.TryGetValue(key1, out value)) { - foreach (var kvp in Dictionary2) + foreach (var kvp in _dictionary2) { if (kvp.Value.Equals(value)) { - Dictionary1.Remove(key1); - Dictionary2.Remove(kvp.Key); + _dictionary1.Remove(key1); + _dictionary2.Remove(kvp.Key); found = true; break; } } } } - finally { rwLock.ExitWriteLock(); } + finally { _rwLock.ExitWriteLock(); } return found; } @@ -123,62 +117,62 @@ namespace OpenMetaverse public bool Remove(TKey2 key2) { bool found = false; - rwLock.EnterWriteLock(); + _rwLock.EnterWriteLock(); try { // This is an O(n) operation! TValue value; - if (Dictionary2.TryGetValue(key2, out value)) + if (_dictionary2.TryGetValue(key2, out value)) { - foreach (var kvp in Dictionary1) + foreach (var kvp in _dictionary1) { if (kvp.Value.Equals(value)) { - Dictionary2.Remove(key2); - Dictionary1.Remove(kvp.Key); + _dictionary2.Remove(key2); + _dictionary1.Remove(kvp.Key); found = true; break; } } } } - finally { rwLock.ExitWriteLock(); } + finally { _rwLock.ExitWriteLock(); } return found; } public void Clear() { - rwLock.EnterWriteLock(); + _rwLock.EnterWriteLock(); try { - Dictionary1.Clear(); - Dictionary2.Clear(); + _dictionary1.Clear(); + _dictionary2.Clear(); } - finally { rwLock.ExitWriteLock(); } + finally { _rwLock.ExitWriteLock(); } } - public int Count => Dictionary1.Count; + public int Count => _dictionary1.Count; public bool ContainsKey(TKey1 key) { - return Dictionary1.ContainsKey(key); + return _dictionary1.ContainsKey(key); } public bool ContainsKey(TKey2 key) { - return Dictionary2.ContainsKey(key); + return _dictionary2.ContainsKey(key); } public bool TryGetValue(TKey1 key, out TValue value) { bool success; - rwLock.EnterReadLock(); + _rwLock.EnterReadLock(); - try { success = Dictionary1.TryGetValue(key, out value); } - finally { rwLock.ExitReadLock(); } + try { success = _dictionary1.TryGetValue(key, out value); } + finally { _rwLock.ExitReadLock(); } return success; } @@ -186,62 +180,62 @@ namespace OpenMetaverse public bool TryGetValue(TKey2 key, out TValue value) { bool success; - rwLock.EnterReadLock(); + _rwLock.EnterReadLock(); - try { success = Dictionary2.TryGetValue(key, out value); } - finally { rwLock.ExitReadLock(); } + try { success = _dictionary2.TryGetValue(key, out value); } + finally { _rwLock.ExitReadLock(); } return success; } public void ForEach(Action action) { - rwLock.EnterReadLock(); + _rwLock.EnterReadLock(); try { - foreach (var value in Dictionary1.Values) + foreach (var value in _dictionary1.Values) action(value); } - finally { rwLock.ExitReadLock(); } + finally { _rwLock.ExitReadLock(); } } public void ForEach(Action> action) { - rwLock.EnterReadLock(); + _rwLock.EnterReadLock(); try { - foreach (var entry in Dictionary1) + foreach (var entry in _dictionary1) action(entry); } - finally { rwLock.ExitReadLock(); } + finally { _rwLock.ExitReadLock(); } } public void ForEach(Action> action) { - rwLock.EnterReadLock(); + _rwLock.EnterReadLock(); try { - foreach (var entry in Dictionary2) + foreach (var entry in _dictionary2) action(entry); } - finally { rwLock.ExitReadLock(); } + finally { _rwLock.ExitReadLock(); } } public TValue FindValue(Predicate predicate) { - rwLock.EnterReadLock(); + _rwLock.EnterReadLock(); try { - foreach (var value in Dictionary1.Values) + foreach (var value in _dictionary1.Values) { if (predicate(value)) return value; } } - finally { rwLock.ExitReadLock(); } + finally { _rwLock.ExitReadLock(); } return default(TValue); } @@ -249,17 +243,17 @@ namespace OpenMetaverse public IList FindAll(Predicate predicate) { IList list = new List(); - rwLock.EnterReadLock(); + _rwLock.EnterReadLock(); try { - foreach (var value in Dictionary1.Values) + foreach (var value in _dictionary1.Values) { if (predicate(value)) list.Add(value); } } - finally { rwLock.ExitReadLock(); } + finally { _rwLock.ExitReadLock(); } return list; } @@ -268,36 +262,36 @@ namespace OpenMetaverse { IList list = new List(); - rwLock.EnterUpgradeableReadLock(); + _rwLock.EnterUpgradeableReadLock(); try { - foreach (var kvp in Dictionary1) + foreach (var kvp in _dictionary1) { if (predicate(kvp.Value)) list.Add(kvp.Key); } IList list2 = new List(list.Count); - foreach (var kvp in Dictionary2) + foreach (var kvp in _dictionary2) { if (predicate(kvp.Value)) list2.Add(kvp.Key); } - rwLock.EnterWriteLock(); + _rwLock.EnterWriteLock(); try { foreach (var t in list) - Dictionary1.Remove(t); + _dictionary1.Remove(t); foreach (var t in list2) - Dictionary2.Remove(t); + _dictionary2.Remove(t); } - finally { rwLock.ExitWriteLock(); } + finally { _rwLock.ExitWriteLock(); } } - finally { rwLock.ExitUpgradeableReadLock(); } + finally { _rwLock.ExitUpgradeableReadLock(); } return list.Count; } diff --git a/LibreMetaverseTypes/ThreadSafeDictionary.cs b/LibreMetaverseTypes/ThreadSafeDictionary.cs index 30312f6d..e4531576 100644 --- a/LibreMetaverseTypes/ThreadSafeDictionary.cs +++ b/LibreMetaverseTypes/ThreadSafeDictionary.cs @@ -70,17 +70,17 @@ namespace OpenMetaverse public int Count { - get { return Dictionary.Count; } + get { lock (syncObject) return Dictionary.Count; } } public bool ContainsKey(TKey key) { - return Dictionary.ContainsKey(key); + lock (syncObject) return Dictionary.ContainsKey(key); } public bool TryGetValue(TKey key, out TValue value) { - return Dictionary.TryGetValue(key, out value); + lock (syncObject) return Dictionary.TryGetValue(key, out value); } public void ForEach(Action action) @@ -152,7 +152,7 @@ namespace OpenMetaverse public TValue this[TKey key] { - get { return Dictionary[key]; } + get { lock (syncObject) return Dictionary[key]; } } } } diff --git a/Programs/examples/TestClient/Commands/Stats/NetstatsCommand.cs b/Programs/examples/TestClient/Commands/Stats/NetstatsCommand.cs index f111e7ac..45848770 100644 --- a/Programs/examples/TestClient/Commands/Stats/NetstatsCommand.cs +++ b/Programs/examples/TestClient/Commands/Stats/NetstatsCommand.cs @@ -44,9 +44,9 @@ namespace OpenMetaverse.TestClient long capsBytesSent = 0; long capsBytesRecv = 0; - foreach (KeyValuePair kvp in Client.Stats.GetStatistics()) + foreach (KeyValuePair kvp in Client.Stats.GetStatistics()) { - if (kvp.Value.Type == OpenMetaverse.Stats.Type.Message) + if (kvp.Value.Type == Stats.Type.Message) { capsOutput.AppendFormat("{0,-30}|{1,4}|{2,4}|{3,-10}|{4,-10}|" + System.Environment.NewLine, kvp.Key, kvp.Value.TxCount, kvp.Value.RxCount, FormatBytes(kvp.Value.TxBytes), FormatBytes(kvp.Value.RxBytes)); @@ -56,7 +56,7 @@ namespace OpenMetaverse.TestClient capsBytesSent += kvp.Value.TxBytes; capsBytesRecv += kvp.Value.RxBytes; } - else if (kvp.Value.Type == OpenMetaverse.Stats.Type.Packet) + else if (kvp.Value.Type == Stats.Type.Packet) { packetOutput.AppendFormat("{0,-30}|{1,4}|{2,4}|{3,-10}|{4,-10}|" + System.Environment.NewLine, kvp.Key, kvp.Value.TxCount, kvp.Value.RxCount, FormatBytes(kvp.Value.TxBytes), FormatBytes(kvp.Value.RxBytes));