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

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