Files
UnrealEngineUWP/Engine/Source/Runtime/StorageServerClient/Public/StorageServerConnection.h
devin doucette 27c1393427 CompressedBuffer: Removed partial decompression from FCompressedBuffer now that FCompressedBufferReader is available
Requiring the use of a separate reader type makes it more likely that readers will be reused, and makes it easier to audit reader usage going forward. Reusing readers is desirable to reduce the number of large temporary allocations made during partial decompression of a buffer.

- Added FCompressedBuffer::Save(FArchive&) and renamed FromCompressed(FArchive&) to Load(FArchive&).
- Added FCompressedBufferReaderSourceScope to set a buffer source within a scope.
- Added proper bounds checks to FNoneDecoder.
- Store the header checksum on the decoder context to allow raw blocks to be reused across sources.
- Decode the header on the fly to avoid a temporary header allocation when the header is in contiguous memory.

#rb Zousar.Shaker
#rnx
#preflight 61a98d53800738dbfbc84c73

#ROBOMERGE-AUTHOR: devin.doucette
#ROBOMERGE-SOURCE: CL 18382211 in //UE5/Release-5.0/... via CL 18382310
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v896-18170469)

[CL 18382377 by devin doucette in ue5-release-engine-test branch]
2021-12-06 10:16:05 -05:00

213 lines
5.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Compression/CompressedBuffer.h"
#include "IO/IoContainerId.h"
#include "Misc/StringBuilder.h"
#include "Serialization/CompactBinarySerialization.h"
#include "Memory/MemoryView.h"
#if !UE_BUILD_SHIPPING
class ISocketSubsystem;
class FInternetAddr;
class FIoChunkId;
class FSocket;
class FStorageServerConnection;
class FIoBuffer;
enum class EStorageServerContentType : uint8
{
Unknown = 0,
CbObject,
Binary,
CompressedBinary,
};
inline FAnsiStringView GetMimeTypeString(EStorageServerContentType ContentType)
{
switch (ContentType)
{
case EStorageServerContentType::CbObject:
return "application/ue-x-cb"_ASV;
case EStorageServerContentType::Binary:
return "application/octet-stream"_ASV;
case EStorageServerContentType::CompressedBinary:
return "application/x-ue-comp"_ASV;
default:
return "unknown"_ASV;
};
};
inline EStorageServerContentType GetMimeType(const FAnsiStringView& ContentType)
{
if (ContentType == "application/octet-stream"_ASV)
{
return EStorageServerContentType::Binary;
}
else if (ContentType == "application/x-ue-comp"_ASV)
{
return EStorageServerContentType::CompressedBinary;
}
else if (ContentType == "application/x-ue-cb"_ASV)
{
return EStorageServerContentType::CbObject;
}
else
{
return EStorageServerContentType::Unknown;
}
};
struct FStorageServerSerializationContext
{
TArray64<uint8> CompressedBuffer;
FCompressedBufferReader Decoder;
};
class FStorageServerRequest
: public FArchive
{
EStorageServerContentType AcceptContentType() const;
protected:
friend class FStorageServerConnection;
FStorageServerRequest(
FAnsiStringView Verb,
FAnsiStringView Resource,
FAnsiStringView Hostname,
EStorageServerContentType Accept = EStorageServerContentType::Binary);
FSocket* Send(FStorageServerConnection& Owner);
virtual void Serialize(void* V, int64 Length) override;
EStorageServerContentType AcceptType;
TAnsiStringBuilder<512> HeaderBuffer;
TArray<uint8, TInlineAllocator<1024>> BodyBuffer;
};
class FStorageServerResponse
: public FArchive
{
public:
~FStorageServerResponse()
{
if (Socket)
{
ReleaseSocket(false);
}
}
bool IsOk() const
{
return bIsOk;
}
const int32 GetErrorCode() const
{
return ErrorCode;
}
const FString& GetErrorMessage() const
{
return ErrorMessage;
}
int64 TotalSize() override
{
return ContentLength;
}
int64 Tell() override
{
return Position;
}
void Serialize(void* V, int64 Length) override;
int64 SerializeChunk(FStorageServerSerializationContext& Context, FIoBuffer& OutChunk, void* TargetVa = nullptr, uint64 RawOffset = 0, uint64 RawSize = MAX_uint64);
inline int64 SerializeChunk(FIoBuffer& OutChunk, void* TargetVa = nullptr, uint64 RawOffset = 0, uint64 RawSize = MAX_uint64)
{
FStorageServerSerializationContext SerializationContext;
return SerializeChunk(SerializationContext, OutChunk, TargetVa, RawOffset, RawSize);
}
int64 SerializeChunkTo(FMutableMemoryView Memory, uint64 RawOffset = 0);
FCbObject GetResponseObject()
{
FCbField Payload = LoadCompactBinary(*this);
return Payload.AsObject();
}
private:
friend class FStorageServerConnection;
friend class FStorageServerChunkBatchRequest;
FStorageServerResponse(class FStorageServerConnection& Owner, FSocket& Socket);
void ReleaseSocket(bool bKeepAlive);
FStorageServerConnection& Owner;
FSocket* Socket = nullptr;
uint64 ContentLength = 0;
uint64 Position = 0;
int32 ErrorCode;
FString ErrorMessage;
bool bIsOk = false;
EStorageServerContentType ContentType = EStorageServerContentType::Unknown;
};
class FStorageServerChunkBatchRequest
: private FStorageServerRequest
{
public:
STORAGESERVERCLIENT_API FStorageServerChunkBatchRequest& AddChunk(const FIoChunkId& ChunkId, int64 Offset, int64 Size);
STORAGESERVERCLIENT_API bool Issue(TFunctionRef<void(uint32 ChunkCount, uint32* ChunkIndices, uint64* ChunkSizes, FStorageServerResponse& ChunkDataStream)> OnResponse);
private:
friend class FStorageServerConnection;
FStorageServerChunkBatchRequest(FStorageServerConnection& Owner, FAnsiStringView Resource, FAnsiStringView Hostname);
FStorageServerConnection& Owner;
int32 ChunkCountOffset = 0;
};
class FStorageServerConnection
{
public:
STORAGESERVERCLIENT_API FStorageServerConnection();
STORAGESERVERCLIENT_API ~FStorageServerConnection();
STORAGESERVERCLIENT_API bool Initialize(TArrayView<const FString> HostAddresses, int32 Port, const TCHAR* ProjectNameOverride = nullptr, const TCHAR* PlatformNameOverride = nullptr);
STORAGESERVERCLIENT_API void FileManifestRequest(TFunctionRef<void(FIoChunkId Id, FStringView Path)> Callback);
STORAGESERVERCLIENT_API int64 ChunkSizeRequest(const FIoChunkId& ChunkId);
STORAGESERVERCLIENT_API bool ReadChunkRequest(const FIoChunkId& ChunkId, uint64 Offset, uint64 Size, TFunctionRef<void(FStorageServerResponse&)> OnResponse);
STORAGESERVERCLIENT_API FStorageServerChunkBatchRequest NewChunkBatchRequest();
STORAGESERVERCLIENT_API FString GetHostAddr() const;
private:
friend class FStorageServerRequest;
friend class FStorageServerResponse;
friend class FStorageServerChunkBatchRequest;
int32 HandshakeRequest(TArrayView<const TSharedPtr<FInternetAddr>> HostAddresses);
FSocket* AcquireSocketFromPool();
FSocket* AcquireNewSocket();
void ReleaseSocket(FSocket* Socket, bool bKeepAlive);
ISocketSubsystem& SocketSubsystem;
TAnsiStringBuilder<1024> OplogPath;
TSharedPtr<FInternetAddr> ServerAddr;
TAnsiStringBuilder<1024> Hostname;
FCriticalSection SocketPoolCritical;
TArray<FSocket*> SocketPool;
};
#endif