source: trunk/FACT++/src/scheduler.cc@ 10771

Last change on this file since 10771 was 10765, checked in by tbretz, 14 years ago
Made it compatible with older boost versions.
File size: 30.5 KB
Line 
1#include <vector>
2
3#include <boost/bind.hpp>
4#if BOOST_VERSION < 104400
5#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
6#undef BOOST_HAS_RVALUE_REFS
7#endif
8#endif
9#include <boost/thread.hpp>
10#include <boost/regex.hpp>
11#include <boost/asio/deadline_timer.hpp>
12#include <boost/date_time/posix_time/posix_time.hpp>
13
14#include <mysql++/mysql++.h>
15
16#include "FACT.h"
17#include "Dim.h"
18#include "Time.h"
19#include "Event.h"
20#include "Shell.h"
21#include "StateMachineDim.h"
22#include "Connection.h"
23#include "Configuration.h"
24#include "Timers.h"
25#include "Console.h"
26#include "Converter.h"
27#include "LocalControl.h"
28
29#include "tools.h"
30
31namespace ba = boost::asio;
32namespace bs = boost::system;
33
34using ba::deadline_timer;
35using ba::ip::tcp;
36
37using namespace std;
38using namespace boost::gregorian;
39using namespace boost::posix_time;
40
41// things to be done/checked/changed
42// * do not use --database, but sth like --database-scheduler
43// to be independent of the configuration database
44// * check if the following include is really needed
45// #include <boost/date_time/posix_time/posix_time.hpp>
46// * string database not as global variable
47// pass reference to conf and the string as a member of the class
48// (see chat of 4.5.2011)
49// * move definition of config parameters to AutoScheduler class
50// + read in from config
51
52// other things to do
53//
54// define what to transmit as info/warn/error
55
56
57// config parameters:
58// mintime
59// runtimec
60// runtimep
61// repostime
62
63// missing:
64//
65// calculate time for std obs
66// calculate sun set/rise
67//
68// return errors and other otherput from sendcommand to webinterface
69
70// in which cases should the scheduler go in error state?
71// when db is unavailable
72// does one also need a 'set scheduler to ready' function then?
73// do we want any error state at all?
74
75
76// =========================================================================
77
78template <class T>
79class AutoScheduler : public T
80{
81 bool fNextIsPreview;
82public:
83 enum states_t
84 {
85 kSM_Scheduling=1,
86 kSM_Comitting,
87 };
88
89 struct ObservationParameters
90 {
91 int obskey;
92 int obsmode;
93 int obstype;
94 int splitflag;
95 int telsetup;
96 float fluxweight;
97 float slope;
98 float flux;
99 float ra;
100 float dec;
101 boost::posix_time::ptime starttime;
102 boost::posix_time::ptime stoptime;
103 boost::posix_time::time_duration duration_db;
104 string sourcename;
105 int sourcekey;
106 };
107
108 struct FixedObs
109 {
110 int obskey_fixed;
111 int sourcekey_fixed;
112 string sourcename_fixed;
113 int obsmode_fixed;
114 int obstype_fixed;
115 int telsetup_fixed;
116 float ra_fixed;
117 float dec_fixed;
118 boost::posix_time::ptime obsfixedstart;
119 boost::posix_time::ptime obsfixedstop;
120 };
121
122 // will need other types of obs
123 // FloatingObs (duration < stop-start + splitflag no)
124 // FloatingSplittedObs (duration < stop-start + splitflag yes)
125 // FixedSlot, i.e. just block a time slot
126
127 struct StdObs
128 {
129 int obskey_std;
130 int sourcekey_std;
131 string sourcename_std;
132 int obsmode_std;
133 int obstype_std;
134 int telsetup_std;
135 float fluxweight_std;
136 float slope_std;
137 float flux_std;
138 float ra_std;
139 float dec_std;
140 boost::posix_time::ptime obsstdstart;
141 boost::posix_time::ptime obsstdstop;
142 };
143
144 struct ScheduledObs
145 {
146 int sourcekey_obs;
147 string sourcename_obs;
148 int obsmode_obs;
149 int obstype_obs;
150 int telsetup_obs;
151 boost::posix_time::ptime obsstart;
152 boost::posix_time::ptime obsstop;
153 };
154
155 struct ScheduledRun
156 {
157 //int runnumber; // to be seen, if runnumber is needed
158 int runtype;
159 int sourcekey_run;
160 string sourcename_run;//for convenience
161 int obsmode_run;
162 int obstype_run;
163 int telsetup_run;
164 boost::posix_time::ptime runstart;
165 boost::posix_time::ptime runstop;
166 };
167
168 int fSessionId;
169 string fDatabase;
170 string fDBName;
171
172
173
174 int Schedule()
175 {
176 bool error = false;
177
178 boost::posix_time::time_duration runtimec(0, 3, 0);
179 boost::posix_time::time_duration runtimep(0, 3, 0);
180 boost::posix_time::time_duration mintime(1, 0, 0);
181 boost::posix_time::time_duration repostime(0, 5, 0);
182 //boost::posix_time::ptime startsched=microsec_clock::local_time();
183 boost::posix_time::ptime startsched(microsec_clock::local_time());
184 boost::posix_time::ptime stopsched=startsched+years(1);
185 cout << "Scheduling for the period from " << startsched << " to " << stopsched << endl;
186
187 static const boost::regex expr("(([[:word:].-]+)(:(.+))?@)?([[:word:].-]+)(:([[:digit:]]+))?(/([[:word:].-]+))");
188 // 2: user
189 // 4: pass
190 // 5: server
191 // 7: port
192 // 9: db
193
194 boost::smatch what;
195 if (!boost::regex_match(fDatabase, what, expr, boost::match_extra))
196 {
197 cout << "Couldn't parse '" << fDatabase << "'." << endl;
198 throw;
199 }
200
201 if (what.size()!=10)
202 {
203 cout << "Error parsing '" << fDatabase << "'." << endl;
204 throw;
205 }
206
207 const string user = what[2];
208 const string passwd = what[4];
209 const string server = what[5];
210 string db = what[9];
211 if (fDBName.size()!=0)
212 db = fDBName;
213 const int port = atoi(string(what[7]).c_str());
214
215 stringstream dbnamemsg;
216 dbnamemsg << "Scheduling started -> using database " << fDBName << ".";
217 T::Message(dbnamemsg);
218
219 cout << "Connecting to '";
220 if (!user.empty())
221 cout << user << "@";
222 cout << server;
223 if (port)
224 cout << ":" << port;
225 if (!db.empty())
226 cout << "/" << db;
227 cout << "'" << endl;
228
229 mysqlpp::Connection conn(db.c_str(), server.c_str(), user.c_str(), passwd.c_str(), port);
230 if (!conn.connected())
231 {
232 cout << "MySQL connection error: " << conn.error() << endl;
233 throw;
234 }
235
236 // get observation parameters from DB
237 // maybe order by priority?
238 mysqlpp::Query query = conn.query("SELECT fObservationKEY, fStartTime, fStopTime, fDuration, fSourceName, fSourceKEY, fSplitFlag, fFluxWeight, fSlope, fFlux, fRightAscension, fDeclination, fObservationModeKEY, fObservationTypeKEY , fTelescopeSetupKEY FROM ObservationParameters LEFT JOIN Source USING(fSourceKEY) ORDER BY fStartTime");
239
240 mysqlpp::StoreQueryResult res = query.store();
241 if (!res)
242 {
243 cout << "MySQL query failed: " << query.error() << endl;
244 throw;
245 }
246
247 cout << "Found " << res.num_rows() << " Observation Parameter sets." << endl;
248
249 ObservationParameters olist[res.num_rows()];
250 std::vector<FixedObs> obsfixedlist;
251 std::vector<StdObs> obsstdlist;
252 std::vector<ScheduledObs> obslist;
253 std::vector<ScheduledRun> runlist;
254
255 // loop over observation parameters from DB
256 // fill these parameters into FixedObs and StdObs
257 int counter=0;
258 int counter2=0;
259 int counter3=0;
260 cout << "Obs: <obskey> <sourcename>(<sourcekey>, <fluxweight>) from <starttime> to <stoptime>" << endl;
261 for (vector<mysqlpp::Row>::iterator v=res.begin(); v<res.end(); v++)
262 {
263 cout << " Obs: " << (*v)[0].c_str() << " " << (*v)[4].c_str() << "(" << (*v)[5].c_str() << flush;
264 cout << ", " << (*v)[7].c_str() << ")" << flush;
265 cout << " from " << (*v)[1].c_str() << " to " << (*v)[2].c_str() << endl;
266
267 //0: obskey
268 //1: startime
269 //2: stoptime
270 //3: duration
271 //4: sourcename
272 //5: sourcekey
273 //6: splitflag
274 //7: fluxweight
275 //8: slope
276 //9: flux
277 //10: ra
278 //11: dec
279 //12: obsmode
280 //13: obstype
281 //14: telsetup
282 stringstream t1;
283 stringstream t2;
284 stringstream t3;
285 t1 << (*v)[1].c_str();
286 t2 << (*v)[2].c_str();
287 t3 << (*v)[3].c_str();
288
289 //boost::posix_time::time_duration mintime(0,conf.Get<int>("mintime"), 0);
290 t1 >> Time::sql >> olist[counter].starttime;
291 t2 >> Time::sql >> olist[counter].stoptime;
292 t3 >> olist[counter].duration_db;
293 boost::posix_time::time_period period(olist[counter].starttime, olist[counter].stoptime);
294 olist[counter].sourcename=(*v)[4].c_str();
295 olist[counter].sourcekey=(*v)[5];
296
297 if (!(*v)[0].is_null())
298 olist[counter].obskey=(*v)[0];
299 if (!(*v)[12].is_null())
300 olist[counter].obsmode=(*v)[12];
301 if (!(*v)[13].is_null())
302 olist[counter].obstype=(*v)[13];
303 if (!(*v)[14].is_null())
304 olist[counter].telsetup=(*v)[14];
305 if (!(*v)[6].is_null())
306 olist[counter].splitflag=(*v)[6];
307 if (!(*v)[7].is_null())
308 olist[counter].fluxweight=(*v)[7];
309 else
310 olist[counter].fluxweight=0;//set fluxweight to 0 for check below
311 if (!(*v)[8].is_null())
312 olist[counter].slope=(*v)[8];
313 if (!(*v)[9].is_null())
314 olist[counter].flux=(*v)[9];
315 if (!(*v)[10].is_null())
316 olist[counter].ra=(*v)[10];
317 if (!(*v)[11].is_null())
318 olist[counter].dec=(*v)[11];
319
320 // time_duration cannot be used, as only up to 99 hours are handeled
321 boost::posix_time::time_duration duration = period.length();
322
323 /*
324 if (olist[counter].stoptime < olist[counter].starttime+mintime)
325 cout << " ====> WARN: Observation too short. " << endl;
326
327 if (olist[counter].starttime.is_not_a_date_time())
328 cout << " WARN: starttime not a date_time. " << endl;
329 else
330 cout << " start: " << Time::sql << olist[counter].starttime << endl;
331 if (olist[counter].stoptime.is_not_a_date_time())
332 cout << " WARN: stoptime not a date_time. " << endl;
333 else
334 cout << " stop: " << Time::sql << olist[counter].stoptime << endl;
335 if (!(olist[counter].starttime.is_not_a_date_time() || olist[counter].stoptime.is_not_a_date_time()))
336 cout << " diff: " << period << endl;
337 if (olist[counter].stoptime < olist[counter].starttime)
338 cout << " ====> WARN: stop time (" << olist[counter].stoptime << ") < start time (" << olist[counter].starttime << "). " << endl;
339 cout << "diff: " << duration << flush;
340 cout << "dur_db: " << olist[counter].duration_db << endl;
341 */
342
343 // always filled: obstype
344 //
345 // fixed observations:
346 // filled: starttime, stoptime
347 // not filled: fluxweight
348 // maybe filled: obsmode, telsetup, source (not filled for FixedSlotObs)
349 // maybe filled: duration (filled for FloatingObs and FloatingSplittedObs)
350 // maybe filled: splitflag (filled for FloatingSplittedObs)
351 //
352 // std observations:
353 // filled: fluxweight, telsetup, obsmore, source
354 // not filled: starttime, stoptime, duration
355
356 // fixed observations
357 if (!(olist[counter].stoptime.is_not_a_date_time()
358 && olist[counter].starttime.is_not_a_date_time())
359 && olist[counter].fluxweight==0
360 )
361 {
362 obsfixedlist.resize(counter2+1);
363 obsfixedlist[counter2].obsfixedstart=olist[counter].starttime;
364 obsfixedlist[counter2].obsfixedstop=olist[counter].stoptime;
365 obsfixedlist[counter2].sourcename_fixed=olist[counter].sourcename;
366 obsfixedlist[counter2].obskey_fixed=olist[counter].obskey;
367 obsfixedlist[counter2].obstype_fixed=olist[counter].obstype;
368 obsfixedlist[counter2].obsmode_fixed=olist[counter].obsmode;
369 obsfixedlist[counter2].telsetup_fixed=olist[counter].telsetup;
370 obsfixedlist[counter2].sourcekey_fixed=olist[counter].sourcekey;
371 obsfixedlist[counter2].ra_fixed=olist[counter].ra;
372 obsfixedlist[counter2].dec_fixed=olist[counter].dec;
373 counter2++;
374 }
375
376 // std obs
377 if (olist[counter].stoptime.is_not_a_date_time()
378 && olist[counter].starttime.is_not_a_date_time()
379 && olist[counter].fluxweight>0
380 )
381 {
382 obsstdlist.resize(counter3+1);
383 obsstdlist[counter3].sourcename_std=olist[counter].sourcename;
384 obsstdlist[counter3].obskey_std=olist[counter].obskey;
385 obsstdlist[counter3].obsmode_std=olist[counter].obsmode;
386 obsstdlist[counter3].obstype_std=olist[counter].obstype;
387 obsstdlist[counter3].telsetup_std=olist[counter].telsetup;
388 obsstdlist[counter3].sourcekey_std=olist[counter].sourcekey;
389 obsstdlist[counter3].fluxweight_std=olist[counter].fluxweight;
390 obsstdlist[counter3].flux_std=olist[counter].flux;
391 obsstdlist[counter3].slope_std=olist[counter].slope;
392 obsstdlist[counter3].ra_std=olist[counter].ra;
393 obsstdlist[counter3].dec_std=olist[counter].dec;
394 counter3++;
395 }
396
397 counter++;
398 }
399 stringstream fixedobsmsg;
400 fixedobsmsg << obsfixedlist.size() << " fixed observations found. ";
401 T::Message(fixedobsmsg);
402 cout << obsfixedlist.size() << " fixed observations found. " << endl;
403
404 stringstream stdobsmsg;
405 stdobsmsg << obsstdlist.size() << " standard observations found. ";
406 T::Message(stdobsmsg);
407 cout << obsstdlist.size() << " standard observations found. " << endl;
408
409 // loop to add the fixed observations to the ScheduledObs list
410 // performed checks:
411 // * overlap of fixed observations: the overlap is split half-half
412 // * check for scheduling time range: only take into account fixed obs within the range
413 // missing checks and evaluation
414 // * check for mintime (pb with overlap checks)
415 // * check for sun
416 // * check for moon
417 counter2=0;
418 int skipcounter=0;
419 boost::posix_time::ptime finalobsfixedstart;
420 boost::posix_time::ptime finalobsfixedstop;
421 boost::posix_time::time_duration delta1;
422 boost::posix_time::time_duration delta2;
423 boost::posix_time::time_duration delta0(0,0,0);
424 struct vector<FixedObs>::iterator vobs;
425 struct vector<FixedObs>::iterator vobs5;
426 cout << "Fixed Observations: " << endl;
427 for (vobs=obsfixedlist.begin(); vobs!=obsfixedlist.end(); vobs++)
428 {
429 if (obsfixedlist[counter2].obsfixedstart < startsched
430 || obsfixedlist[counter2].obsfixedstop > stopsched)
431 {
432 stringstream skipfixedobsmsg;
433 skipfixedobsmsg << "Skip 1 fixed observation (obskey " << obsfixedlist[counter2].obskey_fixed << ") as it is out of scheduling time range.";
434 T::Message(skipfixedobsmsg);
435 counter2++;
436 skipcounter++;
437 continue;
438 }
439 counter3=0;
440 delta1=delta0;
441 delta2=delta0;
442 finalobsfixedstart=obsfixedlist[counter2].obsfixedstart;
443 finalobsfixedstop=obsfixedlist[counter2].obsfixedstop;
444
445 for (vobs5=obsfixedlist.begin(); vobs5!=obsfixedlist.end(); vobs5++)
446 {
447 if ((*vobs5).obsfixedstart < obsfixedlist[counter2].obsfixedstop
448 && obsfixedlist[counter2].obsfixedstop <= (*vobs5).obsfixedstop
449 && obsfixedlist[counter2].obsfixedstart <= (*vobs5).obsfixedstart
450 && counter2!=counter3)
451 {
452 delta1=(obsfixedlist[counter2].obsfixedstop-(*vobs5).obsfixedstart)/2;
453 finalobsfixedstop=obsfixedlist[counter2].obsfixedstop-delta1;
454 stringstream warndelta1;
455 warndelta1 << "Overlap between two fixed observations (" << obsfixedlist[counter2].obskey_fixed << " " << (*vobs5).obskey_fixed << "). The stoptime of " << obsfixedlist[counter2].obskey_fixed << " has been changed.";
456 T::Warn(warndelta1);
457 }
458 if ((*vobs5).obsfixedstart <= obsfixedlist[counter2].obsfixedstart
459 && obsfixedlist[counter2].obsfixedstart < (*vobs5).obsfixedstop
460 && obsfixedlist[counter2].obsfixedstop >= (*vobs5).obsfixedstop
461 && counter2!=counter3)
462 {
463 delta2=((*vobs5).obsfixedstop-obsfixedlist[counter2].obsfixedstart)/2;
464 finalobsfixedstart=obsfixedlist[counter2].obsfixedstart+delta2;
465 stringstream warndelta2;
466 warndelta2 << "Overlap between two fixed observations (" << obsfixedlist[counter2].obskey_fixed << " " << (*vobs5).obskey_fixed << "). The starttime of " << obsfixedlist[counter2].obskey_fixed << " has been changed.";
467 T::Warn(warndelta2);
468 }
469 counter3++;
470 }
471
472 int num=counter2-skipcounter;
473 obslist.resize(num+1);
474 obslist[num].obsstart=finalobsfixedstart;
475 obslist[num].obsstop=finalobsfixedstop;
476 obslist[num].sourcename_obs=obsfixedlist[counter2].sourcename_fixed;
477 obslist[num].obsmode_obs=obsfixedlist[counter2].obsmode_fixed;
478 obslist[num].obstype_obs=obsfixedlist[counter2].obstype_fixed;
479 obslist[num].telsetup_obs=obsfixedlist[counter2].telsetup_fixed;
480 obslist[num].sourcekey_obs=obsfixedlist[counter2].sourcekey_fixed;
481 counter2++;
482 cout << " " << (*vobs).sourcename_fixed << " " << (*vobs).obsfixedstart << flush;
483 cout << " - " << (*vobs).obsfixedstop << endl;
484 }
485 stringstream obsmsg;
486 obsmsg << "Added " << obslist.size() << " fixed observations to ScheduledObs. ";
487 T::Message(obsmsg);
488 cout << "Added " << obslist.size() << " fixed observations to ScheduledObs. " << endl;
489
490 for (int i=0; i<(int)obsstdlist.size(); i++)
491 {
492 for (int j=0; j<(int)obsstdlist.size(); j++)
493 {
494 if (obsstdlist[i].sourcekey_std == obsstdlist[j].sourcekey_std && i!=j)
495 {
496 cout << "One double sourcekey in std observations: " << obsstdlist[j].sourcekey_std << endl;
497 stringstream errdoublestd;
498 errdoublestd << "One double sourcekey in std observations: " << obsstdlist[j].sourcekey_std << " (" << obsstdlist[j].sourcename_std << ").";
499 T::Error(errdoublestd);
500 T::Message("Scheduling stopped.");
501 return error ? T::kSM_Error : T::kSM_Ready;
502 }
503 }
504 }
505
506 // loop over nights
507 // calculate sunset and sunrise
508 // check if there is already scheduled obs in that night
509 //
510
511 // in this loop the standard observations shall be
512 // checked, evaluated
513 // the observation times shall be calculated
514 // and the observations added to the ScheduledObs list
515 struct vector<StdObs>::iterator vobs2;
516 cout << "Standard Observations: " << endl;
517 for (vobs2=obsstdlist.begin(); vobs2!=obsstdlist.end(); vobs2++)
518 {
519 cout << " " << (*vobs2).sourcename_std << endl;
520 }
521
522 // in this loop the ScheduledRuns are filled
523 // (only data runs -> no runtype yet)
524 // might be merged with next loop
525 counter2=0;
526 struct vector<ScheduledObs>::iterator vobs3;
527 for (vobs3=obslist.begin(); vobs3!=obslist.end(); vobs3++)
528 {
529 runlist.resize(counter2+1);
530 runlist[counter2].runstart=obslist[counter2].obsstart;
531 runlist[counter2].runstop=obslist[counter2].obsstop;
532 runlist[counter2].sourcename_run=obslist[counter2].sourcename_obs;
533 runlist[counter2].obsmode_run=obslist[counter2].obsmode_obs;
534 runlist[counter2].obstype_run=obslist[counter2].obstype_obs;
535 runlist[counter2].telsetup_run=obslist[counter2].telsetup_obs;
536 runlist[counter2].sourcekey_run=obslist[counter2].sourcekey_obs;
537 counter2++;
538 //cout << (*vobs3).sourcename_obs << endl;
539 }
540
541 //delete old scheduled runs from the DB
542 mysqlpp::Query query0 = conn.query("DELETE FROM ScheduledRun");
543
544 mysqlpp::SimpleResult res0 = query0.execute();
545 if (!res0)
546 {
547 cout << "MySQL query failed: " << query0.error() << endl;
548 throw;
549 }
550
551 // in this loop the ScheduledRuns are inserted to the DB
552 // before the runtimes are adapted according to
553 // duration of P-Run, C-Run and repositioning
554 counter3=0;
555 int insertcount=0;
556 boost::posix_time::ptime finalstarttime;
557 boost::posix_time::ptime finalstoptime;
558 struct vector<ScheduledRun>::iterator vobs4;
559 for (vobs4=runlist.begin(); vobs4!=runlist.end(); vobs4++)
560 {
561 for (int i=2; i<5; i++)
562 {
563 switch(i)
564 {
565 case 2:
566 finalstarttime=runlist[counter3].runstart+repostime+runtimec+runtimep;
567 finalstoptime=runlist[counter3].runstop;
568 break;
569 case 3:
570 finalstarttime=runlist[counter3].runstart+repostime;
571 finalstoptime=runlist[counter3].runstart+runtimep+repostime;
572 break;
573 case 4:
574 finalstarttime=runlist[counter3].runstart+runtimep+repostime;
575 finalstoptime=runlist[counter3].runstart+repostime+runtimep+runtimec;
576 break;
577 }
578 stringstream q1;
579 //cout << (*vobs4).sourcename_run << endl;
580 q1 << "INSERT ScheduledRun set fStartTime='" << Time::sql << finalstarttime;
581 q1 << "', fStopTime='" << Time::sql << finalstoptime;
582 q1 << "', fSourceKEY='" << (*vobs4).sourcekey_run;
583 q1 << "', fRunTypeKEY='" << i;
584 q1 << "', fTelescopeSetupKEY='" << (*vobs4).telsetup_run;
585 q1 << "', fObservationTypeKEY='" << (*vobs4).obstype_run;
586 q1 << "', fObservationModeKEY='" << (*vobs4).obsmode_run;
587 q1 << "'";
588
589 //cout << "executing query: " << q1.str() << endl;
590
591 mysqlpp::Query query1 = conn.query(q1.str());
592
593 mysqlpp::SimpleResult res1 = query1.execute();
594 if (!res1)
595 {
596 cout << "MySQL query failed: " << query1.error() << endl;
597 throw;
598 }
599 insertcount++;
600 }
601 counter3++;
602 }
603 stringstream insertmsg;
604 insertmsg << "Inserted " << insertcount << " runs into the DB.";
605 T::Message(insertmsg);
606 //usleep(3000000);
607 T::Message("Scheduling done.");
608
609 fSessionId = -1;
610
611 //bool error = false;
612 return error ? T::kSM_Error : T::kSM_Ready;
613 }
614
615 /*
616 // commit probably done by webinterface
617 int Commit()
618 {
619 stringstream str;
620 str << "Comitting preview (id=" << fSessionId << ")";
621 T::Message(str);
622
623 usleep(3000000);
624 T::Message("Comitted.");
625
626 fSessionId = -1;
627
628 bool error = false;
629 return error ? T::kSM_Error : T::kSM_Ready;
630 }
631 */
632
633 AutoScheduler(ostream &out=cout) : T(out, "SCHEDULER"), fNextIsPreview(true), fSessionId(-1), fDBName("")
634 {
635 AddStateName(kSM_Scheduling, "Scheduling");
636 //AddStateName(kSM_Comitting, "Comitting");
637
638 AddEvent(kSM_Scheduling, "SCHEDULE", T::kSM_Ready);
639 //AddEvent(kSM_Comitting, "COMMIT", T::kSM_Ready);
640
641 T::PrintListOfEvents();
642 }
643
644 int Execute()
645 {
646 switch (T::GetCurrentState())
647 {
648 case kSM_Scheduling:
649 return Schedule();
650
651 //case kSM_Comitting:
652 // return Commit();
653 }
654 return T::GetCurrentState();
655 }
656
657 int Transition(const Event &evt)
658 {
659 switch (evt.GetTargetState())
660 {
661 case kSM_Scheduling:
662 if (evt.GetSize()>0)
663 fDBName = evt.GetString();
664 //case kSM_Comitting:
665 //fSessionId = evt.GetInt();
666 break;
667 }
668
669 return evt.GetTargetState();
670 }
671 int Configure(const Event &)
672 {
673 return T::GetCurrentState();
674 }
675
676 bool SetConfiguration(const Configuration &conf)
677 {
678 fDatabase = conf.Get<string>("schedule-database");
679
680 return true;
681 }
682
683};
684
685
686// ------------------------------------------------------------------------
687
688void RunThread(StateMachineImp *io_service)
689{
690 // This is necessary so that the StateMachien Thread can signal the
691 // Readline to exit
692 io_service->Run();
693 Readline::Stop();
694}
695
696template<class S>
697int RunDim(Configuration &conf)
698{
699 WindowLog wout;
700
701 //log.SetWindow(stdscr);
702 if (conf.Has("log"))
703 if (!wout.OpenLogFile(conf.Get<string>("log")))
704 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
705
706 // Start io_service.Run to use the StateMachineImp::Run() loop
707 // Start io_service.run to only use the commandHandler command detaching
708 AutoScheduler<S> io_service(wout);
709 if (!io_service.SetConfiguration(conf))
710 return -1;
711
712 io_service.Run();
713
714 return 0;
715}
716
717template<class T, class S>
718int RunShell(Configuration &conf)
719{
720 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
721
722 WindowLog &win = shell.GetStreamIn();
723 WindowLog &wout = shell.GetStreamOut();
724
725 if (conf.Has("log"))
726 if (!wout.OpenLogFile(conf.Get<string>("log")))
727 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
728
729 AutoScheduler<S> io_service(wout);
730 if (!io_service.SetConfiguration(conf))
731 return -1;
732
733 shell.SetReceiver(io_service);
734
735// boost::thread t(boost::bind(&AutoScheduler<S>::Run, &io_service));
736 boost::thread t(boost::bind(RunThread, &io_service));
737
738 //io_service.SetReady();
739
740 shell.Run(); // Run the shell
741 io_service.Stop(); // Signal Loop-thread to stop
742 // io_service.Close(); // Obsolete, done by the destructor
743 // wout << "join: " << t.timed_join(boost::posix_time::milliseconds(0)) << endl;
744
745 // Wait until the StateMachine has finished its thread
746 // before returning and destroying the dim objects which might
747 // still be in use.
748 t.join();
749
750 return 0;
751}
752
753void SetupConfiguration(Configuration &conf)
754{
755 const string n = conf.GetName()+".log";
756
757 //po::options_description config("Program options");
758 po::options_description config("Configuration");
759 config.add_options()
760 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
761 ("log,l", var<string>(n), "Write log-file")
762 ("no-dim,d", po_switch(), "Disable dim services")
763 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
764 ("schedule-database", var<string>()
765#if BOOST_VERSION >= 104200
766 ->required()
767#endif
768 , "Database link as in\n\t[user:[password]@][server][:port][/database]\nOverwrites options from the default configuration file.")
769 ("mintime", var<int>(), "minimum observation time")
770 ;
771
772 po::positional_options_description p;
773 p.add("schedule-database", 1); // The first positional options
774
775 conf.AddEnv("dns", "DIM_DNS_NODE");
776 conf.AddOptions(config);
777 conf.SetArgumentPositions(p);
778}
779
780void PrintUsage()
781{
782 cout <<
783 "The scheduler... TEXT MISSING\n"
784 "\n"
785 "The default is that the program is started without user intercation. "
786 "All actions are supposed to arrive as DimCommands. Using the -c "
787 "option, a local shell can be initialized. With h or help a short "
788 "help message about the usuage can be brought to the screen.\n"
789 "\n"
790 "Usage: scheduler [-c type] [OPTIONS] <schedule-database>\n"
791 " or: scheduler [OPTIONS] <schedule-database>\n";
792 cout << endl;
793}
794
795void PrintHelp()
796{
797 /* Additional help text which is printed after the configuration
798 options goes here */
799}
800
801int main(int argc, const char* argv[])
802{
803 Configuration conf(argv[0]);
804 conf.SetPrintUsage(PrintUsage);
805 SetupConfiguration(conf);
806
807 po::variables_map vm;
808 try
809 {
810 vm = conf.Parse(argc, argv);
811 }
812 catch (std::exception &e)
813 {
814#if BOOST_VERSION > 104000
815 po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
816 if (MO)
817 cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
818 else
819#endif
820 cout << "Error: " << e.what() << endl;
821 cout << endl;
822
823 return -1;
824 }
825
826 if (conf.HasPrint())
827 return -1;
828
829 if (conf.HasVersion())
830 {
831 FACT::PrintVersion(argv[0]);
832 return -1;
833 }
834
835 if (conf.HasHelp())
836 {
837 PrintHelp();
838 return -1;
839 }
840
841 Dim::Setup(conf.Get<string>("dns"));
842
843// try
844 {
845 // No console access at all
846 if (!conf.Has("console"))
847 {
848 if (conf.Get<bool>("no-dim"))
849 return RunDim<StateMachine>(conf);
850 else
851 return RunDim<StateMachineDim>(conf);
852 }
853 // Cosole access w/ and w/o Dim
854 if (conf.Get<bool>("no-dim"))
855 {
856 if (conf.Get<int>("console")==0)
857 return RunShell<LocalShell, StateMachine>(conf);
858 else
859 return RunShell<LocalConsole, StateMachine>(conf);
860 }
861 else
862 {
863 if (conf.Get<int>("console")==0)
864 return RunShell<LocalShell, StateMachineDim>(conf);
865 else
866 return RunShell<LocalConsole, StateMachineDim>(conf);
867 }
868 }
869/* catch (std::exception& e)
870 {
871 std::cerr << "Exception: " << e.what() << "\n";
872 }*/
873
874 return 0;
875}
Note: See TracBrowser for help on using the repository browser.