Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
util.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet;
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file util.cc
11 ///
12 /// @brief
13 
14 /// @author Tim Jacobs
15 // MPI headers
16 
17 #ifdef USEMPI
18 #include <mpi.h> //keep this first
19 #endif
20 
21 #include <core/types.hh>
22 
26 #include <protocols/jd2/util.hh>
27 #include <basic/message_listening/MessageListenerFactory.hh>
28 #include <basic/message_listening/MessageListener.hh>
29 #include <basic/message_listening/DbMoverMessageListener.hh>
30 #include <basic/message_listening/util.hh>
31 
32 #include <basic/Tracer.hh>
33 #include <basic/database/sql_utils.hh>
34 #include <basic/options/option.hh>
35 #include <basic/options/keys/out.OptionKeys.gen.hh>
36 
37 #include <utility/string_util.hh>
38 #include <utility/mpi_util.hh>
39 #include <utility/exit.hh>
40 #include <utility/pointer/owning_ptr.hh>
41 
42 #include <cppdb/frontend.h>
43 #include <cppdb/errors.h>
44 
45 #include <boost/uuid/uuid.hpp>
46 #include <boost/uuid/uuid_io.hpp>
47 
48 #include <string>
49 #include <sstream>
50 #include <utility>
51 #include <iostream>
52 
53 
54 namespace protocols{
55 namespace features{
56 
57 using std::endl;
58 using std::string;
59 using std::stringstream;
60 using std::pair;
61 using std::map;
62 using cppdb::cppdb_error;
63 using utility::sql_database::sessionOP;
64 using basic::Tracer;
65 using core::Size;
66 using basic::message_listening::request_data_from_head_node;
67 using basic::message_listening::send_data_to_head_node;
68 using basic::message_listening::DATABASE_PROTOCOL_AND_BATCH_ID_TAG;
69 using cppdb::statement;
70 using cppdb::result;
71 
72 
73 // Static data for the serial case
76 map<string, Size> static_batch_id_map_;
77 
78 static Tracer TR("protocols.features.util");
79 // End static data
80 
81 
82 ///@brief Get the protocol and batch ids or create them if they don't
83 ///yet exist. For MPI protocols, only allow the head node to create
84 ///protocol or batch ids and have the other nodes ask the head node
85 ///for the info.
86 pair<Size, Size>
88  string identifier,
89  sessionOP db_session
90 ) {
91  using namespace basic::message_listening;
92 
93  int protocol_id = 0;
94  int batch_id = 0;
95  ProtocolFeaturesOP protocol_features = new ProtocolFeatures();
96  BatchFeaturesOP batch_features = new BatchFeatures();
97 
98 #ifdef USEMPI
99 
100  int rank = 0;
101  MPI_Comm_rank( MPI_COMM_WORLD, (int*)(&rank) );
102 
103  //Send an identifier to the head node, along with a
104  //message_listening tag so that the messageListenerFactory of the
105  //job distributor knows who to give the data to.
106 
107  //Some implementations of mpi don't allow self messaging. So, if we
108  //are the head node, don't try to message yourself, just access the listener directly
109 
110  string listener_data="";
111  //Set the max_batch_id if necessary.
112  if(rank == 0)
113  {
114  DbMoverMessageListenerOP listener(utility::pointer::dynamic_pointer_cast<DbMoverMessageListener,MessageListener>(MessageListenerFactory::get_instance()->get_listener(DATABASE_PROTOCOL_AND_BATCH_ID_TAG)));
115  if(!listener->max_batch_id_set())
116  {
117  std::string select_max = "SELECT MAX(batch_id) FROM batches;";
118  cppdb::statement stmt(basic::database::safely_prepare_statement(select_max,db_session));
119  cppdb::result res(basic::database::safely_read_from_database(stmt));
120 
121  Size max_batch_id(0);
122  while(res.next())
123  {
124  res >> max_batch_id;
125  }
126  listener->set_max_batch_id(max_batch_id);
127 
128  }
129  }
130 
131  if(rank != 0) {
132  listener_data = request_data_from_head_node(DATABASE_PROTOCOL_AND_BATCH_ID_TAG, identifier);
133  TR
134  << "Requesting data on '" << identifier << "' "
135  << "from the DATABASE_PROTOCOL_AND_BATCH_ID_TAG message listener on head node." << std::endl;
136 
137  } else {
138  MessageListenerOP listener(
139  MessageListenerFactory::get_instance()->get_listener(
140  DATABASE_PROTOCOL_AND_BATCH_ID_TAG));
141  listener->request(identifier,listener_data);
142 
143  TR
144  << "Requesting data on '" << identifier << "' "
145  << "from the DATABASE_PROTOCOL_AND_BATCH_ID_TAG message listener." << std::endl;
146  }
147 
148  //deserialize data into protocol_id and batch_id
149  pair<Size, Size> ids = deserialize_db_listener_data(listener_data);
150  protocol_id = ids.first;
151  batch_id = ids.second;
152  TR << "Received protocol_id='" << protocol_id << "' and batch_id='" << batch_id << "'" << std::endl;
153 
154  //no protocol id set yet - create protocol and first batch
155  if(protocol_id==0){
156  try {
157  protocol_id = protocol_features->report_features(protocol_id, db_session);
158  } catch (cppdb_error error){
159  stringstream err_msg;
160  err_msg
161  << "Failed to set the protocol id for batch "
162  << "'" << identifier << "'" << endl
163  << "Error Message:" << endl << error.what() << endl;
164  utility_exit_with_message(err_msg.str());
165  }
166 
167  TR
168  << "Initialize the protocol_id='" << protocol_id << "' "
169  << "and tell it to the head node." << std::endl;
170 
171  if(rank != 0) {
172  TR << "Send the protocol_id '" << protocol_id << "' to the head node." << std::endl;
173  utility::send_string_to_node(0/*HEAD*/, serialize_ids(protocol_id, identifier, batch_id));
174  } else {
175  MessageListenerOP listener(
176  MessageListenerFactory::get_instance()->get_listener(
177  DATABASE_PROTOCOL_AND_BATCH_ID_TAG));
178  listener->receive(serialize_ids(protocol_id, identifier, batch_id));
179  }
180 
181  }
182  TR << "done with protocol" <<std::endl;
183  // setup the batch_id
184 
185  try {
186  batch_features->report_features(batch_id, protocol_id, identifier, "", db_session);
187  } catch (cppdb_error error){
188  stringstream err_msg;
189  err_msg
190  << "Failed to set the batch id for batch '" << identifier << "' "
191  << "with protocol_id '" << protocol_id << "'" << endl
192  << "Error Message:" << endl << error.what() << endl;
193  utility_exit_with_message(err_msg.str());
194  }
195 
196 #endif
197 #ifndef USEMPI
198  //serial case
200  TR << "Initializing protocol table" << endl;
201  try{
202  static_protocol_id_ = protocol_features->report_features(0, db_session);
203  } catch (cppdb_error error){
204  stringstream err_msg;
205  err_msg
206  << "Failed to set the protocol id for batch "
207  << "'" << identifier << "'" << endl
208  << "Error Message:" << endl << error.what() << endl;
209  utility_exit_with_message(err_msg.str());
210  }
212  }
213  protocol_id = static_protocol_id_;
214 
215  if(!static_batch_id_map_.count(identifier)){
216  TR << "Initializing batch table" << endl;
217 
218 
219  std::string select_max = "SELECT MAX(batch_id) FROM batches;";
220  cppdb::statement stmt(basic::database::safely_prepare_statement(select_max,db_session));
221  cppdb::result res(basic::database::safely_read_from_database(stmt));
222 
223  Size max_batch_id(0);
224  while(res.next())
225  {
226  res >> max_batch_id;
227  }
228 
229 
230  for(
231  std::map< std::string, Size >::const_iterator
232  i = static_batch_id_map_.begin(), ie = static_batch_id_map_.end();
233  i != ie; ++i){
234  max_batch_id = std::max(max_batch_id, i->second);
235  }
236  batch_id = max_batch_id + 1;
237  static_batch_id_map_[identifier] = batch_id;
238 
239  try {
240  batch_features->report_features(
241  batch_id, protocol_id, identifier, "", db_session);
242  } catch (cppdb_error error){
243  stringstream err_msg;
244  err_msg
245  << "Failed to set the batch id for batch '" << identifier << "' "
246  << "with protocol_id '" << protocol_id << "'" << endl
247  << "Error Message:" << endl << error.what() << endl;
248  utility_exit_with_message(err_msg.str());
249  }
250  }
251  else{
252  batch_id=static_batch_id_map_[identifier];
253  }
254 #endif
255 
256  return pair<Size, Size>(protocol_id, batch_id);
257 }
258 
259 pair<Size, Size>
261  string data
262 ){
264  if(tokens.size() != 2){
265  utility_exit_with_message("failed to deserialize the message from master node. Message was: " + data + " You will get this message if trying to run ReportToDB mover in MPI mode with only on processor.");
266  }
267  int protocol_id=utility::string2int(tokens[1]);
268  int batch_id=utility::string2int(tokens[2]);
269  return pair<Size, Size>(protocol_id, batch_id);
270 }
271 
272 string
274  int protocol_id,
275  string identifier,
276  Size batch_id
277 ){
278  return
279  utility::to_string(protocol_id) + " " +
280  identifier + " " +
281  utility::to_string(batch_id);
282 }
283 
284 ///@detail look up the batch id given a struct id. Note this should
285 ///only be used once the structure's table has been created, eg in an
286 ///average features reporter's report_features function.
287 Size
289  boost::uuids::uuid struct_id,
290  sessionOP db_session
291 ) {
292 
293  std::string const stmt_str(
294  "SELECT batch_id FROM structures WHERE struct_id = ?;");
295  statement stmt(basic::database::safely_prepare_statement(stmt_str, db_session));
296  stmt.bind(1, struct_id);
297  result res(basic::database::safely_read_from_database(stmt));
298 
299  if(!res.next()){
300  stringstream err_msg;
301  err_msg
302  << "No batch_id found for struct_id '"
303  << to_string(struct_id) << "'";
304  utility_exit_with_message(err_msg.str());
305  }
306  Size batch_id;
307  res >> batch_id;
308  return batch_id;
309 }
310 
311 } //namespace protocols
312 } //namespace features