2 * Copyright (C) 2012-2021 Euclid Science Ground Segment
4 * This library is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 3.0 of the License, or (at your option)
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifndef FILEHANDLER_IMPL
20 #error "This file should not be included directly! Use FileHandler.h instead"
26 template <typename TFD>
27 auto FileHandler::getWriteAccessor(bool try_lock) -> std::unique_ptr<FileAccessor<TFD>> {
28 auto manager = m_file_manager.lock();
31 UniqueLock unique_lock(m_file_mutex, boost::defer_lock);
32 if (try_lock && !unique_lock.try_lock()) {
38 std::lock_guard<std::mutex> this_lock(m_handler_mutex);
40 // If we have changed mode, we need to close all existing fd
42 for (auto& fd : m_available_fd) {
45 m_available_fd.clear();
46 m_is_readonly = false;
49 assert(m_available_fd.size() <= 1);
51 // If there is one, but of a different type, close it
52 if (!m_available_fd.empty()) {
53 auto typed_ptr = dynamic_cast<TypedFdWrapper<TFD>*>(m_available_fd.begin()->second.get());
55 m_available_fd.clear();
59 // Open one file if we need
60 if (m_available_fd.empty()) {
61 auto fd = manager->open<TFD>(m_path, true, [this](FileManager::FileId id) { return this->close(id); });
62 m_available_fd[fd.first] =
63 std::unique_ptr<TypedFdWrapper<TFD>>(new TypedFdWrapper<TFD>(fd.first, std::move(fd.second), manager.get()));
66 assert(m_available_fd.size() == 1);
68 // Build and return accessor
69 auto typed_ptr = dynamic_cast<TypedFdWrapper<TFD>*>(m_available_fd.begin()->second.get());
70 auto fd = std::move(typed_ptr->m_fd);
71 auto id = typed_ptr->m_id;
72 m_available_fd.clear();
74 auto return_callback = [this, id, manager](TFD&& returned_fd) {
75 std::lock_guard<std::mutex> lambda_this_lock(m_handler_mutex);
76 m_available_fd[id] = std::unique_ptr<TypedFdWrapper<TFD>>(new TypedFdWrapper<TFD>(id, std::move(returned_fd), manager.get()));
79 manager->notifyUsed(id);
80 return std::unique_ptr<FileWriteAccessor<TFD>>(
81 new FileWriteAccessor<TFD>(std::move(fd), return_callback, std::move(unique_lock)));
84 template <typename TFD>
85 auto FileHandler::getReadAccessor(bool try_lock) -> std::unique_ptr<FileAccessor<TFD>> {
86 auto manager = m_file_manager.lock();
89 SharedLock shared_lock(m_file_mutex, boost::defer_lock);
90 if (try_lock && !shared_lock.try_lock()) {
96 std::lock_guard<std::mutex> this_lock(m_handler_mutex);
98 // If we have changed mode, we need to close all existing fd
100 for (auto& fd : m_available_fd) {
103 m_available_fd.clear();
104 m_is_readonly = true;
107 // Find the first with a matching type
108 TypedFdWrapper<TFD>* typed_ptr = nullptr;
109 auto avail_i = m_available_fd.begin();
110 while (typed_ptr == nullptr && avail_i != m_available_fd.end()) {
111 if ((typed_ptr = dynamic_cast<TypedFdWrapper<TFD>*>(avail_i->second.get())) == nullptr)
115 // Open one file if we need
117 auto fd = manager->open<TFD>(m_path, false, [this](FileManager::FileId id) { return this->close(id); });
118 typed_ptr = new TypedFdWrapper<TFD>(fd.first, std::move(fd.second), manager.get());
119 avail_i = m_available_fd.emplace(fd.first, std::unique_ptr<TypedFdWrapper<TFD>>(typed_ptr)).first;
122 assert(typed_ptr && avail_i != m_available_fd.end());
124 // Build and return accessor
125 auto fd = std::move(typed_ptr->m_fd);
126 auto id = typed_ptr->m_id;
127 m_available_fd.erase(avail_i);
129 auto return_callback = [this, id, manager](TFD&& returned_fd) {
130 std::lock_guard<std::mutex> lambda_this_lock(m_handler_mutex);
131 m_available_fd[id] = std::unique_ptr<TypedFdWrapper<TFD>>(new TypedFdWrapper<TFD>(id, std::move(returned_fd), manager.get()));
134 manager->notifyUsed(id);
135 return std::unique_ptr<FileReadAccessor<TFD>>(new FileReadAccessor<TFD>(std::move(fd), return_callback, std::move(shared_lock)));
138 template <typename TFD>
139 auto FileHandler::getAccessor(Mode mode) -> std::unique_ptr<FileAccessor<TFD>> {
140 bool write_bool = mode & kWrite;
141 bool try_bool = mode & kTry;
144 return getWriteAccessor<TFD>(try_bool);
146 return getReadAccessor<TFD>(try_bool);
149 } // namespace FilePool
150 } // namespace Euclid