source: trunk/CrypPlugins/KeySearcher/P2P/DistributedBruteForceManager.cs @ 2115

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

some p2p keysearcher changes (all related to better disconnect handling)

File size: 13.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Numerics;
5using System.Threading;
6using System.Windows.Threading;
7using Cryptool.P2P;
8using Cryptool.P2P.Internal;
9using Cryptool.PluginBase;
10using KeySearcher.Helper;
11using KeySearcher.KeyPattern;
12using KeySearcher.P2P.Exceptions;
13using KeySearcher.P2P.Helper;
14using KeySearcher.P2P.Presentation;
15using KeySearcher.P2P.Storage;
16using KeySearcher.P2P.Tree;
17using KeySearcherPresentation.Controls;
18using System.Timers;
19using Timer = System.Timers.Timer;
20
21namespace KeySearcher.P2P
22{
23    internal class DistributedBruteForceManager
24    {
25        private readonly StorageKeyGenerator keyGenerator;
26        private readonly KeySearcher keySearcher;
27        private readonly KeySearcherSettings settings;
28        private readonly KeyQualityHelper keyQualityHelper;
29        private readonly P2PQuickWatchPresentation quickWatch;
30        private readonly KeyPatternPool patternPool;
31        private readonly StatusContainer status;
32        internal readonly StatisticsGenerator StatisticsGenerator;
33        internal readonly Stopwatch StopWatch;
34
35        private KeyPoolTree keyPoolTree;
36        private AutoResetEvent systemJoinEvent = new AutoResetEvent(false);
37
38        public DistributedBruteForceManager(KeySearcher keySearcher, KeyPattern.KeyPattern keyPattern, KeySearcherSettings settings,
39                                            KeyQualityHelper keyQualityHelper, P2PQuickWatchPresentation quickWatch)
40        {
41            this.keySearcher = keySearcher;
42            this.settings = settings;
43            this.keyQualityHelper = keyQualityHelper;
44            this.quickWatch = quickWatch;
45
46            // TODO when setting is still default (21), it is only displayed as 21 - but the settings-instance contains 0 for that key!
47            if (settings.ChunkSize == 0)
48            {
49                settings.ChunkSize = 21;
50            }
51
52            StopWatch = new Stopwatch();
53            status = new StatusContainer(keySearcher);
54            status.IsCurrentProgressIndeterminate = true;
55
56            keyGenerator = new StorageKeyGenerator(keySearcher, settings);
57            patternPool = new KeyPatternPool(keyPattern, new BigInteger(Math.Pow(2, settings.ChunkSize)));
58            StatisticsGenerator = new StatisticsGenerator(status, quickWatch, keySearcher, settings, this);
59            quickWatch.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(UpdateStatusContainerInQuickWatch));
60        }
61
62        public void Execute()
63        {
64            status.CurrentOperation = "Initializing connection to the peer-to-peer system";
65            new ConnectionHelper(keySearcher, settings).ValidateConnectionToPeerToPeerSystem();
66
67            if (!P2PManager.IsConnected)
68            {
69                keySearcher.GuiLogMessage("Unable to use peer-to-peer system.", NotificationLevel.Error);
70                status.CurrentOperation = "Unable to use peer-to-peer system";
71                return;
72            }
73
74            status.CurrentOperation = "Initializing distributed key pool tree";
75            keyPoolTree = new KeyPoolTree(patternPool, keySearcher, keyQualityHelper, keyGenerator, status, StatisticsGenerator);
76
77            keySearcher.GuiLogMessage(
78                "Total amount of patterns: " + patternPool.Length + ", each containing " + patternPool.PartSize +
79                " keys.", NotificationLevel.Info);
80            status.CurrentOperation = "Ready for calculation";
81
82            status.StartDate = keyPoolTree.StartDate();
83            //----------------------------------------------
84            status.JobSubmitterID = keyPoolTree.SubmitterID();
85            //-----------------------------------------------
86
87            keyPoolTree.UpdateStatusForNewCalculation();
88
89            Leaf currentLeaf;
90            while (!keySearcher.stop)
91            {
92                status.IsCurrentProgressIndeterminate = true;
93
94                BigInteger displayablePatternId;
95                try
96                {
97                    status.CurrentOperation = "Finding next leaf to calculate";
98                    currentLeaf = keyPoolTree.FindNextLeaf();
99                    if (currentLeaf == null)
100                    {
101                        break;
102                    }
103                    displayablePatternId = currentLeaf.PatternId() + 1;
104                }
105                catch (AlreadyCalculatedException)
106                {
107                    keySearcher.GuiLogMessage("Node was already calculated.", NotificationLevel.Info);
108                    keyPoolTree.Reset();
109                    continue;
110                }
111                catch (KeySearcherStopException)  //Fullstopfunction
112                {
113                    keySearcher.GuiLogMessage("Keysearcher Fullstop.", NotificationLevel.Error);
114                    keySearcher.GuiLogMessage("Please Update your Version.", NotificationLevel.Error);
115                    keySearcher.stop = true;
116                    return;
117                }
118
119                // TODO if reserve returns successfully, start timer to update our reserveration every few minutes
120                // if we cannot reacquire our lock in the timer, calculation must be aborted
121                if (!currentLeaf.ReserveLeaf())
122                {
123                    keySearcher.GuiLogMessage(
124                        "Pattern #" + displayablePatternId +
125                        " was reserved before it could be reserved for this CrypTool instance.",
126                        NotificationLevel.Info);
127                    keyPoolTree.Reset();
128                    continue;
129                }
130
131                bool reservationRemoved = false;
132                var reservationTimer = new Timer {Interval = 5*60*1000};    //Every 5 minutes
133                reservationTimer.Elapsed += new ElapsedEventHandler(delegate
134                                                                        {
135                                                                            var oldMessage = status.CurrentOperation;
136                                                                            var message = string.Format("Rereserving pattern #{0}", displayablePatternId);
137                                                                            keySearcher.GuiLogMessage(message, NotificationLevel.Info);
138                                                                            status.CurrentOperation = message;
139                                                                            try
140                                                                            {
141                                                                                if (!currentLeaf.ReserveLeaf())
142                                                                                {
143                                                                                    keySearcher.GuiLogMessage("Rereserving pattern failed! Skipping to next pattern!", 
144                                                                                        NotificationLevel.Warning);
145                                                                                    reservationRemoved = true;
146                                                                                    keySearcher.stop = true;
147                                                                                }
148                                                                            }
149                                                                            catch (Cryptool.P2P.Internal.NotConnectedException)
150                                                                            {
151                                                                                keySearcher.GuiLogMessage("Rereserving pattern failed, because there is no connection!",
152                                                                                        NotificationLevel.Warning);
153                                                                                //TODO: Register OnSystemJoined event to rereserve pattern immediately after reconnect
154                                                                            }
155                                                                            status.CurrentOperation = oldMessage;
156                                                                        });
157
158                keySearcher.GuiLogMessage(
159                    "Running pattern #" + displayablePatternId + " of " + patternPool.Length,
160                    NotificationLevel.Info);
161                status.CurrentChunk = displayablePatternId;
162                status.CurrentOperation = "Calculating pattern " + status.CurrentChunk;
163
164                try
165                {
166                    LinkedList<KeySearcher.ValueKey> result;
167
168                    status.IsCurrentProgressIndeterminate = false;
169                    StopWatch.Start();
170                    reservationTimer.Start();
171                    try
172                    {
173                        result = keySearcher.BruteForceWithLocalSystem(patternPool[currentLeaf.PatternId()], true);
174                        if (reservationRemoved)
175                        {
176                            keySearcher.stop = false;
177                            throw new ReservationRemovedException("");
178                        }
179                    }
180                    finally
181                    {
182                        reservationTimer.Stop();
183                        reservationTimer.Dispose();
184                        StopWatch.Stop();
185                        status.IsCurrentProgressIndeterminate = true;
186                    }
187
188                    if (!keySearcher.stop)
189                    {
190                        if (!P2PManager.IsConnected)
191                        {
192                            status.CurrentOperation = "Connection lost! Waiting for reconnection to store the results!";
193                            keySearcher.GuiLogMessage(status.CurrentOperation, NotificationLevel.Info);
194                           
195                            P2PManager.P2PBase.OnSystemJoined += new P2PBase.SystemJoined(P2PBase_OnSystemJoined);
196                            systemJoinEvent.WaitOne();
197                        }
198
199                        status.CurrentOperation = "Processing results of calculation";
200                        KeyPoolTree.ProcessCurrentPatternCalculationResult(currentLeaf, result);
201                        StatisticsGenerator.ProcessPatternResults(result);
202
203                        status.CurrentOperation = "Calculating global statistics";
204                        StatisticsGenerator.CalculateGlobalStatistics(displayablePatternId);
205
206                        status.LocalFinishedChunks++;
207                        keySearcher.GuiLogMessage(
208                            string.Format("Best match: {0} with {1}", result.First.Value.key, result.First.Value.value),
209                            NotificationLevel.Info);
210
211                        status.CurrentOperation = "Updating status in DHT";
212                        keyPoolTree.UpdateStatus(currentLeaf);
213                    }
214                    else
215                    {
216                        keySearcher.GuiLogMessage("Brute force was stopped, not saving results...",
217                                                  NotificationLevel.Info);
218                        status.ProgressOfCurrentChunk = 0;
219                        currentLeaf.GiveLeafFree();
220                        var message = string.Format("Removed reservation of pattern #{0}", displayablePatternId);
221                        keySearcher.GuiLogMessage(message, NotificationLevel.Info);
222                        status.CurrentOperation = message;
223                    }
224                }
225                catch (ReservationRemovedException)
226                {
227                    keySearcher.GuiLogMessage("Reservation removed by another node (while calculating). " +
228                                              "To avoid a state in limbo, proceeding to first available leaf...",
229                                              NotificationLevel.Info);
230                    keyPoolTree.Reset();
231                    continue;
232                }
233                catch (UpdateFailedException e)
234                {
235                    keySearcher.GuiLogMessage("Could not store results: " + e.Message, NotificationLevel.Info);
236                    keyPoolTree.Reset();
237                    continue;
238                }
239
240                // Push statistics to database
241                status.CurrentOperation = "Pushing statistics to evaluation database";
242                DatabaseStatistics.PushToDatabase(status, StopWatch.ElapsedMilliseconds, keyPoolTree.Identifier, settings, keySearcher);
243            }
244
245            // Set progress to 100%
246            if (!keySearcher.stop && keyPoolTree.IsCalculationFinished())
247            {
248                keySearcher.showProgress(keySearcher.costList, 1, 1, 1);
249                keySearcher.GuiLogMessage("Calculation complete.", NotificationLevel.Info);
250                keyPoolTree.UpdateStatusForFinishedCalculation();
251            }
252
253            StatisticsGenerator.CalculationStopped();
254            status.ProgressOfCurrentChunk = 0;
255            status.IsSearchingForReservedNodes = false;
256            status.IsCurrentProgressIndeterminate = false;
257            status.CurrentOperation = "Idle";
258            status.RemainingTimeTotal = new TimeSpan(0);
259        }
260
261        void P2PBase_OnSystemJoined()
262        {
263            P2PManager.P2PBase.OnSystemJoined -= P2PBase_OnSystemJoined;
264            systemJoinEvent.Set();
265        }
266
267        private void UpdateStatusContainerInQuickWatch()
268        {
269            quickWatch.DataContext = status;
270            quickWatch.UpdateSettings(keySearcher, settings);
271        }
272    }
273}
Note: See TracBrowser for help on using the repository browser.