FileManager v1.7.0
Manage access to files with async model
Loading...
Searching...
No Matches
FileManager.cpp
1#include "FileManager.h"
2
3#include <iostream>
4
5#include "Handlers/ReadBinaryFileHandle.h"
6#include "Handlers/WriteBinaryFileHandle.h"
7#include "Handlers/AppendFileHandle.h"
8#include "Handlers/AppendBinaryFileHandle.h"
9
10#include "Exceptions/FileDoesNotExistException.h"
11#include "Exceptions/NotAFileException.h"
12
13#include "ThreadPool.h"
14
15using namespace std;
16
17static unique_ptr<file_manager::FileManager> instance;
18static mutex instanceMutex;
19
21{
22 promise<void> requestPromise;
23
24 RequestPromiseHandler(promise<void>&& requestPromise) :
25 requestPromise(move(requestPromise))
26 {
27
28 }
29
31 {
32 (*this) = other;
33 }
34
35 RequestPromiseHandler& operator = (const RequestPromiseHandler& other)
36 {
37 requestPromise = move(const_cast<RequestPromiseHandler&>(other).requestPromise);
38
39 return *this;
40 }
41};
42
43namespace file_manager
44{
45 FileManager::RequestStruct::RequestStruct(FileCallback&& callback, promise<void>&& requestPromise, RequestFileHandleType handleType) :
46 callback(move(callback)),
47 requestPromise(move(requestPromise)),
48 handleType(handleType)
49 {
50
51 }
52
53 bool operator == (const FileManager::RequestStruct& request, FileManager::RequestType type)
54 {
55 return request.callback.index() == static_cast<size_t>(type);
56 }
57
58 FileManager::FileNode::FilePathState::FilePathState() :
59 readRequests(0),
60 isWriteRequest(false)
61 {
62
63 }
64
65 void FileManager::FileNode::addRequest(FileCallback&& callback, std::promise<void>&& requestPromise, RequestFileHandleType handleType)
66 {
67 unique_lock<mutex> lock(requestsMutex);
68
69 requests.emplace(move(callback), move(requestPromise), handleType);
70 }
71
72 void FileManager::FileNode::processQueue(const filesystem::path& filePath)
73 {
74 unique_lock<mutex> lock(requestsMutex);
75 FileManager& manager = FileManager::getInstance();
76
77 while (requests.size())
78 {
79 RequestStruct& request = requests.front();
80
81 if (request == RequestType::read)
82 {
83 if (state.isWriteRequest)
84 {
85 return;
86 }
87
88 state.readRequests++;
89
90 function<void(unique_ptr<ReadFileHandle>&&)> readCallback = move(get<function<void(unique_ptr<ReadFileHandle>&&)>>(request.callback));
91 RequestPromiseHandler handler(move(request.requestPromise));
92 RequestFileHandleType handleType = request.handleType;
93
94 requests.pop();
95
96 manager.threadPool->addTask
97 (
98 [this, &manager, filePath, readCallback = move(readCallback), handler = move(handler), handleType = handleType]() mutable
99 {
100 readCallback(unique_ptr<ReadFileHandle>(static_cast<ReadFileHandle*>(manager.createHandle(filePath, handleType))));
101
102 handler.requestPromise.set_value();
103 }
104 );
105 }
106 else if (request == RequestType::write)
107 {
108 if (state.isWriteRequest || state.readRequests)
109 {
110 return;
111 }
112
113 state.isWriteRequest = true;
114
115 manager.cache.clear(filePath);
116
117 function<void(unique_ptr<WriteFileHandle>&&)> writeCallback = move(get<function<void(unique_ptr<WriteFileHandle>&&)>>(request.callback));
118 RequestPromiseHandler handler(move(request.requestPromise));
119 RequestFileHandleType handleType = request.handleType;
120
121 requests.pop();
122
123 manager.threadPool->addTask
124 (
125 [this, &manager, filePath, writeCallback = move(writeCallback), handler = move(handler), handleType]() mutable
126 {
127 writeCallback(unique_ptr<WriteFileHandle>(static_cast<WriteFileHandle*>(manager.createHandle(filePath, handleType))));
128
129 handler.requestPromise.set_value();
130 }
131 );
132
133 return;
134 }
135 }
136 }
137
138 void FileManager::NodesContainer::addNode(const filesystem::path& filePath)
139 {
140 unique_lock<mutex> lock(readWriteMutex);
141
142 if (data.contains(filePath))
143 {
144 return;
145 }
146
147 data[filePath] = new FileNode();
148 }
149
150 FileManager::FileNode* FileManager::NodesContainer::operator [](const filesystem::path& filePath) const
151 {
152 unique_lock<mutex> lock(readWriteMutex);
153
154 return data.at(filePath);
155 }
156
157 void FileManager::threadPoolCallback(promise<void>&& requestPromise)
158 {
159 requestPromise.set_value();
160 }
161
162 FileHandle* FileManager::createHandle(const filesystem::path& filePath, RequestFileHandleType handleType)
163 {
164 switch (handleType)
165 {
166 case file_manager::FileManager::RequestFileHandleType::read:
167 return new ReadFileHandle(filePath);
168
169 case file_manager::FileManager::RequestFileHandleType::write:
170 return new WriteFileHandle(filePath);
171
172 case file_manager::FileManager::RequestFileHandleType::readBinary:
173 return new ReadBinaryFileHandle(filePath);
174
175 case file_manager::FileManager::RequestFileHandleType::writeBinary:
176 return new WriteBinaryFileHandle(filePath);
177
178 case file_manager::FileManager::RequestFileHandleType::append:
179 return new AppendFileHandle(filePath);
180
181 case file_manager::FileManager::RequestFileHandleType::appendBinary:
182 return new AppendBinaryFileHandle(filePath);
183 }
184
185 return new FileHandle(filePath, ios_base::in);
186 }
187
188 void FileManager::notify(filesystem::path&& filePath)
189 {
190 threadPool->addTask([this, tem = move(filePath)]()
191 {
192 nodes[tem]->processQueue(tem);
193 });
194 }
195
196 void FileManager::addRequest(const filesystem::path& filePath, FileCallback&& callback, promise<void>&& requestPromise, RequestFileHandleType handleType)
197 {
198 FileNode* node = nodes[filePath];
199
200 node->addRequest(move(callback), move(requestPromise), handleType);
201
202 node->processQueue(filePath);
203 }
204
205 void FileManager::decreaseReadRequests(const filesystem::path& filePath)
206 {
207 nodes[filePath]->state.readRequests--;
208 }
209
210 void FileManager::completeWriteRequest(const filesystem::path& filePath)
211 {
212 nodes[filePath]->state.isWriteRequest = false;
213 }
214
215 FileManager::FileManager() :
216 threadPool(nullptr)
217 {
218
219 }
220
221 FileManager::FileManager(size_t threadsNumber) :
222 threadPool(new threading::ThreadPool(threadsNumber))
223 {
224
225 }
226
227 FileManager::FileManager(shared_ptr<threading::ThreadPool> threadPool) :
228 threadPool(threadPool)
229 {
230
231 }
232
233 future<void> FileManager::addReadRequest(const filesystem::path& filePath, const function<void(unique_ptr<ReadFileHandle>&&)>& callback, RequestFileHandleType handleType, bool isWait)
234 {
235 this->addFile(filePath);
236
237 promise<void> requestPromise;
238 future<void> isReady = requestPromise.get_future();
239
240 this->addRequest(filePath, callback, move(requestPromise), handleType);
241
242 if (isWait)
243 {
244 isReady.wait();
245 }
246
247 return isReady;
248 }
249
250 future<void> FileManager::addWriteRequest(const filesystem::path& filePath, const function<void(unique_ptr<WriteFileHandle>&&)>& callback, RequestFileHandleType handleType, bool isWait)
251 {
252 this->addFile(filePath, false);
253
254 promise<void> requestPromise;
255 future<void> isReady = requestPromise.get_future();
256
257 this->addRequest(filePath, callback, move(requestPromise), handleType);
258
259 if (isWait)
260 {
261 isReady.wait();
262 }
263
264 return isReady;
265 }
266
267 FileManager& FileManager::getInstance()
268 {
269 if (!instance)
270 {
271 constexpr size_t defaultThreadsNumber = 2;
272 unique_lock<mutex> lock(instanceMutex);
273
274 instance = unique_ptr<FileManager>(new FileManager(defaultThreadsNumber));
275 }
276
277 return *instance;
278 }
279
280 FileManager& FileManager::getInstance(size_t threadsNumber)
281 {
282 if (!instance)
283 {
284 unique_lock<mutex> lock(instanceMutex);
285
286 instance = unique_ptr<FileManager>(new FileManager(threadsNumber));
287 }
288
289 if (instance->threadPool->getThreadsCount() != threadsNumber)
290 {
291 instance->threadPool = make_shared<threading::ThreadPool>(threadsNumber);
292 }
293
294 return *instance;
295 }
296
297 FileManager& FileManager::getInstance(shared_ptr<threading::ThreadPool> threadPool)
298 {
299 if (!instance)
300 {
301 unique_lock<mutex> lock(instanceMutex);
302
303 instance = unique_ptr<FileManager>(new FileManager(threadPool));
304 }
305
306 if (instance->threadPool != threadPool)
307 {
308 instance->threadPool = threadPool;
309 }
310
311 return *instance;
312 }
313
314 string FileManager::getVersion()
315 {
316 string version = "1.6.0";
317
318 return version;
319 }
320
321 void FileManager::addFile(const filesystem::path& filePath, bool isFileAlreadyExist)
322 {
323 if (isFileAlreadyExist)
324 {
325 if (!filesystem::exists(filePath))
326 {
327 for (const auto& it : filesystem::directory_iterator(filePath.parent_path()))
328 {
329 cout << it << endl;
330 }
331
333 }
334
335 if (!filesystem::is_regular_file(filePath))
336 {
337 throw exceptions::NotAFileException(filePath);
338 }
339 }
340
341 nodes.addNode(filePath);
342 }
343
344 future<void> FileManager::readFile(const filesystem::path& filePath, const function<void(unique_ptr<ReadFileHandle>&&)>& callback, bool isWait)
345 {
346 return this->addReadRequest(filePath, callback, RequestFileHandleType::read, isWait);
347 }
348
349 future<void> FileManager::readBinaryFile(const filesystem::path& filePath, const function<void(unique_ptr<ReadFileHandle>&&)>& callback, bool isWait)
350 {
351 return this->addReadRequest(filePath, callback, RequestFileHandleType::readBinary, isWait);
352 }
353
354 future<void> FileManager::writeFile(const filesystem::path& filePath, const function<void(unique_ptr<WriteFileHandle>&&)>& callback, bool isWait)
355 {
356 return this->addWriteRequest(filePath, callback, RequestFileHandleType::write, isWait);
357 }
358
359 future<void> FileManager::appendFile(const filesystem::path& filePath, const function<void(unique_ptr<WriteFileHandle>&&)>& callback, bool isWait)
360 {
361 return this->addWriteRequest(filePath, callback, RequestFileHandleType::append, isWait);
362 }
363
364 future<void> FileManager::writeBinaryFile(const filesystem::path& filePath, const function<void(unique_ptr<WriteFileHandle>&&)>& callback, bool isWait)
365 {
366 return this->addWriteRequest(filePath, callback, RequestFileHandleType::writeBinary, isWait);
367 }
368
369 future<void> FileManager::appendBinaryFile(const filesystem::path& filePath, const function<void(unique_ptr<WriteFileHandle>&&)>& callback, bool isWait)
370 {
371 return this->addWriteRequest(filePath, callback, RequestFileHandleType::appendBinary, isWait);
372 }
373
374 Cache& FileManager::getCache()
375 {
376 return cache;
377 }
378
379 const Cache& FileManager::getCache() const
380 {
381 return cache;
382 }
383}
Files cache.
Definition Cache.h:19
Provides files accessing from multiple threads. Singleton.
Definition FileManager.h:25
Thrown if path represents not a regular file.