00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 #include "omniEventsLog.h"
00084
00085 #ifdef HAVE_CONFIG_H
00086 # include "config.h"
00087 #endif
00088
00089 #include <stdio.h>
00090
00091 #ifdef HAVE_STDLIB_H
00092 # include <stdlib.h>
00093 #endif
00094
00095 #ifdef HAVE_SYS_TYPES_H
00096 # include <sys/types.h>
00097 #endif
00098
00099 #ifdef HAVE_SYS_STAT_H
00100 # include <sys/stat.h>
00101 #endif
00102
00103 #ifdef HAVE_FCNTL_H
00104 # include <fcntl.h>
00105 #endif
00106
00107 #if defined(__VMS) && __CRTL_VER < 70000000
00108 # include <omniVMS/unlink.hxx>
00109 #endif
00110
00111 #ifdef __WIN32__
00112 # include <io.h>
00113 # include <winbase.h>
00114 # define stat(x,y) _stat(x,y)
00115 # define unlink(x) _unlink(x)
00116 #endif // __WIN32__
00117
00118 #ifdef HAVE_UNISTD_H
00119 # include <unistd.h>
00120 #endif
00121
00122 #ifdef HAVE_LIBC_H
00123 # include <libc.h>
00124 #endif
00125
00126 #ifdef HAVE_SYS_PARAM_H
00127 # include <sys/param.h>
00128 #endif
00129
00130 #include <errno.h>
00131 #include <time.h>
00132 #include "gethostname.h"
00133 #include "oep_global.h"
00134
00135 #include "EventChannelFactory.h"
00136
00137
00138
00139
00140
00141 #if defined(HAVE_FSTREAM_OPEN)
00142 # define FLAG_TRUNCATE ios::trunc
00143 # define FLAG_APPEND ios::app
00144 # define FLAG_SYNC 0
00145 #elif defined(HAVE_FSTREAM_ATTACH)
00146 # if defined(__WIN32__)
00147 # define FLAG_SYNC 0
00148 # elif defined(O_SYNC)
00149 # define FLAG_SYNC O_SYNC
00150 # else
00151 # define FLAG_SYNC O_FSYNC // FreeBSD 3.2 does not have O_SYNC???
00152 # endif
00153 # define FLAG_TRUNCATE O_CREAT|O_TRUNC
00154 # define FLAG_APPEND O_APPEND
00155 #else
00156 # error "Can't open a file without ofstream::open() or ofstream::attach()"
00157 #endif
00158
00159
00160
00161
00162
00163
00164 #ifndef OMNIEVENTS_LOG_CHECKPOINT_PERIOD
00165 # define DEFAULT_IDLE_TIME_BTW_CHKPT (15*60)
00166 #else
00167 # define DEFAULT_IDLE_TIME_BTW_CHKPT OMNIEVENTS_LOG_CHECKPOINT_PERIOD
00168 #endif
00169
00170
00171
00172
00173
00174 #ifdef __VMS
00175 # define VMS_SEMICOLON ";"
00176 #else
00177 # define VMS_SEMICOLON
00178 #endif
00179
00180 #define DB(l,x) ((omniORB::traceLevel >= l) && (cerr << x << endl))
00181
00182 extern int yyparse();
00183 extern int yydebug;
00184 extern FILE *yyin;
00185
00186 namespace OmniEvents {
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 class timestamp {
00198 char str[29];
00199 public:
00200 timestamp(void) {
00201 str[0] = '\n';
00202 str[1] = str[28] = '\0';
00203 }
00204 char* t(void) {
00205 time_t t = time(NULL);
00206 char *p = ctime(&t);
00207 if (strncmp(p, &str[1], 24) == 0) {
00208 return &str[28];
00209 }
00210 strncpy(&str[1], p, 24);
00211 str[25] = ':';
00212 str[26] = '\n';
00213 str[27] = '\n';
00214 return str;
00215 }
00216 };
00217
00218 timestamp ts;
00219
00220
00221
00222
00223
00224 omniEventsLog *omniEventsLog::theLog = NULL;
00225
00226 omniEventsLog::omniEventsLog(int p, const char* logdir) :
00227 port(p),
00228 logfile(),
00229 firstTime(0),
00230 active(NULL),
00231 backup(NULL),
00232 checkpt(NULL),
00233 recorder(NULL),
00234 factory(NULL),
00235 checkpointNeeded(1),
00236 _lock()
00237 {
00238 omniEventsLog::theLog = this;
00239
00240 initializeFileNames(logdir);
00241
00242 #ifdef __WIN32__
00243 struct _stat sb;
00244 #else
00245 struct stat sb;
00246 #endif
00247
00248 if (port != 0)
00249 {
00250
00251
00252
00253
00254
00255 firstTime = 1;
00256
00257 if (stat(active,&sb) == 0)
00258 {
00259 cerr << ts.t() <<
00260 "Error: persistency log file '" << active << "' exists.\n"
00261 " Run without the -s option to recover the"
00262 " server's state, or remove the file\n"
00263 " (and any backup) and then run with -s to"
00264 " create a new persistency log." << endl;
00265 exit(1);
00266 }
00267 if (stat(backup,&sb) == 0)
00268 {
00269 cerr << ts.t() <<
00270 "Error: backup file '" << backup << "' exists.\n"
00271 " Rename it to '" << active << "'\n"
00272 " and then run without the -s option to"
00273 " recover the server's state, or delete\n"
00274 " it and then run with -s to create a new persistency log." << endl;
00275 exit(1);
00276 }
00277 }
00278 else
00279 {
00280
00281
00282
00283
00284 firstTime = 0;
00285
00286 FILE *file = fopen(active, "r");
00287
00288 if (!file)
00289 {
00290 cerr << ts.t() << "Error: cannot open persistency log file '" << active
00291 << "'." << endl;
00292
00293 if (stat(backup,&sb) == 0)
00294 {
00295 cerr <<
00296 " Backup file '" << backup << "' exists.\n"
00297 " Either rename it to '" << active << "' to\n"
00298 " recover the server's state, or delete it and"
00299 " then run with the -s option to\n"
00300 " create a new persistency log." <<endl;
00301 }
00302 else
00303 {
00304 cerr <<
00305 " Use the -s option the first time you run the server, to create the\n"
00306 " persistency log file." << endl;
00307 }
00308 exit(1);
00309 }
00310
00311 yyin = file;
00312 oep_global = new OEP_GlobalData();
00313 int result = yyparse();
00314 if (result == 1)
00315 {
00316 cerr << ts.t() << "Error: parsing log file '" << active << "'." << endl;
00317 exit(1);
00318 }
00319 fclose(file);
00320 cerr << ts.t() << "Read log file successfully." << endl;
00321
00322
00323
00324 OEP_cfps *fdata = oep_global->getFactory();
00325 port = fdata->getPort();
00326 }
00327 }
00328
00329 void
00330 omniEventsLog::init(EventChannelFactory_i *&f)
00331 {
00332 factory = f;
00333
00334 try
00335 {
00336 if (firstTime)
00337 {
00338
00339
00340 cerr << ts.t() << "Starting omniEvents on port "
00341 << port << endl;
00342
00343 openOfstream(logfile,active,FLAG_TRUNCATE|FLAG_SYNC);
00344 _lock.lock();
00345 output(logfile);
00346 _lock.unlock();
00347
00348 checkpointNeeded = 1;
00349 cerr << ts.t() << "Wrote initial log file.\n" << endl;
00350 }
00351 else
00352 {
00353 openOfstream(logfile,active,FLAG_APPEND);
00354
00355
00356
00357 OEP_cfps fdata =*oep_global->getFactory();
00358
00359
00360
00361 factory =new EventChannelFactory_i(fdata.getPort(),fdata.getChannels());
00362 f = factory;
00363 }
00364 }
00365 catch (IOError& ex)
00366 {
00367 cerr << ts.t() << "Error: cannot open" << (firstTime?" initial":"")
00368 << " log file '" << active
00369 << "': " << endl;
00370 perror("");
00371 cerr << "\nYou can set the environment variable "
00372 << OMNIEVENTS_LOGDIR_ENV_VAR
00373 << " to specify the\ndirectory where the log files are kept.\n"
00374 << endl;
00375 logfile.close();
00376 unlink(active);
00377 exit(1);
00378 }
00379
00380
00381
00382 recorder = new omniEventsLogWorker(this,
00383 &omniEventsLog::checkpoint,
00384 omni_thread::PRIORITY_NORMAL);
00385 return;
00386 }
00387
00388 void
00389 omniEventsLog::persist()
00390 {
00391 omniEventsLog *log = omniEventsLog::theLog;
00392 if(log && log->factory)
00393 {
00394 omni_mutex_lock l(log->_lock);
00395 log->output(log->logfile);
00396 log->logfile.flush();
00397 log->checkpointNeeded = 1;
00398 }
00399 }
00400
00401 void
00402 omniEventsLog::output(ostream& os)
00403 {
00404 factory->output(os);
00405 os<<endl;
00406 }
00407
00408 int
00409 omniEventsLog::getPort()
00410 {
00411 return port;
00412 }
00413
00414 void
00415 omniEventsLog::checkpoint(void)
00416 {
00417
00418 int idle_time_btw_chkpt;
00419 static int firstCheckPoint = 1;
00420 char *itbc = getenv("OMNIEVENTS_ITBC");
00421 if (itbc == NULL || sscanf(itbc,"%d",&idle_time_btw_chkpt) != 1)
00422 {
00423 idle_time_btw_chkpt = DEFAULT_IDLE_TIME_BTW_CHKPT;
00424 }
00425
00426 omni_mutex mutex;
00427 omni_condition cond(&mutex);
00428
00429 mutex.lock();
00430 while (1) {
00431
00432
00433
00434
00435
00436 if (! firstCheckPoint)
00437 {
00438 unsigned long s, n;
00439 omni_thread::get_time(&s, &n, idle_time_btw_chkpt);
00440 cond.timedwait(s,n);
00441
00442 _lock.lock();
00443 if (!checkpointNeeded)
00444 {
00445 _lock.unlock();
00446 continue;
00447 }
00448 }
00449 else
00450 {
00451 _lock.lock();
00452 firstCheckPoint = 0;
00453 }
00454
00455 cerr << ts.t() << "Checkpointing Phase 1: Prepare." << endl;
00456
00457 ofstream ckpf;
00458 int fd = -1;
00459
00460 try
00461 {
00462 try
00463 {
00464 openOfstream(ckpf,checkpt,FLAG_TRUNCATE|FLAG_SYNC,&fd);
00465 }
00466 catch (IOError& ex)
00467 {
00468 cerr << ts.t() << "Error: cannot open checkpoint file '"
00469 << checkpt << "' for writing." << endl;
00470 throw;
00471 }
00472
00473 output(ckpf);
00474
00475 ckpf.close();
00476 if (!ckpf)
00477 throw IOError();
00478
00479
00480 #if defined(__sunos__) && defined(__SUNPRO_CC) && __SUNPRO_CC < 0x500
00481 if (close(fd) < 0)
00482 throw IOError();
00483 #endif
00484
00485 } catch (IOError& ex) {
00486 cerr << ts.t() << flush;
00487 perror("I/O error writing checkpoint file");
00488 cerr << "Abandoning checkpoint" << endl;
00489 ckpf.close();
00490
00491 #if defined(__sunos__) && defined(__SUNPRO_CC) && __SUNPRO_CC < 0x500
00492 close(fd);
00493 #endif
00494 unlink(checkpt);
00495 _lock.unlock();
00496 continue;
00497 }
00498
00499
00500
00501
00502
00503 cerr << ts.t() << "Checkpointing Phase 2: Commit." << endl;
00504
00505
00506 #if defined(__sunos__) && defined(__SUNPRO_CC) && __SUNPRO_CC < 0x500
00507 close(logfile.rdbuf()->fd());
00508 #endif
00509
00510 logfile.close();
00511
00512 unlink(backup);
00513
00514 #if defined(__WIN32__)
00515 if (rename(active, backup) != 0) {
00516 #elif defined(__VMS)
00517 if (rename(active, backup) < 0) {
00518 #else
00519 if (link(active,backup) < 0) {
00520 #endif
00521
00522 cerr << ts.t() << "Error: failed to link backup file '" << backup
00523 << "' to old log file '" << active << "'." << endl;
00524 exit(1);
00525 }
00526
00527 #if !defined( __VMS) && !defined(__WIN32__)
00528 if (unlink(active) < 0) {
00529
00530 cerr << ts.t() << "Error: failed to unlink old log file '" << active
00531 << "'." << endl;
00532 perror("");
00533 exit(1);
00534 }
00535 #endif
00536
00537 #if defined(__WIN32__)
00538 if (rename(checkpt,active) != 0) {
00539 #elif defined(__VMS)
00540 if (rename(checkpt,active) < 0) {
00541 #else
00542 if (link(checkpt,active) < 0) {
00543 #endif
00544
00545 cerr << ts.t() << "Error: failed to link log file '" << active
00546 << "' to checkpoint file '" << checkpt << "'." << endl;
00547 exit(1);
00548 }
00549
00550 #if !defined( __VMS) && !defined(__WIN32__)
00551 if (unlink(checkpt) < 0) {
00552
00553 cerr << ts.t() << "Error: failed to unlink checkpoint file '" << checkpt
00554 << "'." << endl;
00555 exit(1);
00556 }
00557 #endif
00558
00559 try
00560 {
00561 openOfstream(logfile,active,FLAG_APPEND|FLAG_SYNC,&fd);
00562 }
00563 catch (IOError& ex)
00564 {
00565 cerr << ts.t() << "Error: cannot open new log file '" << active
00566 << "' for writing." << endl;
00567 exit(1);
00568 }
00569
00570 cerr << ts.t() << "Checkpointing completed." << endl;
00571
00572 checkpointNeeded = 0;
00573 _lock.unlock();
00574 }
00575 mutex.unlock();
00576 }
00577
00578
00589 void omniEventsLog::initializeFileNames(const char* logdir)
00590 {
00591 if (!logdir)
00592 logdir = getenv(OMNIEVENTS_LOGDIR_ENV_VAR);
00593 if (!logdir)
00594 {
00595 #if defined(OMNIEVENTS_LOG_DEFAULT_LOCATION)
00596 logdir = OMNIEVENTS_LOG_DEFAULT_LOCATION;
00597 #elif defined(__WIN32__)
00598 logdir = "C:\\TEMP";
00599 #elif defined(__VMS)
00600 logdir = "[]";
00601 #else // Unix
00602 logdir = "/var/omniEvents";
00603 #endif
00604 }
00605
00606 const char* logname ="omnievents-";
00607 char hostname[MAXHOSTNAMELEN];
00608 if (0!=gethostname(hostname,MAXHOSTNAMELEN))
00609 {
00610 cerr << ts.t() << "Error: cannot get the name of this host." << endl;
00611 exit(1);
00612 }
00613 const char* sep ="";
00614
00615 #if defined(__WIN32__)
00616 sep="\\";
00617 #elif defined(__VMS)
00618 char last( logdir[strlen(logdir)-1] );
00619 if (last != ':' && last != ']')
00620 {
00621 cerr << ts.t() << "Error: " << OMNIEVENTS_LOGDIR_ENV_VAR << " (" << logdir
00622 << ") is not a directory name." << endl;
00623 exit(1);
00624 }
00625 #else // Unix
00626 if (logdir[0] != '/')
00627 {
00628 cerr << ts.t() << "Error: " << OMNIEVENTS_LOGDIR_ENV_VAR << " (" << logdir
00629 << ") is not an absolute path name." << endl;
00630 exit(1);
00631 }
00632 if (logdir[strlen(logdir)-1] != '/')
00633 sep="/";
00634 #endif
00635
00636
00637
00638
00639 setFilename(active, logdir,sep,logname,hostname,".log" VMS_SEMICOLON);
00640 setFilename(backup, logdir,sep,logname,hostname,".bak" VMS_SEMICOLON);
00641 setFilename(checkpt,logdir,sep,logname,hostname,".ckp" VMS_SEMICOLON);
00642 }
00643
00644
00648 void
00649 omniEventsLog::setFilename(
00650 char*& filename, const char* logdir, const char* sep,
00651 const char* logname, const char* hostname, const char* ext)
00652 {
00653 size_t len=1+
00654 strlen(logdir)+strlen(sep)+strlen(logname)+strlen(hostname)+strlen(ext);
00655 filename=new char[len];
00656 sprintf(filename,"%s%s%s%s%s",logdir,sep,logname,hostname,ext);
00657 }
00658
00659
00673 void
00674 omniEventsLog::openOfstream(
00675 ofstream& s, const char* filename, int flags, int* fd)
00676 {
00677 #if defined(HAVE_FSTREAM_OPEN)
00678 # ifdef FSTREAM_OPEN_PROT
00679 s.open(filename,ios::out|flags,0666);
00680 # else
00681 s.open(filename,ios::out|flags);
00682 # endif
00683 if (!s)
00684 throw IOError();
00685
00686 #elif defined(HAVE_FSTREAM_ATTACH)
00687 # ifdef __WIN32__
00688 int localFd = _open(filename, O_WRONLY | flags, _S_IWRITE);
00689 # else
00690 int localFd = open(filename, O_WRONLY | flags, 0666);
00691 # endif
00692 if (localFd < 0)
00693 throw IOError();
00694 if(fd)
00695 (*fd)=localFd;
00696 s.attach(localFd);
00697 #endif
00698 }
00699
00700
00701
00702
00703
00704 omniEventsLogWorker::omniEventsLogWorker(omniEventsLog *object,
00705 Method method,
00706 priority_t priority) :
00707 omni_thread(NULL, priority)
00708 {
00709
00710 DB(10, "omniEventsLogWorker : Constructor Start");
00711
00712 _method = method;
00713 _object = object;
00714
00715 start_undetached();
00716
00717 DB(10, "omniEventsLogWorker : Constructor End");
00718 }
00719
00720 void*
00721 omniEventsLogWorker::run_undetached (void *) {
00722
00723 DB(10, "omniEventsLogWorker : run_undetached Start");
00724
00725 (_object->*_method)();
00726
00727 DB(10, "omniEventsLogWorker : run_undetached End");
00728
00729 return(0);
00730 }
00731
00732 omniEventsLogWorker::~omniEventsLogWorker () {
00733
00734 DB(10, "omniEventsLogWorker : Destructor Start");
00735
00736 DB(10, "omniEventsLogWorker : Destructor End");
00737 }
00738
00739
00740 };
00741