Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 410 was 402, checked in by gkronber, 16 years ago

moved GZip persistence into the PersistenceManager in HeuristicLab.Core because compression is needed in several plugins (CEDMA and Grid)

File size: 7.9 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      IEngine engine = (IEngine)sender;
154      byte[] resultXml = SaveEngine(engine);
155      bool success = false;
156      int retries = 0;
157      do {
158        lock(connectionLock) {
159          if(!stopped) {
160            try {
161              engineStore.StoreResult(currentGuid, resultXml);
162              success = true;
163            } catch(TimeoutException) {
164              Trace.TraceWarning("TimeoutException while trying to store the result of an engine");
165              success = false;
166              retries++;
167              Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
168            } catch(CommunicationException) {
169              Trace.TraceWarning("CommunicationException while trying to store the result of an engine");
170              ResetConnection();
171              success = false;
172              retries++;
173              Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
174            }
175          }
176        }
177      } while(!stopped && !success && retries < MAX_RETRIES);
178      // ok if we could store the result it's probable that the server can send us another engine use a small time-interval
179      if(success)
180        fetchOperationTimer.Interval = 100;
181      else fetchOperationTimer.Interval = CONNECTION_RETRY_TIMEOUT_SEC; // if there were problems -> sleep for a longer time
182      // clear state
183      currentEngine = null;
184      currentGuid = Guid.Empty;
185      // start the timer
186      fetchOperationTimer.Start();
187    }
188
189    private ProcessingEngine RestoreEngine(byte[] engine) {
190      return (ProcessingEngine)PersistenceManager.RestoreFromGZip(engine);
191    }
192    private byte[] SaveEngine(IEngine engine) {
193      return PersistenceManager.SaveToGZip(engine);
194    }
195  }
196}
Note: See TracBrowser for help on using the repository browser.