source: trunk/CrypPlugins/KeySearcher/P2P/Storage/StorageHelper.cs @ 2454

Last change on this file since 2454 was 2454, checked in by Sven Rech, 11 years ago

Storage Helper

File size: 16.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Threading;
5using Cryptool.P2P;
6using Cryptool.P2P.Internal;
7using Cryptool.PluginBase;
8using KeySearcher.P2P.Exceptions;
9using KeySearcher.P2P.Presentation;
10using KeySearcher.P2P.Tree;
11
12namespace KeySearcher.P2P.Storage
13{
14    class StorageHelper
15    {
16        private readonly KeySearcher keySearcher;
17        private readonly StatisticsGenerator statisticsGenerator;
18        private readonly StatusContainer statusContainer;
19
20        //VERSIONNUMBER: Important. Set it +1 manually everytime the length of the MemoryStream Changes
21        private const int version = 5;
22        /*
23        -----------------------------Versionnumber Changelog---------------------------------------------
24        |   Version 1: Added the Versionnumber to the Stream (Leafs)
25        |   Version 2: Added the first User Statistics (Avatar,ID,Count) to the Stream
26        |   Version 3: Added version question (in front of results) + more statistic information (hostname,date) to the Stream
27        |   Version 4: Reorganisation of the DHT structure. Update fully working now + features from previous versions available
28        |   Version 5: Extended the key information by the user who found it. (Username,Date,Maschid,Host)
29        -------------------------------------------------------------------------------------------------
30         */
31
32        public StorageHelper(KeySearcher keySearcher, StatisticsGenerator statisticsGenerator, StatusContainer statusContainer)
33        {
34            this.keySearcher = keySearcher;
35            this.statisticsGenerator = statisticsGenerator;
36            this.statusContainer = statusContainer;
37        }
38
39        //-------------------------------------------------------------------------------------------
40        //AFTER CHANGING THE FOLLOWING METHODS INCREASE THE VERSION-NUMBER AT THE TOP OF THIS CLASS!
41        //-------------------------------------------------------------------------------------------
42        internal RequestResult UpdateInDht(NodeBase nodeToUpdate)
43        {
44            var memoryStream = new MemoryStream();
45            var binaryWriter = new BinaryWriter(memoryStream);
46
47            //Append Updater Version
48            binaryWriter.Write('W');
49            binaryWriter.Write(version); 
50
51            if (nodeToUpdate is Node)
52            {
53                UpdateNodeInDht((Node) nodeToUpdate, binaryWriter);
54            } else
55            {
56                UpdateLeafInDht((Leaf) nodeToUpdate, binaryWriter);
57            }
58
59            // Append results
60            binaryWriter.Write(nodeToUpdate.Result.Count);
61            foreach (var valueKey in nodeToUpdate.Result)
62            {
63                binaryWriter.Write(valueKey.key);
64                binaryWriter.Write(valueKey.value);
65                binaryWriter.Write(valueKey.decryption.Length);
66                binaryWriter.Write(valueKey.decryption);
67
68                //--------------------------------------------------------
69                binaryWriter.Write(valueKey.user);
70                var buffertime = valueKey.time.ToBinary();
71                binaryWriter.Write(buffertime);
72                binaryWriter.Write(valueKey.maschid);
73                binaryWriter.Write(valueKey.maschname);
74                //---------------------------------------------------------
75            }                       
76             
77            //Creating a copy of the activity dictionary
78            var copyAct = nodeToUpdate.Activity;
79
80            //Write number of avatarnames
81            binaryWriter.Write(copyAct.Keys.Count);
82            foreach (string avatar in copyAct.Keys)
83            {
84                var maschCopy = copyAct[avatar];
85                //write avatarname
86                binaryWriter.Write(avatar);
87                //write the number of maschines for this avatar
88                binaryWriter.Write(maschCopy.Keys.Count);
89
90                foreach (long maschID in maschCopy.Keys)
91                {
92                    //write the maschines and their patterncount
93                    binaryWriter.Write(maschID);
94                    binaryWriter.Write(maschCopy[maschID].Count); //int 32
95                    binaryWriter.Write(maschCopy[maschID].Hostname); //String
96                    binaryWriter.Write(maschCopy[maschID].Date.ToBinary()); //DateTime
97                }
98            }
99            return StoreWithStatistic(KeyInDht(nodeToUpdate), memoryStream.ToArray());
100        }
101
102        private static void UpdateNodeInDht(Node nodeToUpdate, BinaryWriter binaryWriter)
103        {
104            binaryWriter.Write(nodeToUpdate.LeftChildFinished);
105            binaryWriter.Write(nodeToUpdate.RightChildFinished);
106        }
107
108        private static void UpdateLeafInDht(Leaf nodeToUpdate, BinaryWriter binaryWriter)
109        {
110            binaryWriter.Write('V');
111            binaryWriter.Write(version);
112            var buffer = nodeToUpdate.LastReservationDate.ToBinary();
113            binaryWriter.Write(buffer);
114            binaryWriter.Write(nodeToUpdate.getClientIdentifier());
115        }
116
117        internal RequestResult UpdateFromDht(NodeBase nodeToUpdate, bool forceUpdate = false)
118        {
119            try
120            {
121                if (!forceUpdate && nodeToUpdate.LastUpdate > DateTime.Now.Subtract(new TimeSpan(0, 0, 5)))
122                {
123                    return new RequestResult { Status = RequestResultType.Success };
124                }
125
126                nodeToUpdate.LastUpdate = DateTime.Now;
127
128                var requestResult = RetrieveWithStatistic(KeyInDht(nodeToUpdate));
129                var nodeBytes = requestResult.Data;
130
131                if (nodeBytes == null)
132                {
133                    return requestResult;
134                }
135
136                var binaryReader = new BinaryReader(new MemoryStream(nodeBytes));
137
138                //oldVersionFlag will be used to garantee further changes in the Stream
139                var oldVersionFlag = CheckNodeVersion(binaryReader);
140
141                if (nodeToUpdate is Node)
142                {
143                    UpdateNodeFromDht((Node)nodeToUpdate, binaryReader);
144                }
145                else
146                {
147                    UpdateLeafFromDht((Leaf)nodeToUpdate, binaryReader);
148                }
149
150                // Load results
151                var resultCount = binaryReader.ReadInt32();
152
153                for (var i = 0; i < resultCount; i++)
154                {
155                    if (oldVersionFlag < 5)
156                    {
157                        var newResult = new KeySearcher.ValueKey
158                                            {
159                                                key = binaryReader.ReadString(),
160                                                value = binaryReader.ReadDouble(),
161                                                decryption = binaryReader.ReadBytes(binaryReader.ReadInt32()),
162                                                user = "Unknown",
163                                                time = DateTime.MinValue,
164                                                maschid = 666,
165                                                maschname = "Devil"
166                                            };
167                        nodeToUpdate.Result.AddLast(newResult);
168                    }
169                    else
170                    {
171                        var newResult = new KeySearcher.ValueKey
172                                            {
173                                                key = binaryReader.ReadString(),
174                                                value = binaryReader.ReadDouble(),
175                                                decryption = binaryReader.ReadBytes(binaryReader.ReadInt32()),
176                                                user = binaryReader.ReadString(),
177                                                time = DateTime.FromBinary(binaryReader.ReadInt64()),
178                                                maschid = binaryReader.ReadInt64(),
179                                                maschname = binaryReader.ReadString()
180                                            };
181                        nodeToUpdate.Result.AddLast(newResult);
182                    }
183                }
184
185                if (binaryReader.BaseStream.Length != binaryReader.BaseStream.Position)
186                {
187                    //Reading the number of avatarnames
188                    int avatarcount = binaryReader.ReadInt32();
189                    for (int i = 0; i < avatarcount; i++)
190                    {
191                        //Reading the avatarname and the maschine-count for this name
192                        string avatarname = binaryReader.ReadString();
193                        int maschcount = binaryReader.ReadInt32();
194                        var readMaschcount = new Dictionary<long, Information>();
195
196                        for (int j = 0; j < maschcount; j++)
197                        {
198                            //reading the IDs and patterncount
199                            long maschID = binaryReader.ReadInt64();
200                            int count = binaryReader.ReadInt32();
201                            string host = binaryReader.ReadString();
202                            var date = DateTime.FromBinary(binaryReader.ReadInt64());
203                            readMaschcount.Add(maschID, new Information() { Count = count, Hostname = host, Date = date });
204
205                        }
206
207                        if (nodeToUpdate.Activity.ContainsKey(avatarname))
208                        {
209                            nodeToUpdate.Activity[avatarname] = readMaschcount;
210                        }
211                        else
212                        {
213                            nodeToUpdate.Activity.Add(avatarname, readMaschcount);
214                        }
215                    }
216                }
217
218                if (resultCount > 0)
219                {
220                    keySearcher.IntegrateNewResults(nodeToUpdate.Result, nodeToUpdate.Activity,
221                                                    nodeToUpdate.DistributedJobIdentifier);
222                    statisticsGenerator.ProcessPatternResults(nodeToUpdate.Result);
223                }
224
225                nodeToUpdate.UpdateCache();
226                return requestResult;
227            }
228            catch (Exception e)
229            {
230                if (e is KeySearcherStopException)
231                    throw new KeySearcherStopException();
232                else if (e is NotConnectedException)
233                    throw new NotConnectedException();
234
235                // client id not available, use default
236                keySearcher.GuiLogMessage(e.Message + ": Node causing the failure: " + nodeToUpdate.ToString(), NotificationLevel.Error);
237                nodeToUpdate.Reset();
238                throw new InvalidOperationException();
239            }
240        }
241
242        private static void UpdateNodeFromDht(Node nodeToUpdate, BinaryReader binaryReader)
243        {
244            nodeToUpdate.LeftChildFinished = binaryReader.ReadBoolean() || nodeToUpdate.LeftChildFinished;
245            nodeToUpdate.RightChildFinished = binaryReader.ReadBoolean() || nodeToUpdate.RightChildFinished;
246        }
247
248        private static void UpdateLeafFromDht(Leaf nodeToUpdate, BinaryReader binaryReader)
249        {
250            var oldVersionFlag = CheckVersion(binaryReader);
251
252            try
253            {   
254                var date = DateTime.FromBinary(binaryReader.ReadInt64());
255                if (date > nodeToUpdate.LastReservationDate)
256                {
257                    nodeToUpdate.LastReservationDate = date;
258                }
259           
260
261                if (binaryReader.BaseStream.Length - binaryReader.BaseStream.Position >= 8)
262                {
263                    nodeToUpdate.setClientIdentifier(binaryReader.ReadInt64());
264                }
265                else
266                {
267                    throw new Exception();
268                }
269            }
270            catch (Exception)
271            {
272                throw new Exception();
273            }
274           
275        }
276
277        internal static string KeyInDht(NodeBase node)
278        {
279            return string.Format("{0}_node_{1}_{2}", node.DistributedJobIdentifier, node.From, node.To);
280        }
281
282        private static int CheckVersion(BinaryReader binaryReader)
283        {           
284            try
285            {
286                //Checking if there's a version in the stream
287                int vers = binaryReader.PeekChar();
288                if (vers == 86) //V infront of a Leaf
289                {
290                    //Reading the char and the versionnumber
291                    char magic = binaryReader.ReadChar();
292                    int versionInUse = binaryReader.ReadInt32();
293                    //Check if a newer Version is in use
294                    if (versionInUse > version)
295                    {
296                        throw new KeySearcherStopException();
297                    }
298                    return versionInUse;
299                }
300                else
301                {
302                    return 0;
303                }
304            }
305            catch(KeySearcherStopException)
306            {
307                throw new KeySearcherStopException();
308            }           
309        }
310
311        private static int CheckNodeVersion(BinaryReader binaryReader)
312        {
313            try
314            {
315                //Checking if there's a version in the stream
316                int vers = binaryReader.PeekChar();
317                if (vers == 87) //W infront of a Node
318                {
319                    //Reading the char and the versionnumber
320                    char magic = binaryReader.ReadChar();
321                    int versionInUse = binaryReader.ReadInt32();
322                    //Check if a newer Version is in use
323                    if (versionInUse > version)
324                    {
325                        throw new KeySearcherStopException();
326                    }
327                    return versionInUse;
328                }
329                else
330                {
331                    return 0;
332                }
333            }
334            catch (KeySearcherStopException)
335            {
336                throw new KeySearcherStopException();
337            }
338        }
339
340        public DateTime StartDate(String ofJobIdentifier)
341        {
342            var key = ofJobIdentifier + "_startdate";
343            var requestResult = RetrieveWithStatistic(key);
344
345            if (requestResult.IsSuccessful() && requestResult.Data != null)
346            {
347                var startTimeUtc = DateTime.SpecifyKind(
348                    DateTime.FromBinary(BitConverter.ToInt64(requestResult.Data, 0)), DateTimeKind.Utc);
349                return startTimeUtc.ToLocalTime();
350            }
351
352            StoreWithStatistic(key, BitConverter.GetBytes((DateTime.UtcNow.ToBinary())));
353            return DateTime.Now;
354        }
355
356        public long SubmitterID(String ofJobIdentifier)
357        {
358            var key = ofJobIdentifier + "_submitterid";
359            var requestResult = RetrieveWithStatistic(key);
360
361            if (requestResult.IsSuccessful() && requestResult.Data != null)
362            {
363                var submitterid = BitConverter.ToInt64(requestResult.Data, 0);
364                return submitterid;
365            }
366
367            StoreWithStatistic(key, BitConverter.GetBytes(Cryptool.PluginBase.Miscellaneous.UniqueIdentifier.GetID()));
368            return Cryptool.PluginBase.Miscellaneous.UniqueIdentifier.GetID();
369        }
370
371        public RequestResult RetrieveWithStatistic(string key)
372        {
373            statusContainer.RetrieveRequests++;
374            statusContainer.TotalDhtRequests++;
375            var requestResult = P2PManager.Retrieve(key);
376
377            if (requestResult.Data != null)
378            {
379                statusContainer.RetrievedBytes += requestResult.Data.Length;
380                statusContainer.TotalBytes += requestResult.Data.Length;
381            }
382
383            return requestResult;
384        }
385
386        public RequestResult RemoveWithStatistic(string key)
387        {
388            statusContainer.RemoveRequests++;
389            statusContainer.TotalDhtRequests++;
390            return P2PManager.Remove(key);
391        }
392
393        public RequestResult StoreWithStatistic(string key, byte[] data)
394        {
395            statusContainer.StoreRequests++;
396            statusContainer.TotalDhtRequests++;
397            var requestResult = P2PManager.Store(key, data);
398
399            if (requestResult.Data != null)
400            {
401                statusContainer.StoredBytes += requestResult.Data.Length;
402                statusContainer.TotalBytes += requestResult.Data.Length;
403            }
404
405            return requestResult;
406        }
407    }
408}
Note: See TracBrowser for help on using the repository browser.