diff --git a/source/Base/CMakeLists.txt b/source/Base/CMakeLists.txt index 9a38c1374..215720ba0 100644 --- a/source/Base/CMakeLists.txt +++ b/source/Base/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(Base Singleton.h StringHelper.cpp StringHelper.h + UnlockGuard.h Vector2D.cpp Vector2D.h VersionChecker.cpp diff --git a/source/Base/UnlockGuard.h b/source/Base/UnlockGuard.h new file mode 100644 index 000000000..df9603a30 --- /dev/null +++ b/source/Base/UnlockGuard.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +class UnlockGuard +{ +public: + UnlockGuard(std::unique_lock& lock) + : _lock(lock) + { + _lock.unlock(); + } + ~UnlockGuard() { _lock.lock(); } + +private: + std::unique_lock& _lock; +}; diff --git a/source/PersisterImpl/CMakeLists.txt b/source/PersisterImpl/CMakeLists.txt index 4edf8a2e4..0e025e3b6 100644 --- a/source/PersisterImpl/CMakeLists.txt +++ b/source/PersisterImpl/CMakeLists.txt @@ -6,7 +6,6 @@ add_library(PersisterImpl PersisterRequest.h PersisterRequestError.cpp PersisterRequestError.h - PersisterRequestResult.h PersisterWorker.cpp PersisterWorker.h) diff --git a/source/PersisterImpl/PersisterFacadeImpl.cpp b/source/PersisterImpl/PersisterFacadeImpl.cpp index eba39cd87..d0e1496e8 100644 --- a/source/PersisterImpl/PersisterFacadeImpl.cpp +++ b/source/PersisterImpl/PersisterFacadeImpl.cpp @@ -1,9 +1,8 @@ #include "PersisterFacadeImpl.h" -#include "PersisterInterface/DeserializedSimulation.h" #include "EngineInterface/SimulationFacade.h" - -#include "PersisterRequestResult.h" +#include "PersisterInterface/DeserializedSimulation.h" +#include "PersisterInterface/PersisterRequestResult.h" _PersisterFacadeImpl::~_PersisterFacadeImpl() { @@ -46,6 +45,11 @@ std::optional _PersisterFacadeImpl::getRequestState(Persi return _worker->getRequestState(id); } +PersisterRequestResult _PersisterFacadeImpl::fetchPersisterRequestResult(PersisterRequestId const& id) +{ + return _worker->fetchRequestResult(id); +} + std::vector _PersisterFacadeImpl::fetchAllErrorInfos(SenderId const& senderId) { return _worker->fetchAllErrorInfos(senderId); @@ -186,6 +190,16 @@ GetPeakSimulationResultData _PersisterFacadeImpl::fetchGetPeakSimulationData(Per return fetchData<_GetPeakSimulationRequestResult, GetPeakSimulationResultData>(id); } +PersisterRequestId _PersisterFacadeImpl::scheduleSaveDeserializedSimulation(SenderInfo const& senderInfo, SaveDeserializedSimulationRequestData const& data) +{ + return scheduleRequest<_SaveDeserializedSimulationRequest>(senderInfo, data); +} + +SaveDeserializedSimulationResultData _PersisterFacadeImpl::fetchSaveDeserializedSimulationData(PersisterRequestId const& id) +{ + return fetchData<_SaveDeserializedSimulationRequestResult, SaveDeserializedSimulationResultData>(id); +} + PersisterRequestId _PersisterFacadeImpl::generateNewRequestId() { ++_latestRequestId; diff --git a/source/PersisterImpl/PersisterFacadeImpl.h b/source/PersisterImpl/PersisterFacadeImpl.h index c8f7828cd..8a154e369 100644 --- a/source/PersisterImpl/PersisterFacadeImpl.h +++ b/source/PersisterImpl/PersisterFacadeImpl.h @@ -19,6 +19,7 @@ class _PersisterFacadeImpl : public _PersisterFacade bool isBusy() const override; std::optional getRequestState(PersisterRequestId const& id) const override; + PersisterRequestResult fetchPersisterRequestResult(PersisterRequestId const& id) override; std::vector fetchAllErrorInfos(SenderId const& senderId) override; PersisterErrorInfo fetchError(PersisterRequestId const& id) override; @@ -61,6 +62,9 @@ class _PersisterFacadeImpl : public _PersisterFacade PersisterRequestId scheduleGetPeakSimulation(SenderInfo const& senderInfo, GetPeakSimulationRequestData const& data) override; GetPeakSimulationResultData fetchGetPeakSimulationData(PersisterRequestId const& id) override; + PersisterRequestId scheduleSaveDeserializedSimulation(SenderInfo const& senderInfo, SaveDeserializedSimulationRequestData const& data) override; + SaveDeserializedSimulationResultData fetchSaveDeserializedSimulationData(PersisterRequestId const& id) override; + private: static auto constexpr MaxWorkerThreads = 4; diff --git a/source/PersisterImpl/PersisterRequest.h b/source/PersisterImpl/PersisterRequest.h index fe1055b5a..3c304f8f8 100644 --- a/source/PersisterImpl/PersisterRequest.h +++ b/source/PersisterImpl/PersisterRequest.h @@ -11,8 +11,9 @@ #include "PersisterInterface/ReadSimulationRequestData.h" #include "PersisterInterface/PersisterRequestId.h" #include "PersisterInterface/ReplaceNetworkResourceRequestData.h" -#include "PersisterInterface/SenderInfo.h" +#include "PersisterInterface/SaveDeserializedSimulationRequestData.h" #include "PersisterInterface/SaveSimulationRequestData.h" +#include "PersisterInterface/SenderInfo.h" #include "PersisterInterface/ToggleReactionNetworkResourceRequestData.h" #include "PersisterInterface/UploadNetworkResourceRequestData.h" @@ -95,3 +96,6 @@ using ToggleReactionNetworkResourceRequest = std::shared_ptr<_ToggleReactionNetw using _GetPeakSimulationRequest = _ConcreteRequest; using GetPeakSimulationRequest = std::shared_ptr<_GetPeakSimulationRequest>; + +using _SaveDeserializedSimulationRequest = _ConcreteRequest; +using SaveDeserializedSimulationRequest = std::shared_ptr<_SaveDeserializedSimulationRequest>; diff --git a/source/PersisterImpl/PersisterWorker.cpp b/source/PersisterImpl/PersisterWorker.cpp index 89470a8f1..8a65922a4 100644 --- a/source/PersisterImpl/PersisterWorker.cpp +++ b/source/PersisterImpl/PersisterWorker.cpp @@ -7,7 +7,9 @@ #include "Base/LoggingService.h" #include "Base/StringHelper.h" +#include "Base/UnlockGuard.h" #include "PersisterInterface/SerializerService.h" +#include "PersisterInterface/PersisterRequestResult.h" #include "EngineInterface/SimulationFacade.h" #include "EngineInterface/GenomeDescriptionService.h" #include "Network/NetworkService.h" @@ -156,6 +158,8 @@ void _PersisterWorker::processRequests(std::unique_lock& lock) processingResult = processRequest(lock, concreteRequest); } else if (auto const& concreteRequest = std::dynamic_pointer_cast<_GetPeakSimulationRequest>(request)) { processingResult = processRequest(lock, concreteRequest); + } else if (auto const& concreteRequest = std::dynamic_pointer_cast<_SaveDeserializedSimulationRequest>(request)) { + processingResult = processRequest(lock, concreteRequest); } auto inProgressJobsIter = std::ranges::find_if( _inProgressRequests, [&](PersisterRequest const& otherRequest) { return otherRequest->getRequestId() == request->getRequestId(); }); @@ -176,15 +180,17 @@ void _PersisterWorker::processRequests(std::unique_lock& lock) namespace { - class UnlockGuard + std::filesystem::path generateFilename(std::filesystem::path const& directory, uint64_t timestep) { - public: - UnlockGuard(std::unique_lock& lock) : _lock(lock) { _lock.unlock(); } - ~UnlockGuard() { _lock.lock(); } - - private: - std::unique_lock& _lock; - }; + std::filesystem::path result; + int i = 0; + do { + auto postfix = i == 0 ? std::string() : "-" + std::to_string(i); + result = directory / ("save_" + StringHelper::format(timestep, '_') + postfix + ".sim"); + ++i; + } while (std::filesystem::exists(result) && i < 100); + return result; + } } auto _PersisterWorker::processRequest(std::unique_lock& lock, SaveSimulationRequest const& request) -> PersisterRequestResultOrError @@ -215,14 +221,7 @@ auto _PersisterWorker::processRequest(std::unique_lock& lock, SaveSi try { auto filename = requestData.filename; if (requestData.generateNameFromTimestep) { - std::filesystem::path fullFilename; - int i = 0; - do { - auto postfix = i == 0 ? std::string() : "-" + std::to_string(i); - fullFilename = filename / ("save_" + StringHelper::format(deserializedData.auxiliaryData.timestep, '_') + postfix + ".sim"); - ++i; - } while (std::filesystem::exists(fullFilename) && i < 100); - filename = fullFilename; + filename = generateFilename(filename, deserializedData.auxiliaryData.timestep); } if (!SerializerService::get().serializeSimulationToFiles(filename, deserializedData)) { throw std::runtime_error("Error"); @@ -640,7 +639,7 @@ _PersisterWorker::PersisterRequestResultOrError _PersisterWorker::processRequest deserializedSimulation.auxiliaryData.simulationParameters = _simulationFacade->getSimulationParameters(); deserializedSimulation.auxiliaryData.timestep = static_cast(_simulationFacade->getCurrentTimestep()); deserializedSimulation.mainData = _simulationFacade->getClusteredSimulationData(); - requestData.peakDeserializedSimulation->setDeserializedSimulation(std::move(deserializedSimulation)); + requestData.peakDeserializedSimulation->set(std::move(deserializedSimulation)); } return std::make_shared<_GetPeakSimulationRequestResult>(request->getRequestId(), GetPeakSimulationResultData()); } catch (...) { @@ -648,3 +647,38 @@ _PersisterWorker::PersisterRequestResultOrError _PersisterWorker::processRequest request->getRequestId(), request->getSenderInfo().senderId, PersisterErrorInfo{"No valid data could be obtained from the GPU."}); } } + +_PersisterWorker::PersisterRequestResultOrError _PersisterWorker::processRequest( + std::unique_lock& lock, + SaveDeserializedSimulationRequest const& request) +{ + try { + UnlockGuard unlockGuard(lock); + + auto const& requestData = request->getData(); + + auto timestamp = std::chrono::system_clock::now(); + auto deserializedData = requestData.sharedDeserializedSimulation->get(); + + auto filename = requestData.filename; + if (requestData.generateNameFromTimestep) { + filename = generateFilename(filename, deserializedData.auxiliaryData.timestep); + } + if (!SerializerService::get().serializeSimulationToFiles(filename, deserializedData)) { + throw std::runtime_error("Error"); + } + + return std::make_shared<_SaveDeserializedSimulationRequestResult>( + request->getRequestId(), + SaveDeserializedSimulationResultData{ + .filename = filename, + .projectName = deserializedData.auxiliaryData.simulationParameters.projectName, + .timestep = deserializedData.auxiliaryData.timestep, + .timestamp = timestamp}); + } catch (...) { + return std::make_shared<_PersisterRequestError>( + request->getRequestId(), + request->getSenderInfo().senderId, + PersisterErrorInfo{"The simulation could not be saved because an error occurred when writing the data to the specified file."}); + } +} diff --git a/source/PersisterImpl/PersisterWorker.h b/source/PersisterImpl/PersisterWorker.h index 9dd4b6afc..858d9471b 100644 --- a/source/PersisterImpl/PersisterWorker.h +++ b/source/PersisterImpl/PersisterWorker.h @@ -6,11 +6,11 @@ #include #include "PersisterInterface/PersisterRequestState.h" +#include "PersisterInterface/PersisterRequestResult.h" #include "Definitions.h" #include "PersisterRequest.h" #include "PersisterRequestError.h" -#include "PersisterRequestResult.h" class _PersisterWorker { @@ -47,6 +47,7 @@ class _PersisterWorker PersisterRequestResultOrError processRequest(std::unique_lock& lock, MoveNetworkResourceRequest const& request); PersisterRequestResultOrError processRequest(std::unique_lock& lock, ToggleReactionNetworkResourceRequest const& request); PersisterRequestResultOrError processRequest(std::unique_lock& lock, GetPeakSimulationRequest const& request); + PersisterRequestResultOrError processRequest(std::unique_lock& lock, SaveDeserializedSimulationRequest const& request); SimulationFacade _simulationFacade; diff --git a/source/PersisterInterface/CMakeLists.txt b/source/PersisterInterface/CMakeLists.txt index f87a3127b..39755b246 100644 --- a/source/PersisterInterface/CMakeLists.txt +++ b/source/PersisterInterface/CMakeLists.txt @@ -28,6 +28,7 @@ add_library(PersisterInterface PersisterErrorInfo.h PersisterFacade.h PersisterRequestId.h + PersisterRequestResult.h PersisterRequestState.h ReadSimulationRequestData.h ReadSimulationResultData.h diff --git a/source/PersisterInterface/PersisterFacade.h b/source/PersisterInterface/PersisterFacade.h index 6f8147ed1..25d381627 100644 --- a/source/PersisterInterface/PersisterFacade.h +++ b/source/PersisterInterface/PersisterFacade.h @@ -29,6 +29,8 @@ #include "PersisterRequestState.h" #include "ReplaceNetworkResourceRequestData.h" #include "ReplaceNetworkResourceResultData.h" +#include "SaveDeserializedSimulationRequestData.h" +#include "SaveDeserializedSimulationResultData.h" #include "SaveSimulationResultData.h" #include "SaveSimulationRequestData.h" #include "SenderId.h" @@ -37,6 +39,7 @@ #include "ToggleReactionNetworkResourceResultData.h" #include "UploadNetworkResourceRequestData.h" #include "UploadNetworkResourceResultData.h" +#include "PersisterRequestResult.h" class _PersisterFacade { @@ -51,6 +54,7 @@ class _PersisterFacade //generic logic virtual bool isBusy() const = 0; virtual std::optional getRequestState(PersisterRequestId const& id) const = 0; + virtual PersisterRequestResult fetchPersisterRequestResult(PersisterRequestId const& id) = 0; virtual std::vector fetchAllErrorInfos(SenderId const& senderId) = 0; virtual PersisterErrorInfo fetchError(PersisterRequestId const& id) = 0; @@ -93,4 +97,7 @@ class _PersisterFacade virtual PersisterRequestId scheduleGetPeakSimulation(SenderInfo const& senderInfo, GetPeakSimulationRequestData const& data) = 0; virtual GetPeakSimulationResultData fetchGetPeakSimulationData(PersisterRequestId const& id) = 0; + + virtual PersisterRequestId scheduleSaveDeserializedSimulation(SenderInfo const& senderInfo, SaveDeserializedSimulationRequestData const& data) = 0; + virtual SaveDeserializedSimulationResultData fetchSaveDeserializedSimulationData(PersisterRequestId const& id) = 0; }; diff --git a/source/PersisterImpl/PersisterRequestResult.h b/source/PersisterInterface/PersisterRequestResult.h similarity index 75% rename from source/PersisterImpl/PersisterRequestResult.h rename to source/PersisterInterface/PersisterRequestResult.h index 44ec1beb2..2b0725fad 100644 --- a/source/PersisterImpl/PersisterRequestResult.h +++ b/source/PersisterInterface/PersisterRequestResult.h @@ -3,7 +3,18 @@ #include "PersisterInterface/ReadSimulationResultData.h" #include "PersisterInterface/PersisterRequestId.h" #include "PersisterInterface/SaveSimulationResultData.h" +#include "PersisterInterface/LoginResultData.h" +#include "PersisterInterface/GetNetworkResourcesResultData.h" +#include "PersisterInterface/DownloadNetworkResourceResultData.h" +#include "PersisterInterface/UploadNetworkResourceResultData.h" +#include "PersisterInterface/ReplaceNetworkResourceResultData.h" +#include "PersisterInterface/GetUserNamesForReactionResultData.h" +#include "PersisterInterface/DeleteNetworkResourceResultData.h" +#include "PersisterInterface/EditNetworkResourceResultData.h" +#include "PersisterInterface/MoveNetworkResourceResultData.h" +#include "PersisterInterface/ToggleReactionNetworkResourceResultData.h" #include "PersisterInterface/GetPeakSimulationResultData.h" +#include "PersisterInterface/SaveDeserializedSimulationResultData.h" class _PersisterRequestResult { @@ -52,3 +63,4 @@ using _EditNetworkResourceRequestResult = _ConcreteRequestResult; using _ToggleReactionNetworkResourceRequestResult = _ConcreteRequestResult; using _GetPeakSimulationRequestResult = _ConcreteRequestResult; +using _SaveDeserializedSimulationRequestResult = _ConcreteRequestResult; diff --git a/source/PersisterInterface/SaveDeserializedSimulationRequestData.h b/source/PersisterInterface/SaveDeserializedSimulationRequestData.h index bc4b85de4..16fc442da 100644 --- a/source/PersisterInterface/SaveDeserializedSimulationRequestData.h +++ b/source/PersisterInterface/SaveDeserializedSimulationRequestData.h @@ -1,16 +1,12 @@ #pragma once #include -#include - -#include "Base/Vector2D.h" #include "SharedDeserializedSimulation.h" struct SaveDeserializedSimulationRequestData { std::filesystem::path filename; - float zoom = 1.0f; - RealVector2D center; SharedDeserializedSimulation sharedDeserializedSimulation; + bool generateNameFromTimestep = false; }; diff --git a/source/PersisterInterface/SaveDeserializedSimulationResultData.h b/source/PersisterInterface/SaveDeserializedSimulationResultData.h index 6f70f09be..b734830ef 100644 --- a/source/PersisterInterface/SaveDeserializedSimulationResultData.h +++ b/source/PersisterInterface/SaveDeserializedSimulationResultData.h @@ -1 +1,9 @@ #pragma once + +struct SaveDeserializedSimulationResultData +{ + std::filesystem::path filename; + std::string projectName; + uint64_t timestep = 0; + std::chrono::system_clock::time_point timestamp; +}; diff --git a/source/PersisterInterface/SharedDeserializedSimulation.h b/source/PersisterInterface/SharedDeserializedSimulation.h index 30b1a32c6..92901115e 100644 --- a/source/PersisterInterface/SharedDeserializedSimulation.h +++ b/source/PersisterInterface/SharedDeserializedSimulation.h @@ -16,12 +16,18 @@ class _SharedDeserializedSimulation return _deserializedSimulation.statistics.back(); } - void setDeserializedSimulation(DeserializedSimulation&& value) + void set(DeserializedSimulation&& value) { std::lock_guard lock(_mutex); _deserializedSimulation = std::move(value); } + DeserializedSimulation get() const + { + std::lock_guard lock(_mutex); + return _deserializedSimulation; + } + private: mutable std::mutex _mutex; DeserializedSimulation _deserializedSimulation;