1#include "FileManager.h"
5#include "Handlers/ReadBinaryFileHandle.h"
6#include "Handlers/WriteBinaryFileHandle.h"
7#include "Handlers/AppendFileHandle.h"
8#include "Handlers/AppendBinaryFileHandle.h"
10#include "Exceptions/FileDoesNotExistException.h"
11#include "Exceptions/NotAFileException.h"
13#include "ThreadPool.h"
17static unique_ptr<file_manager::FileManager> instance;
18static mutex instanceMutex;
22 promise<void> requestPromise;
25 requestPromise(move(requestPromise))
45 FileManager::RequestStruct::RequestStruct(FileCallback&& callback, promise<void>&& requestPromise, RequestFileHandleType handleType) :
46 callback(move(callback)),
47 requestPromise(move(requestPromise)),
48 handleType(handleType)
53 bool operator == (
const FileManager::RequestStruct& request, FileManager::RequestType type)
55 return request.callback.index() ==
static_cast<size_t>(type);
58 FileManager::FileNode::FilePathState::FilePathState() :
65 void FileManager::FileNode::addRequest(FileCallback&& callback, std::promise<void>&& requestPromise, RequestFileHandleType handleType)
67 unique_lock<mutex> lock(requestsMutex);
69 requests.emplace(move(callback), move(requestPromise), handleType);
72 void FileManager::FileNode::processQueue(
const filesystem::path& filePath)
74 unique_lock<mutex> lock(requestsMutex);
75 FileManager& manager = FileManager::getInstance();
77 while (requests.size())
79 RequestStruct& request = requests.front();
81 if (request == RequestType::read)
83 if (state.isWriteRequest)
90 function<void(unique_ptr<ReadFileHandle>&&)> readCallback = move(get<function<
void(unique_ptr<ReadFileHandle>&&)>>(request.callback));
92 RequestFileHandleType handleType = request.handleType;
96 manager.threadPool->addTask
98 [
this, &manager, filePath, readCallback = move(readCallback), handler = move(handler), handleType = handleType]()
mutable
100 readCallback(unique_ptr<ReadFileHandle>(
static_cast<ReadFileHandle*
>(manager.createHandle(filePath, handleType))));
102 handler.requestPromise.set_value();
106 else if (request == RequestType::write)
108 if (state.isWriteRequest || state.readRequests)
113 state.isWriteRequest =
true;
115 manager.cache.clear(filePath);
117 function<void(unique_ptr<WriteFileHandle>&&)> writeCallback = move(get<function<
void(unique_ptr<WriteFileHandle>&&)>>(request.callback));
119 RequestFileHandleType handleType = request.handleType;
123 manager.threadPool->addTask
125 [
this, &manager, filePath, writeCallback = move(writeCallback), handler = move(handler), handleType]()
mutable
127 writeCallback(unique_ptr<WriteFileHandle>(
static_cast<WriteFileHandle*
>(manager.createHandle(filePath, handleType))));
129 handler.requestPromise.set_value();
138 void FileManager::NodesContainer::addNode(
const filesystem::path& filePath)
140 unique_lock<mutex> lock(readWriteMutex);
142 if (data.contains(filePath))
147 data[filePath] =
new FileNode();
150 FileManager::FileNode* FileManager::NodesContainer::operator [](
const filesystem::path& filePath)
const
152 unique_lock<mutex> lock(readWriteMutex);
154 return data.at(filePath);
157 void FileManager::threadPoolCallback(promise<void>&& requestPromise)
159 requestPromise.set_value();
162 FileHandle* FileManager::createHandle(
const filesystem::path& filePath, RequestFileHandleType handleType)
166 case file_manager::FileManager::RequestFileHandleType::read:
167 return new ReadFileHandle(filePath);
169 case file_manager::FileManager::RequestFileHandleType::write:
170 return new WriteFileHandle(filePath);
172 case file_manager::FileManager::RequestFileHandleType::readBinary:
173 return new ReadBinaryFileHandle(filePath);
175 case file_manager::FileManager::RequestFileHandleType::writeBinary:
176 return new WriteBinaryFileHandle(filePath);
178 case file_manager::FileManager::RequestFileHandleType::append:
179 return new AppendFileHandle(filePath);
181 case file_manager::FileManager::RequestFileHandleType::appendBinary:
182 return new AppendBinaryFileHandle(filePath);
185 return new FileHandle(filePath, ios_base::in);
188 void FileManager::notify(filesystem::path&& filePath)
190 threadPool->addTask([
this, tem = move(filePath)]()
192 nodes[tem]->processQueue(tem);
196 void FileManager::addRequest(
const filesystem::path& filePath, FileCallback&& callback, promise<void>&& requestPromise, RequestFileHandleType handleType)
198 FileNode* node = nodes[filePath];
200 node->addRequest(move(callback), move(requestPromise), handleType);
202 node->processQueue(filePath);
205 void FileManager::decreaseReadRequests(
const filesystem::path& filePath)
207 nodes[filePath]->state.readRequests--;
210 void FileManager::completeWriteRequest(
const filesystem::path& filePath)
212 nodes[filePath]->state.isWriteRequest =
false;
215 FileManager::FileManager() :
221 FileManager::FileManager(
size_t threadsNumber) :
222 threadPool(new threading::ThreadPool(threadsNumber))
227 FileManager::FileManager(shared_ptr<threading::ThreadPool> threadPool) :
228 threadPool(threadPool)
233 future<void> FileManager::addReadRequest(
const filesystem::path& filePath,
const function<
void(unique_ptr<ReadFileHandle>&&)>& callback, RequestFileHandleType handleType,
bool isWait)
235 this->addFile(filePath);
237 promise<void> requestPromise;
238 future<void> isReady = requestPromise.get_future();
240 this->addRequest(filePath, callback, move(requestPromise), handleType);
250 future<void> FileManager::addWriteRequest(
const filesystem::path& filePath,
const function<
void(unique_ptr<WriteFileHandle>&&)>& callback, RequestFileHandleType handleType,
bool isWait)
252 this->addFile(filePath,
false);
254 promise<void> requestPromise;
255 future<void> isReady = requestPromise.get_future();
257 this->addRequest(filePath, callback, move(requestPromise), handleType);
271 constexpr size_t defaultThreadsNumber = 2;
272 unique_lock<mutex> lock(instanceMutex);
274 instance = unique_ptr<FileManager>(
new FileManager(defaultThreadsNumber));
284 unique_lock<mutex> lock(instanceMutex);
286 instance = unique_ptr<FileManager>(
new FileManager(threadsNumber));
289 if (instance->threadPool->getThreadsCount() != threadsNumber)
291 instance->threadPool = make_shared<threading::ThreadPool>(threadsNumber);
297 FileManager& FileManager::getInstance(shared_ptr<threading::ThreadPool> threadPool)
301 unique_lock<mutex> lock(instanceMutex);
303 instance = unique_ptr<FileManager>(
new FileManager(threadPool));
306 if (instance->threadPool != threadPool)
308 instance->threadPool = threadPool;
314 string FileManager::getVersion()
316 string version =
"1.6.0";
321 void FileManager::addFile(
const filesystem::path& filePath,
bool isFileAlreadyExist)
323 if (isFileAlreadyExist)
325 if (!filesystem::exists(filePath))
327 for (
const auto& it : filesystem::directory_iterator(filePath.parent_path()))
335 if (!filesystem::is_regular_file(filePath))
341 nodes.addNode(filePath);
344 future<void> FileManager::readFile(
const filesystem::path& filePath,
const function<
void(unique_ptr<ReadFileHandle>&&)>& callback,
bool isWait)
346 return this->addReadRequest(filePath, callback, RequestFileHandleType::read, isWait);
349 future<void> FileManager::readBinaryFile(
const filesystem::path& filePath,
const function<
void(unique_ptr<ReadFileHandle>&&)>& callback,
bool isWait)
351 return this->addReadRequest(filePath, callback, RequestFileHandleType::readBinary, isWait);
354 future<void> FileManager::writeFile(
const filesystem::path& filePath,
const function<
void(unique_ptr<WriteFileHandle>&&)>& callback,
bool isWait)
356 return this->addWriteRequest(filePath, callback, RequestFileHandleType::write, isWait);
359 future<void> FileManager::appendFile(
const filesystem::path& filePath,
const function<
void(unique_ptr<WriteFileHandle>&&)>& callback,
bool isWait)
361 return this->addWriteRequest(filePath, callback, RequestFileHandleType::append, isWait);
364 future<void> FileManager::writeBinaryFile(
const filesystem::path& filePath,
const function<
void(unique_ptr<WriteFileHandle>&&)>& callback,
bool isWait)
366 return this->addWriteRequest(filePath, callback, RequestFileHandleType::writeBinary, isWait);
369 future<void> FileManager::appendBinaryFile(
const filesystem::path& filePath,
const function<
void(unique_ptr<WriteFileHandle>&&)>& callback,
bool isWait)
371 return this->addWriteRequest(filePath, callback, RequestFileHandleType::appendBinary, isWait);
379 const Cache& FileManager::getCache()
const
Provides files accessing from multiple threads. Singleton.
Thrown if file does not exist.
Thrown if path represents not a regular file.