[41c1b7] | 1 | /*
|
---|
| 2 | * Project: MoleCuilder
|
---|
| 3 | * Description: creates and alters molecular systems
|
---|
| 4 | * Copyright (C) 2012 University of Bonn. All rights reserved.
|
---|
| 5 | * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
|
---|
| 6 | */
|
---|
| 7 |
|
---|
| 8 | /*
|
---|
| 9 | * \file PoolWorker.cpp
|
---|
| 10 | *
|
---|
| 11 | * This file strongly follows the Serialization example from the boost::asio
|
---|
| 12 | * library (see client.cpp).
|
---|
| 13 | *
|
---|
| 14 | * Created on: Feb 28, 2012
|
---|
| 15 | * Author: heber
|
---|
| 16 | */
|
---|
| 17 |
|
---|
| 18 | // include config.h
|
---|
| 19 | #ifdef HAVE_CONFIG_H
|
---|
| 20 | #include <config.h>
|
---|
| 21 | #endif
|
---|
| 22 |
|
---|
| 23 | // boost asio needs specific operator new
|
---|
| 24 | #include <boost/asio.hpp>
|
---|
| 25 |
|
---|
| 26 | #include "CodePatterns/MemDebug.hpp"
|
---|
| 27 |
|
---|
| 28 | #include <boost/bind.hpp>
|
---|
| 29 | #include <boost/lexical_cast.hpp>
|
---|
| 30 | #include <iostream>
|
---|
| 31 | #include <vector>
|
---|
| 32 | #include "Connection.hpp" // Must come before boost/serialization headers.
|
---|
| 33 | #include <boost/serialization/vector.hpp>
|
---|
| 34 | #include "CodePatterns/Info.hpp"
|
---|
| 35 | #include "CodePatterns/Log.hpp"
|
---|
| 36 | #include "Jobs/FragmentJob.hpp"
|
---|
| 37 | #include "Jobs/MPQCCommandJob.hpp"
|
---|
| 38 | #include "Jobs/SystemCommandJob.hpp"
|
---|
[9d7c6a] | 39 | #include "Operations/Workers/EnrollInPoolOperation.hpp"
|
---|
| 40 | #include "Operations/Workers/RemoveFromPoolOperation.hpp"
|
---|
| 41 | #include "Operations/Workers/SubmitResultOperation.hpp"
|
---|
[41c1b7] | 42 | #include "Results/FragmentResult.hpp"
|
---|
| 43 | #include "PoolWorker.hpp"
|
---|
| 44 |
|
---|
| 45 | /** Helper function to enforce binding of PoolWorker to possible derived
|
---|
| 46 | * FragmentJob classes.
|
---|
| 47 | */
|
---|
| 48 | void dummyInit() {
|
---|
| 49 | SystemCommandJob("/bin/false", "something", JobId::IllegalJob);
|
---|
| 50 | MPQCCommandJob("nofile", JobId::IllegalJob);
|
---|
| 51 | }
|
---|
| 52 |
|
---|
| 53 | /** Constructor for class PoolWorker.
|
---|
| 54 | *
|
---|
| 55 | * We automatically connect to the given pool and enroll.
|
---|
| 56 | *
|
---|
[aec098] | 57 | * @param _io_service io service for creating connections
|
---|
[9d7c6a] | 58 | * @param _host host part of MyAddress of pool to connect to
|
---|
| 59 | * @param _service service part of MyAddress of pool to connect to
|
---|
| 60 | * @param listenhost host part of MyAddress of this instance for listening to pool connections
|
---|
| 61 | * @param listenservice seervice part of MyAddress of this instance for listening to pool connections
|
---|
[41c1b7] | 62 | */
|
---|
| 63 | PoolWorker::PoolWorker(
|
---|
[aec098] | 64 | boost::asio::io_service& _io_service,
|
---|
[41c1b7] | 65 | const std::string& _host,
|
---|
| 66 | const std::string& _service,
|
---|
| 67 | const std::string& listenhost,
|
---|
| 68 | const std::string& listenservice) :
|
---|
[aec098] | 69 | io_service(_io_service),
|
---|
| 70 | PoolListener(_io_service, boost::lexical_cast<unsigned short>(listenservice), *this),
|
---|
[b08c7c] | 71 | MyAddress(listenhost, listenservice),
|
---|
[9d7c6a] | 72 | ServerAddress(_host, _service),
|
---|
[aec098] | 73 | connection_(_io_service),
|
---|
[9d7c6a] | 74 | failed(boost::bind(&ExitflagContainer::setExitflag, this, ExitflagContainer::ErrorFlag))
|
---|
[41c1b7] | 75 | {
|
---|
| 76 | Info info(__FUNCTION__);
|
---|
| 77 |
|
---|
[9d7c6a] | 78 | // always enroll and make listenining initiation depend on its success
|
---|
| 79 | const boost::function<void ()> initiateme =
|
---|
| 80 | boost::bind(&PoolListener_t::initiateSocket, boost::ref(PoolListener));
|
---|
| 81 | AsyncOperation *enrollOp = new EnrollInPoolOperation(connection_, MyAddress, initiateme, failed);
|
---|
| 82 | LOG(2, "DEBUG: Putting enroll in pool operation into queue ...");
|
---|
| 83 | OpQueue.push_back(enrollOp, ServerAddress);
|
---|
[41c1b7] | 84 | }
|
---|
| 85 |
|
---|
| 86 | /// Handle completion of a accept server operation.
|
---|
| 87 | void PoolWorker::PoolListener_t::handle_Accept(const boost::system::error_code& e, connection_ptr conn)
|
---|
| 88 | {
|
---|
| 89 | Info info(__FUNCTION__);
|
---|
| 90 | if (!e)
|
---|
| 91 | {
|
---|
| 92 | conn->async_read(job,
|
---|
| 93 | boost::bind(&PoolWorker::PoolListener_t::handle_ReceiveJob, this,
|
---|
| 94 | boost::asio::placeholders::error, conn));
|
---|
| 95 | // and listen for following connections
|
---|
[e8f397] | 96 | initiateSocket();
|
---|
[41c1b7] | 97 | }
|
---|
| 98 | else
|
---|
| 99 | {
|
---|
| 100 | // An error occurred. Log it and return. Since we are not starting a new
|
---|
| 101 | // accept operation the io_service will run out of work to do and the
|
---|
| 102 | // server will exit.
|
---|
[81c96b6] | 103 | Exitflag = ErrorFlag;
|
---|
[41c1b7] | 104 | ELOG(0, e.message());
|
---|
| 105 | }
|
---|
| 106 | }
|
---|
| 107 |
|
---|
| 108 | /// Controller callback function when job has been sent.
|
---|
| 109 | void PoolWorker::PoolListener_t::handle_ReceiveJob(const boost::system::error_code& e, connection_ptr conn)
|
---|
| 110 | {
|
---|
| 111 | Info info(__FUNCTION__);
|
---|
| 112 |
|
---|
| 113 | if (!e)
|
---|
| 114 | {
|
---|
[8acd85] | 115 | if (job->getId() != JobId::NoJob) {
|
---|
| 116 | LOG(1, "INFO: Working on job " << job->getId() << ".");
|
---|
| 117 | callback.WorkOnJob(job);
|
---|
| 118 | } else {
|
---|
| 119 | LOG(1, "INFO: Received NoJob.");
|
---|
| 120 | callback.shutdown();
|
---|
| 121 | }
|
---|
[41c1b7] | 122 | }
|
---|
| 123 | else
|
---|
| 124 | {
|
---|
| 125 | // An error occurred. Log it and return. Since we are not starting a new
|
---|
| 126 | // accept operation the io_service will run out of work to do and the
|
---|
| 127 | // server will exit.
|
---|
[81c96b6] | 128 | Exitflag = ErrorFlag;
|
---|
[41c1b7] | 129 | ELOG(0, e.message());
|
---|
| 130 | }
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | /** Works on the given job and send the results.
|
---|
| 134 | *
|
---|
| 135 | * @param job job to work on
|
---|
| 136 | */
|
---|
| 137 | void PoolWorker::WorkOnJob(FragmentJob::ptr &job)
|
---|
| 138 | {
|
---|
| 139 | // work on job and create result
|
---|
| 140 | LOG(2, "DEBUG: Beginning to work on " << job->getId() << ".");
|
---|
| 141 | FragmentResult::ptr result = job->Work();
|
---|
| 142 | LOG(2, "DEBUG: Setting result " << result->getId() << ".");
|
---|
[9d7c6a] | 143 |
|
---|
| 144 | AsyncOperation *submitOp = new SubmitResultOperation(connection_, MyAddress, AsyncOperation::NoOpCallback, failed);
|
---|
| 145 | static_cast<SubmitResultOperation *>(submitOp)->setResult(result);
|
---|
[41c1b7] | 146 |
|
---|
| 147 | // submit result
|
---|
[9d7c6a] | 148 | LOG(2, "DEBUG: Putting send result operation into queue ...");
|
---|
| 149 | OpQueue.push_back(submitOp, ServerAddress);
|
---|
[41c1b7] | 150 | }
|
---|
[aec098] | 151 |
|
---|
[8acd85] | 152 | /** Wrapper function to allow use as signal handler.
|
---|
[aec098] | 153 | *
|
---|
[8acd85] | 154 | * We remove us from server's pool and then just call \sa PoolWorker::shutdown().
|
---|
[aec098] | 155 | *
|
---|
[8acd85] | 156 | * @param sig signal received
|
---|
[aec098] | 157 | */
|
---|
| 158 | void PoolWorker::shutdown(int sig)
|
---|
| 159 | {
|
---|
| 160 | LOG(1, "INFO: Shutting down due to signal "+toString(sig)+".");
|
---|
| 161 |
|
---|
[8acd85] | 162 | shutdown();
|
---|
| 163 | }
|
---|
| 164 |
|
---|
| 165 | /** Helper function to shutdown the worker properly.
|
---|
| 166 | *
|
---|
| 167 | * Note that we will use ShutdownWorkerOperation to unlist from server's pool.
|
---|
[bff93d] | 168 | * We stop the io_service via its callback handler in case of success.
|
---|
[8acd85] | 169 | */
|
---|
| 170 | void PoolWorker::shutdown()
|
---|
| 171 | {
|
---|
[b15c4f] | 172 | // remove us from pool
|
---|
[9d7c6a] | 173 | boost::function<void ()> closingdown = boost::bind(&PoolWorker::finish, this);
|
---|
| 174 | AsyncOperation *removeOp = new RemoveFromPoolOperation(connection_, MyAddress, closingdown, failed);
|
---|
| 175 | LOG(2, "DEBUG: Putting remove from pool operation into queue ...");
|
---|
| 176 | OpQueue.push_back(removeOp, ServerAddress);
|
---|
[bff93d] | 177 | }
|
---|
[b15c4f] | 178 |
|
---|
[bff93d] | 179 | /** Helper function to close down listener and stop service.
|
---|
| 180 | *
|
---|
| 181 | * This is called after we have been removed from server's pool
|
---|
| 182 | *
|
---|
| 183 | */
|
---|
| 184 | void PoolWorker::finish()
|
---|
| 185 | {
|
---|
[aec098] | 186 | // somehow stop listener
|
---|
| 187 | PoolListener.closeSocket();
|
---|
| 188 |
|
---|
| 189 | // finally, stop io_service
|
---|
| 190 | io_service.stop();
|
---|
| 191 | }
|
---|
[bff93d] | 192 |
|
---|