libSplash
HandleMgr.cpp
1 
25 #include <limits>
26 #include <iostream>
27 #include <hdf5.h>
28 
29 #include "splash/core/HandleMgr.hpp"
30 #include "splash/core/logging.hpp"
31 #include "splash/core/DCHelper.hpp"
32 
33 namespace splash
34 {
35 
36  HandleMgr::HandleMgr(uint32_t maxHandles, FileNameScheme fileNameScheme) :
37  maxHandles(maxHandles),
38  mpiSize(1, 1, 1),
39  fileNameScheme(fileNameScheme),
40  fileFlags(0),
41  fileCreateCallback(NULL),
42  fileCreateUserData(NULL),
43  fileOpenCallback(NULL),
44  fileOpenUserData(NULL),
45  fileCloseCallback(NULL),
46  fileCloseUserData(NULL)
47  {
48  if (maxHandles == 0)
49  this->maxHandles = std::numeric_limits<uint32_t>::max() - 1;
50 
51  leastAccIndex.ctr = 0;
52  leastAccIndex.index = 0;
53  }
54 
55  HandleMgr::~HandleMgr()
56  {
57  }
58 
59  std::string HandleMgr::getExceptionString(std::string func,
60  std::string msg, const char *info)
61  {
62  std::stringstream full_msg;
63  full_msg << "Exception for HandleMgr::" << func <<
64  ": " << msg;
65 
66  if (info != NULL)
67  full_msg << " (" << info << ")";
68 
69  return full_msg.str();
70  }
71 
72  void HandleMgr::setFileNameScheme(FileNameScheme fileNameScheme) throw (DCException)
73  {
74  if (this->fileNameScheme == fileNameScheme)
75  return;
76  if (!filename.empty())
77  throw DCException(getExceptionString("setFileNameScheme",
78  "Tried to change scheme while file(s) were still open", ""));
79  this->fileNameScheme = fileNameScheme;
80  }
81 
82  void HandleMgr::open(Dimensions mpiSize, const std::string baseFilename,
83  hid_t fileAccProperties, unsigned flags)
84  throw (DCException)
85  {
86  this->mpiSize.set(mpiSize);
87  this->filename = baseFilename;
88  this->fileAccProperties = fileAccProperties;
89  this->fileFlags = flags;
90  // Validation: For parallel files we normally append MPI rank or iteration number.
91  // This is disabled by using FNS_FULLNAME
92  // or when the filename already contains an h5-extension.
93  if (fileNameScheme != FNS_FULLNAME && baseFilename.find(".h5") == baseFilename.length() - 3)
94  {
95  if (mpiSize.getScalarSize() > 1)
96  {
97  throw DCException(getExceptionString("open",
98  "Passed full filename for parallel file operations",
99  baseFilename.c_str()));
100  } else
101  {
102  log_msg(1, "\n"
103  "\tWarning: Passed full filename for parallel file operations: %s\n"
104  "It is recommended to pass only the base name (no extension)"
105  "and let the implementation choose a filename.\n", filename.c_str());
106  }
107  }
108  }
109 
110  void HandleMgr::open(const std::string fullFilename,
111  hid_t fileAccProperties, unsigned flags)
112  throw (DCException)
113  {
114  setFileNameScheme(FNS_FULLNAME);
115  this->mpiSize.set(1, 1, 1);
116  this->filename = fullFilename;
117  this->fileAccProperties = fileAccProperties;
118  this->fileFlags = flags;
119  }
120 
121  uint32_t HandleMgr::indexFromPos(Dimensions& mpiPos)
122  {
123  return mpiPos[0] + mpiPos[1] * mpiSize[0] +
124  mpiPos[2] * mpiSize[0] * mpiSize[1];
125  }
126 
127  Dimensions HandleMgr::posFromIndex(uint32_t index)
128  {
129  Dimensions pos(0, 0, 0);
130 
131  if (index > 0)
132  {
133  if (fileNameScheme == FNS_MPI)
134  pos.set(
135  index % mpiSize[0],
136  (index / mpiSize[0]) % mpiSize[1],
137  index / (mpiSize[1] * mpiSize[0]));
138  else
139  pos.set(index, 0, 0);
140  }
141 
142  return pos;
143  }
144 
145  H5Handle HandleMgr::get(uint32_t index)
146  throw (DCException)
147  {
148  return get(posFromIndex(index));
149  }
150 
151  H5Handle HandleMgr::get(Dimensions mpiPos)
152  throw (DCException)
153  {
154  uint32_t index = 0;
155  if (fileNameScheme != FNS_FULLNAME)
156  index = indexFromPos(mpiPos);
157 
158  HandleMap::iterator iter = handles.find(index);
159  if (iter == handles.end())
160  {
161  if (handles.size() + 1 > maxHandles)
162  {
163  HandleMap::iterator rmHandle = handles.find(leastAccIndex.index);
164  if (fileCloseCallback)
165  {
166  fileCloseCallback(rmHandle->second.handle,
167  leastAccIndex.index, fileCloseUserData);
168  }
169 
170  if (H5Fclose(rmHandle->second.handle) < 0)
171  {
172  throw DCException(getExceptionString("get", "Failed to close file handle",
173  mpiPos.toString().c_str()));
174  }
175 
176  handles.erase(rmHandle);
177  leastAccIndex.ctr = 0;
178  }
179 
180  // Append prefix and extension if we don't have a full filename (extension)
181  std::string fullFilename;
182  if (fileNameScheme != FNS_FULLNAME && filename.find(".h5") != filename.length() - 3)
183  {
184  std::stringstream filenameStream;
185  filenameStream << filename;
186  if (fileNameScheme == FNS_MPI)
187  {
188  filenameStream << "_" << mpiPos[0] << "_" << mpiPos[1] <<
189  "_" << mpiPos[2] << ".h5";
190  } else if(fileNameScheme == FNS_ITERATIONS)
191  filenameStream << "_" << mpiPos[0] << ".h5";
192  fullFilename = filenameStream.str();
193  }else
194  fullFilename = filename;
195 
196  H5Handle newHandle = 0;
197 
198  // serve requests to create files once as create and as read/write afterwards
199  if ((fileFlags & H5F_ACC_TRUNC) && (createdFiles.find(index) == createdFiles.end()))
200  {
201  DCHelper::testFilename(fullFilename);
202 
203  newHandle = H5Fcreate(fullFilename.c_str(), fileFlags,
204  H5P_FILE_CREATE_DEFAULT, fileAccProperties);
205  if (newHandle < 0)
206  throw DCException(getExceptionString("get", "Failed to create file",
207  fullFilename.c_str()));
208 
209  createdFiles.insert(index);
210 
211  if (fileCreateCallback)
212  fileCreateCallback(newHandle, index, fileCreateUserData);
213  } else
214  {
215  // file open or already created
216  unsigned tmp_flags = fileFlags;
217  if (fileFlags & H5F_ACC_TRUNC)
218  tmp_flags = H5F_ACC_RDWR;
219 
220  newHandle = H5Fopen(fullFilename.c_str(), tmp_flags, fileAccProperties);
221  if (newHandle < 0)
222  throw DCException(getExceptionString("get", "Failed to open file",
223  fullFilename.c_str()));
224 
225  if (fileOpenCallback)
226  fileOpenCallback(newHandle, index, fileOpenUserData);
227  }
228 
229 
230  handles[index].handle = newHandle;
231  handles[index].ctr = 1;
232 
233  if ((leastAccIndex.ctr == 0) || (1 < leastAccIndex.ctr))
234  {
235  leastAccIndex.ctr = 1;
236  leastAccIndex.index = index;
237  }
238 
239  return newHandle;
240  } else
241  {
242  iter->second.ctr++;
243  if (leastAccIndex.index == index)
244  leastAccIndex.ctr++;
245 
246  return iter->second.handle;
247  }
248  }
249 
250  void HandleMgr::close()
251  {
252  // clean internal state
253  createdFiles.clear();
254  filename = "";
255  fileAccProperties = 0;
256  fileFlags = 0;
257  leastAccIndex.ctr = 0;
258  leastAccIndex.index = 0;
259  mpiSize.set(1, 1, 1);
260 
261  // close all remaining handles
262  HandleMap::const_iterator iter = handles.begin();
263  for (; iter != handles.end(); ++iter)
264  {
265  if (fileCloseCallback)
266  fileCloseCallback(iter->second.handle, iter->first, fileCloseUserData);
267 
268  if (H5Fclose(iter->second.handle) < 0)
269  {
270  throw DCException(getExceptionString("close", "Failed to close file handle",
271  posFromIndex(iter->first).toString().c_str()));
272  }
273  }
274 
275  handles.clear();
276  }
277 
278  void HandleMgr::registerFileCreate(FileCreateCallback callback, void *userData)
279  {
280  fileCreateCallback = callback;
281  fileCreateUserData = userData;
282  }
283 
284  void HandleMgr::registerFileOpen(FileOpenCallback callback, void *userData)
285  {
286  fileOpenCallback = callback;
287  fileOpenUserData = userData;
288  }
289 
290  void HandleMgr::registerFileClose(FileCloseCallback callback, void *userData)
291  {
292  fileCloseCallback = callback;
293  fileCloseUserData = userData;
294  }
295 
296 }
EXTERN void log_msg(int level, const char *fmt,...)
Definition: logging.cpp:56