Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Problems.ExternalEvaluation/3.4/Drivers/EvaluationServiceClient.cs @ 16300

Last change on this file since 16300 was 15018, checked in by gkronber, 8 years ago

#2520 introduced StorableConstructorFlag type for StorableConstructors

File size: 6.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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.IO;
24using Google.ProtocolBuffers;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Parameters;
29using HeuristicLab.Persistence;
30
31namespace HeuristicLab.Problems.ExternalEvaluation {
32  [Item("EvaluationServiceClient", "An RPC client that evaluates a solution.")]
33  [StorableType("99f4f039-b9f1-47fd-8eb2-5ceea57d9197")]
34  public class EvaluationServiceClient : ParameterizedNamedItem, IEvaluationServiceClient {
35
36    public override bool CanChangeName { get { return false; } }
37    public override bool CanChangeDescription { get { return false; } }
38
39    #region Parameters
40    public IValueParameter<IEvaluationChannel> ChannelParameter {
41      get { return (IValueParameter<IEvaluationChannel>)Parameters["Channel"]; }
42    }
43    public IValueParameter<IntValue> RetryParameter {
44      get { return (IValueParameter<IntValue>)Parameters["Retry"]; }
45    }
46
47    private IEvaluationChannel Channel {
48      get { return ChannelParameter.Value; }
49    }
50    #endregion
51
52
53    #region Construction & Cloning
54    [StorableConstructor]
55    protected EvaluationServiceClient(StorableConstructorFlag deserializing) : base(deserializing) { }
56    protected EvaluationServiceClient(EvaluationServiceClient original, Cloner cloner)
57      : base(original, cloner) {
58      RegisterEvents();
59    }
60    public EvaluationServiceClient()
61      : base() {
62      Parameters.Add(new ValueParameter<IEvaluationChannel>("Channel", "The channel over which to call the remote function."));
63      Parameters.Add(new ValueParameter<IntValue>("Retry", "How many times the client should retry obtaining a quality in case there is an exception. Note that it immediately aborts when the channel cannot be opened.", new IntValue(10)));
64      RegisterEvents();
65    }
66    public override IDeepCloneable Clone(Cloner cloner) {
67      return new EvaluationServiceClient(this, cloner);
68    }
69    [StorableHook(HookType.AfterDeserialization)]
70    private void AfterDeserialization() {
71      ChannelParameter_ValueChanged(this, EventArgs.Empty);
72      RegisterEvents();
73    }
74    #endregion
75
76    #region IEvaluationServiceClient Members
77    public QualityMessage Evaluate(SolutionMessage solution, ExtensionRegistry qualityExtensions) {
78      int tries = 0, maxTries = RetryParameter.Value.Value;
79      bool success = false;
80      QualityMessage result = null;
81      while (!success) {
82        try {
83          tries++;
84          CheckAndOpenChannel();
85          Channel.Send(solution);
86          result = (QualityMessage)Channel.Receive(QualityMessage.CreateBuilder(), qualityExtensions);
87          success = true;
88        } catch (InvalidOperationException) {
89          throw;
90        } catch {
91          if (tries >= maxTries)
92            throw;
93        }
94      }
95      if (result != null && result.SolutionId != solution.SolutionId) throw new InvalidDataException(Name + ": Received a quality for a different solution.");
96      return result;
97    }
98
99    public void EvaluateAsync(SolutionMessage solution, ExtensionRegistry qualityExtensions, Action<QualityMessage> callback) {
100      int tries = 0, maxTries = RetryParameter.Value.Value;
101      bool success = false;
102      while (!success) {
103        try {
104          tries++;
105          CheckAndOpenChannel();
106          Channel.Send(solution);
107          success = true;
108        } catch (InvalidOperationException) {
109          throw;
110        } catch {
111          if (tries >= maxTries)
112            throw;
113        }
114      }
115      System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(ReceiveAsync), new ReceiveAsyncInfo(solution, callback, qualityExtensions));
116    }
117    #endregion
118
119    #region Auxiliary Methods
120    private void CheckAndOpenChannel() {
121      if (Channel == null) throw new InvalidOperationException(Name + ": The channel is not defined.");
122      if (!Channel.IsInitialized) {
123        try {
124          Channel.Open();
125        } catch (Exception e) {
126          throw new InvalidOperationException(Name + ": The channel could not be opened.", e);
127        }
128      }
129    }
130
131    private void ReceiveAsync(object callbackInfo) {
132      var info = (ReceiveAsyncInfo)callbackInfo;
133      QualityMessage message = null;
134      try {
135        message = (QualityMessage)Channel.Receive(QualityMessage.CreateBuilder(), info.QualityExtensions);
136      } catch { }
137      if (message != null && message.SolutionId != info.SolutionMessage.SolutionId) throw new InvalidDataException(Name + ": Received a quality for a different solution.");
138      info.CallbackDelegate.Invoke(message);
139    }
140
141    private void RegisterEvents() {
142      ChannelParameter.ValueChanged += new EventHandler(ChannelParameter_ValueChanged);
143    }
144
145    void ChannelParameter_ValueChanged(object sender, EventArgs e) {
146      if (ChannelParameter.Value == null)
147        name = "Empty EvaluationServiceClient";
148      else
149        name = String.Format("{0} ServiceClient", ChannelParameter.Value.Name);
150      OnNameChanged();
151    }
152    #endregion
153
154    private class ReceiveAsyncInfo {
155      public SolutionMessage SolutionMessage { get; set; }
156      public Action<QualityMessage> CallbackDelegate { get; set; }
157      public ExtensionRegistry QualityExtensions { get; set; }
158      public ReceiveAsyncInfo(SolutionMessage solutionMessage, Action<QualityMessage> callbackDelegate, ExtensionRegistry qualityExtensions) {
159        SolutionMessage = solutionMessage;
160        CallbackDelegate = callbackDelegate;
161        QualityExtensions = qualityExtensions;
162      }
163    }
164  }
165}
Note: See TracBrowser for help on using the repository browser.