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

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