Files
UnrealEngineUWP/Engine/Source/Developer/DerivedDataCache/Public/DerivedDataCache.h
Devin Doucette a077feffbd DDC: Reworked ICacheStore to allow partial records, filtering of payloads, and loading parts of payloads
- ICacheStore::Put() has updated documentation to reflect the requirements of partial records.
- ICacheStore::Get() now takes a FCacheRecordPolicy, which is implicitly constructible from ECachePolicy, and allows setting the policy by payload.
- ICacheStore::GetPayload() is replaced by ICacheStore::GetChunks(), which allows loading parts of payloads.
- ICacheStore::CancelAll() is moved to ICache::CancelAll() because the cache can track requests at the top level and cancel them without exposing cancellation on individual cache stores.
- ECachePolicy::SkipLocalCopy has been removed because it is difficult to reason about.
- ECachePolicy::SkipData flags now have a documented meaning for put requests, to hint that record existence implies payload existence.
- The filesystem and memory cache stores have been updated to support partial records, filtering of payloads, and loading parts of payloads.
- Requesting part of a payload will decompress the entire payload for now, until compressed buffers expose a way to decompress only part.
- Fixed a bug in FTexturePlatformData::AreDerivedMipsAvailable() that caused it to return false for structured cache keys.

#rb Zousar.Shaker
#rnx
#preflight 615e03241ed62f0001b95454

#ROBOMERGE-OWNER: Devin.Doucette
#ROBOMERGE-AUTHOR: devin.doucette
#ROBOMERGE-SOURCE: CL 17748550 in //UE5/Release-5.0/... via CL 17748555
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v879-17706426)
#ROBOMERGE-CONFLICT from-shelf
#ROBOMERGE[STARSHIP]: UE5-Main

[CL 17748602 by Devin Doucette in ue5-release-engine-test branch]
2021-10-07 09:11:32 -04:00

386 lines
15 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreTypes.h"
#include "Containers/StringFwd.h"
#include "DerivedDataCacheKey.h"
#include "DerivedDataPayloadId.h"
#include "DerivedDataRequestTypes.h"
#include "Math/NumericLimits.h"
#include "Misc/EnumClassFlags.h"
#include "Templates/Function.h"
#include "Templates/RefCounting.h"
#define UE_API DERIVEDDATACACHE_API
namespace UE::DerivedData { class FCacheRecord; }
namespace UE::DerivedData { class FCacheRecordPolicy; }
namespace UE::DerivedData { class IRequestOwner; }
namespace UE::DerivedData { struct FCacheChunkRequest; }
namespace UE::DerivedData { struct FCacheGetChunkCompleteParams; }
namespace UE::DerivedData { struct FCacheGetCompleteParams; }
namespace UE::DerivedData { struct FCachePutCompleteParams; }
namespace UE::DerivedData::Private { class ICacheRecordPolicyShared; }
namespace UE::DerivedData
{
using FOnCachePutComplete = TUniqueFunction<void (FCachePutCompleteParams&& Params)>;
using FOnCacheGetComplete = TUniqueFunction<void (FCacheGetCompleteParams&& Params)>;
using FOnCacheGetChunkComplete = TUniqueFunction<void (FCacheGetChunkCompleteParams&& Params)>;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Flags to control the behavior of cache requests.
*
* The cache policy flags can be combined to support a variety of usage patterns. Examples:
*
* Get(Default): read from any cache; put to writable caches if missing.
* Get(Remote): read any remote cache; put to writable remote caches if missing.
* Get(Local): read any local cache; put to writable local caches if missing.
* Get(Query | StoreRemote): read from any cache; put to writable remote caches if missing.
* Get(Query | StoreLocal): read from any cache; put to writable local caches if missing.
* Get(Query | SkipData): check for existence in any cache; do not modify any cache.
* Get(Default | SkipData): check for existence in any cache; put to writable caches if missing.
* Get(Default | SkipLocalCopy): read from any cache; put to writable remote caches if missing,
* and to writable local caches if not present in any local cache.
*
* Put(Default): write to every writable cache.
* Put(Remote): write to every writable remote cache, skipping local caches.
* Put(Local): write to every writable local cache, skipping remote caches.
*/
enum class ECachePolicy : uint32
{
/** A value without any flags set. */
None = 0,
/** Allow a cache request to query local caches. */
QueryLocal = 1 << 0,
/** Allow a cache request to query remote caches. */
QueryRemote = 1 << 1,
/** Allow a cache request to query local and remote caches. */
Query = QueryLocal | QueryRemote,
/** Allow cache records and values to be stored in local caches. */
StoreLocal = 1 << 2,
/** Allow cache records and values to be stored in remote caches. */
StoreRemote = 1 << 3,
/** Allow cache records and values to be stored in local and remote caches. */
Store = StoreLocal | StoreRemote,
/** Skip fetching the metadata for record requests. */
SkipMeta = 1 << 4,
/** Skip fetching the value for record, chunk, or value requests. */
SkipValue = 1 << 5,
/** Skip fetching the attachments for record requests. */
SkipAttachments = 1 << 6,
/**
* Skip fetching the data for any requests.
*
* Put requests with skip flags may assume that record existence implies payload existence.
*/
SkipData = SkipMeta | SkipValue | SkipAttachments,
/**
* Keep records in the cache for at least the duration of the session.
*
* This is a hint that the record may be accessed again in this session. This is mainly meant
* to be used when subsequent accesses will not tolerate a cache miss.
*/
KeepAlive = 1 << 7,
/** Allow cache requests to query and store records in local caches. */
Local = QueryLocal | StoreLocal,
/** Allow cache requests to query and store records in remote caches. */
Remote = QueryRemote | StoreRemote,
/** Allow cache requests to query and store records in local and remote caches. */
Default = Query | Store,
/** Do not allow cache requests to query or store records in local or remote caches. */
Disable = None,
};
ENUM_CLASS_FLAGS(ECachePolicy);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** A payload ID and the policy to use for that payload. */
struct FCachePayloadPolicy
{
FPayloadId Id;
ECachePolicy Policy = ECachePolicy::Default;
};
/** Interface for the private implementation of the cache record policy. */
class Private::ICacheRecordPolicyShared
{
public:
virtual ~ICacheRecordPolicyShared() = default;
virtual void AddRef() const = 0;
virtual void Release() const = 0;
virtual TConstArrayView<FCachePayloadPolicy> GetPayloadPolicies() const = 0;
virtual void AddPayloadPolicy(const FCachePayloadPolicy& Policy) = 0;
virtual void Build() = 0;
};
/** A policy for cache record requests, with optional overrides by payload. */
class FCacheRecordPolicy
{
public:
/** Construct a cache record policy that uses the default policy for records and payloads. */
FCacheRecordPolicy() = default;
/** Construct a cache record policy from a single policy for both records and payloads. */
inline FCacheRecordPolicy(ECachePolicy Policy)
: BasePolicy(Policy)
, RecordPolicy(Policy)
{
}
/** Returns true if the record and every payload use the same policy. */
inline bool IsUniform() const { return !Shared && BasePolicy == RecordPolicy; }
/** Returns the cache policy to use for the record. */
inline ECachePolicy GetRecordPolicy() const { return RecordPolicy; }
/** Returns the cache policy to use for the payload. */
UE_API ECachePolicy GetPayloadPolicy(const FPayloadId& Id) const;
/** Returns the cache policy to use for payloads with no override. */
inline ECachePolicy GetDefaultPayloadPolicy() const { return BasePolicy; }
/** Returns the array of cache policy overrides for payloads, sorted by ID. */
inline TConstArrayView<FCachePayloadPolicy> GetPayloadPolicies() const
{
return Shared ? Shared->GetPayloadPolicies() : TConstArrayView<FCachePayloadPolicy>();
}
private:
friend class FCacheRecordPolicyBuilder;
ECachePolicy BasePolicy = ECachePolicy::Default;
ECachePolicy RecordPolicy = ECachePolicy::Default;
TRefCountPtr<const Private::ICacheRecordPolicyShared> Shared;
};
/** A cache record policy builder is used to construct a cache record policy. */
class FCacheRecordPolicyBuilder
{
public:
/** Construct a cache record policy builder that uses the default policy as its base policy. */
FCacheRecordPolicyBuilder() = default;
/** Construct a cache record policy builder from the base policy for the record and its payloads. */
inline explicit FCacheRecordPolicyBuilder(ECachePolicy Policy)
: BasePolicy(Policy)
{
}
/** Adds a cache policy override for a payload. */
UE_API void AddPayloadPolicy(const FCachePayloadPolicy& Policy);
inline void AddPayloadPolicy(const FPayloadId& Id, ECachePolicy Policy) { AddPayloadPolicy({Id, Policy}); }
/** Build a cache record policy, which makes this builder subsequently unusable. */
UE_API FCacheRecordPolicy Build();
private:
ECachePolicy BasePolicy = ECachePolicy::Default;
TRefCountPtr<Private::ICacheRecordPolicyShared> Shared;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Interface to a store of cache records.
*
* Functions on this interface may be called from any thread. When a callback is provided, it may
* be invoked from a different thread than the request was made on, and may be invoked before the
* request function returns, both of which must be supported by the caller and the callback.
*/
class ICacheStore
{
public:
virtual ~ICacheStore() = default;
/**
* Asynchronous request to put cache records according to the policy.
*
* The callback will always be called for every key, and may be called from an arbitrary thread.
* Records may finish storing in any order, and from multiple threads concurrently.
*
* A cache store is free to interpret a record containing only a key as a request to delete that
* record from the store. Records may contain payloads that do not have data, and these payloads
* must reference an existing copy of the payload in the store, if available, and must otherwise
* be stored as a partial record that can attempt recovery of missing payloads when fetched.
*
* @param Records The cache records to store. Must have a key.
* @param Context A description of the request. An object path is typically sufficient.
* @param Policy Flags to control the behavior of the request. See ECachePolicy.
* @param Owner The owner to execute the request within.
* @param OnComplete A callback invoked for every record as it completes or is canceled.
*/
virtual void Put(
TConstArrayView<FCacheRecord> Records,
FStringView Context,
ECachePolicy Policy,
IRequestOwner& Owner,
FOnCachePutComplete&& OnComplete = FOnCachePutComplete()) = 0;
/**
* Asynchronous request to get cache records according to the policy.
*
* The callback will always be called for every key, and may be called from an arbitrary thread.
* Records may become available in any order, and from multiple threads concurrently.
*
* Records may propagate into other cache stores, in accordance with the policy. A propagated
* record may be a partial record, with some payloads missing data, depending on the policy.
*
* When payloads are required by the policy, but not available, the status must be Error, but
* the cache store may provide a partial record with the available payloads, to be completed,
* when possible, by another cache store.
*
* @param Keys The keys identifying the cache records to query.
* @param Context A description of the request. An object path is typically sufficient.
* @param Policy Flags to control the behavior of the request. See FCacheRecordPolicy.
* @param Owner The owner to execute the request within.
* @param OnComplete A callback invoked for every key as it completes or is canceled.
*/
virtual void Get(
TConstArrayView<FCacheKey> Keys,
FStringView Context,
FCacheRecordPolicy Policy,
IRequestOwner& Owner,
FOnCacheGetComplete&& OnComplete) = 0;
/**
* Asynchronous request to get chunks, which are subsets of payloads, from cache records.
*
* The callback will always be called for every chunk, and may be called from an arbitrary thread.
* Chunks may become available in any order, and from multiple threads concurrently.
*
* There is no requirement that the cache store validate the existence of other payloads from
* the requested records. Requests for whole payloads may propagate those payloads into other
* cache stores, in accordance with the policy, through a put of a partial record.
*
* @param Chunks The keys, IDs, offsets, and sizes of the chunks to query.
* @param Context A description of the request. An object path is typically sufficient.
* @param Owner The owner to execute the request within.
* @param OnComplete A callback invoked for every chunk as it completes or is canceled.
*/
virtual void GetChunks(
TConstArrayView<FCacheChunkRequest> Chunks,
FStringView Context,
IRequestOwner& Owner,
FOnCacheGetChunkComplete&& OnComplete) = 0;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Interface to the cache.
*
* @see ICacheStore for cache record storage.
*/
class ICache : public ICacheStore
{
public:
virtual ~ICache() = default;
/**
* Cancel all queued and active cache requests and invoke their callbacks.
*
* This is meant to be called before destroying the cache. Any new requests that are made during
* execution of this function will also be canceled, because callbacks might queue requests when
* they are invoked. This does not block any future cache requests, which must be handled by the
* owner of the cache if future requests are meant to be avoided.
*/
virtual void CancelAll() = 0;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Parameters for the completion callback for cache put requests. */
struct FCachePutCompleteParams
{
/** Key for the part of the put request that completed or was canceled. */
FCacheKey Key;
/** Status of the cache request. */
EStatus Status = EStatus::Error;
};
/** Parameters for the completion callback for cache get requests. */
struct FCacheGetCompleteParams
{
/**
* Record for the part of the get request that completed or was canceled.
*
* The key is always populated. The remainder of the record is populated when Status is Ok.
*
* The value, attachments, and metadata may be skipped based on cache policy flags. When a value
* or attachment has been skipped, it will have a payload but its data will be null.
*/
FCacheRecord&& Record;
/** Status of the cache request. */
EStatus Status = EStatus::Error;
};
/** Parameters to request a chunk, which is a subset of a payload, from a cache record. */
struct FCacheChunkRequest
{
/** The key identifying the cache record to fetch the payload from. */
FCacheKey Key;
/** The ID of the payload to fetch from the cache record. */
FPayloadId Id;
/** The offset into the raw bytes of the payload at which to start fetching. */
uint64 RawOffset = 0;
/** The maximum number of raw bytes of the payload to fetch, starting from the offset. */
uint64 RawSize = MAX_uint64;
/** Flags to control the behavior of the request. See ECachePolicy. */
ECachePolicy Policy = ECachePolicy::Default;
};
/** Parameters for the completion callback for cache chunk requests. */
struct FCacheGetChunkCompleteParams
{
/** Key from the chunk request that completed or was canceled. */
FCacheKey Key;
/** ID from the chunk request that completed or was canceled. */
FPayloadId Id;
/** Offset from the chunk request that completed or was canceled. */
uint64 RawOffset = 0;
/** Size, in bytes, of the subset of the payload that was fetched, if any. */
uint64 RawSize = 0;
/** Hash of the entire payload, even if only a subset was fetched. */
const FIoHash& RawHash;
/** Data for the subset of the payload that was fetched when Status is Ok, otherwise null. */
FSharedBuffer&& RawData;
/** Status of the cache request. */
EStatus Status = EStatus::Error;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Returns a reference to the cache. Asserts if not available. */
UE_API ICache& GetCache();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} // UE::DerivedData
#undef UE_API