Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Grid/ClientForm.cs @ 428

Last change on this file since 428 was 415, checked in by gkronber, 16 years ago

fixed #219 (Grid-client returns the whole engine as result)

File size: 8.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Data;
26using System.Drawing;
27using System.Linq;
28using System.Text;
29using System.Windows.Forms;
30using System.ServiceModel;
31using HeuristicLab.Core;
32using System.Xml;
33using System.Threading;
34using System.IO;
35using System.Net;
36using System.Diagnostics;
37
38namespace HeuristicLab.Grid {
39  [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
40  public partial class ClientForm : Form {
41    private ChannelFactory<IEngineStore> factory;
42    private System.Timers.Timer fetchOperationTimer;
43    private IEngineStore engineStore;
44    private Guid currentGuid;
45    private ProcessingEngine currentEngine;
46    private object connectionLock = new object();
47    private bool stopped;
48    private const int CONNECTION_RETRY_TIMEOUT_SEC = 10;
49    private const int MAX_RETRIES = 10;
50
51    public ClientForm() {
52      InitializeComponent();
53      fetchOperationTimer = new System.Timers.Timer();
54      fetchOperationTimer.Interval = 200;
55      fetchOperationTimer.Elapsed += new System.Timers.ElapsedEventHandler(fetchOperationTimer_Elapsed);
56      statusTextBox.Text = "Stopped";
57      stopped = true;
58      currentGuid = Guid.Empty;
59    }
60
61    private void startButton_Click(object sender, EventArgs e) {
62      try {
63        Trace.Listeners.Clear();
64        Trace.Listeners.Add(new EventLogTraceListener("HeuristicLab.Grid"));
65
66        ResetConnection();
67        fetchOperationTimer.Start();
68        startButton.Enabled = false;
69        stopButton.Enabled = true;
70        statusTextBox.Text = "Waiting for engine";
71        stopped = false;
72
73      } catch(CommunicationException ex) {
74        MessageBox.Show("Exception while connecting to the server: " + ex.Message);
75        startButton.Enabled = true;
76        stopButton.Enabled = false;
77        fetchOperationTimer.Stop();
78      }
79    }
80
81    private void ResetConnection() {
82      Trace.TraceInformation("Reset connection in GridClient");
83      NetTcpBinding binding = new NetTcpBinding();
84      binding.MaxReceivedMessageSize = 100000000; // 100Mbytes
85      binding.ReaderQuotas.MaxStringContentLength = 100000000; // also 100M chars
86      binding.ReaderQuotas.MaxArrayLength = 100000000; // also 100M elements;
87      binding.Security.Mode = SecurityMode.None;
88      factory = new ChannelFactory<IEngineStore>(binding);
89      engineStore = factory.CreateChannel(new EndpointAddress(addressTextBox.Text));
90    }
91
92    private void stopButton_Click(object sender, EventArgs e) {
93      stopped = true;
94      fetchOperationTimer.Stop();
95      if(currentEngine != null)
96        currentEngine.Abort();
97      lock(connectionLock) {
98        if(factory.State == CommunicationState.Opened || factory.State == CommunicationState.Opening) {
99          IAsyncResult closeResult = factory.BeginClose(null, null);
100          factory.EndClose(closeResult);
101        }
102      }
103      statusTextBox.Text = "Stopped";
104      stopButton.Enabled = false;
105      startButton.Enabled = true;
106    }
107
108    private void fetchOperationTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
109      byte[] engineXml = null;
110      // first stop the timer!
111      fetchOperationTimer.Stop();
112      bool gotEngine = false;
113      lock(connectionLock) {
114        if(stopped) return;
115        try {
116          gotEngine = engineStore.TryTakeEngine(out currentGuid, out engineXml);
117        } catch(TimeoutException) {
118          Trace.TraceWarning("TimeoutException while trying to get an engine");
119          currentEngine = null;
120          currentGuid = Guid.Empty;
121          // timeout -> just start the timer again
122          fetchOperationTimer.Interval = 5000;
123          fetchOperationTimer.Start();
124        } catch(CommunicationException) {
125          Trace.TraceWarning("CommunicationException while trying to get an engine");
126          // connection problem -> reset connection and start the timer again
127          ResetConnection();
128          currentEngine = null;
129          currentGuid = Guid.Empty;
130          fetchOperationTimer.Interval = 5000;
131          fetchOperationTimer.Start();
132        }
133      }
134      // got engine from server and user didn't press stop -> execute the engine
135      if(gotEngine && !stopped) {
136        currentEngine = RestoreEngine(engineXml);
137        if(InvokeRequired) { Invoke((MethodInvoker)delegate() { statusTextBox.Text = "Executing engine"; }); } else statusTextBox.Text = "Executing engine";
138        currentEngine.Finished += new EventHandler(currentEngine_Finished); // register event-handler that sends result back to server and restarts timer
139        currentEngine.Execute();
140      } else {
141        // ok we didn't get engine -> if the user didn't press stop this means that the server doesn't have engines for us
142        // if the user pressed stop we must not start the timer
143        if(!stopped) {
144          if(InvokeRequired) { Invoke((MethodInvoker)delegate() { statusTextBox.Text = "Waiting for engine"; }); } else statusTextBox.Text = "Waiting for engine";
145          // start the timer again
146          fetchOperationTimer.Interval = 5000;
147          fetchOperationTimer.Start();
148        }
149      }
150    }
151
152    void currentEngine_Finished(object sender, EventArgs e) {
153      ProcessingEngine engine = (ProcessingEngine)sender;
154
155      // if the engine was stopped because of an error (not suspended because of a breakpoint)
156      // it's not necessary to return the whole engine
157      // instead just return an empty engine that has the aborted flag set
158      if(engine.Canceled && !engine.Suspended) {
159        engine.Reset();
160        engine.OperatorGraph.Clear();
161        engine.Abort();
162      }
163
164      if(!engine.Canceled && !engine.Suspended) {
165        engine.OperatorGraph.Clear();
166        engine.GlobalScope.Clear();
167      }
168
169      byte[] resultXml = SaveEngine(engine);
170      bool success = false;
171      int retries = 0;
172      do {
173        lock(connectionLock) {
174          if(!stopped) {
175            try {
176              engineStore.StoreResult(currentGuid, resultXml);
177              success = true;
178            } catch(TimeoutException) {
179              Trace.TraceWarning("TimeoutException while trying to store the result of an engine");
180              success = false;
181              retries++;
182              Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
183            } catch(CommunicationException) {
184              Trace.TraceWarning("CommunicationException while trying to store the result of an engine");
185              ResetConnection();
186              success = false;
187              retries++;
188              Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
189            }
190          }
191        }
192      } while(!stopped && !success && retries < MAX_RETRIES);
193      // ok if we could store the result it's probable that the server can send us another engine use a small time-interval
194      if(success)
195        fetchOperationTimer.Interval = 100;
196      else fetchOperationTimer.Interval = CONNECTION_RETRY_TIMEOUT_SEC; // if there were problems -> sleep for a longer time
197      // clear state
198      currentEngine = null;
199      currentGuid = Guid.Empty;
200      // start the timer
201      fetchOperationTimer.Start();
202    }
203
204    private ProcessingEngine RestoreEngine(byte[] engine) {
205      return (ProcessingEngine)PersistenceManager.RestoreFromGZip(engine);
206    }
207    private byte[] SaveEngine(IEngine engine) {
208      return PersistenceManager.SaveToGZip(engine);
209    }
210  }
211}
Note: See TracBrowser for help on using the repository browser.