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 { 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); //each hour 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 MakeLog(PeerInfo source, string msg) { try { // TODO lock (logLock) { File.AppendAllText("Log.txt", string.Concat(source.IpAddress, ":", source.Port, ",", source.ProblemInstance, ",", msg, Environment.NewLine)); } } catch (Exception ex) { //Nothing to do because maybe called from adderror } } 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.AddHours(1f) < deadline) if (tmp.AddMinutes(1) < deadline) //TODO { //if (tmp < deadline.AddHours(1f)) { 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) { MakeLog(new PeerInfo() { ProblemInstance = "ContactServer Error at " + source }, ex.Message); } } }