source: src/Fragmentation/Automation/FragmentController.cpp@ 5adb84

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 5adb84 was 5adb84, checked in by Frederik Heber <heber@…>, 13 years ago

Factored out Operation and derived all operations from it.

  • a number of subclass of FragmentController that encapsulate each operation.
  • Operation contains getEndpointIterator(), handle_FinishOperation() and disconnect().
  • Operation now also contains Exitflag that was formerly in FragmentController.
  • new derived Operations: ReceiveJobsOperation(), CheckResultsOperation(), SendResultsOperation(), ShutdownOperation() that each contain the connect_..., handle_... functions.
  • functions to initiate operation have been placed into these Operation- derived classes as implemented virtual operator().
  • most of the required member variables have also been associated with the class that needs them. Getters and Setters have been relayed for the moment.
  • each Operation as of now needs ref to connection, host and service. This should be changed and the stuff around getEndpointIterator() refactored along with it.
  • Property mode set to 100644
File size: 15.9 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2011 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * FragmentController.cpp
10 *
11 * Created on: Nov 27, 2011
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20// boost asio needs specific operator new
21#include <boost/asio.hpp>
22
23#include "CodePatterns/MemDebug.hpp"
24
25#include <boost/bind.hpp>
26#include <boost/foreach.hpp>
27#include <iostream>
28#include <vector>
29#include "Connection.hpp" // Must come before boost/serialization headers.
30#include <boost/serialization/vector.hpp>
31#include "CodePatterns/Info.hpp"
32#include "CodePatterns/Log.hpp"
33#include "FragmentJob.hpp"
34#include "FragmentResult.hpp"
35#include "ControllerChoices.hpp"
36
37#include "FragmentController.hpp"
38
39/** Constructor of class FragmentController.
40 *
41 * \param io_service io_service for the asynchronous operations
42 * \param _host hostname of server that accepts jobs
43 * \param _service of server
44 */
45FragmentController::FragmentController(
46 boost::asio::io_service& io_service,
47 const std::string& _host,
48 const std::string& _service) :
49 connection_(io_service),
50 host(_host),
51 service(_service),
52 recjobs(connection_, _host, _service),
53 checkres(connection_, _host, _service),
54 sendres(connection_, _host, _service),
55 shutdown(connection_, _host, _service)
56{
57 Info info(__FUNCTION__);
58}
59
60/** Destructor of class FragmentController.
61 *
62 */
63FragmentController::~FragmentController()
64{}
65
66/** Constructor for class Operation.
67 *
68 * \param _connection connection to operate on
69 */
70FragmentController::Operation::Operation(Connection &_connection, const std::string& _host, const std::string& _service) :
71 connection_(_connection),
72 host(_host),
73 service(_service),
74 Exitflag(OkFlag)
75{}
76
77/** Destructor for class Operation.
78 *
79 */
80FragmentController::Operation::~Operation()
81{}
82
83/** Handle connect operation to receive jobs from controller
84 *
85 * \param e error code if something went wrong
86 * \param endpoint_iterator endpoint of the connection
87 */
88void FragmentController::ReceiveJobsOperation::handle_connect_calc(const boost::system::error_code& e,
89 boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
90{
91 Info info(__FUNCTION__);
92 if (!e)
93 {
94 // Successfully established connection. Give choice.
95 enum ControllerChoices choice = ReceiveJobs;
96 connection_.async_write(choice,
97 boost::bind(&FragmentController::ReceiveJobsOperation::handle_SendJobs, this,
98 boost::asio::placeholders::error));
99 } else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) {
100 // Try the next endpoint.
101 connection_.socket().close();
102 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
103 connection_.socket().async_connect(endpoint,
104 boost::bind(&FragmentController::ReceiveJobsOperation::handle_connect_calc, this,
105 boost::asio::placeholders::error, ++endpoint_iterator));
106 } else {
107 // An error occurred. Log it and return. Since we are not starting a new
108 // operation the io_service will run out of work to do and the client will
109 // exit.
110 Exitflag = ErrorFlag;
111 ELOG(1, e.message());
112 }
113}
114
115/** Callback function when an operation has been completed.
116 *
117 * \param e error code if something went wrong
118 */
119void FragmentController::ReceiveJobsOperation::handle_FinishOperation(const boost::system::error_code& e)
120{
121 Info info(__FUNCTION__);
122
123 LOG(1, "INFO: Jobs have been sent. Clearing.");
124 jobs.clear();
125
126 Operation::handle_FinishOperation(e);
127}
128
129
130/** Handle connect operation to send number of done jobs.
131 *
132 * \param e error code if something went wrong
133 * \param endpoint_iterator endpoint of the connection
134 */
135void FragmentController::CheckResultsOperation::handle_connect_check(const boost::system::error_code& e,
136 boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
137{
138 Info info(__FUNCTION__);
139 if (!e)
140 {
141 // Successfully established connection. Give choice.
142 enum ControllerChoices choice = CheckState;
143 connection_.async_write(choice,
144 boost::bind(&FragmentController::CheckResultsOperation::handle_ReceiveDoneJobs, this,
145 boost::asio::placeholders::error));
146 } else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) {
147 // Try the next endpoint.
148 connection_.socket().close();
149 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
150 connection_.socket().async_connect(endpoint,
151 boost::bind(&FragmentController::CheckResultsOperation::handle_connect_check, this,
152 boost::asio::placeholders::error, ++endpoint_iterator));
153 } else {
154 // An error occurred. Log it and return. Since we are not starting a new
155 // operation the io_service will run out of work to do and the client will
156 // exit.
157 Exitflag = ErrorFlag;
158 ELOG(1, e.message());
159 }
160}
161
162/** Handle connect operation to send results.
163 *
164 * \param e error code if something went wrong
165 * \param endpoint_iterator endpoint of the connection
166 */
167void FragmentController::SendResultsOperation::handle_connect_get(const boost::system::error_code& e,
168 boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
169{
170 Info info(__FUNCTION__);
171 if (!e)
172 {
173 // Successfully established connection. Give choice.
174 enum ControllerChoices choice = SendResults;
175 connection_.async_write(choice,
176 boost::bind(&FragmentController::SendResultsOperation::handle_ReceivingResults, this,
177 boost::asio::placeholders::error));
178 } else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) {
179 // Try the next endpoint.
180 connection_.socket().close();
181 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
182 connection_.socket().async_connect(endpoint,
183 boost::bind(&FragmentController::SendResultsOperation::handle_connect_get, this,
184 boost::asio::placeholders::error, ++endpoint_iterator));
185 } else {
186 // An error occurred. Log it and return. Since we are not starting a new
187 // operation the io_service will run out of work to do and the client will
188 // exit.
189 Exitflag = ErrorFlag;
190 ELOG(1, e.message());
191 }
192}
193
194/** Handle connect operation to shutdown scheduler.
195 *
196 * \param e error code if something went wrong
197 * \param endpoint_iterator endpoint of the connection
198 */
199void FragmentController::ShutdownOperation::handle_connect_shutdown(const boost::system::error_code& e,
200 boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
201{
202 Info info(__FUNCTION__);
203 if (!e)
204 {
205 // Successfully established connection. Give choice.
206 enum ControllerChoices choice = Shutdown;
207 connection_.async_write(choice,
208 boost::bind(&FragmentController::ShutdownOperation::handle_FinishOperation, this,
209 boost::asio::placeholders::error));
210 } else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) {
211 // Try the next endpoint.
212 connection_.socket().close();
213 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
214 connection_.socket().async_connect(endpoint,
215 boost::bind(&FragmentController::ShutdownOperation::handle_connect_shutdown, this,
216 boost::asio::placeholders::error, ++endpoint_iterator));
217 } else {
218 // An error occurred. Log it and return. Since we are not starting a new
219 // operation the io_service will run out of work to do and the client will
220 // exit.
221 Exitflag = ErrorFlag;
222 ELOG(1, e.message());
223 }
224}
225
226/** Callback function when an operation has been completed.
227 *
228 * \param e error code if something went wrong
229 */
230void FragmentController::Operation::handle_FinishOperation(const boost::system::error_code& e)
231{
232 Info info(__FUNCTION__);
233 if (!e)
234 {
235 LOG(1, "INFO: Operation completed.");
236 }
237 else
238 {
239 // An error occurred.
240 Exitflag = ErrorFlag;
241 ELOG(1, e.message());
242 }
243
244 // Since we are not starting a new operation the io_service will run out of
245 // work to do and the client will exit.
246}
247
248/** Callback function when jobs have been sent.
249 *
250 * \param e error code if something went wrong
251 */
252void FragmentController::ReceiveJobsOperation::handle_SendJobs(const boost::system::error_code& e)
253{
254 Info info(__FUNCTION__);
255 if (!e)
256 {
257 // Successfully established connection. Start operation to read the vector
258 // of jobs. The connection::async_write() function will automatically
259 // encode the data that is written to the underlying socket.
260 LOG(1, "INFO: Sending "+toString(jobs.size())+" jobs ...");
261 connection_.async_write(jobs,
262 boost::bind(&FragmentController::ReceiveJobsOperation::handle_FinishOperation, this,
263 boost::asio::placeholders::error));
264 }
265 else
266 {
267 // An error occurred.
268 Exitflag = ErrorFlag;
269 ELOG(1, e.message());
270 }
271
272 // Since we are not starting a new operation the io_service will run out of
273 // work to do and the client will exit.
274}
275
276/** Callback function when results have been received.
277 *
278 * \param e error code if something went wrong
279 */
280void FragmentController::SendResultsOperation::handle_ReceivingResults(const boost::system::error_code& e)
281{
282 Info info(__FUNCTION__);
283 if (!e)
284 {
285 // The connection::async_read() function will automatically
286 // decode the data that is written to the underlying socket.
287 connection_.async_read(results,
288 boost::bind(&FragmentController::SendResultsOperation::handle_ReceivedResults, this,
289 boost::asio::placeholders::error));
290 }
291 else
292 {
293 // An error occurred.
294 Exitflag = ErrorFlag;
295 ELOG(1, e.message());
296 }
297
298 // Since we are not starting a new operation the io_service will run out of
299 // work to do and the client will exit.
300}
301
302/** Callback function when doneJobs have been received.
303 *
304 * \param e error code if something went wrong
305 */
306void FragmentController::SendResultsOperation::handle_ReceivedResults(const boost::system::error_code& e)
307{
308 Info info(__FUNCTION__);
309
310 LOG(1, "INFO: Received "+toString(results.size())+" results ...");
311
312 handle_FinishOperation(e);
313}
314
315/** Callback function when doneJobs have been received.
316 *
317 * \param e error code if something went wrong
318 */
319void FragmentController::CheckResultsOperation::handle_ReceiveDoneJobs(const boost::system::error_code& e)
320{
321 Info info(__FUNCTION__);
322 if (!e)
323 {
324 // The connection::async_read() function will automatically
325 // decode the data that is written to the underlying socket.
326 LOG(1, "INFO: Checking number of done jobs ...");
327 connection_.async_read(doneJobs,
328 boost::bind(&FragmentController::Operation::handle_FinishOperation, this,
329 boost::asio::placeholders::error));
330 }
331 else
332 {
333 // An error occurred.
334 Exitflag = ErrorFlag;
335 ELOG(1, e.message());
336 }
337}
338
339/** Internal function to resolve all possible connection endpoints.
340 *
341 * \return endpoint iterator of connection
342 */
343boost::asio::ip::tcp::resolver::iterator FragmentController::Operation::getEndpointIterator()
344{
345 // Resolve the host name into an IP address.
346 boost::asio::ip::tcp::resolver resolver(connection_.socket().get_io_service());
347 boost::asio::ip::tcp::resolver::query query(host, service);
348 boost::asio::ip::tcp::resolver::iterator endpoint_iterator =
349 resolver.resolve(query);
350
351 return endpoint_iterator;
352}
353
354/** Internal function to connect to the endpoint of the server asynchronuously.
355 *
356 * We require internal connetion_ and host and service to be set up for this.
357 */
358void FragmentController::ReceiveJobsOperation::connect_calc()
359{
360 Info info(__FUNCTION__);
361 // Resolve the host name into an IP address.
362 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = getEndpointIterator();
363 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
364
365 // Start an asynchronous connect operation.
366 std::cout << "Connecting to endpoint " << endpoint << " to calc " << std::endl;
367 connection_.socket().async_connect(endpoint,
368 boost::bind(&FragmentController::ReceiveJobsOperation::handle_connect_calc, this,
369 boost::asio::placeholders::error, ++endpoint_iterator));
370}
371
372/** Internal function to connect to the endpoint of the server asynchronuously.
373 *
374 * We require internal connetion_ and host and service to be set up for this.
375 */
376void FragmentController::CheckResultsOperation::connect_check()
377{
378 Info info(__FUNCTION__);
379 // Resolve the host name into an IP address.
380 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = getEndpointIterator();
381 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
382
383 // Start an asynchronous connect operation.
384 std::cout << "Connecting to endpoint " << endpoint << " to check " << std::endl;
385 connection_.socket().async_connect(endpoint,
386 boost::bind(&FragmentController::CheckResultsOperation::handle_connect_check, this,
387 boost::asio::placeholders::error, ++endpoint_iterator));
388}
389
390/** Internal function to connect to the endpoint of the server asynchronuously.
391 *
392 * We require internal connetion_ and host and service to be set up for this.
393 */
394void FragmentController::SendResultsOperation::connect_get()
395{
396 Info info(__FUNCTION__);
397 // Resolve the host name into an IP address.
398 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = getEndpointIterator();
399 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
400
401 // Start an asynchronous connect operation.
402 std::cout << "Connecting to endpoint " << endpoint << " to get results " << std::endl;
403 connection_.socket().async_connect(endpoint,
404 boost::bind(&FragmentController::SendResultsOperation::handle_connect_get, this,
405 boost::asio::placeholders::error, ++endpoint_iterator));
406}
407
408/** Internal function to connect to the endpoint of the server asynchronuously.
409 *
410 * We require internal connetion_ and host and service to be set up for this.
411 */
412void FragmentController::ShutdownOperation::connect_shutdown()
413{
414 Info info(__FUNCTION__);
415 // Resolve the host name into an IP address.
416 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = getEndpointIterator();
417 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
418
419 // Start an asynchronous connect operation.
420 std::cout << "Connecting to endpoint " << endpoint << " to get results " << std::endl;
421 connection_.socket().async_connect(endpoint,
422 boost::bind(&FragmentController::ShutdownOperation::handle_connect_shutdown, this,
423 boost::asio::placeholders::error, ++endpoint_iterator));
424}
425
426/** Internal function to disconnect connection_ correctly.
427 *
428 */
429void FragmentController::Operation::disconnect()
430{
431 //connection_.socket().close();
432}
433
434/** Place number of jobs into this controller.
435 *
436 * \param _jobs jobs to add
437 */
438void FragmentController::ReceiveJobsOperation::addJobs(const std::vector<FragmentJob> &_jobs)
439{
440 jobs.reserve(jobs.size()+_jobs.size());
441 BOOST_FOREACH(FragmentJob job, _jobs) {
442 jobs.push_back(job);
443 }
444}
445
446/** Prepares the calculation of the results for the current jobs.
447 */
448void FragmentController::ReceiveJobsOperation::operator()()
449{
450 Info info(__FUNCTION__);
451 // connect
452 connect_calc();
453 //disconnect
454 disconnect();
455}
456
457/** Prepares the calculation of the results for the current jobs.
458 */
459void FragmentController::CheckResultsOperation::operator()()
460{
461 Info info(__FUNCTION__);
462 // connect
463 connect_check();
464 //disconnect
465 disconnect();
466}
467
468/** Getter for results.
469 *
470 * \return vector of results for the added jobs (\sa addJobs()).
471 */
472std::vector<FragmentResult> FragmentController::SendResultsOperation::getResults()
473{
474 Info info(__FUNCTION__);
475 return results;
476}
477
478/** Function to initiate receival of results.
479 *
480 */
481void FragmentController::SendResultsOperation::operator()()
482{
483 // connect
484 connect_get();
485 //disconnect
486 disconnect();
487}
488
489/** Function to initiate shutdown of server.
490 *
491 */
492void FragmentController::ShutdownOperation::operator()()
493{
494 // connect
495 connect_shutdown();
496 //disconnect
497 disconnect();
498}
499
500/** Getter for doneJobs.
501 *
502 * \sa checkResults()
503 * \param doneJobs
504 */
505size_t FragmentController::CheckResultsOperation::getDoneJobs() const
506{
507 return doneJobs;
508}
509
510/** Getter for number of jobs present in the queue.
511 *
512 * \return jobs.size()
513 */
514size_t FragmentController::ReceiveJobsOperation::getPresentJobs() const
515{
516 return jobs.size();
517}
Note: See TracBrowser for help on using the repository browser.