source: trunk/CrypPlugins/PeerToPeerPublisher/SubscribersManagement.cs @ 1199

Last change on this file since 1199 was 1199, checked in by arnold, 12 years ago

P2PManager

  • Enlarged KeyPatternSize range to 1.000, because the new DES/AES-Implementation runs so fast, that a KeyPattern with KeyPatternSize of 150 will be processed in approximately 40 seconds on a modern PC
  • Embellished Layout
  • Enhanced information display (total processing time)
  • Jobs in progress change their color every second between Yellow and LightGray

Samples:

  • Changed from CFB to CBC, because this modus is much faster than CFB!
  • Changed KeyPatternSize to 150, because the new DES/AES Implementation runs much faster
File size: 10.3 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Collections;
6using System.IO;
7using Cryptool.PluginBase.Control;
8
9namespace Cryptool.Plugins.PeerToPeer
10{
11    public class SubscriberManagement
12    {
13        public delegate void SubscriberRemoved(PeerId peerId);
14        /// <summary>
15        /// this event is thrown when a subscriber/worker has been removed from managing list
16        /// </summary>
17        public event SubscriberRemoved OnSubscriberRemoved;
18
19        private DateTime dateTimeNow;
20        /// <summary>
21        /// contains all active subscribers
22        /// </summary>
23        private Dictionary<PeerId, DateTime> checkList;
24        /// <summary>
25        /// when a peer is in this list, it will be deleted on the next vitality check
26        /// </summary>
27        private HashSet<PeerId> secondChanceList;
28
29        private long expirationTime;
30        /// <summary>
31        /// Timespan in which subscriber gets marked secondChance first and twice is removed from Subscriber list.
32        /// Latency of 3 seconds will be added because of network latency.
33        /// </summary>
34        public long ExpirationTime
35        {
36            get { return this.expirationTime + 3000;  }
37            set { this.expirationTime = value; } 
38        }
39
40        /// <summary>
41        ///
42        /// </summary>
43        /// <param name="expirationTime">expiration Time of a subscriber in milliseconds</param>
44        public SubscriberManagement(long expirationTime)
45        {
46            this.dateTimeNow = new DateTime();
47            this.checkList = new Dictionary<PeerId, DateTime>();
48            this.secondChanceList = new HashSet<PeerId>();
49            this.ExpirationTime = expirationTime;
50        }
51
52        /// <summary>
53        /// Add a subscriber to the subscriber list if it doesn't already exist
54        /// </summary>
55        /// <param name="subscriberId">ID of the Subscriber</param>
56        /// <returns>true if subscriber wasn't in List and is added, otherwise false</returns>
57        public virtual bool Add(PeerId subscriberId)
58        {
59            bool retValue = false;
60
61            lock (this.checkList)
62            {
63                if (!this.checkList.ContainsKey(subscriberId))
64                {
65                    this.dateTimeNow = DateTime.Now;
66                    // locking checkList instead of activeSubsList, because all other functions work on checkList, not on activeSubsList
67                    lock (this.checkList)
68                    {
69                        this.checkList.Add(subscriberId, this.dateTimeNow);
70                        retValue = true;
71                    }
72                }
73            } // end lock
74            return retValue;
75
76        }
77
78        /// <summary>
79        /// Updates the Timestamp of the given subscriber if it exists.
80        /// </summary>
81        /// <param name="subscriberId"></param>
82        /// <returns></returns>
83        public bool Update(PeerId subscriberId)
84        {
85            this.dateTimeNow = DateTime.Now;
86            if (this.checkList.ContainsKey(subscriberId))
87            {
88                this.checkList[subscriberId] = this.dateTimeNow;
89                // remove subscriber from this list, because it's updated now and hence alive!
90                if (this.secondChanceList.Contains(subscriberId))
91                    this.secondChanceList.Remove(subscriberId);
92                return true;
93            }
94            return false;
95        }
96
97        /// <summary>
98        /// Removes Subscriber/Worker from all managment lists
99        /// </summary>
100        /// <param name="subscriberId">ID of the removed subscriber/worker</param>
101        /// <returns></returns>
102        public virtual bool Remove(PeerId subscriberId)
103        {
104            bool result = false;
105            lock (this.checkList)
106            {
107                if (this.secondChanceList.Contains(subscriberId))
108                    this.secondChanceList.Remove(subscriberId);
109                if (this.checkList.ContainsKey(subscriberId))
110                {
111                    this.checkList.Remove(subscriberId);
112                    result = true;
113                }
114
115                if (result && OnSubscriberRemoved != null)
116                    OnSubscriberRemoved(subscriberId);
117            }
118            return result;
119        }
120
121        /// <summary>
122        /// Removes all Subscribers which are long-rated outdated (expiration time is considered).
123        /// The recently outdated subscribers will be added to the returned second chance list.
124        /// </summary>
125        /// <returns>all recently outdated subscribers</returns>
126        public List<PeerId> CheckVitality()
127        {
128            this.dateTimeNow = DateTime.Now;
129
130            List<PeerId> removeSubscribersFromDict = new List<PeerId>();
131
132            lock (this.checkList)
133            {
134                foreach (KeyValuePair<PeerId, DateTime> entry in this.checkList)
135                {
136                    DateTime valueWithExpirationTime = entry.Value.AddMilliseconds(ExpirationTime);
137
138                    // if time is expired AND the ID is already in the secondChanceList --> Add to remove list
139                    if (this.dateTimeNow > valueWithExpirationTime && secondChanceList.Contains(entry.Key))
140                    {
141                        removeSubscribersFromDict.Add(entry.Key);
142                    }
143                    else if (this.dateTimeNow > valueWithExpirationTime) //otherwise give a second chance
144                    {
145                        this.secondChanceList.Add(entry.Key);
146                    }
147                }
148            } //end lock(this.checkList)
149
150            foreach (PeerId removeSub in removeSubscribersFromDict)
151            {
152                Remove(removeSub);
153            }
154
155            return this.secondChanceList.ToList<PeerId>();
156        }
157
158        public List<PeerId> GetAllSubscribers()
159        {
160            return this.checkList.Keys.ToList<PeerId>();
161        }
162
163        public virtual void Dispose()
164        {
165            this.checkList.Clear();
166            this.checkList = null;
167            this.secondChanceList.Clear();
168            this.secondChanceList = null;
169        }
170
171        private Encoding enc = Encoding.UTF8;
172        /// <summary>
173        /// serializes only the active subscribers list,
174        /// either the second chance list or the timestamps
175        /// are nonrelevant, because after Deserializing
176        /// this stuff, the availablity is obsolete and have
177        /// to be additionally checked
178        /// </summary>
179        /// <returns></returns>
180        public virtual byte[] Serialize()
181        {
182            byte[] ret = null; 
183            lock (this.checkList)
184            {
185                if (this.checkList == null || this.checkList.Count == 0)
186                {
187                    return null;
188                }
189                List<PeerId> lstActivePeers = this.checkList.Keys.ToList<PeerId>();
190                using (MemoryStream memStream = new MemoryStream())
191                {
192                    // first write dataset count to list
193                    memStream.WriteByte(Convert.ToByte(lstActivePeers.Count));
194                    // than write every peer id as an byte array - first byte is the length of the id
195                    foreach (PeerId pid in lstActivePeers)
196                    {
197                        byte[] byPid = pid.ToByteArray();
198                        byte[] enhancedByte = new byte[byPid.Length + 1];
199                        //additional store PeerId length to ease reconstructing
200                        enhancedByte[0] = Convert.ToByte(byPid.Length);
201                        Buffer.BlockCopy(byPid, 0, enhancedByte, 1, byPid.Length);
202                        memStream.Write(enhancedByte, 0, enhancedByte.Length);
203                    }
204                    ret = memStream.ToArray();
205                }
206            }
207            return ret;
208        }
209
210        /// <summary>
211        /// Deserializes a Subscriber/Worker list and reconstructs the PeerIds. Returns
212        /// the deserialized PeerId, so you can ping the peers to check whether they are
213        /// available anymore.
214        /// </summary>
215        /// <param name="serializedPeerIds">the already serialized peerId byte-array</param>
216        /// <param name="p2pControl">a reference to the p2pControl to convert deserialized byte arrays to valid PeerIds</param>
217        /// <returns></returns>
218        public virtual List<PeerId> Deserialize(byte[] serializedPeerIds, ref IP2PControl p2pControl)
219        {
220            if (serializedPeerIds == null || serializedPeerIds.Length < 2)
221            {
222                throw (new Exception("Invalid byte[] input - deserialization not possible"));
223            }
224            List<PeerId> deserializedPeers = new List<PeerId>();
225
226            MemoryStream memStream = new MemoryStream(serializedPeerIds);
227            try
228            {
229                int peerIdAmount = Convert.ToInt32(memStream.ReadByte());
230                int peerIdLen, readResult;
231                PeerId pid;
232                for (int i = 0; i < peerIdAmount; i++)
233                {
234                    peerIdLen = Convert.ToInt32(memStream.ReadByte());
235                    byte[] byPeerId = new byte[peerIdLen];
236                    readResult = memStream.Read(byPeerId, 0, byPeerId.Length);
237                    if (readResult == 0)
238                        throw (new Exception("Deserialization process of the byte[] was canceled, because byte[] didn't achieve to the conventions."));
239                    // create a new PeerId Object and add it to the list
240                    pid = p2pControl.GetPeerID(byPeerId);
241                    //deserializedPeers.Add(byPeerId);
242                    deserializedPeers.Add(pid);
243                }
244            }
245            catch (Exception ex)
246            {
247                memStream.Flush();
248                memStream.Close();
249                memStream.Dispose();
250                deserializedPeers.Clear();
251                deserializedPeers = null;
252                throw new Exception("Deserialization process of byte[] was canceled, because byte[] didn't achieve to the conventions.", ex);
253            }
254            return deserializedPeers;
255        }
256    }
257}
Note: See TracBrowser for help on using the repository browser.