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

Last change on this file since 10699 was 10688, checked in by tbretz, 14 years ago
Renamed AddConfiguration and AddTransition to AddEvent
File size: 29.1 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// return errors and other otherput from sendcommand to webinterface
72
73// in which cases should the scheduler go in error state?
74// when db is unavailable
75// does one also need a 'set scheduler to ready' function then?
76// do we want any error state at all?
77
78
79// =========================================================================
80
81template <class T>
82class AutoScheduler : public T
83{
84 bool fNextIsPreview;
85public:
86 enum states_t
87 {
88 kSM_Scheduling=1,
89 kSM_Comitting,
90 };
91
92 struct ObservationParameters
93 {
94 int obskey;
95 int obsmode;
96 int obstype;
97 int splitflag;
98 int telsetup;
99 float fluxweight;
100 float slope;
101 float flux;
102 float ra;
103 float dec;
104 boost::posix_time::ptime starttime;
105 boost::posix_time::ptime stoptime;
106 boost::posix_time::time_duration duration_db;
107 string sourcename;
108 int sourcekey;
109 };
110
111 struct FixedObs
112 {
113 int obskey_fixed;
114 int sourcekey_fixed;
115 string sourcename_fixed;
116 int obsmode_fixed;
117 int obstype_fixed;
118 int telsetup_fixed;
119 float ra_fixed;
120 float dec_fixed;
121 boost::posix_time::ptime obsfixedstart;
122 boost::posix_time::ptime obsfixedstop;
123 };
124
125 // will need other types of obs
126 // FloatingObs (duration < stop-start + splitflag no)
127 // FloatingSplittedObs (duration < stop-start + splitflag yes)
128 // FixedSlot, i.e. just block a time slot
129
130 struct StdObs
131 {
132 int obskey_std;
133 int sourcekey_std;
134 string sourcename_std;
135 int obsmode_std;
136 int obstype_std;
137 int telsetup_std;
138 float fluxweight_std;
139 float slope_std;
140 float flux_std;
141 float ra_std;
142 float dec_std;
143 boost::posix_time::ptime obsstdstart;
144 boost::posix_time::ptime obsstdstop;
145 };
146
147 struct ScheduledObs
148 {
149 int sourcekey_obs;
150 string sourcename_obs;
151 int obsmode_obs;
152 int obstype_obs;
153 int telsetup_obs;
154 boost::posix_time::ptime obsstart;
155 boost::posix_time::ptime obsstop;
156 };
157
158 struct ScheduledRun
159 {
160 //int runnumber; // to be seen, if runnumber is needed
161 int runtype;
162 int sourcekey_run;
163 string sourcename_run;//for convenience
164 int obsmode_run;
165 int obstype_run;
166 int telsetup_run;
167 boost::posix_time::ptime runstart;
168 boost::posix_time::ptime runstop;
169 };
170
171 int fSessionId;
172 string fDBName;
173
174
175
176 int Schedule()
177 {
178 bool error = false;
179
180 boost::posix_time::time_duration runtimec(0, 3, 0);
181 boost::posix_time::time_duration runtimep(0, 3, 0);
182 boost::posix_time::time_duration mintime(1, 0, 0);
183 boost::posix_time::time_duration repostime(0, 5, 0);
184 //boost::posix_time::ptime startsched=microsec_clock::local_time();
185 boost::posix_time::ptime startsched(microsec_clock::local_time());
186 boost::posix_time::ptime stopsched=startsched+years(1);
187 cout << "Scheduling for the period from " << startsched << " to " << stopsched << endl;
188
189 static const boost::regex expr("(([[:word:].-]+)(:(.+))?@)?([[:word:].-]+)(:([[:digit:]]+))?(/([[:word:].-]+))");
190 // 2: user
191 // 4: pass
192 // 5: server
193 // 7: port
194 // 9: db
195
196 boost::smatch what;
197 if (!boost::regex_match(database, what, expr, boost::match_extra))
198 {
199 cout << "Couldn't parse '" << database << "'." << endl;
200 throw;
201 }
202
203 if (what.size()!=10)
204 {
205 cout << "Error parsing '" << database << "'." << endl;
206 throw;
207 }
208
209 const string user = what[2];
210 const string passwd = what[4];
211 const string server = what[5];
212 string db = what[9];
213 if (fDBName.size()!=0)
214 db = fDBName;
215 const int port = atoi(string(what[7]).c_str());
216
217 stringstream dbnamemsg;
218 dbnamemsg << "Scheduling started -> using database " << fDBName << ".";
219 T::Message(dbnamemsg);
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), fDBName("")
636 {
637 AddStateName(kSM_Scheduling, "Scheduling");
638 //AddStateName(kSM_Comitting, "Comitting");
639
640 AddEvent(kSM_Scheduling, "SCHEDULE", T::kSM_Ready);
641 //AddEvent(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 if (evt.GetSize()>0)
665 fDBName = evt.GetString();
666 //case kSM_Comitting:
667 //fSessionId = evt.GetInt();
668 break;
669 }
670
671 return evt.GetTargetState();
672 }
673 int Configure(const Event &)
674 {
675 return T::GetCurrentState();
676 }
677};
678
679
680// ------------------------------------------------------------------------
681
682template<class S>
683int RunDim(Configuration &conf)
684{
685 WindowLog wout;
686
687 //log.SetWindow(stdscr);
688 if (conf.Has("log"))
689 if (!wout.OpenLogFile(conf.Get<string>("log")))
690 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
691
692 // Start io_service.Run to use the StateMachineImp::Run() loop
693 // Start io_service.run to only use the commandHandler command detaching
694 AutoScheduler<S> io_service(wout);
695 io_service.Run();
696
697 return 0;
698}
699
700template<class T, class S>
701int RunShell(Configuration &conf)
702{
703 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
704
705 WindowLog &win = shell.GetStreamIn();
706 WindowLog &wout = shell.GetStreamOut();
707
708 if (conf.Has("log"))
709 if (!wout.OpenLogFile(conf.Get<string>("log")))
710 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
711
712 AutoScheduler<S> io_service(wout);
713 shell.SetReceiver(io_service);
714
715 boost::thread t(boost::bind(&AutoScheduler<S>::Run, &io_service));
716
717 //io_service.SetReady();
718
719 shell.Run(); // Run the shell
720 io_service.Stop(); // Signal Loop-thread to stop
721 // io_service.Close(); // Obsolete, done by the destructor
722 // wout << "join: " << t.timed_join(boost::posix_time::milliseconds(0)) << endl;
723
724 // Wait until the StateMachine has finished its thread
725 // before returning and destroying the dim objects which might
726 // still be in use.
727 t.join();
728
729 return 0;
730}
731
732void SetupConfiguration(Configuration &conf)
733{
734 const string n = conf.GetName()+".log";
735
736 //po::options_description config("Program options");
737 po::options_description config("Configuration");
738 config.add_options()
739 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
740 ("log,l", var<string>(n), "Write log-file")
741 ("no-dim,d", po_switch(), "Disable dim services")
742 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
743 ("mintime", var<int>(), "minimum observation time")
744 ;
745
746 conf.AddEnv("dns", "DIM_DNS_NODE");
747
748 conf.AddOptions(config);
749 conf.AddOptionsDatabase(config);
750}
751
752int main(int argc, const char* argv[])
753{
754 Configuration conf(argv[0]);
755 SetupConfiguration(conf);
756
757 po::variables_map vm;
758 try
759 {
760 vm = conf.Parse(argc, argv);
761 }
762 catch (std::exception &e)
763 {
764#if BOOST_VERSION > 104000
765 po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
766 if (MO)
767 cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
768 else
769#endif
770 cout << "Error: " << e.what() << endl;
771 cout << endl;
772
773 return -1;
774 }
775
776 if (conf.Has("database"))
777 {
778 database = conf.Get<string>("database").c_str();
779 }
780 else
781 {
782 cout << "Please provide which database you want to use for scheduling." << endl;
783 return -1;
784 }
785
786 if (conf.HasHelp() || conf.HasPrint())
787 return -1;
788
789 // To allow overwriting of DIM_DNS_NODE set 0 to 1
790 setenv("DIM_DNS_NODE", conf.Get<string>("dns").c_str(), 1);
791
792 try
793 {
794 // No console access at all
795 if (!conf.Has("console"))
796 {
797 if (conf.Get<bool>("no-dim"))
798 return RunDim<StateMachine>(conf);
799 else
800 return RunDim<StateMachineDim>(conf);
801 }
802 // Cosole access w/ and w/o Dim
803 if (conf.Get<bool>("no-dim"))
804 {
805 if (conf.Get<int>("console")==0)
806 return RunShell<LocalShell, StateMachine>(conf);
807 else
808 return RunShell<LocalConsole, StateMachine>(conf);
809 }
810 else
811 {
812 if (conf.Get<int>("console")==0)
813 return RunShell<LocalShell, StateMachineDim>(conf);
814 else
815 return RunShell<LocalConsole, StateMachineDim>(conf);
816 }
817 }
818 catch (std::exception& e)
819 {
820 std::cerr << "Exception: " << e.what() << "\n";
821 }
822
823 return 0;
824}
Note: See TracBrowser for help on using the repository browser.