HOPS
HOPS class reference
MHO_BinaryFileInterface.hh
Go to the documentation of this file.
1 #ifndef MHO_BinaryFileInterface_HH__
2 #define MHO_BinaryFileInterface_HH__
3 
5 #include "MHO_ClassIdentity.hh"
6 #include "MHO_FileKey.hh"
8 #include "MHO_Message.hh"
9 #include "MHO_Serializable.hh"
10 #include "MHO_UUIDGenerator.hh"
11 
12 namespace hops
13 {
14 
27 {
28  public:
29  MHO_BinaryFileInterface(): fCollectKeys(false){};
30 
32 
39  {
40  if(fCollectKeys)
41  {
42  return (fObjectStreamer.IsOpenForWrite() && fKeyStreamer.IsOpenForWrite());
43  }
44  else
45  {
46  return fObjectStreamer.IsOpenForWrite();
47  }
48  }
49 
55  bool IsOpenForRead() { return fObjectStreamer.IsOpenForRead(); }
56 
64  bool OpenToWrite(const std::string& obj_filename, const std::string& index_filename = "")
65  {
66  fObjectStreamer.SetFilename(obj_filename);
67  fObjectStreamer.OpenToWrite();
68 
69  if(index_filename != "") //stream keys to a separate index file
70  {
71  fCollectKeys = true;
72  fKeyStreamer.SetFilename(index_filename);
73  fKeyStreamer.OpenToWrite();
74  return fObjectStreamer.IsOpenForWrite() && fKeyStreamer.IsOpenForWrite();
75  }
76 
77  return fObjectStreamer.IsOpenForWrite();
78  }
79 
87  bool OpenToAppend(const std::string& obj_filename, const std::string& index_filename = "")
88  {
89  fObjectStreamer.SetFilename(obj_filename);
90  fObjectStreamer.OpenToAppend();
91 
92  if(index_filename != "") //stream keys to a separate index file
93  {
94  fCollectKeys = true;
95  fKeyStreamer.SetFilename(index_filename);
96  fKeyStreamer.OpenToAppend();
97  return fObjectStreamer.IsOpenForWrite() && fKeyStreamer.IsOpenForWrite();
98  }
99 
100  return fObjectStreamer.IsOpenForWrite();
101  }
102 
109  bool OpenToRead(const std::string& filename)
110  {
111  fObjectStreamer.SetFilename(filename);
112  fObjectStreamer.OpenToRead();
113 
114  return fObjectStreamer.IsOpenForRead();
115  }
116 
124  bool OpenToReadAtOffset(const std::string& filename, uint64_t offset_bytes)
125  {
126  fObjectStreamer.SetFilename(filename);
127  fObjectStreamer.OpenToRead();
128  fObjectStreamer.GetStream().seekg(offset_bytes, std::ios_base::cur);
129  return fObjectStreamer.IsOpenForRead();
130  }
131 
139  bool ExtractIndexFileObjectKeys(const std::string& index_filename, std::vector< MHO_FileKey >& keys)
140  {
141  keys.clear();
142 
143  if(fObjectStreamer.IsOpenForRead() || fObjectStreamer.IsOpenForWrite() || fKeyStreamer.IsOpenForRead() ||
144  fKeyStreamer.IsOpenForWrite())
145  {
146  msg_warn("file", "Cannot extract index file keys with active stream. Close open file first." << eom);
147  return false;
148  }
149  else
150  {
151  fKeyStreamer.SetFilename(index_filename);
152  fKeyStreamer.OpenToRead();
153  if(fKeyStreamer.IsOpenForRead())
154  {
155  while(fKeyStreamer.GetStream().good())
156  {
157  MHO_FileKey key;
158  fKeyStreamer >> key;
159  if(fKeyStreamer.GetStream().good())
160  {
161  keys.push_back(key);
162  }
163  }
164  fKeyStreamer.Close();
165  return true;
166  }
167  else
168  {
169  msg_error("file", "Failed to read object keys, file not open for reading." << eom);
170  fKeyStreamer.Close();
171  return false;
172  }
173  }
174  }
175 
184  bool ExtractFileObjectKeys(const std::string& filename, std::vector< MHO_FileKey >& keys)
185  {
186  keys.clear();
187 
188  if(fObjectStreamer.IsOpenForRead() || fObjectStreamer.IsOpenForWrite() || fKeyStreamer.IsOpenForRead() ||
189  fKeyStreamer.IsOpenForWrite())
190  {
191  msg_warn("file", "Cannot extract file keys with active stream. Close open file first." << eom);
192  return false;
193  }
194  else
195  {
196  fKeyStreamer.SetFilename(filename);
197  fKeyStreamer.OpenToRead();
198  if(fKeyStreamer.IsOpenForRead())
199  {
200  while(fKeyStreamer.GetStream().good())
201  {
202  MHO_FileKey key;
203  fKeyStreamer >> key;
204  if(fKeyStreamer.GetStream().good()) //make sure we haven't hit EOF
205  {
206  //first check if the sync word matches, if not then we have
207  //gotten off track and are in unknown territory
208  bool key_ok = true;
209  if(key.fSync != MHO_FileKeySyncWord)
210  {
211  key_ok = false;
212  }
213  if(key_ok)
214  {
215  keys.push_back(key);
216  //now skip ahead by the size of the object
217  fKeyStreamer.SkipAhead(key.fSize);
218  }
219  else
220  {
221  msg_error("file",
222  "Failed to read object key, sync word " << key.fSync << " not recognized." << eom);
223  break;
224  }
225  }
226  else
227  {
228  break;
229  } //EOF
230  }
231  fKeyStreamer.Close();
232  return true;
233  }
234  else
235  {
236  msg_error("file", "Failed to read key, file not open for reading." << eom);
237  fKeyStreamer.Close();
238  return false; //non-recoverable error
239  }
240  }
241  }
242 
251  bool ExtractFileObjectKeysAndOffsets(const std::string& filename, std::vector< MHO_FileKey >& keys,
252  std::vector< std::size_t >& byte_offsets)
253  {
254  keys.clear();
255  byte_offsets.clear();
256  std::size_t byte_count = 0;
257 
258  if(fObjectStreamer.IsOpenForRead() || fObjectStreamer.IsOpenForWrite() || fKeyStreamer.IsOpenForRead() ||
259  fKeyStreamer.IsOpenForWrite())
260  {
261  msg_warn("file", "Cannot extract file keys with active stream. Close open file first." << eom);
262  return false;
263  }
264  else
265  {
266  fKeyStreamer.SetFilename(filename);
267  fKeyStreamer.OpenToRead();
268  if(fKeyStreamer.IsOpenForRead())
269  {
270  while(fKeyStreamer.GetStream().good())
271  {
272  MHO_FileKey key;
273  fKeyStreamer >> key;
274  if(fKeyStreamer.GetStream().good()) //make sure we haven't hit EOF
275  {
276  //first check if the sync word matches, if not then we have
277  //gotten off track and are in unknown territory
278  bool key_ok = true;
279  if(key.fSync != MHO_FileKeySyncWord)
280  {
281  key_ok = false;
282  }
283  if(key_ok)
284  {
285  byte_offsets.push_back(byte_count);
286  keys.push_back(key);
287  byte_count += MHO_FileKeySize + key.fSize;
288  //now skip ahead by the size of the object
289  fKeyStreamer.SkipAhead(key.fSize);
290  }
291  else
292  {
293  msg_error("file",
294  "Failed to read object key, sync word " << key.fSync << " not recognized." << eom);
295  break;
296  }
297  }
298  else
299  {
300  break;
301  } //EOF
302  }
303  fKeyStreamer.Close();
304  return true;
305  }
306  else
307  {
308  msg_error("file", "Failed to read key, file not open for reading." << eom);
309  fKeyStreamer.Close();
310  return false; //non-recoverable error
311  }
312  }
313  }
314 
318  void Close()
319  {
320  fObjectStreamer.Close();
321  if(!(fObjectStreamer.IsClosed()))
322  {
323  msg_error("file", "Failed to close file." << eom);
324  }
325 
326  if(fCollectKeys)
327  {
328  fKeyStreamer.Close();
329  if(!(fKeyStreamer.IsClosed()))
330  {
331  msg_error("file", "Failed to close key/index file." << eom);
332  }
333  }
334  fCollectKeys = false;
335  }
336 
346  template< class XWriteType > bool Write(const XWriteType& obj, const std::string& shortname = "")
347  {
348  if(fObjectStreamer.IsOpenForWrite())
349  {
350  MHO_FileKey key = GenerateObjectFileKey(obj, shortname);
351  fObjectStreamer.ResetByteCount();
352  fObjectStreamer << key;
353  msg_debug("file", "wrote object key of size: " << fObjectStreamer.GetNBytesWritten() << " bytes" << eom);
354  fObjectStreamer.ResetByteCount();
355  fObjectStreamer << obj;
356  msg_debug("file", "wrote object of size: " << fObjectStreamer.GetNBytesWritten() << " bytes" << eom);
357  //check actual streamed byte count agrees with the object's GetSerializedSize()), if not, then every
358  //object after this one in the file will be misaligned/corrupted
359  if(fObjectStreamer.GetNBytesWritten() != key.fSize)
360  {
361  msg_error("file", "Object serialized size mismatch for object of type: "
362  << MHO_ClassIdentity::ClassName(obj) << ", declared " << key.fSize
363  << " bytes but wrote " << fObjectStreamer.GetNBytesWritten()
364  << " bytes; GetSerializedSize() is out of sync with the streaming operator" << eom);
365  return false;
366  }
367  if(fObjectStreamer.GetStream().good())
368  {
369  if(fCollectKeys && fKeyStreamer.IsOpenForWrite())
370  {
371  fKeyStreamer << key;
372  }
373  return true;
374  }
375  else
376  {
377  msg_error("file", "Failed to write object, stream state returned: " << fObjectStreamer.GetStream().rdstate()
378  << eom);
379  return false;
380  }
381  }
382  else
383  {
384  msg_error("file", "Failed to write object, file not open for writing." << eom);
385  return false;
386  }
387  }
388 
389  //
399  template< class XWriteType > bool Write(const XWriteType& obj, const char* shortname)
400  {
401  std::string sshortname(shortname);
402  return this->Write(obj, sshortname);
403  }
404 
412  template< class XReadType > bool Read(XReadType& obj, MHO_FileKey& obj_key)
413  {
414  if(fObjectStreamer.IsOpenForRead())
415  {
416  MHO_FileKey key;
417  fObjectStreamer >> key;
418  obj_key = key;
419 
420  //first check if the sync word matches, if not then we have
421  //gotten off track and are in unknown territory
422  bool key_ok = true;
423  if(key.fSync != MHO_FileKeySyncWord)
424  {
425  key_ok = false;
426  }
427 
428  fMD5Generator.Initialize();
429  std::string name = MHO_ClassIdentity::ClassName(obj);
430  fMD5Generator << name;
431  fMD5Generator.Finalize();
432  MHO_UUID type_uuid = fMD5Generator.GetDigestAsUUID();
433  if(key.fTypeId != type_uuid)
434  {
435  key_ok = false;
436  }
437 
438  if(key_ok)
439  {
440  obj.SetObjectUUID(obj_key.fObjectId);
441  fObjectStreamer >> obj;
442  if(fObjectStreamer.IsObjectUnknown())
443  {
444  //object version was not recognized, skip this object's data
445  if(key.fSize > sizeof(MHO_ClassVersion))
446  {
447  uint64_t skip_size = key.fSize - sizeof(MHO_ClassVersion);
448  fObjectStreamer.GetStream().seekg(skip_size, std::ios_base::cur);
449  msg_warn("file", "Encountered and skipped an unrecognized version of object with class name: "
450  << name << "." << eom);
451  fObjectStreamer.ResetObjectState(); //reset streamer state for next object
452  return true; //recoverable error
453  }
454  else
455  {
456  msg_error("file", "Encountered object with wrong/corrupt object size");
457  return false; //non-recoverable error
458  }
459  }
460  return true;
461  }
462  else
463  {
464  msg_error("file",
465  "Failed to read object, object type/key mismatch for object of type: " << name << "." << eom);
466  msg_error("file", "Object uuid: " << type_uuid.as_string() << " file key uuid: " << key.fTypeId.as_string()
467  << "." << eom);
468  return false; //non-recoverable error
469  }
470  }
471  else
472  {
473  msg_error("file", "Failed to read object, file not open for reading." << eom);
474  return false; //non-recoverable error
475  }
476  }
477 
478  private:
479  //the file streamer
480  MHO_BinaryFileStreamer fObjectStreamer;
481  MHO_BinaryFileStreamer fKeyStreamer;
482  MHO_UUIDGenerator fUUIDGenerator;
483  MHO_MD5HashGenerator fMD5Generator;
484 
492  template< class XWriteType > MHO_FileKey GenerateObjectFileKey(const XWriteType& obj, const std::string& shortname)
493  {
494  MHO_FileKey key; //sync and label set in constructor
495 
496  //add short name
497  CopyTruncatedString(shortname, key.fName);
498 
499  fMD5Generator.Initialize();
500  std::string name = MHO_ClassIdentity::ClassName(obj);
501  fMD5Generator << name;
502  fMD5Generator.Finalize();
503  key.fTypeId = fMD5Generator.GetDigestAsUUID(); //type uuid
504 
505  key.fObjectId = obj.GetObjectUUID();
506  msg_debug("file", "constructing a file key with object uuid of: " << key.fObjectId.as_string() << eom);
507  //key.fObjectId = fUUIDGenerator.GenerateUUID(); //random uuid of object id
508  key.fSize = obj.GetSerializedSize();
509 
510  return key;
511  }
512 
513  void CopyTruncatedString(const std::string& s, char* arr)
514  {
515  size_t len = s.size();
516  if(MHO_FileKeyNameLength <= len)
517  {
518  len = MHO_FileKeyNameLength;
519  }
520  for(size_t i = 0; i < len; i++)
521  {
522  if(i < s.size())
523  {
524  arr[i] = s[i];
525  }
526  else
527  {
528  arr[i] = '\0';
529  }
530  }
531  }
532 
533  //file object keys, collected as we go
534  bool fCollectKeys;
535 };
536 
537 } // namespace hops
538 
539 #endif
#define msg_debug(xKEY, xCONTENT)
Definition: MHO_Message.hh:291
#define msg_warn(xKEY, xCONTENT)
Definition: MHO_Message.hh:248
#define msg_error(xKEY, xCONTENT)
Definition: MHO_Message.hh:238
Class MHO_BinaryFileInterface.
Definition: MHO_BinaryFileInterface.hh:27
bool Read(XReadType &obj, MHO_FileKey &obj_key)
Reads the object (XReadType) specified by the object file key from the file.
Definition: MHO_BinaryFileInterface.hh:412
bool OpenToWrite(const std::string &obj_filename, const std::string &index_filename="")
Opens a file for writing and optionally opens an index file if provided.
Definition: MHO_BinaryFileInterface.hh:64
bool OpenToRead(const std::string &filename)
Opens a file for reading and checks if it's open.
Definition: MHO_BinaryFileInterface.hh:109
virtual ~MHO_BinaryFileInterface()
Definition: MHO_BinaryFileInterface.hh:31
bool ExtractFileObjectKeysAndOffsets(const std::string &filename, std::vector< MHO_FileKey > &keys, std::vector< std::size_t > &byte_offsets)
pulls out the object keys and the bytes offsets to the key entry of each object from the start of the...
Definition: MHO_BinaryFileInterface.hh:251
bool OpenToAppend(const std::string &obj_filename, const std::string &index_filename="")
Opens a file for appending objects and optionally streams keys to an index file.
Definition: MHO_BinaryFileInterface.hh:87
void Close()
Closes file and key/index streamers if open.
Definition: MHO_BinaryFileInterface.hh:318
bool Write(const XWriteType &obj, const char *shortname)
Writes an object (must inherit from MHO_Serializable) to a file (with optional shortname string - ove...
Definition: MHO_BinaryFileInterface.hh:399
bool Write(const XWriteType &obj, const std::string &shortname="")
Writes an object (must inherit from MHO_Serializable) to a file (with optional shortname string)....
Definition: MHO_BinaryFileInterface.hh:346
bool ExtractFileObjectKeys(const std::string &filename, std::vector< MHO_FileKey > &keys)
reads an object file and extracts the object file keys while skipping over the object data (cannot be...
Definition: MHO_BinaryFileInterface.hh:184
bool OpenToReadAtOffset(const std::string &filename, uint64_t offset_bytes)
Opens a file for reading at a specified byte offset.
Definition: MHO_BinaryFileInterface.hh:124
bool IsOpenForWrite()
Checks if both object and key streamers are open for writing when fCollectKeys is true,...
Definition: MHO_BinaryFileInterface.hh:38
MHO_BinaryFileInterface()
Definition: MHO_BinaryFileInterface.hh:29
bool IsOpenForRead()
Checks if the object streamer is open for reading.
Definition: MHO_BinaryFileInterface.hh:55
bool ExtractIndexFileObjectKeys(const std::string &index_filename, std::vector< MHO_FileKey > &keys)
reads an index file and extracts the object file keys (cannot be actively streaming to another open f...
Definition: MHO_BinaryFileInterface.hh:139
Class MHO_BinaryFileStreamer declare the concrete class which does the work for file streams.
Definition: MHO_BinaryFileStreamer.hh:293
virtual void OpenToWrite() override
Opens a file for binary writing and sets appropriate state.
Definition: MHO_BinaryFileStreamer.cc:39
virtual void OpenToAppend() override
Opens a binary file for appending and sets appropriate file state.
Definition: MHO_BinaryFileStreamer.cc:23
virtual void OpenToRead() override
Opens a file for binary reading and sets appropriate state.
Definition: MHO_BinaryFileStreamer.cc:7
virtual void ResetByteCount() override
Resets byte count to zero.
Definition: MHO_BinaryFileStreamer.hh:343
virtual uint64_t GetNBytesWritten() const override
Getter for N bytes written.
Definition: MHO_BinaryFileStreamer.hh:359
virtual std::fstream & GetStream() override
Getter for fstream object.
Definition: MHO_BinaryFileStreamer.hh:329
virtual void Close() override
Closes the open file if it exists and sets the file state to closed.
Definition: MHO_BinaryFileStreamer.cc:55
Class MHO_FileKey the version-0 size of the file key is (512 bits / 64 bytes), and all of the version...
Definition: MHO_FileKey.hh:54
char fName[MHO_FileKeyNameLength]
Definition: MHO_FileKey.hh:158
MHO_UUID fTypeId
Definition: MHO_FileKey.hh:157
uint32_t fSync
Definition: MHO_FileKey.hh:150
uint64_t fSize
Definition: MHO_FileKey.hh:159
MHO_UUID fObjectId
Definition: MHO_FileKey.hh:156
virtual bool IsOpenForRead()
Checks if a file is open for reading.
Definition: MHO_FileStreamer.hh:99
virtual void ResetObjectState()
Resets the object state to unset.
Definition: MHO_FileStreamer.hh:135
virtual bool IsClosed()
Checks if the file is closed.
Definition: MHO_FileStreamer.hh:114
void SetFilename(const std::string filename)
Setter for filename.
Definition: MHO_FileStreamer.hh:41
virtual bool IsObjectUnknown()
Checks if object state is unknown.
Definition: MHO_FileStreamer.hh:143
virtual void SkipAhead(size_t n_bytes)
Seeks ahead in file by specified number of bytes and updates object state.
Definition: MHO_FileStreamer.hh:151
virtual bool IsOpenForWrite()
Checks if file is open for writing.
Definition: MHO_FileStreamer.hh:84
Class MHO_MD5HashGenerator declares the concrete class which does the work for file streams.
Definition: MHO_MD5HashGenerator.hh:134
void Finalize()
Finalizes the MD5 hash calculation and stores the result in fDigest.
Definition: MHO_MD5HashGenerator.hh:155
MHO_UUID GetDigestAsUUID()
Getter for digest as uuid.
Definition: MHO_MD5HashGenerator.hh:181
void Initialize()
Recursive function to initialize a game state.
Definition: MHO_MD5HashGenerator.hh:143
Definition: MHO_UUIDGenerator.hh:23
Class MHO_UUID - a class for a 16 byte UUID (for object and type identification)
Definition: MHO_UUID.hh:27
std::string as_string() const
Definition: MHO_UUID.hh:125
Definition: MHO_AdhocFlagging.hh:18
uint32_t MHO_ClassVersion
Definition: MHO_ClassIdentity.hh:22
static std::string ClassName()
Returns the class name as a string.
Definition: MHO_ClassIdentity.hh:51