ALPSCore reference
archivecontext.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1998-2018 ALPS Collaboration. See COPYRIGHT.TXT
3  * All rights reserved. Use is subject to license terms. See LICENSE.TXT
4  * For use in publications, see ACKNOWLEDGE.TXT
5  */
6 
7 #include <iostream>
8 #include <fstream>
9 
12 #include <alps/hdf5/errors.hpp>
13 #include <alps/utilities/cast.hpp>
14 
15 #include "common.hpp"
16 #include "archivecontext.hpp"
17 
18 namespace alps {
19  namespace hdf5 {
20  namespace detail {
21 
22  archivecontext::archivecontext(std::string const & filename, bool write, bool replace, bool compress, bool memory)
23  : compress_(compress)
24  , write_(write || replace)
25  , replace_(!memory && replace)
26  , memory_(memory)
27  , filename_(filename)
28  , filename_new_(filename)
29  {
30  construct();
31  }
32 
33  archivecontext::~archivecontext() {
34  destruct(true);
35  }
36 
37  void archivecontext::grant(bool write, bool replace) {
38  if (!write_ && (write || replace)) {
39  destruct(false);
40  write_ = write || replace;
41  replace_ = !memory_ && replace;
42  construct();
43  }
44  }
45 
46  void archivecontext::construct() {
48  if (memory_) {
49  property_type prop_id(H5Pcreate(H5P_FILE_ACCESS));
50  check_error(H5Pset_fapl_core(prop_id, 1 << 20, true));
51  #ifndef ALPS_HDF5_CLOSE_GREEDY
52  check_error(H5Pset_fclose_degree(prop_id, H5F_CLOSE_SEMI));
53  #endif
54  if (write_) {
55  if ((file_id_ = H5Fopen(filename_new_.c_str(), H5F_ACC_RDWR, prop_id)) < 0) {
56  property_type fcrt_id(H5Pcreate(H5P_FILE_CREATE));
57  check_error(H5Pset_link_creation_order(fcrt_id, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)));
58  check_error(H5Pset_attr_creation_order(fcrt_id, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)));
59  check_error(file_id_ = H5Fcreate(filename_new_.c_str(), H5F_ACC_TRUNC, fcrt_id, prop_id));
60  }
61  } else if ((file_id_ = H5Fopen(filename_new_.c_str(), H5F_ACC_RDONLY, prop_id)) < 0)
62  throw archive_not_found("file does not exists or is not a valid hdf5 archive: " + filename_new_ + ALPS_STACKTRACE);
63  else
64  check_error(file_id_);
65  } else {
66  if (replace_) {
67  throw std::logic_error("'Replace' functionality is not yet implemented by hdf5::archive"
69  // @todo:FIXME_DEBOOST:insert proper tempname generation
70  // for (std::size_t i = 0; boost::filesystem::exists(filename_new_=(filename_ + ".tmp." + cast<std::string>(i))); ++i);
71  }
72  if (write_ && replace_ /* && boost::filesystem::exists(filename_)*/) { // @todo:FIXME_DEBOOST:verify exists() necessity
73  throw std::logic_error("'Replace' functionality is not yet implemented by hdf5::archive"
75  // @todo:FIXME_DEBOOST boost::filesystem::copy_file(filename_, filename_new_);
76  }
77  if (!write_) {
78  // pre-check that file is readable. HDF5 would complain anyway,
79  // but the pre-check makes the exception less scary.
80  // It is potentially time-consuming, so do not open archives in a tight loop!
81  if (!std::ifstream(filename_new_.c_str(),std::ios::in).good())
82  throw archive_not_found("file cannot be read or does not exist: " + filename_new_ + ALPS_STACKTRACE);
83  if (check_error(H5Fis_hdf5(filename_new_.c_str())) == 0)
84  throw archive_error("no valid hdf5 file: " + filename_new_ + ALPS_STACKTRACE);
85  }
86  #ifndef ALPS_HDF5_CLOSE_GREEDY
87  property_type ALPS_HDF5_FILE_ACCESS(H5Pcreate(H5P_FILE_ACCESS));
88  check_error(H5Pset_fclose_degree(ALPS_HDF5_FILE_ACCESS, H5F_CLOSE_SEMI));
89  #else
90  #define ALPS_HDF5_FILE_ACCESS H5P_DEFAULT
91  #endif
92  if (write_) {
93  if ((file_id_ = H5Fopen(filename_new_.c_str(), H5F_ACC_RDWR, ALPS_HDF5_FILE_ACCESS)) < 0) {
94  property_type fcrt_id(H5Pcreate(H5P_FILE_CREATE));
95  check_error(H5Pset_link_creation_order(fcrt_id, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)));
96  check_error(H5Pset_attr_creation_order(fcrt_id, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)));
97  check_error(file_id_ = H5Fcreate(filename_new_.c_str(), H5F_ACC_TRUNC, fcrt_id, ALPS_HDF5_FILE_ACCESS));
98  }
99  } else
100  check_error(file_id_ = H5Fopen(filename_new_.c_str(), H5F_ACC_RDONLY, ALPS_HDF5_FILE_ACCESS));
101  #ifdef ALPS_HDF5_CLOSE_GREEDY
102  #undef(ALPS_HDF5_FILE_ACCESS)
103  #endif
104  }
105  }
106 
107  void archivecontext::destruct(bool abort) {
108  try {
109  H5Fflush(file_id_, H5F_SCOPE_GLOBAL);
110  #ifndef ALPS_HDF5_CLOSE_GREEDY
111  if (
112  H5Fget_obj_count(file_id_, H5F_OBJ_DATATYPE) > 0
113  || H5Fget_obj_count(file_id_, H5F_OBJ_ALL) - H5Fget_obj_count(file_id_, H5F_OBJ_FILE) > 0
114  ) {
115  std::cerr << "Not all resources closed in file '" << filename_new_ << "'" << std::endl;
116  std::abort();
117  }
118  #endif
119  if (H5Fclose(file_id_) < 0)
120  std::cerr << "Error in "
121  << __FILE__
122  << " on "
123  << ALPS_STRINGIFY(__LINE__)
124  << " in "
125  << __FUNCTION__ // TODO: check for gcc and use __PRETTY_FUNCTION__
126  << ":"
127  << std::endl
128  << error().invoke(file_id_)
129  << std::endl;
130  if (replace_) {
131  throw std::logic_error("'Replace' functionality is not yet implemented by hdf5::archive"
132  +ALPS_STACKTRACE);
133  //@todo:FIXME_DEBOOST if (boost::filesystem::exists(filename_))
134  //@todo:FIXME_DEBOOST boost::filesystem::remove(filename_);
135  //@todo:FIXME_DEBOOST boost::filesystem::rename(filename_new_, filename_);
136  }
137  } catch (std::exception & ex) {
138  if (abort) {
139  std::cerr << "Error destroying HDF5 context of file '" << filename_new_ << "'\n" << ex.what() << std::endl;
140  std::abort();
141  } else
142  throw ex;
143  }
144  }
145  }
146  }
147 }
static void listen()
Definition: signal.cpp:54
error_type< T >::type error(T const &arg)
Definition: error.hpp:47
#define ALPS_STACKTRACE
Definition: stacktrace.hpp:37
#define ALPS_STRINGIFY(arg)
Definition: stringify.hpp:10