Alexandria  2.27.0
SDC-CH common library for the Euclid project
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FileHandler.icpp
Go to the documentation of this file.
1 
19 #ifndef FILEHANDLER_IMPL
20 #error "This file should not be included directly! Use FileHandler.h instead"
21 #else
22 
23 namespace Euclid {
24 namespace FilePool {
25 
26 template <typename TFD>
28  auto manager = m_file_manager.lock();
29  assert(manager);
30 
31  UniqueLock unique_lock(m_file_mutex, boost::defer_lock);
32  if (try_lock && !unique_lock.try_lock()) {
33  return nullptr;
34  } else {
35  unique_lock.lock();
36  }
37 
39  {
40  std::unique_lock<std::mutex> this_lock(m_handler_mutex);
41 
42  // If we have changed mode, we need to close all existing fd
43  if (m_is_readonly) {
44  for (auto& fd : m_available_fd) {
45  fd.second->close();
46  }
47  m_available_fd.clear();
48  m_is_readonly = false;
49  }
50 
51  assert(m_available_fd.size() <= 1);
52 
53  // If there is one, but of a different type, close it
54  if (!m_available_fd.empty()) {
55  auto typed_ptr = dynamic_cast<TypedFdWrapper<TFD>*>(m_available_fd.begin()->second.get());
56  if (!typed_ptr) {
57  m_available_fd.clear();
58  }
59  }
60 
61  // Open one file if we need
62  if (m_available_fd.empty()) {
63  this_lock.unlock();
64  auto fd = manager->open<TFD>(m_path, true, [this](FileManager::FileId id) { return this->close(id); });
65  this_lock.lock();
66  m_available_fd[fd.first].reset(new TypedFdWrapper<TFD>(fd.first, std::move(fd.second), manager.get()));
67  }
68 
69  assert(m_available_fd.size() == 1);
70 
71  // Build and return accessor
72  fd_ptr = std::move(m_available_fd.begin()->second);
73  m_available_fd.clear();
74  }
75 
76  auto typed_ptr = dynamic_cast<TypedFdWrapper<TFD>*>(fd_ptr.get());
77  if (typed_ptr == nullptr) {
78  throw std::logic_error("Failed to cast type-erased file descriptor wrapper");
79  }
80  auto fd = std::move(typed_ptr->m_fd);
81  auto id = typed_ptr->m_id;
82 
83  auto return_callback = [this, id, manager](TFD&& returned_fd) {
84  std::lock_guard<std::mutex> lambda_this_lock(m_handler_mutex);
85  m_available_fd[id] =
86  std::unique_ptr<TypedFdWrapper<TFD>>(new TypedFdWrapper<TFD>(id, std::move(returned_fd), manager.get()));
87  };
88 
89  manager->notifyUsed(id);
91  new FileWriteAccessor<TFD>(std::move(fd), return_callback, std::move(unique_lock)));
92 }
93 
94 template <typename TFD>
96  auto manager = m_file_manager.lock();
97  assert(manager);
98 
99  SharedLock shared_lock(m_file_mutex, boost::defer_lock);
100  if (try_lock && !shared_lock.try_lock()) {
101  return nullptr;
102  } else {
103  shared_lock.lock();
104  }
105 
106  std::unique_ptr<FdWrapper> fd_ptr = nullptr;
107  {
108  std::unique_lock<std::mutex> this_lock(m_handler_mutex);
109 
110  // If we have changed mode, we need to close all existing fd
111  if (!m_is_readonly) {
112  for (auto& fd : m_available_fd) {
113  fd.second->close();
114  }
115  m_available_fd.clear();
116  m_is_readonly = true;
117  }
118 
119  // Find the first with a matching type
120  auto avail_i = m_available_fd.begin();
121  TypedFdWrapper<TFD>* typed_ptr = nullptr;
122  while (typed_ptr == nullptr && avail_i != m_available_fd.end()) {
123  if ((typed_ptr = dynamic_cast<TypedFdWrapper<TFD>*>(avail_i->second.get())) == nullptr)
124  ++avail_i;
125  }
126 
127  // Open one file if we need
128  if (!typed_ptr) {
129  this_lock.unlock();
130  auto fd = manager->open<TFD>(m_path, false, [this](FileManager::FileId id) { return this->close(id); });
131  typed_ptr = new TypedFdWrapper<TFD>(fd.first, std::move(fd.second), manager.get());
132  this_lock.lock();
133  avail_i = m_available_fd.emplace(fd.first, std::unique_ptr<TypedFdWrapper<TFD>>(typed_ptr)).first;
134  }
135 
136  assert(typed_ptr && avail_i != m_available_fd.end());
137 
138  fd_ptr = std::move(avail_i->second);
139  m_available_fd.erase(avail_i);
140  }
141 
142  // Build and return accessor
143  TypedFdWrapper<TFD>* typed_ptr = dynamic_cast<TypedFdWrapper<TFD>*>(fd_ptr.get());
144  if (typed_ptr == nullptr) {
145  throw std::logic_error("Failed to cast type-erased file descriptor wrapper");
146  }
147  auto fd = std::move(typed_ptr->m_fd);
148  auto id = typed_ptr->m_id;
149 
150  auto return_callback = [this, id, manager](TFD&& returned_fd) {
151  std::lock_guard<std::mutex> lambda_this_lock(m_handler_mutex);
152  m_available_fd[id] =
153  std::unique_ptr<TypedFdWrapper<TFD>>(new TypedFdWrapper<TFD>(id, std::move(returned_fd), manager.get()));
154  };
155 
156  manager->notifyUsed(id);
158  new FileReadAccessor<TFD>(std::move(fd), return_callback, std::move(shared_lock)));
159 }
160 
161 template <typename TFD>
163  bool write_bool = mode & kWrite;
164  bool try_bool = mode & kTry;
165 
166  if (write_bool) {
167  return getWriteAccessor<TFD>(try_bool);
168  }
169  return getReadAccessor<TFD>(try_bool);
170 }
171 
172 } // namespace FilePool
173 } // namespace Euclid
174 
175 #endif
std::unique_ptr< FileAccessor< TFD > > getWriteAccessor(bool try_lock)
std::unique_ptr< FileAccessor< TFD > > getReadAccessor(bool try_lock)
intptr_t FileId
Opaque FileId, its concrete type should only be assumed to be copyable and hashable.
Definition: FileManager.h:65
std::unique_ptr< FileAccessor< TFD > > getAccessor(Mode mode=kRead)
T move(T...args)
STL class.
STL class.