diff --git a/Source/Engine/Content/Storage/ContentStorageManager.cpp b/Source/Engine/Content/Storage/ContentStorageManager.cpp index 11209ae24..13c2dcf1d 100644 --- a/Source/Engine/Content/Storage/ContentStorageManager.cpp +++ b/Source/Engine/Content/Storage/ContentStorageManager.cpp @@ -4,9 +4,11 @@ #include "FlaxFile.h" #include "FlaxPackage.h" #include "Engine/Core/Log.h" +#include "Engine/Engine/Engine.h" #include "Engine/Engine/EngineService.h" #include "Engine/Platform/FileSystem.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Threading/TaskGraph.h" namespace { @@ -21,20 +23,31 @@ namespace Dictionary StorageMap(2048); } -class ContentStorageManagerService : public EngineService +class ContentStorageService : public EngineService { public: - - ContentStorageManagerService() - : EngineService(TEXT("ContentStorageManager"), -800) + ContentStorageService() + : EngineService(TEXT("ContentStorage"), -800) { } - void Update() override; + bool Init() override; void Dispose() override; }; -ContentStorageManagerService ContentStorageManagerServiceInstance; +class ContentStorageSystem : public TaskGraphSystem +{ +public: + void Job(int32 index); + void Execute(TaskGraph* graph) override; +}; + +namespace +{ + TaskGraphSystem* System = nullptr; +} + +ContentStorageService ContentStorageServiceInstance; TimeSpan ContentStorageManager::UnusedDataChunksLifetime = TimeSpan::FromSeconds(10); @@ -201,12 +214,30 @@ void ContentStorageManager::GetStorage(Array& result) result.Add(Files[i]); } -void ContentStorageManagerService::Update() +bool ContentStorageService::Init() { - PROFILE_CPU(); + System = New(); + Engine::UpdateGraph->AddSystem(System); + return false; +} + +void ContentStorageService::Dispose() +{ + ScopeLock lock(Locker); + for (auto i = StorageMap.Begin(); i.IsNotEnd(); ++i) + i->Value->Dispose(); + Files.ClearDelete(); + Packages.ClearDelete(); + StorageMap.Clear(); + ASSERT(Files.IsEmpty() && Packages.IsEmpty()); + SAFE_DELETE(System); +} + +void ContentStorageSystem::Job(int32 index) +{ + PROFILE_CPU_NAMED("ContentStorage.Job"); ScopeLock lock(Locker); - for (auto i = StorageMap.Begin(); i.IsNotEnd(); ++i) { auto storage = i->Value; @@ -230,17 +261,14 @@ void ContentStorageManagerService::Update() } } -void ContentStorageManagerService::Dispose() +void ContentStorageSystem::Execute(TaskGraph* graph) { ScopeLock lock(Locker); + if (StorageMap.Count() == 0) + return; - // Cleanup - for (auto i = StorageMap.Begin(); i.IsNotEnd(); ++i) - i->Value->Dispose(); - Files.ClearDelete(); - Packages.ClearDelete(); - StorageMap.Clear(); - - // Ensure that data has been disposed - ASSERT(Files.IsEmpty() && Packages.IsEmpty()); + // Schedule work to update all storage containers in async + Function job; + job.Bind(this); + graph->DispatchJob(job, 1); } diff --git a/Source/Engine/Content/Storage/FlaxChunk.h b/Source/Engine/Content/Storage/FlaxChunk.h index a5af7cc72..e97d0de89 100644 --- a/Source/Engine/Content/Storage/FlaxChunk.h +++ b/Source/Engine/Content/Storage/FlaxChunk.h @@ -3,7 +3,6 @@ #pragma once #include "Engine/Core/Types/DataContainer.h" -#include "Engine/Core/Types/DateTime.h" #include "../Config.h" /// @@ -78,12 +77,12 @@ public: /// /// The chunk flags. /// - FlaxChunkFlags Flags; + FlaxChunkFlags Flags = FlaxChunkFlags::None; /// - /// The last usage time (UTC). + /// The last usage time (atomic, ticks of DateTime in UTC). /// - DateTime LastAccessTime; + int64 LastAccessTime = 0; /// /// The chunk data. @@ -96,48 +95,9 @@ public: /// Initializes a new instance of the class. /// FlaxChunk() - : Flags(FlaxChunkFlags::None) - , LastAccessTime(0) { } - /// - /// Initializes a new instance of the class. - /// - /// The chunk location in the file. - FlaxChunk(const Location& location) - : LocationInFile(location) - , Flags(FlaxChunkFlags::None) - , LastAccessTime(0) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The chunk location in the file. - /// The flags. - FlaxChunk(const Location& location, const FlaxChunkFlags flags) - : LocationInFile(location) - , Flags(flags) - , LastAccessTime(0) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The address in the file. - /// The size in bytes. - FlaxChunk(uint32 address, uint32 size) - : LocationInFile(address, size) - , Flags(FlaxChunkFlags::None) - , LastAccessTime(0) - { - } - -public: - /// /// Finalizes an instance of the class. /// @@ -150,7 +110,6 @@ public: /// /// Gets this chunk data pointer. /// - /// Data FORCE_INLINE byte* Get() { return Data.Get(); @@ -159,7 +118,6 @@ public: /// /// Gets this chunk data pointer. /// - /// Data FORCE_INLINE const byte* Get() const { return Data.Get(); @@ -168,7 +126,6 @@ public: /// /// Gets this chunk data pointer. /// - /// Data template FORCE_INLINE T* Get() const { @@ -178,18 +135,14 @@ public: /// /// Gets this chunk data size (in bytes). /// - /// Data size FORCE_INLINE int32 Size() const { return Data.Length(); } -public: - /// /// Determines whether this chunk is loaded. /// - /// True if this instance is loaded, otherwise false. FORCE_INLINE bool IsLoaded() const { return Data.IsValid(); @@ -198,7 +151,6 @@ public: /// /// Determines whether this chunk is missing (no data loaded or assigned). /// - /// True if this instance is missing, otherwise false. FORCE_INLINE bool IsMissing() const { return Data.IsInvalid(); @@ -207,7 +159,6 @@ public: /// /// Determines whether this chunk exists in a file. /// - /// True if this instance is in a file, otherwise false. FORCE_INLINE bool ExistsInFile() const { return LocationInFile.Size > 0; @@ -216,10 +167,7 @@ public: /// /// Registers the usage operation of chunk data. /// - void RegisterUsage() - { - LastAccessTime = DateTime::NowUTC(); - } + void RegisterUsage(); /// /// Unloads this chunk data. diff --git a/Source/Engine/Content/Storage/FlaxStorage.cpp b/Source/Engine/Content/Storage/FlaxStorage.cpp index 50ed82595..7c65dc6e1 100644 --- a/Source/Engine/Content/Storage/FlaxStorage.cpp +++ b/Source/Engine/Content/Storage/FlaxStorage.cpp @@ -22,6 +22,11 @@ String AssetHeader::ToString() const return String::Format(TEXT("ID: {0}, TypeName: {1}, Chunks Count: {2}"), ID, TypeName, GetChunksCount()); } +void FlaxChunk::RegisterUsage() +{ + Platform::AtomicStore(&LastAccessTime, DateTime::NowUTC().Ticks); +} + const int32 FlaxStorage::MagicCode = 1180124739; FlaxStorage::LockData FlaxStorage::LockData::Invalid(nullptr); @@ -231,7 +236,7 @@ FlaxStorage::LockData FlaxStorage::LockSafe() bool FlaxStorage::ShouldDispose() const { - return _refCount == 0 && DateTime::NowUTC() - _lastRefLostTime >= TimeSpan::FromMilliseconds(500) && Platform::AtomicRead((int64*)&_chunksLock) == 0; + return _refCount == 0 && Platform::AtomicRead((int64*)&_chunksLock) == 0 && DateTime::NowUTC() - _lastRefLostTime >= TimeSpan::FromMilliseconds(500); } uint32 FlaxStorage::GetMemoryUsage() const @@ -319,9 +324,10 @@ bool FlaxStorage::Load() LOG(Warning, "Empty chunk found."); return true; } - FlaxChunkFlags flags; - stream->ReadInt32(reinterpret_cast(&flags)); - AddChunk(New(e, flags)); + auto chunk = New(); + chunk->LocationInFile = e; + stream->ReadInt32(reinterpret_cast(&chunk->Flags)); + AddChunk(chunk); } break; @@ -369,9 +375,10 @@ bool FlaxStorage::Load() LOG(Warning, "Empty chunk found."); return true; } - FlaxChunkFlags flags; - stream->ReadInt32(reinterpret_cast(&flags)); - AddChunk(New(e, flags)); + auto chunk = New(); + chunk->LocationInFile = e; + stream->ReadInt32(reinterpret_cast(&chunk->Flags)); + AddChunk(chunk); } break; @@ -403,7 +410,9 @@ bool FlaxStorage::Load() LOG(Warning, "Empty chunk found."); return true; } - AddChunk(New(e)); + auto chunk = New(); + chunk->LocationInFile = e; + AddChunk(chunk); } break; @@ -436,7 +445,9 @@ bool FlaxStorage::Load() LOG(Warning, "Empty chunk found."); return true; } - AddChunk(New(e)); + auto chunk = New(); + chunk->LocationInFile = e; + AddChunk(chunk); } break; @@ -473,7 +484,9 @@ bool FlaxStorage::Load() LOG(Warning, "Empty chunk found."); return true; } - AddChunk(New(e)); + auto chunk = New(); + chunk->LocationInFile = e; + AddChunk(chunk); } break; @@ -529,7 +542,9 @@ bool FlaxStorage::Load() auto& oldChunk = chunks[i]; if (oldChunk.Size > 0) { - AddChunk(New(oldChunk.Adress, oldChunk.Size)); + auto chunk = New(); + chunk->LocationInFile = FlaxChunk::Location(oldChunk.Adress, oldChunk.Size); + AddChunk(chunk); } } @@ -1305,7 +1320,7 @@ void FlaxStorage::Tick() for (int32 i = 0; i < _chunks.Count(); i++) { auto chunk = _chunks[i]; - const bool wasUsed = (now - chunk->LastAccessTime) < ContentStorageManager::UnusedDataChunksLifetime; + const bool wasUsed = (now - DateTime(Platform::AtomicRead(&chunk->LastAccessTime))) < ContentStorageManager::UnusedDataChunksLifetime; if (!wasUsed && chunk->IsLoaded()) { chunk->Unload(); diff --git a/Source/Engine/Content/Storage/FlaxStorage.h b/Source/Engine/Content/Storage/FlaxStorage.h index 55eadaa42..f1b4d62eb 100644 --- a/Source/Engine/Content/Storage/FlaxStorage.h +++ b/Source/Engine/Content/Storage/FlaxStorage.h @@ -142,9 +142,6 @@ public: struct LockData { friend FlaxStorage; - - public: - static LockData Invalid; private: @@ -166,8 +163,12 @@ public: if (_storage) _storage->LockChunks(); } - - public: + + LockData(LockData&& other) noexcept + : _storage(other._storage) + { + other._storage = nullptr; + } ~LockData() { @@ -184,12 +185,8 @@ public: } } - public: - - // Assignment operator LockData& operator=(const LockData& other) { - // Protect against invalid self-assignment if (this != &other) { if (_storage) @@ -198,9 +195,18 @@ public: if (_storage) _storage->LockChunks(); } - return *this; } + + LockData& operator=(LockData&& other) noexcept + { + if (this == &other) + return *this; + _storage = other._storage; + other._storage = nullptr; + return *this; + } + }; /// @@ -224,7 +230,6 @@ public: /// /// Gets the references count. /// - /// Amount of references to that storage container. FORCE_INLINE uint32 GetRefCount() const { return _refCount; @@ -233,13 +238,11 @@ public: /// /// Checks if storage container should be disposed (it's not used anymore). /// - /// True if should be disposed, otherwise false. bool ShouldDispose() const; /// /// Gets the path. /// - /// File path FORCE_INLINE const String& GetPath() const { return _path; @@ -248,7 +251,6 @@ public: /// /// Determines whether this instance is loaded. /// - /// True if this instance is loaded, otherwise false. FORCE_INLINE bool IsLoaded() const { return _version != 0; @@ -257,7 +259,6 @@ public: /// /// Determines whether this instance is disposed. /// - /// True if this instance is disposed, otherwise false. FORCE_INLINE bool IsDisposed() const { return _version == 0; @@ -266,19 +267,16 @@ public: /// /// Gets total memory used by chunks (in bytes). /// - /// Memory usage in bytes. uint32 GetMemoryUsage() const; /// /// Determines whether this storage container is a package. /// - /// True if this container is a package, otherwise false. virtual bool IsPackage() const = 0; /// /// Checks whenever storage container allows the data modifications. /// - /// True if can write data to the storage, otherwise it's readonly. virtual bool AllowDataModifications() const = 0; /// @@ -298,7 +296,6 @@ public: /// /// Gets amount of entries in the storage. /// - /// Entries count. virtual int32 GetEntriesCount() const = 0; ///