3 #include <CesiumAsync/AsyncSystem.h>
4 #include <CesiumAsync/Future.h>
5 #include <CesiumAsync/IAssetAccessor.h>
6 #include <CesiumUtility/DoublyLinkedList.h>
7 #include <CesiumUtility/IDepotOwningAsset.h>
8 #include <CesiumUtility/IntrusivePointer.h>
9 #include <CesiumUtility/ReferenceCounted.h>
10 #include <CesiumUtility/Result.h>
18 #include <unordered_map>
21 template <
typename T>
class SharedAsset;
32 template <
typename TAssetType,
typename TAssetKey>
35 SharedAssetDepot<TAssetType, TAssetKey>>,
50 int64_t inactiveAssetSizeLimitBytes = 16 * 1024 * 1024;
52 using FactorySignature =
55 const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
56 const TAssetKey& key);
61 _deletionCandidates(),
62 _totalDeletionCandidateMemoryUsage(0),
64 _factory(std::move(factory)),
65 _pKeepAlive(nullptr) {}
89 CESIUM_ASSERT(this->_assets.size() == this->_deletionCandidates.size());
104 const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
105 const TAssetKey& assetKey) {
108 std::unique_lock lock(this->_mutex);
110 auto existingIt = this->_assets.find(assetKey);
111 if (existingIt != this->_assets.end()) {
114 const AssetEntry& entry = *existingIt->second;
115 if (entry.maybePendingAsset) {
117 return *entry.maybePendingAsset;
140 new AssetEntry(assetKey);
144 .thenImmediately([pDepot, pEntry, asyncSystem, pAssetAccessor]() {
145 return pDepot->_factory(asyncSystem, pAssetAccessor, pEntry->key);
147 .catchImmediately([](std::exception&& e) {
151 std::string(
"Error creating asset: ") + e.what()));
157 std::lock_guard lock(pDepot->_mutex);
160 result.pValue->_pDepot = pDepot.get();
161 pDepot->_assetsByPointer[result.pValue.get()] =
168 std::unique_ptr<TAssetType>(result.pValue.get());
169 pEntry->errorsAndWarnings = std::move(result.errors);
170 pEntry->maybePendingAsset.
reset();
175 pDepot->_pKeepAlive = pDepot;
177 return pEntry->toResultUnderLock();
181 std::move(future).share();
183 pEntry->maybePendingAsset = sharedFuture;
185 auto [it, added] = this->_assets.emplace(assetKey, pEntry);
189 CESIUM_ASSERT(added);
203 std::lock_guard lock(this->_mutex);
204 return this->_assets.size();
212 std::lock_guard lock(this->_mutex);
213 return this->_assets.size() - this->_deletionCandidates.size();
221 std::lock_guard lock(this->_mutex);
222 return this->_deletionCandidates.size();
230 std::lock_guard lock(this->_mutex);
231 return this->_totalDeletionCandidateMemoryUsage;
246 void markDeletionCandidate(
const TAssetType& asset,
bool threadOwnsDepotLock)
248 if (threadOwnsDepotLock) {
249 this->markDeletionCandidateUnderLock(asset);
251 std::lock_guard lock(this->_mutex);
252 this->markDeletionCandidateUnderLock(asset);
256 void markDeletionCandidateUnderLock(
const TAssetType& asset) {
257 auto it = this->_assetsByPointer.find(
const_cast<TAssetType*
>(&asset));
258 CESIUM_ASSERT(it != this->_assetsByPointer.end());
259 if (it == this->_assetsByPointer.end()) {
263 CESIUM_ASSERT(it->second !=
nullptr);
265 AssetEntry& entry = *it->second;
266 entry.sizeInDeletionList = asset.getSizeBytes();
267 this->_totalDeletionCandidateMemoryUsage += entry.sizeInDeletionList;
269 this->_deletionCandidates.insertAtTail(entry);
271 if (this->_totalDeletionCandidateMemoryUsage >
272 this->inactiveAssetSizeLimitBytes) {
274 while (this->_deletionCandidates.size() > 0 &&
275 this->_totalDeletionCandidateMemoryUsage >
276 this->inactiveAssetSizeLimitBytes) {
277 AssetEntry* pOldEntry = this->_deletionCandidates.head();
278 this->_deletionCandidates.remove(*pOldEntry);
280 this->_totalDeletionCandidateMemoryUsage -=
281 pOldEntry->sizeInDeletionList;
284 pOldEntry->pAsset ==
nullptr ||
285 pOldEntry->pAsset->_referenceCount == 0);
287 if (pOldEntry->pAsset) {
288 this->_assetsByPointer.erase(pOldEntry->pAsset.get());
292 this->_assets.erase(pOldEntry->key);
298 if (this->_assets.size() == this->_deletionCandidates.size()) {
299 this->_pKeepAlive.reset();
311 void unmarkDeletionCandidate(
312 const TAssetType& asset,
313 bool threadOwnsDepotLock)
override {
314 if (threadOwnsDepotLock) {
315 this->unmarkDeletionCandidateUnderLock(asset);
317 std::lock_guard lock(this->_mutex);
318 this->unmarkDeletionCandidateUnderLock(asset);
322 void unmarkDeletionCandidateUnderLock(
const TAssetType& asset) {
323 auto it = this->_assetsByPointer.find(
const_cast<TAssetType*
>(&asset));
324 CESIUM_ASSERT(it != this->_assetsByPointer.end());
325 if (it == this->_assetsByPointer.end()) {
329 CESIUM_ASSERT(it->second !=
nullptr);
331 AssetEntry& entry = *it->second;
332 bool isFound = this->_deletionCandidates.contains(entry);
334 CESIUM_ASSERT(isFound);
337 this->_totalDeletionCandidateMemoryUsage -= entry.sizeInDeletionList;
338 this->_deletionCandidates.remove(entry);
342 this->_pKeepAlive =
this;
351 AssetEntry(TAssetKey&& key_)
353 key(std::move(key_)),
357 sizeInDeletionList(0),
358 deletionListPointers() {}
360 AssetEntry(
const TAssetKey& key_) : AssetEntry(TAssetKey(key_)) {}
371 std::unique_ptr<TAssetType> pAsset;
378 std::optional<SharedFuture<CesiumUtility::ResultPointer<TAssetType>>>
394 int64_t sizeInDeletionList;
407 pAsset->addReference(
true);
409 pAsset->releaseReference(
true);
416 std::unordered_map<TAssetKey, CesiumUtility::IntrusivePointer<AssetEntry>>
421 std::unordered_map<TAssetType*, AssetEntry*> _assetsByPointer;
430 int64_t _totalDeletionCandidateMemoryUsage;
434 mutable std::mutex _mutex;
437 std::function<FactorySignature> _factory;
A system for managing asynchronous requests and tasks.
Promise< T > createPromise() const
Create a Promise that can be used at a later time to resolve or reject a Future.
Future< T > createResolvedFuture(T &&value) const
Creates a future that is already resolved.
A value that will be available in the future, as produced by AsyncSystem.
A depot for SharedAsset instances, which are potentially shared between multiple objects.
size_t getActiveAssetCount() const
Gets the number of assets owned by this depot that are active, meaning that they are currently being ...
size_t getInactiveAssetCount() const
Gets the number of assets owned by this depot that are inactive, meaning that they are not currently ...
size_t getAssetCount() const
Returns the total number of distinct assets contained in this depot, including both active and inacti...
int64_t getInactiveAssetTotalSizeBytes() const
Gets the total bytes used by inactive (unused) assets owned by this depot.
SharedFuture< CesiumUtility::ResultPointer< TAssetType > > getOrCreate(const AsyncSystem &asyncSystem, const std::shared_ptr< IAssetAccessor > &pAssetAccessor, const TAssetKey &assetKey)
Gets an asset from the depot if it already exists, or creates it using the depot's factory if it does...
A value that will be available in the future, as produced by AsyncSystem. Unlike Future,...
An interface representing the depot that owns a SharedAsset. This interface is an implementation deta...
A smart pointer that calls addReference and releaseReference on the controlled object.
T * get() const noexcept
Returns the internal pointer.
void reset()
Reset this pointer to nullptr.
A reference-counted base class, meant to be used with IntrusivePointer.
Classes that support asynchronous operations.
Utility classes for Cesium.
ReferenceCounted< T, true > ReferenceCountedThreadSafe
A reference-counted base class, meant to be used with IntrusivePointer. The reference count is thread...
The container to store the error and warning list when loading a tile or glTF content.
static ErrorList error(std::string errorMessage)
Creates an ErrorList containing a single error.
Holds the result of an operation. If the operation succeeds, it will provide a value....