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

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