using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.ServiceModel; using System.Timers; using DistributedGA.Core.Domain; namespace DistributedGA.ContactServer { [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class ContactServiceImpl : IContactService, IDisposable { private ConcurrentDictionary allPeers = null; private Timer timer = null; private Object logLock = new Object(); private Object timerLock = new Object();//if elapsed takes too long, another thread also enters the method public ContactServiceImpl() { allPeers = new ConcurrentDictionary(); timer = new Timer(1000 * 60 * 2); //each minute timer.Elapsed += CleanUpContactTable; timer.Start(); } public void RegisterPeer(PeerInfo source) { try { UpdateHeartbeat(source); } catch (Exception ex) { AddError("ContactServiceImpl.RegisterPeer", ex); } } public List GetPeerList(PeerInfo source) { try { UpdateHeartbeat(source); //only return peers of the same work group and not the sender itself return allPeers.Keys.Where(x => { if (source.ProblemInstance.Equals(x.ProblemInstance) && (!(x.IpAddress.Equals(source.IpAddress) && (x.Port.Equals(source.Port))))) return true; else return false; }).ToList(); } catch (Exception ex) { AddError("ContactServiceImpl.GetPeerList", ex); return null; } } public void UpdateHeartbeat(PeerInfo source) { try { Console.WriteLine("hb from {0}:{1}", source.IpAddress, source.Port); DateTime now = DateTime.Now; allPeers.AddOrUpdate(source, now, (k, v) => v = now); } catch (Exception ex) { AddError("ContactServiceImpl.UpdateHeartbeat", ex); } } private void CleanUpContactTable(object sender, ElapsedEventArgs e) { lock (timerLock) { DateTime deadline = DateTime.Now; //collect items to remove List itemsToDelete = new List(); foreach (PeerInfo pi in allPeers.Keys) { DateTime tmp; if (allPeers.TryGetValue(pi, out tmp)) { if (tmp.AddMinutes(2) < deadline) { itemsToDelete.Add(pi); } } } //remove items foreach (PeerInfo pi in itemsToDelete) { DateTime tmp; allPeers.TryRemove(pi, out tmp); Console.WriteLine(string.Format("Removed peer {0}:{1} from dictionary because last access was: {2}", pi.IpAddress, pi.Port, tmp)); } } } private void AddError(string source, Exception ex) { } public void Dispose() { timer.Stop(); timer.Dispose(); timer = null; } } }