CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Namespaces | Macros | Functions
refresh.cc File Reference
#include "FWCore/PluginManager/interface/CacheParser.h"
#include "FWCore/PluginManager/interface/PluginCapabilities.h"
#include "FWCore/PluginManager/interface/PluginFactoryBase.h"
#include "FWCore/PluginManager/interface/PluginFactoryManager.h"
#include "FWCore/PluginManager/interface/SharedLibrary.h"
#include "FWCore/PluginManager/interface/standard.h"
#include "FWCore/Utilities/interface/Exception.h"
#include "FWCore/Utilities/interface/Algorithms.h"
#include <boost/program_options.hpp>
#include <algorithm>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iostream>
#include <set>
#include <string>
#include <utility>
#include <sys/wait.h>

Go to the source code of this file.

Namespaces

 std
 

Macros

#define PER_PROCESS_DSO   2000
 

Functions

int main (int argc, char **argv)
 
ostream & std::operator<< (std::ostream &o, vector< std::string > const &iValue)
 

Macro Definition Documentation

#define PER_PROCESS_DSO   2000

Definition at line 43 of file refresh.cc.

Referenced by main().

Function Documentation

int main ( int  argc,
char **  argv 
)

Definition at line 74 of file refresh.cc.

References edmplugin::standard::cachefileName(), cms::Exception::category(), EcnaPython_AdcPeg12_S1_10_R170298_1_0_150_Dee0::cerr, edmplugin::standard::config(), gather_cfg::cout, submitPVResolutionJobs::desc, createBeamHaloJobs::directory, dataset::end, relativeConstraints::error, cppFunctionSkipper::exception, Exception, beamvalidation::exit(), validate-o2o-wbm::f, mergeVDriftHistosByStation::file, lut2db_cfg::filename, submitPVResolutionJobs::files, edm::for_all(), edmplugin::PluginCapabilities::get(), edmplugin::PluginFactoryManager::get(), kHelpCommandOpt, kHelpOpt, mps_check::lib, SiStripPI::min, edmplugin::PluginFactoryManager::newFactory_, AlCaHLTBitMon_ParallelJobs::options, AlCaHLTBitMon_ParallelJobs::p, fed_dqm_sourceclient-live_cfg::path, PER_PROCESS_DSO, edmplugin::standard::pluginPrefix(), edmplugin::CacheParser::read(), submitPVValidationJobs::run, edmplugin::PluginManager::Config::searchPath(), mps_update::status, AlCaHLTBitMon_QueryRunRegistry::string, edmplugin::PluginCapabilities::tryToFind(), relativeConstraints::value, cms::Exception::what(), and edmplugin::CacheParser::write().

74  {
75  using namespace boost::program_options;
76  using std::placeholders::_1;
77 
78  static char const* const kPathsOpt = "paths";
79  static char const* const kPathsCommandOpt = "paths,p";
80  //static char const* const kAllOpt = "all";
81  //static char const* const kAllCommandOpt = "all,a";
82  static char const* const kHelpOpt = "help";
83  static char const* const kHelpCommandOpt = "help,h";
84 
85  std::string descString(argv[0]);
86  descString += " [options] [[--";
87  descString += kPathsOpt;
88  descString += "] path [path]] \nAllowed options";
89  options_description desc(descString);
90  std::string defaultDir(".");
91  std::vector<std::string> defaultDirList = edmplugin::standard::config().searchPath();
92  if (!defaultDirList.empty()) {
93  defaultDir = defaultDirList[0];
94  }
95  desc.add_options()(kHelpCommandOpt, "produce help message")(
96  kPathsCommandOpt,
97  value<std::vector<std::string> >()->default_value(std::vector<std::string>(1, defaultDir)),
98  "a directory or a list of files to scan")
99  //(kAllCommandOpt, "when no paths given, try to update caches for all known directories [default is to only scan the first directory]")
100  ;
101 
102  positional_options_description p;
103  p.add(kPathsOpt, -1);
104 
105  variables_map vm;
106  try {
107  store(command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
108  notify(vm);
109  } catch (error const& iException) {
110  std::cerr << iException.what();
111  return 1;
112  }
113 
114  if (vm.count(kHelpOpt)) {
115  std::cout << desc << std::endl;
116  return 0;
117  }
118 
119  using std::filesystem::path;
120 
121  /*if(argc == 1) {
122  std::cerr << "Requires at least one argument. Please pass either one directory or a list of files (all in the same directory)." << std::endl;
123  return 1;
124  } */
125 
126  int returnValue = EXIT_SUCCESS;
127 
128  try {
129  std::vector<std::string> requestedPaths(vm[kPathsOpt].as<std::vector<std::string> >());
130 
131  //first find the directory and create a list of files to look at in that directory
132  path directory(requestedPaths[0]);
133  std::vector<std::string> files;
134  bool removeMissingFiles = false;
135  if (std::filesystem::is_directory(directory)) {
136  if (requestedPaths.size() > 1) {
137  std::cerr << "if a directory is given then only one argument is allowed" << std::endl;
138  return 1;
139  }
140 
141  //if asked to look at whole directory, then we can also remove missing files
142  removeMissingFiles = true;
143 
144  std::filesystem::directory_iterator file(directory);
145  std::filesystem::directory_iterator end;
146 
147  path cacheFile(directory);
148  cacheFile /= standard::cachefileName();
149 
150  std::filesystem::file_time_type cacheLastChange = std::filesystem::file_time_type::min();
151  if (exists(cacheFile)) {
152  cacheLastChange = last_write_time(cacheFile);
153  }
154  for (; file != end; ++file) {
155  path filename(*file);
156  path shortName(file->path().filename());
157  const std::string& stringName = shortName.string();
158 
159  static std::string const kPluginPrefix(standard::pluginPrefix());
160  if (stringName.size() < kPluginPrefix.size()) {
161  continue;
162  }
163  if (stringName.substr(0, kPluginPrefix.size()) != kPluginPrefix) {
164  continue;
165  }
166 
167  if (last_write_time(filename) > cacheLastChange) {
168  files.push_back(stringName);
169  }
170  }
171  } else {
172  //we have files
173  directory = directory.parent_path();
174  for (std::vector<std::string>::iterator it = requestedPaths.begin(), itEnd = requestedPaths.end(); it != itEnd;
175  ++it) {
177  if (!exists(f)) {
178  std::cerr << "the file '" << f.string() << "' does not exist" << std::endl;
179  return 1;
180  }
181  if (is_directory(f)) {
182  std::cerr << "either one directory or a list of files are allowed as arguments" << std::endl;
183  return 1;
184  }
185  if (directory != f.parent_path()) {
186  std::cerr << "all files must have be in the same directory (" << directory.string()
187  << ")\n"
188  " the file "
189  << f.string() << " does not." << std::endl;
190  }
191 #if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 47
192  files.push_back(f.filename().string());
193 #else
194  files.push_back(f.leaf());
195 #endif
196  }
197  }
198 
199  path cacheFile(directory);
200  cacheFile /= edmplugin::standard::cachefileName(); //path(s_cacheFile);
201 
202  CacheParser::LoadableToPlugins old;
203  if (exists(cacheFile)) {
204  std::ifstream cf(cacheFile.string().c_str());
205  if (!cf) {
206  cms::Exception("FailedToOpen") << "unable to open file '" << cacheFile.string()
207  << "' for reading even though it is present.\n"
208  "Please check permissions on the file.";
209  }
210  CacheParser::read(cf, old);
211  }
212 
213  //load each file and 'listen' to which plugins are loaded
214  Listener listener;
216  pfm->newFactory_.connect(std::bind(std::mem_fn(&Listener::newFactory), &listener, _1));
217  edm::for_all(*pfm, std::bind(std::mem_fn(&Listener::newFactory), &listener, _1));
218 
219  // We open the cache file before forking so that all the children will
220  // use it.
221  std::string temporaryFilename = (cacheFile.string() + ".tmp");
222  std::ofstream cf(temporaryFilename.c_str());
223  if (!cf) {
224  cms::Exception("FailedToOpen") << "unable to open file '" << temporaryFilename
225  << "' for writing.\n"
226  "Please check permissions on the file.";
227  }
228  // Sort the files so that they are loaded "by subsystem", hopefully meaning
229  // they share more dependencies.
230  std::sort(files.begin(), files.end());
231 
232  for (size_t fi = 0, fe = files.size(); fi < fe; fi += PER_PROCESS_DSO) {
233  CacheParser::LoadableToPlugins ltp;
234  pid_t worker = fork();
235  if (worker == 0) {
236  // This the child process.
237  // We load the DSO and find out its plugins, write to the cache
238  // stream and exit, leaving the parent to spawn a new proces.
239  size_t ci = PER_PROCESS_DSO;
240  while (ci && fi != fe) {
241  path loadableFile(directory);
242  loadableFile /= (files[fi]);
243  listener.nameAndTypes_.clear();
244 
245  try {
246  try {
247  edmplugin::SharedLibrary lib(loadableFile);
248  //PluginCapabilities is special, the plugins do not call it. Instead, for each shared library load
249  // we need to ask it to try to find plugins
250  PluginCapabilities::get()->tryToFind(lib);
251  ltp[files[fi]] = listener.nameAndTypes_;
252 
253  } catch (cms::Exception const& iException) {
254  if (iException.category() == "PluginLibraryLoadError") {
255  std::cerr << "Caught exception " << iException.what() << " will ignore " << files[fi]
256  << " and continue." << std::endl;
257  } else {
258  throw;
259  }
260  }
261  } catch (std::exception& iException) {
262  std::cerr << "Caught exception " << iException.what() << std::endl;
263  exit(1);
264  }
265  ++fi;
266  --ci;
267  }
268  CacheParser::write(ltp, cf);
269  cf << std::flush;
270  _exit(0);
271  } else {
272  // Throw if any of the child died with non 0 status.
273  int status = 0;
274  waitpid(worker, &status, 0);
275  if (WIFEXITED(status) == true && status != 0) {
276  std::cerr << "Error while processing." << std::endl;
277  exit(status);
278  }
279  }
280  }
281 
282  cf << std::flush;
283 
284  // We read the new cache and we merge it with the old one.
285  CacheParser::LoadableToPlugins ltp;
286  std::ifstream icf(temporaryFilename.c_str());
287  if (!icf) {
288  cms::Exception("FailedToOpen") << "unable to open file '" << temporaryFilename.c_str()
289  << "' for reading even though it is present.\n"
290  "Please check permissions on the file.";
291  }
292  CacheParser::read(icf, ltp);
293 
294  for (CacheParser::LoadableToPlugins::iterator itFile = ltp.begin(); itFile != ltp.end(); ++itFile) {
295  old[itFile->first] = itFile->second;
296  }
297 
298  // If required, we remove the plugins which are missing. Notice that old is
299  // now the most updated copy of the cache.
300  if (removeMissingFiles) {
301  for (CacheParser::LoadableToPlugins::iterator itFile = old.begin(); itFile != old.end();
302  /*don't advance the iterator here because it may have become invalid */) {
303  path loadableFile(directory);
304  loadableFile /= (itFile->first);
305  if (not exists(loadableFile)) {
306  std::cout << "removing file '" << temporaryFilename.c_str() << "'" << std::endl;
307  CacheParser::LoadableToPlugins::iterator itToItemBeingRemoved = itFile;
308  //advance the iterator while it is still valid
309  ++itFile;
310  old.erase(itToItemBeingRemoved);
311  } else {
312  //since we are not advancing the iterator in the for loop, do it here
313  ++itFile;
314  }
315  }
316  }
317 
318  // We finally write the final cache.
319  std::ofstream fcf(temporaryFilename.c_str());
320  if (!fcf) {
321  cms::Exception("FailedToOpen") << "unable to open file '" << temporaryFilename.c_str()
322  << "' for writing.\n"
323  "Please check permissions on the file.";
324  }
325  CacheParser::write(old, fcf);
326  rename(temporaryFilename.c_str(), cacheFile.string().c_str());
327  } catch (std::exception& iException) {
328  std::cerr << "Caught exception " << iException.what() << std::endl;
329  returnValue = EXIT_FAILURE;
330  }
331 
332  return returnValue;
333 } catch (std::exception const& iException) {
334  std::cerr << iException.what() << std::endl;
335  return 1;
336 }
#define PER_PROCESS_DSO
Definition: refresh.cc:43
list status
Definition: mps_update.py:107
const std::filesystem::path & cachefileName()
Definition: standard.cc:47
std::string const & category() const
Definition: Exception.cc:143
const std::string & pluginPrefix()
Definition: standard.cc:57
Func for_all(ForwardSequence &s, Func f)
wrapper for std::for_each
Definition: Algorithms.h:14
tuple lib
Definition: mps_check.py:21
PluginManager::Config config()
Definition: standard.cc:21
edm::signalslot::Signal< void(const PluginFactoryBase *)> newFactory_
char const * what() const noexceptoverride
Definition: Exception.cc:103
static const char *const kHelpCommandOpt
Definition: CmsShowMain.cc:106
tuple argc
Definition: dir2webdir.py:39
tuple filename
Definition: lut2db_cfg.py:20
string end
Definition: dataset.py:937
Config & searchPath(const SearchPath &iPath)
Definition: PluginManager.h:56
tuple cout
Definition: gather_cfg.py:144
#define get
static const char *const kHelpOpt
Definition: CmsShowMain.cc:105
static PluginFactoryManager * get()