CMS 3D CMS Logo

BinaryArchiveBase.cc
Go to the documentation of this file.
1 #include <cassert>
2 #include <cctype>
3 #include <cerrno>
4 #include <climits>
5 #include <cstdlib>
6 #include <cstring>
7 
8 #include "Alignment/Geners/interface/BinaryArchiveBase.hh"
9 #include "Alignment/Geners/interface/CatalogIO.hh"
10 #include "Alignment/Geners/interface/binaryIO.hh"
11 
12 #ifdef GENERS_BINARY_ARCHIVE_FORMAT_ID
13 #undef GENERS_BINARY_ARCHIVE_FORMAT_ID
14 #endif
15 #define GENERS_BINARY_ARCHIVE_FORMAT_ID (0x1f2e3d4c)
16 
17 static bool parse_unsigned(std::ostringstream &err, const char *c, unsigned *result) {
18  char *endptr;
19  errno = 0;
20  const unsigned long value = strtoul(c, &endptr, 0);
21  if (errno || *endptr != '\0') {
22  err << "expected an unsigned integer, got \"" << c << '"';
23  if (errno)
24  err << ", " << strerror(errno);
25  return false;
26  }
27  if (value > UINT_MAX) {
28  err << "unsigned value \"" << c << "\" is out of range";
29  return false;
30  }
31  *result = value;
32  return true;
33 }
34 
35 static bool parse_int(std::ostringstream &err, const char *c, int *result) {
36  char *endptr;
37  errno = 0;
38  const long value = strtol(c, &endptr, 0);
39  if (errno || *endptr != '\0') {
40  err << "expected an integer, got \"" << c << '"';
41  if (errno)
42  err << ", " << strerror(errno);
43  return false;
44  }
45  if (value < INT_MIN || value > INT_MAX) {
46  err << "integer value \"" << c << "\" is out of range";
47  return false;
48  }
49  *result = value;
50  return true;
51 }
52 
53 namespace gs {
54  BinaryArchiveBase::BinaryArchiveBase(const char *name, const char *mode)
55  : AbsArchive(name),
56  mode_(parseMode(mode)),
57  errorStream_(nullptr),
58  cStream_(nullptr),
59  catalog_(nullptr),
60  storedEntryId_(nullptr),
61  storedLocationId_(nullptr),
62  catalogIsSet_(false),
63  addCatalogToData_(false) {
64  CStringStream::CompressionMode m = CStringStream::NOT_COMPRESSED;
65  int compressionLevel = -1;
66  unsigned minSizeToCompress = 1024U;
67  unsigned bufSize = 1048576U; // 1024*1024
68 
69  std::ostringstream err;
70  modeIsValid_ =
71  parseArchiveOptions(err, mode, &m, &compressionLevel, &minSizeToCompress, &bufSize, &addCatalogToData_);
72  if (modeIsValid_)
73  cStream_ = new CStringStream(m, compressionLevel, minSizeToCompress, bufSize);
74  else {
75  errorStream() << "In BinaryArchiveBase constructor: "
76  << "invalid archive opening mode \"" << mode << '"';
77  const std::string &errInfo = err.str();
78  if (!errInfo.empty())
79  errorStream() << ": " << errInfo;
80  }
81  }
82 
83  void BinaryArchiveBase::releaseClassIds() {
84  delete storedEntryId_;
85  storedEntryId_ = nullptr;
86  delete storedLocationId_;
87  storedLocationId_ = nullptr;
88  }
89 
90  BinaryArchiveBase::~BinaryArchiveBase() {
91  releaseClassIds();
92  delete errorStream_;
93  delete catalog_;
94  delete cStream_;
95  }
96 
97  void BinaryArchiveBase::writeHeader(std::ostream &os) {
98  const unsigned format = GENERS_BINARY_ARCHIVE_FORMAT_ID;
99  write_pod(os, format);
100 
101  // Write some other info
102  const unsigned multiplex = addCatalogToData_ ? 1 : 0;
103  const unsigned sizeoflong = sizeof(long);
104  const unsigned infoword = (sizeoflong << 1) | multiplex;
105  write_pod(os, infoword);
106 
107  if (multiplex) {
108  // Write class ids for CatalogEntry and ItemLocation
109  releaseClassIds();
110  storedEntryId_ = new ClassId(ClassId::makeId<CatalogEntry>());
111  storedEntryId_->write(os);
112  storedLocationId_ = new ClassId(ClassId::makeId<ItemLocation>());
113  storedLocationId_->write(os);
114  }
115  }
116 
117  bool BinaryArchiveBase::readHeader(std::istream &is) {
118  const unsigned expectedFormat = GENERS_BINARY_ARCHIVE_FORMAT_ID;
119  is.seekg(0, std::ios_base::beg);
120  unsigned format = 0;
121  read_pod(is, &format);
122  if (format != expectedFormat)
123  return false;
124 
125  unsigned infoword = 0xffffffff;
126  read_pod(is, &infoword);
127  const unsigned multiplex = infoword & 0x1U;
128  const unsigned sizeoflong = infoword >> 1;
129 
130  // The following check will make sure that we are not reading
131  // an archive created on a 32-bit machine with a 64-bit system
132  // (and otherwise)
133  if (sizeoflong != sizeof(long))
134  return false;
135 
136  addCatalogToData_ = multiplex;
137  if (addCatalogToData_) {
138  releaseClassIds();
139  storedEntryId_ = new ClassId(is, 1);
140  storedLocationId_ = new ClassId(is, 1);
141 
142  // Can't open this archive for update if the above class ids
143  // are obsolete -- otherwise we will loose the capability to
144  // restore the catalog
145  if (mode_ & std::ios_base::out) {
146  const ClassId &entryId = ClassId::makeId<CatalogEntry>();
147  const ClassId &locId = ClassId::makeId<ItemLocation>();
148  if (entryId != *storedEntryId_ || locId != *storedLocationId_)
149  throw IOInvalidData(
150  "In gs::BinaryArchiveBase::readHeader: this "
151  "archive can no longer be open for update as it was "
152  "created using an older version of I/O software");
153  }
154  }
155  return !is.fail();
156  }
157 
158  void BinaryArchiveBase::openDataFile(std::fstream &stream, const char *filename) {
159  assert(filename);
160  if (stream.is_open())
161  stream.close();
162  stream.clear();
163  stream.open(filename, mode_);
164  if (!stream.is_open())
165  throw IOOpeningFailure("gs::BinaryArchiveBase::openDataFile", filename);
166 
167  // Do we need to write the header out or to read it in?
168  bool writeHead = false;
169  if (mode_ & std::ios_base::out) {
170  if (mode_ & std::ios_base::trunc)
171  writeHead = true;
172  else if (isEmptyFile(stream))
173  writeHead = true;
174  }
175 
176  if (writeHead) {
178  if (stream.fail()) {
179  stream.close();
180  std::string e =
181  "In gs::BinaryArchiveBase::openDataFile: "
182  "failed to write archive header to file \"";
183  e += filename;
184  e += "\"";
185  throw IOWriteFailure(e);
186  }
187  } else {
188  if (!readHeader(stream)) {
189  const bool failed = stream.fail();
190  stream.close();
191  std::string e = "In gs::BinaryArchiveBase::openDataFile: ";
192  if (failed) {
193  e += "could not read archive header from file \"";
194  e += filename;
195  e += "\"";
196  throw IOReadFailure(e);
197  } else {
198  e += "no valid archive header in file \"";
199  e += filename;
200  e += "\"";
201  throw IOInvalidData(e);
202  }
203  }
204  }
205  }
206 
207  void BinaryArchiveBase::setCatalog(AbsCatalog *c) {
208  if (c) {
209  assert(!catalogIsSet_);
210  catalogIsSet_ = true;
211  }
212  delete catalog_;
213  catalog_ = c;
214  }
215 
216  void BinaryArchiveBase::itemSearch(const SearchSpecifier &namePattern,
217  const SearchSpecifier &categoryPattern,
218  std::vector<unsigned long long> *idsFound) const {
219  if (catalog_)
220  catalog_->search(namePattern, categoryPattern, idsFound);
221  else {
222  assert(idsFound);
223  idsFound->clear();
224  }
225  }
226 
227  bool BinaryArchiveBase::parseArchiveOptions(std::ostringstream &err,
228  const char *modeIn,
229  CStringStream::CompressionMode *m,
230  int *compressionLevel,
231  unsigned *minSizeToCompress,
232  unsigned *bufSize,
233  bool *multiplexCatalog) {
234  if (!modeIn)
235  return true;
236  std::string cmode(modeIn ? modeIn : "");
237  if (cmode.empty())
238  return true;
239  char *mode = const_cast<char *>(cmode.c_str());
240 
241  unsigned cnt = 0;
242  for (char *opt = strtok(mode, ":"); opt; opt = strtok(nullptr, ":"), ++cnt) {
243  // Skip the first word -- this is the file opening mode
244  if (!cnt)
245  continue;
246  char *eq = strchr(opt, '=');
247  if (eq) {
248  // Get rid of spaces around option name
249  char *optname = opt;
250  while (isspace(*optname) && optname < eq)
251  ++optname;
252  if (optname == eq) {
253  err << "invalid binary archive option \"\"";
254  return false;
255  }
256  char *optend = eq - 1;
257  while (isspace(*optend))
258  --optend;
259  ++optend;
260  *optend = '\0';
261 
262  // Get rid of spaces around option value
263  char *optval = eq + 1;
264  while (*optval && isspace(*optval))
265  ++optval;
266  if (!*optval) {
267  err << "invalid binary archive option value \"\"";
268  return false;
269  }
270  char *valend = opt + strlen(opt) - 1;
271  while (isspace(*valend))
272  --valend;
273  ++valend;
274  *valend = '\0';
275  if (strlen(optval) == 0) {
276  err << "invalid binary archive option value \"\"";
277  return false;
278  }
279 
280  // Go over possible options
281  if (!strcasecmp(optname, "z")) {
282  // Compression type
283  if (!CStringStream::getCompressionModeByName(optval, m)) {
284  err << "invalid compression type \"" << optval << '"';
285  return false;
286  }
287  } else if (!strcasecmp(optname, "cl")) {
288  // Compression level
289  if (!parse_int(err, optval, compressionLevel))
290  return false;
291  if (*compressionLevel < -1 || *compressionLevel > 9) {
292  err << "compression level is out of range";
293  return false;
294  }
295  } else if (!strcasecmp(optname, "cb")) {
296  // Compression buffer size
297  if (!parse_unsigned(err, optval, bufSize))
298  return false;
299  } else if (!strcasecmp(optname, "cm")) {
300  // Compression minimum size
301  if (!parse_unsigned(err, optval, minSizeToCompress))
302  return false;
303  } else if (!strcasecmp(optname, "cat")) {
304  // Internal or external catalog
305  if (optval[0] == 'i' || optval[0] == 'I')
306  *multiplexCatalog = true;
307  else if (optval[0] == 's' || optval[0] == 'S')
308  *multiplexCatalog = false;
309  else {
310  err << "invalid catalog mode \"" << optval << '"';
311  return false;
312  }
313  } else {
314  // Unknown option
315  err << "unrecognized binary archive option \"" << optname << '"';
316  return false;
317  }
318  } else {
319  err << "invalid binary archive option \"" << opt << '"';
320  return false;
321  }
322  }
323  return true;
324  }
325 
326  std::ios_base::openmode BinaryArchiveBase::parseMode(const char *mode) {
327  std::ios_base::openmode m = std::ios_base::binary;
328  if (mode) {
329  const unsigned len = strlen(mode);
330  for (unsigned i = 0; i < len; ++i) {
331  // Note that all characters other than 'r', 'w',
332  // 'a', and '+' are basically ignored inside this cycle
333  if (mode[i] == 'r')
334  m |= std::ios_base::in;
335  else if (mode[i] == 'w')
337  else if (mode[i] == 'a')
338  m |= (std::ios_base::out | std::ios_base::app);
339  else if (mode[i] == '+')
341  else if (mode[i] == ':')
342  break;
343  }
344  }
345 
346  // Make sure that we are at least reading
348  m |= std::ios_base::in;
349  return m;
350  }
351 
352  void BinaryArchiveBase::search(AbsReference &reference) {
353  if (catalog_) {
354  std::vector<unsigned long long> idlist;
355  catalog_->search(reference.namePattern(), reference.categoryPattern(), &idlist);
356  const unsigned long nfound = idlist.size();
357  for (unsigned long i = 0; i < nfound; ++i) {
358  std::shared_ptr<const CatalogEntry> pentry = catalog_->retrieveEntry(idlist[i]);
359  if (reference.isIOCompatible(*pentry))
360  addItemToReference(reference, idlist[i]);
361  }
362  }
363  }
364 
365  bool BinaryArchiveBase::isEmptyFile(std::fstream &s) {
366  s.seekg(0, std::ios_base::end);
367  return s.tellg() == std::streampos(0);
368  }
369 
370  std::istream &BinaryArchiveBase::inputStream(const unsigned long long id, long long *sz) {
371  unsigned long long length = 0;
372  unsigned compressionCode = 0;
373  std::istream &is = plainInputStream(id, &compressionCode, &length);
374  if (cStream_->compressionMode() == CStringStream::NOT_COMPRESSED) {
375  if (sz)
376  *sz = -1LL;
377  return is;
378  } else {
379  cStream_->readCompressed(is, compressionCode, length);
380  if (sz) {
381  std::streamoff off = cStream_->tellp();
382  *sz = off;
383  }
384  return *cStream_;
385  }
386  }
387 
388  std::ostream &BinaryArchiveBase::outputStream() { return plainOutputStream(); }
389 
390  std::ostream &BinaryArchiveBase::compressedStream(std::ostream &os) {
391  if (cStream_->compressionMode() == CStringStream::NOT_COMPRESSED)
392  return os;
393  else {
394  cStream_->reset();
395  cStream_->setSink(os);
396  return *cStream_;
397  }
398  }
399 
400  unsigned BinaryArchiveBase::flushCompressedRecord(std::ostream &) {
401  CStringStream::CompressionMode m = cStream_->compressionMode();
402  if (m != CStringStream::NOT_COMPRESSED) {
403  cStream_->flush();
404  m = cStream_->writeCompressed();
405  }
406  return static_cast<unsigned>(m);
407  }
408 } // namespace gs
std::vector< T >::const_iterator search(const cond::Time_t &val, const std::vector< T > &container)
Definition: IOVProxy.cc:21
static bool parse_unsigned(std::ostringstream &err, const char *c, unsigned *result)
uint32_t T const *__restrict__ uint32_t const *__restrict__ int32_t int Histo::index_type cudaStream_t stream
assert(be >=bs)
void readHeader(xercesc::DOMNode *parentNode, EcalCondHeader &header)
read header from
void writeHeader(xercesc::DOMNode *parentNode, const EcalCondHeader &header)
write
Definition: value.py:1
static bool parse_int(std::ostringstream &err, const char *c, int *result)
#define GENERS_BINARY_ARCHIVE_FORMAT_ID
Definition: AbsArchive.cc:46