Click here to Skip to main content
15,896,557 members
Articles / Web Development / ASP.NET

Legion: Build your own virtual super computer with Silverlight

Rate me:
Please Sign up or sign in to vote.
4.87/5 (139 votes)
27 Oct 2008LGPL321 min read 423.4K   1.1K   335  
Legion is a grid computing framework that uses the Silverlight CLR to execute user definable tasks. It provides grid-wide thread-safe operations for web clients. Client performance metrics, such as bandwidth and processor speed, may be used to tailor jobs. Also includes a WPF Manager application.
/*
<File>
	<Copyright>Copyright © 2007, Daniel Vaughan. All rights reserved.</Copyright>
	<License see="prj:///Documentation/License.txt"/>
	<Owner Name="Daniel Vaughan" Email="dbvaughan@gmail.com"/>
	<CreationDate>2007-12-13 22:19:43Z</CreationDate>
	<LastSubmissionDate>$Date: $</LastSubmissionDate>
	<Version>$Revision: $</Version>
</File>
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

namespace Orpius.GridComputing.Collections
{
	/// <summary>
	/// A dictionary collection that automatically
	/// removes items from its own contents once
	/// a specified duration has passed.
	/// </summary>
	/// <typeparam name="TKey">The type of the key.</typeparam>
	/// <typeparam name="TValue">The type of the value.</typeparam>
	class ExpiringDictionary<TKey, TValue> : IDictionary<TKey, TValue>
	{
		readonly Dictionary<TKey, TValue> innerDictionary = new Dictionary<TKey, TValue>();
		readonly List<KeyValuePair<TKey, DateTime>> expiries = new List<KeyValuePair<TKey, DateTime>>();
		TimeSpan itemLiveTime;
		readonly object syncLock = new object();
		readonly Timer timer = new Timer();

		/// <summary>
		/// Gets the sync lock, used for asynchronous access
		/// to the inner collection.
		/// </summary>
		/// <value>The sync lock.</value>
		public object SyncLock
		{
			get
			{
				return syncLock;
			}
		}

		/// <summary>
		/// Gets or sets the time that an item should remain
		/// in the collection before it is automatically removed.
		/// </summary>
		/// <value>The item live time.</value>
		public TimeSpan ItemLiveTime
		{
			get
			{
				return itemLiveTime;
			}
			set
			{
				itemLiveTime = value;
			}
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ExpiringDictionary&lt;TKey, TValue&gt;"/> class.
		/// </summary>
		/// <param name="itemLiveTime">The item live time. <seealso cref="ItemLiveTime"/></param>
		/// <param name="interval">The interval. How frequently to scan
		/// for items to eject.</param>
		public ExpiringDictionary(TimeSpan itemLiveTime, TimeSpan interval)
		{
			this.itemLiveTime = itemLiveTime;
			timer.Interval = interval.TotalMilliseconds;
			timer.Elapsed += RemoveExpiredItems;
			timer.Start();
		}

		void RemoveExpiredItems(object sender, ElapsedEventArgs e)
		{
			lock (SyncLock)
			{
				List<TKey> itemsToBeRemoved = new List<TKey>();
				DateTime expiryTime = DateTime.Now - itemLiveTime;

				foreach (KeyValuePair<TKey, DateTime> pair in expiries)
				{
					if (pair.Value < expiryTime)
					{
						itemsToBeRemoved.Add(pair.Key);
					}
					else
					{
						break;
					}
				}
				foreach (TKey key in itemsToBeRemoved)
				{
					Remove(key);
				}
			}
		}

		public bool ContainsKey(TKey key)
		{
			return innerDictionary.ContainsKey(key);
		}

		public void Add(TKey key, TValue value)
		{
			lock (SyncLock)
			{
				innerDictionary.Add(key, value);
				expiries.Add(new KeyValuePair<TKey, DateTime>(key, DateTime.Now));
			}
		}

		public bool Remove(TKey key)
		{
			lock (SyncLock)
			{
				bool result = innerDictionary.Remove(key);
				return result;
			}
		}

		public bool TryGetValue(TKey key, out TValue value)
		{
			return innerDictionary.TryGetValue(key, out value);
		}

		public TValue this[TKey key]
		{
			get
			{
				return innerDictionary[key];
			}
			set
			{
				lock (SyncLock)
				{
					innerDictionary[key] = value;
					expiries.RemoveAll(delegate(KeyValuePair<TKey, DateTime> k)
					                   	{
					                   		return EqualityComparer<TKey>.Default.Equals(k.Key, key);
					                   	});
					if (!EqualityComparer<TValue>.Default.Equals(value))
					{
						expiries.Add(new KeyValuePair<TKey, DateTime>(key, DateTime.Now));
					}
				}
			}
		}

		public ICollection<TKey> Keys
		{
			get
			{ 
				return innerDictionary.Keys;
			}
		}

		public ICollection<TValue> Values
		{
			get
			{
				return innerDictionary.Values;
			}
		}

		public void Add(KeyValuePair<TKey, TValue> item)
		{
			lock (SyncLock)
			{
				innerDictionary.Add(item.Key, item.Value);
				if (!EqualityComparer<KeyValuePair<TKey, TValue>>.Default.Equals(item))
				{
					expiries.Add(new KeyValuePair<TKey, DateTime>(item.Key, DateTime.Now));
				}
			}
		}

		public void Clear()
		{
			lock (SyncLock)
			{
				innerDictionary.Clear();
				expiries.Clear();
			}
		}

		public bool Contains(KeyValuePair<TKey, TValue> item)
		{
			if (EqualityComparer<KeyValuePair<TKey, TValue>>.Default.Equals(item))
			{
				return false;
			}
			return innerDictionary.ContainsKey(item.Key);
		}

		public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}

			if (arrayIndex < 0 || arrayIndex > array.Length)
			{
				throw new ArgumentOutOfRangeException("arrayIndex", "Must be greater than zero.");
			}
			if (array.Length - arrayIndex < Count)
			{
				throw new ArgumentException("array.Length must be greater than arrayIndex.");
			}
			lock (SyncLock)
			{
				foreach (KeyValuePair<TKey, TValue> pair in innerDictionary)
				{
					array[arrayIndex++] = new KeyValuePair<TKey, TValue>(pair.Key, pair.Value);
				}
			}
		}

		public bool Remove(KeyValuePair<TKey, TValue> item)
		{
			if (EqualityComparer<KeyValuePair<TKey, TValue>>.Default.Equals(item))
			{
				return false;
			}
			lock (SyncLock)
			{
				bool result = innerDictionary.Remove(item.Key);
				return result;
			}
		}

		public int Count
		{
			get
			{
				return innerDictionary.Count;
			}
		}

		public bool IsReadOnly
		{
			get
			{
				return false;
			}
		}

		IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
		{
			return innerDictionary.GetEnumerator();
		}

		public IEnumerator GetEnumerator()
		{
			return ((IEnumerable<KeyValuePair<TKey, TValue>>)this).GetEnumerator();
		}

		/// <summary>
		/// Updates the expiry time on an item in the collection;
		/// thus renewing it so that the time it will remain in the
		/// collection will be increased.
		/// </summary>
		/// <param name="key">The key.</param>
		public void Touch(TKey key)
		{
			lock (SyncLock)
			{
				this[key] = this[key]; /* Forces DateTime update. */
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Engineer
Switzerland Switzerland
Daniel is a former senior engineer in Technology and Research at the Office of the CTO at Microsoft, working on next generation systems.

Previously Daniel was a nine-time Microsoft MVP and co-founder of Outcoder, a Swiss software and consulting company.

Daniel is the author of Windows Phone 8 Unleashed and Windows Phone 7.5 Unleashed, both published by SAMS.

Daniel is the developer behind several acclaimed mobile apps including Surfy Browser for Android and Windows Phone. Daniel is the creator of a number of popular open-source projects, most notably Codon.

Would you like Daniel to bring value to your organisation? Please contact

Blog | Twitter


Xamarin Experts
Windows 10 Experts

Comments and Discussions