00001 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationBase.h"
00002 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationInfoReader.h"
00003
00004 #include <iostream>
00005 #include <typeinfo>
00006
00007
00008 using namespace ots;
00009
00010
00011 #undef __MF_SUBJECT__
00012 #define __MF_SUBJECT__ "ConfigurationBase"
00013 #undef __MF_HDR__
00014 #define __MF_HDR__ __COUT_HDR_FL__ << getConfigurationName() << ": "
00015
00016
00017
00018
00019
00020
00021
00022 ConfigurationBase::ConfigurationBase(std::string configurationName,
00023 std::string *accumulatedExceptions)
00024 : MAX_VIEWS_IN_CACHE (20)
00025 , configurationName_ (configurationName)
00026 , activeConfigurationView_(0)
00027 {
00028
00029 ConfigurationInfoReader configurationInfoReader(accumulatedExceptions);
00030 try
00031 {
00032 std::string returnedExceptions = configurationInfoReader.read(this);
00033
00034 if(returnedExceptions != "")
00035 __COUT_ERR__ << returnedExceptions << std::endl;
00036
00037 if(accumulatedExceptions) *accumulatedExceptions += std::string("\n") + returnedExceptions;
00038 }
00039 catch(...)
00040 {
00041 __SS__ << "Failure in configurationInfoReader.read(this)" << std::endl;
00042 __COUT_ERR__ << "\n" << ss.str();
00043 if(accumulatedExceptions) *accumulatedExceptions += std::string("\n") +
00044 ss.str();
00045 else throw;
00046 return;
00047 }
00048
00049
00050 try
00051 {
00052 getMockupViewP()->init();
00053 }
00054 catch(std::runtime_error& e)
00055 {
00056 if(accumulatedExceptions) *accumulatedExceptions += std::string("\n") + e.what();
00057 else throw;
00058 }
00059 }
00060
00061
00062
00063
00064
00065 ConfigurationBase::ConfigurationBase(void)
00066 : MAX_VIEWS_IN_CACHE (1)
00067 , configurationName_ ("")
00068 , activeConfigurationView_(0)
00069 {
00070 }
00071
00072
00073 ConfigurationBase::~ConfigurationBase(void)
00074 {
00075 }
00076
00077
00078 std::string ConfigurationBase::getTypeId()
00079 {
00080 return typeid(this).name();
00081 }
00082
00083
00084 void ConfigurationBase::init(ConfigurationManager *configurationManager)
00085 {
00086
00087 }
00088
00089
00090 void ConfigurationBase::reset(bool keepTemporaryVersions)
00091 {
00092
00093 deactivate();
00094 if(keepTemporaryVersions)
00095 trimCache(0);
00096 else
00097 configurationViews_.clear();
00098 }
00099
00100
00101 void ConfigurationBase::print(std::ostream &out) const
00102 {
00103
00104 if(!activeConfigurationView_)
00105 {
00106 __COUT_ERR__ << "ERROR: No active view set" << std::endl;
00107 return;
00108 }
00109 activeConfigurationView_->print(out);
00110 }
00111
00112
00113
00114
00115 void ConfigurationBase::setupMockupView(ConfigurationVersion version)
00116 {
00117 if(!isStored(version))
00118 {
00119 configurationViews_[version].copy(mockupConfigurationView_,
00120 version,
00121 mockupConfigurationView_.getAuthor());
00122 trimCache();
00123 if(!isStored(version))
00124 {
00125 __SS__ << "\nsetupMockupView() IMPOSSIBLE ERROR: trimCache() is deleting the latest view version " <<
00126 version << "!" << std::endl;
00127 __COUT_ERR__ << "\n" << ss.str();
00128 throw std::runtime_error(ss.str());
00129 }
00130 }
00131 else
00132 {
00133 __SS__ << "\nsetupMockupView() ERROR: View to fill with mockup already exists: " << version
00134 << ". Cannot overwrite!" << std::endl;
00135 __COUT_ERR__ << "\n" << ss.str();
00136 throw std::runtime_error(ss.str());
00137 }
00138 }
00139
00140
00141
00142
00143
00144
00145
00146 void ConfigurationBase::trimCache(unsigned int trimSize)
00147 {
00148
00149
00150 if(trimSize == (unsigned int)-1)
00151 trimSize = MAX_VIEWS_IN_CACHE;
00152
00153 int i=0;
00154 while(getNumberOfStoredViews() > trimSize)
00155 {
00156 ConfigurationVersion versionToDelete;
00157 time_t stalestTime = -1;
00158
00159 for(auto &viewPair : configurationViews_)
00160 if(!viewPair.first.isTemporaryVersion())
00161 {
00162 if(stalestTime == -1 ||
00163 viewPair.second.getLastAccessTime() < stalestTime)
00164 {
00165 versionToDelete = viewPair.first;
00166 stalestTime = viewPair.second.getLastAccessTime();
00167 if(!trimSize) break;
00168 }
00169 }
00170
00171 if(versionToDelete.isInvalid())
00172 {
00173 __SS__ << "Can NOT have a stored view with an invalid version!";
00174 throw std::runtime_error(ss.str());
00175 }
00176
00177 eraseView(versionToDelete);
00178 }
00179 }
00180
00181
00182
00183
00184
00185
00186 void ConfigurationBase::trimTemporary(ConfigurationVersion targetVersion)
00187 {
00188 if(targetVersion.isInvalid())
00189 {
00190 for(auto it = configurationViews_.begin(); it != configurationViews_.end(); )
00191 {
00192 if(it->first.isTemporaryVersion())
00193 {
00194 __COUT__ << "Trimming temporary version: " << it->first << std::endl;
00195 if(activeConfigurationView_ &&
00196 getViewVersion() == it->first)
00197 deactivate();
00198 configurationViews_.erase(it++);
00199 }
00200 else
00201 ++it;
00202 }
00203 }
00204 else if(targetVersion.isTemporaryVersion())
00205 {
00206 __COUT__ << "Trimming temporary version: " << targetVersion << std::endl;
00207 eraseView(targetVersion);
00208 }
00209 else
00210 {
00211
00212 __SS__ << "Temporary trim target was a persistent version: " <<
00213 targetVersion << std::endl;
00214 __COUT_ERR__ << "\n" << ss.str();
00215 throw std::runtime_error(ss.str());
00216 }
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 ConfigurationVersion ConfigurationBase::checkForDuplicate(ConfigurationVersion needleVersion,
00229 ConfigurationVersion ignoreVersion) const
00230 {
00231 auto needleIt = configurationViews_.find(needleVersion);
00232 if(needleIt == configurationViews_.end())
00233 {
00234
00235 __SS__ << "needleVersion does not exist: " <<
00236 needleVersion << std::endl;
00237 __COUT_ERR__ << "\n" << ss.str();
00238 throw std::runtime_error(ss.str());
00239 }
00240
00241 const ConfigurationView *needleView = &(needleIt->second);
00242 unsigned int rows = needleView->getNumberOfRows();
00243 unsigned int cols = needleView->getNumberOfColumns();
00244
00245 bool match;
00246 unsigned int potentialMatchCount = 0;
00247
00248
00249
00250
00251
00252
00253 auto viewPairReverseIterator = configurationViews_.rbegin();
00254 for(;viewPairReverseIterator != configurationViews_.rend(); ++viewPairReverseIterator)
00255 {
00256 if(viewPairReverseIterator->first == needleVersion) continue;
00257 if(viewPairReverseIterator->first == ignoreVersion) continue;
00258 if(viewPairReverseIterator->first.isTemporaryVersion()) continue;
00259
00260 if(viewPairReverseIterator->second.getNumberOfRows() != rows)
00261 continue;
00262
00263 if(viewPairReverseIterator->second.getDataColumnSize() != cols ||
00264 viewPairReverseIterator->second.getSourceColumnMismatch() != 0)
00265 continue;
00266
00267
00268 ++potentialMatchCount;
00269 __COUT__ << "Checking version... " << viewPairReverseIterator->first << std::endl;
00270
00271
00272
00273 match = true;
00274
00275 auto viewColInfoIt = viewPairReverseIterator->second.getColumnsInfo().begin();
00276 for(unsigned int col=0; match &&
00277 viewPairReverseIterator->second.getColumnsInfo().size() > 3 &&
00278 col<viewPairReverseIterator->second.getColumnsInfo().size()-3;++col,viewColInfoIt++)
00279 if(viewColInfoIt->getName() !=
00280 needleView->getColumnsInfo()[col].getName())
00281 {
00282 match = false;
00283
00284
00285
00286 }
00287
00288 for(unsigned int row=0;match && row<rows;++row)
00289 {
00290 for(unsigned int col=0;col<cols-2;++col)
00291 if(viewPairReverseIterator->second.getDataView()[row][col] !=
00292 needleView->getDataView()[row][col])
00293 {
00294 match = false;
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 break;
00305 }
00306 }
00307 if(match)
00308 {
00309 __COUT_INFO__ << "Duplicate version found: " << viewPairReverseIterator->first << std::endl;
00310 return viewPairReverseIterator->first;
00311 }
00312 }
00313
00314 __COUT__ << "No duplicates found in " << potentialMatchCount << " potential matches." << std::endl;
00315 return ConfigurationVersion();
00316 }
00317
00318
00319 void ConfigurationBase::changeVersionAndActivateView(ConfigurationVersion temporaryVersion,
00320 ConfigurationVersion version)
00321 {
00322 if(configurationViews_.find(temporaryVersion) == configurationViews_.end())
00323 {
00324 __SS__ << "ERROR: Temporary view version " << temporaryVersion << " doesn't exists!" << std::endl;
00325 __COUT_ERR__ << "\n" << ss.str();
00326 throw std::runtime_error(ss.str());
00327 }
00328 if(version.isInvalid())
00329 {
00330 __SS__ << "ERROR: Attempting to create an invalid version " << version <<
00331 "! Did you really run out of versions? (this should never happen)" << std::endl;
00332 __COUT_ERR__ << "\n" << ss.str();
00333 throw std::runtime_error(ss.str());
00334 }
00335
00336 if(configurationViews_.find(version) != configurationViews_.end())
00337 __COUT_WARN__ << "WARNING: View version " << version << " already exists! Overwriting." << std::endl;
00338
00339 configurationViews_[version].copy(configurationViews_[temporaryVersion],
00340 version,
00341 configurationViews_[temporaryVersion].getAuthor());
00342 setActiveView(version);
00343 eraseView(temporaryVersion);
00344 }
00345
00346
00347 bool ConfigurationBase::isStored(const ConfigurationVersion &version) const
00348 {
00349 return (configurationViews_.find(version) != configurationViews_.end());
00350 }
00351
00352
00353 bool ConfigurationBase::eraseView(ConfigurationVersion version)
00354 {
00355 if(!isStored(version))
00356 return false;
00357
00358 if(activeConfigurationView_ &&
00359 getViewVersion() == version)
00360 deactivate();
00361
00362 configurationViews_.erase(version);
00363
00364 return true;
00365 }
00366
00367
00368 const std::string& ConfigurationBase::getConfigurationName(void) const
00369 {
00370 return configurationName_;
00371 }
00372
00373
00374 const std::string& ConfigurationBase::getConfigurationDescription(void) const
00375 {
00376 return configurationDescription_;
00377 }
00378
00379
00380 const ConfigurationVersion& ConfigurationBase::getViewVersion(void) const
00381 {
00382 return getView().getVersion();
00383 }
00384
00385
00386
00387
00388
00389 bool ConfigurationBase::latestAndMockupColumnNumberMismatch(void) const
00390 {
00391 std::set<ConfigurationVersion> retSet = getStoredVersions();
00392 if(retSet.size() && !retSet.rbegin()->isTemporaryVersion())
00393 {
00394 return configurationViews_.find(*(retSet.rbegin()))->second.getNumberOfColumns() !=
00395 mockupConfigurationView_.getNumberOfColumns();
00396 }
00397
00398 return true;
00399 }
00400
00401
00402 std::set<ConfigurationVersion> ConfigurationBase::getStoredVersions(void) const
00403 {
00404 std::set<ConfigurationVersion> retSet;
00405 for(auto &configs:configurationViews_)
00406 retSet.emplace(configs.first);
00407 return retSet;
00408 }
00409
00410
00411
00412
00413
00414 unsigned int ConfigurationBase::getNumberOfStoredViews(void) const
00415 {
00416 unsigned int sz = 0;
00417 for(auto &viewPair : configurationViews_)
00418 if(viewPair.first.isTemporaryVersion()) continue;
00419 else if(viewPair.first.isInvalid())
00420 {
00421
00422
00423
00424
00425
00426
00427
00428 __COUT__ << "There is an invalid version now!.. where did it come from?" << std::endl;
00429 }
00430 else ++sz;
00431 return sz;
00432 }
00433
00434
00435 const ConfigurationView& ConfigurationBase::getView(void) const
00436 {
00437 if(!activeConfigurationView_)
00438 {
00439 __SS__ << "activeConfigurationView_ pointer is null! (...likely the active view was not setup properly. Check your system setup.)";
00440 throw std::runtime_error(ss.str());
00441 }
00442 return *activeConfigurationView_;
00443 }
00444
00445
00446 ConfigurationView* ConfigurationBase::getViewP(void)
00447 {
00448 if(!activeConfigurationView_)
00449 {
00450 __SS__ << "activeConfigurationView_ pointer is null! (...likely the active view was not setup properly. Check your system setup.)";
00451 throw std::runtime_error(ss.str());
00452 }
00453 return activeConfigurationView_;
00454 }
00455
00456
00457 ConfigurationView* ConfigurationBase::getMockupViewP(void)
00458 {
00459 return &mockupConfigurationView_;
00460 }
00461
00462
00463 void ConfigurationBase::setConfigurationName(const std::string &configurationName)
00464 {
00465 configurationName_ = configurationName;
00466 }
00467
00468
00469 void ConfigurationBase::setConfigurationDescription(const std::string &configurationDescription)
00470 {
00471 configurationDescription_ = configurationDescription;
00472 }
00473
00474
00475
00476
00477 void ConfigurationBase::deactivate()
00478 {
00479 activeConfigurationView_ = 0;
00480 }
00481
00482
00483
00484 bool ConfigurationBase::isActive()
00485 {
00486 return activeConfigurationView_?true:false;
00487 }
00488
00489
00490 bool ConfigurationBase::setActiveView(ConfigurationVersion version)
00491 {
00492 if(!isStored(version))
00493 {
00494
00495 __SS__ << "\nsetActiveView() ERROR: View with version " << version <<
00496 " has never been stored before!" << std::endl;
00497 __COUT_ERR__ << "\n" << ss.str();
00498 throw std::runtime_error(ss.str());
00499 return false;
00500 }
00501 activeConfigurationView_ = &configurationViews_[version];
00502
00503 if(configurationViews_[version].getVersion() != version)
00504 {
00505 __SS__ << "Something has gone very wrong with the version handling!" << std::endl;
00506 throw std::runtime_error(ss.str());
00507 }
00508
00509 return true;
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 ConfigurationVersion ConfigurationBase::copyView (const ConfigurationView &sourceView,
00522 ConfigurationVersion destinationVersion, const std::string &author)
00523 throw(std::runtime_error)
00524 {
00525
00526 if(sourceView.getNumberOfColumns() !=
00527 mockupConfigurationView_.getNumberOfColumns())
00528 {
00529 __SS__ << "Error! Number of Columns of source view must match destination mock-up view." <<
00530 "Dimension of source is [" << sourceView.getNumberOfColumns() <<
00531 "] and of destination mockup is [" <<
00532 mockupConfigurationView_.getNumberOfColumns() << "]." << std::endl;
00533 throw std::runtime_error(ss.str());
00534 }
00535
00536
00537 if(!destinationVersion.isInvalid() &&
00538 configurationViews_.find(sourceView.getVersion()) != configurationViews_.end())
00539 {
00540 __SS__ << "Error! Asked to copy a view with a conflicting version: " <<
00541 sourceView.getVersion() << std::endl;
00542 throw std::runtime_error(ss.str());
00543 }
00544
00545
00546 destinationVersion = createTemporaryView(ConfigurationVersion(),
00547 destinationVersion);
00548
00549 __COUT__ << "Copying from " << sourceView.getTableName() << "_v" <<
00550 sourceView.getVersion() << " to " << getConfigurationName() << "_v" <<
00551 destinationVersion << std::endl;
00552
00553 try
00554 {
00555 configurationViews_[destinationVersion].copy(sourceView,destinationVersion,author);
00556 }
00557 catch(...)
00558 {
00559 __COUT_ERR__ << "Failed to copy from " << sourceView.getTableName() << "_v" <<
00560 sourceView.getVersion() << " to " << getConfigurationName() << "_v" <<
00561 destinationVersion << std::endl;
00562 __COUT_WARN__ << "Deleting the failed destination version " <<
00563 destinationVersion << std::endl;
00564 eraseView(destinationVersion);
00565 throw;
00566 }
00567
00568 return destinationVersion;
00569 }
00570
00571
00572
00573
00574
00575
00576
00577
00578 ConfigurationVersion ConfigurationBase::createTemporaryView(ConfigurationVersion sourceViewVersion,
00579 ConfigurationVersion destTemporaryViewVersion)
00580 {
00581 __COUT__ << "Configuration: " <<
00582 getConfigurationName()<< std::endl;
00583
00584 __COUT__ << "Num of Views: " <<
00585 configurationViews_.size() << " (Temporary Views: " <<
00586 (configurationViews_.size() - getNumberOfStoredViews()) << ")" << std::endl;
00587
00588 ConfigurationVersion tmpVersion = destTemporaryViewVersion;
00589 if(tmpVersion.isInvalid()) tmpVersion = ConfigurationVersion::getNextTemporaryVersion();
00590 while(isStored(tmpVersion) &&
00591 !(tmpVersion = ConfigurationVersion::getNextTemporaryVersion(tmpVersion)).isInvalid());
00592 if(isStored(tmpVersion) || tmpVersion.isInvalid())
00593 {
00594 __SS__ << "Invalid destination temporary version: " <<
00595 destTemporaryViewVersion << ". Expected next temporary version < " << tmpVersion << std::endl;
00596 __COUT_ERR__ << ss.str();
00597 throw std::runtime_error(ss.str());
00598 }
00599
00600 if(sourceViewVersion == ConfigurationVersion::INVALID ||
00601 configurationViews_.find(sourceViewVersion) == configurationViews_.end())
00602 {
00603 if(sourceViewVersion != -1)
00604 {
00605 __SS__ << "ERROR: sourceViewVersion " << sourceViewVersion << " not found. " <<
00606 "Invalid source version. Version requested is not stored (yet?) or does not exist." << std::endl;
00607 __COUT_ERR__ << ss.str();
00608 throw std::runtime_error(ss.str());
00609 }
00610 __COUT__ << "Using Mock-up view" << std::endl;
00611 configurationViews_[tmpVersion].copy(mockupConfigurationView_,
00612 tmpVersion,
00613 mockupConfigurationView_.getAuthor());
00614 }
00615 else
00616 {
00617 try
00618 {
00619 configurationViews_[tmpVersion].copy(configurationViews_[sourceViewVersion],
00620 tmpVersion,
00621 configurationViews_[sourceViewVersion].getAuthor());
00622 }
00623 catch(...)
00624 {
00625 __COUT_WARN__ << "createTemporaryView() Source view failed init(). " <<
00626 "This is being ignored (hopefully the new copy is being fixed)." << std::endl;
00627 }
00628 }
00629
00630 return tmpVersion;
00631 }
00632
00633
00634
00635
00636
00637 ConfigurationVersion ConfigurationBase::getNextTemporaryVersion() const
00638 {
00639 ConfigurationVersion tmpVersion;
00640
00641
00642 if(configurationViews_.size() != 0 && configurationViews_.begin()->first.isTemporaryVersion())
00643 tmpVersion =
00644 ConfigurationVersion::getNextTemporaryVersion(configurationViews_.begin()->first);
00645 else
00646 tmpVersion = ConfigurationVersion::getNextTemporaryVersion();
00647
00648
00649 if(isStored(tmpVersion) || tmpVersion.isInvalid() || !tmpVersion.isTemporaryVersion())
00650 {
00651 __SS__ << "Invalid destination temporary version: " <<
00652 tmpVersion << std::endl;
00653 __COUT_ERR__ << ss.str();
00654 throw std::runtime_error(ss.str());
00655 }
00656 return tmpVersion;
00657 }
00658
00659
00660
00661
00662
00663 ConfigurationVersion ConfigurationBase::getNextVersion() const
00664 {
00665 ConfigurationVersion tmpVersion;
00666
00667
00668 if(configurationViews_.size() != 0 && !configurationViews_.rbegin()->first.isTemporaryVersion())
00669 tmpVersion =
00670 ConfigurationVersion::getNextVersion(configurationViews_.rbegin()->first);
00671 else
00672 tmpVersion = ConfigurationVersion::getNextVersion();
00673
00674
00675 if(isStored(tmpVersion) || tmpVersion.isInvalid() || tmpVersion.isTemporaryVersion())
00676 {
00677 __SS__ << "Invalid destination next version: " <<
00678 tmpVersion << std::endl;
00679 __COUT_ERR__ << ss.str();
00680 throw std::runtime_error(ss.str());
00681 }
00682 return tmpVersion;
00683 }
00684
00685
00686
00687
00688
00689 ConfigurationView* ConfigurationBase::getTemporaryView(ConfigurationVersion temporaryVersion)
00690 {
00691 if(!temporaryVersion.isTemporaryVersion() ||
00692 !isStored(temporaryVersion))
00693 {
00694 __SS__ << getConfigurationName() << ":: Error! Temporary version not found!" << std::endl;
00695 __COUT_ERR__ << ss.str();
00696 throw std::runtime_error(ss.str());
00697 }
00698 return &configurationViews_[temporaryVersion];
00699 }
00700
00701
00702
00703
00704
00705
00706 std::string ConfigurationBase::convertToCaps(std::string& str, bool isConfigName)
00707 throw(std::runtime_error)
00708 {
00709
00710 unsigned int configPos = (unsigned int)std::string::npos;
00711 if(isConfigName && (configPos = str.find("Configuration")) !=
00712 str.size() - strlen("Configuration"))
00713 str += "Configuration";
00714
00715
00716
00717
00718
00719
00720 std::string capsStr = "";
00721 for(unsigned int c=0;c<str.size();++c)
00722 if(str[c] >= 'A' && str[c] <= 'Z')
00723 {
00724
00725 if(c == configPos ||
00726 (c && str[c-1] >= 'a' && str[c-1] <= 'z') ||
00727 (c && str[c-1] >= 'A' && str[c-1] <= 'Z' &&
00728 c+1 < str.size() && str[c+1] >= 'a' && str[c+1] <= 'z')
00729 )
00730 capsStr += "_";
00731 capsStr += str[c];
00732 }
00733 else if(str[c] >= 'a' && str[c] <= 'z')
00734 capsStr += char(str[c] -32);
00735 else if(str[c] >= '0' && str[c] <= '9')
00736 capsStr += str[c];
00737 else
00738 throw std::runtime_error(std::string("ConfigurationBase::convertToCaps::") +
00739 "Invalid character found in name (allowed: A-Z, a-z, 0-9):" +
00740 str );
00741
00742 return capsStr;
00743 }
00744
00745
00746
00747