2020-01-07 17:07:47 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-12-13 11:07:03 -05:00
2021-12-15 03:24:48 -05:00
# include "IoDispatcherFileBackend.h"
2021-09-15 04:29:36 -04:00
# include "Misc/CommandLine.h"
2021-09-15 02:54:32 -04:00
# include "Misc/Parse.h"
2019-12-13 11:07:03 -05:00
# include "Misc/ScopeRWLock.h"
2020-03-25 09:54:13 -04:00
# include "Misc/StringBuilder.h"
2019-12-13 11:07:03 -05:00
# include "ProfilingDebugging/CountersTrace.h"
2020-05-06 17:58:18 -04:00
# include "HAL/PlatformFileManager.h"
2019-12-13 11:07:03 -05:00
# include "GenericPlatform/GenericPlatformFile.h"
2021-12-15 03:24:48 -05:00
# include "GenericPlatformIoDispatcher.h"
2020-01-28 06:54:05 -05:00
# include "HAL/IConsoleManager.h"
2020-04-01 05:00:26 -04:00
# include "Async/AsyncWork.h"
# include "Async/MappedFileHandle.h"
# include "HAL/RunnableThread.h"
# include "Misc/ScopeLock.h"
2020-05-05 07:49:15 -04:00
# include "Misc/Paths.h"
2021-05-27 13:40:37 -04:00
# include "Algo/AllOf.h"
# include "Algo/IsSorted.h"
# include "Algo/MinElement.h"
# include "Templates/Greater.h"
2021-06-03 18:48:17 -04:00
# include "Containers/Ticker.h"
2021-09-15 02:54:32 -04:00
# include "Modules/ModuleManager.h"
2021-09-28 04:00:33 -04:00
# include "IO/IoContainerHeader.h"
# include "Serialization/MemoryReader.h"
2022-01-10 13:43:28 -05:00
# include "FileCache/FileCache.h"
2019-12-13 11:07:03 -05:00
2020-01-28 06:54:05 -05:00
//PRAGMA_DISABLE_OPTIMIZATION
2020-04-01 05:00:26 -04:00
int32 GIoDispatcherBufferSizeKB = 256 ;
static FAutoConsoleVariableRef CVar_IoDispatcherBufferSizeKB (
TEXT ( " s.IoDispatcherBufferSizeKB " ) ,
GIoDispatcherBufferSizeKB ,
TEXT ( " IoDispatcher read buffer size (in kilobytes). " )
2020-01-28 06:54:05 -05:00
) ;
2020-04-22 06:25:12 -04:00
int32 GIoDispatcherBufferAlignment = 4096 ;
static FAutoConsoleVariableRef CVar_IoDispatcherBufferAlignment (
TEXT ( " s.IoDispatcherBufferAlignment " ) ,
GIoDispatcherBufferAlignment ,
TEXT ( " IoDispatcher read buffer alignment. " )
) ;
2020-04-01 05:00:26 -04:00
int32 GIoDispatcherBufferMemoryMB = 8 ;
static FAutoConsoleVariableRef CVar_IoDispatcherBufferMemoryMB (
TEXT ( " s.IoDispatcherBufferMemoryMB " ) ,
GIoDispatcherBufferMemoryMB ,
TEXT ( " IoDispatcher buffer memory size (in megabytes). " )
) ;
int32 GIoDispatcherDecompressionWorkerCount = 4 ;
static FAutoConsoleVariableRef CVar_IoDispatcherDecompressionWorkerCount (
TEXT ( " s.IoDispatcherDecompressionWorkerCount " ) ,
GIoDispatcherDecompressionWorkerCount ,
TEXT ( " IoDispatcher decompression worker count. " )
) ;
2020-09-01 14:07:48 -04:00
int32 GIoDispatcherCacheSizeMB = 0 ;
static FAutoConsoleVariableRef CVar_IoDispatcherCacheSizeMB (
TEXT ( " s.IoDispatcherCacheSizeMB " ) ,
GIoDispatcherCacheSizeMB ,
TEXT ( " IoDispatcher cache memory size (in megabytes). " )
) ;
2021-05-27 13:40:37 -04:00
int32 GIoDispatcherSortRequestsByOffset = 1 ;
static FAutoConsoleVariableRef CVar_IoDispatcherSortRequestsByOffset (
TEXT ( " s.IoDispatcherSortRequestsByOffset " ) ,
GIoDispatcherSortRequestsByOffset ,
TEXT ( " If > 0, io dispatcher sorts the outstanding request queue by offset rather than sequence. " )
) ;
int32 GIoDispatcherMaintainSortingOnPriorityChange = 1 ;
static FAutoConsoleVariableRef CVar_IoDispatcherMaintainSortingOnPriorityChange (
TEXT ( " s.IoDispatcherMaintainSortingOnPriorityChange " ) ,
GIoDispatcherMaintainSortingOnPriorityChange ,
TEXT ( " If s.IoDispatcherSortRequestsByOffset > 0 and this > 0, io dispatcher remembers the last file handle/offset read from even when switching priority levels. " )
) ;
int32 GIoDispatcherMaxForwardSeekKB = 0 ;
static FAutoConsoleVariableRef CVar_IoDispatcherMaxForwardSeekKB (
TEXT ( " s.IoDispatcherMaxForwardSeekKB " ) ,
GIoDispatcherMaxForwardSeekKB ,
TEXT ( " If s.IoDispatcherSortRequestsByOffset is enabled and this is > 0, if the next sequential read is further than this offset from the last one, read the oldest request instead " )
) ;
int32 GIoDispatcherRequestLatencyCircuitBreakerMS = 0 ;
static FAutoConsoleVariableRef CVar_IoDispatcherRequestLatencyCircuitBreakerMS (
TEXT ( " s.IoDispatcherRequestLatencyCircuitBreakerMS " ) ,
GIoDispatcherRequestLatencyCircuitBreakerMS ,
TEXT ( " If s.IoDispatcherSortRequestsByOffset is enabled and this is >0, if the oldest request has been in the queue for this long, read it instead of the most optimal read " )
) ;
2021-11-18 14:37:34 -05:00
int32 GIoDispatcherTocsEnablePerfectHashing = 1 ;
2021-11-07 23:43:01 -05:00
static FAutoConsoleVariableRef CVar_IoDispatcherTocsEnablePerfectHashing (
TEXT ( " s.IoDispatcherTocsEnablePerfectHashing " ) ,
GIoDispatcherTocsEnablePerfectHashing ,
TEXT ( " Enable perfect hashmap lookups for iostore tocs " )
) ;
2020-11-24 18:42:39 -04:00
uint32 FFileIoStoreReadRequest : : NextSequence = 0 ;
2021-05-27 13:40:37 -04:00
# if CHECK_IO_STORE_READ_REQUEST_LIST_MEMBERSHIP
uint32 FFileIoStoreReadRequestList : : NextListCookie = 0 ;
# endif
2021-01-08 19:56:07 -04:00
TAtomic < uint32 > FFileIoStoreReader : : GlobalPartitionIndex { 0 } ;
2021-04-29 19:32:06 -04:00
TAtomic < uint32 > FFileIoStoreReader : : GlobalContainerInstanceId { 0 } ;
2020-11-24 18:42:39 -04:00
2020-04-01 05:00:26 -04:00
class FMappedFileProxy final : public IMappedFileHandle
{
public :
FMappedFileProxy ( IMappedFileHandle * InSharedMappedFileHandle , uint64 InSize )
: IMappedFileHandle ( InSize )
, SharedMappedFileHandle ( InSharedMappedFileHandle )
{
check ( InSharedMappedFileHandle ! = nullptr ) ;
}
virtual ~ FMappedFileProxy ( ) { }
virtual IMappedFileRegion * MapRegion ( int64 Offset = 0 , int64 BytesToMap = MAX_int64 , bool bPreloadHint = false ) override
{
return SharedMappedFileHandle - > MapRegion ( Offset , BytesToMap , bPreloadHint ) ;
}
private :
IMappedFileHandle * SharedMappedFileHandle ;
} ;
2021-09-01 12:09:24 -04:00
void FFileIoStoreBufferAllocator : : Initialize ( uint64 InMemorySize , uint64 InBufferSize , uint32 InBufferAlignment )
2020-09-01 14:07:48 -04:00
{
2021-09-01 12:09:24 -04:00
uint64 BufferCount = InMemorySize / InBufferSize ;
uint64 MemorySize = BufferCount * InBufferSize ;
BufferMemory = reinterpret_cast < uint8 * > ( FMemory : : Malloc ( MemorySize , InBufferAlignment ) ) ;
BufferSize = InBufferSize ;
2020-09-01 14:07:48 -04:00
for ( uint64 BufferIndex = 0 ; BufferIndex < BufferCount ; + + BufferIndex )
{
FFileIoStoreBuffer * Buffer = new FFileIoStoreBuffer ( ) ;
Buffer - > Memory = BufferMemory + BufferIndex * BufferSize ;
Buffer - > Next = FirstFreeBuffer ;
FirstFreeBuffer = Buffer ;
2021-11-22 16:44:27 -05:00
Stats . OnBufferReleased ( ) ;
2020-09-01 14:07:48 -04:00
}
}
FFileIoStoreBuffer * FFileIoStoreBufferAllocator : : AllocBuffer ( )
{
2021-11-22 16:44:27 -05:00
FFileIoStoreBuffer * Buffer ;
2020-09-01 14:07:48 -04:00
{
2021-11-22 16:44:27 -05:00
FScopeLock Lock ( & BuffersCritical ) ;
Buffer = FirstFreeBuffer ;
if ( ! Buffer )
{
return nullptr ;
}
2020-09-01 14:07:48 -04:00
FirstFreeBuffer = Buffer - > Next ;
}
2021-11-22 16:44:27 -05:00
Stats . OnBufferAllocated ( ) ;
return Buffer ;
2020-09-01 14:07:48 -04:00
}
void FFileIoStoreBufferAllocator : : FreeBuffer ( FFileIoStoreBuffer * Buffer )
{
check ( Buffer ) ;
2021-11-22 16:44:27 -05:00
{
FScopeLock Lock ( & BuffersCritical ) ;
Buffer - > Next = FirstFreeBuffer ;
FirstFreeBuffer = Buffer ;
}
Stats . OnBufferReleased ( ) ;
2020-09-01 14:07:48 -04:00
}
2021-11-22 16:44:27 -05:00
FFileIoStoreBlockCache : : FFileIoStoreBlockCache ( FFileIoStoreStats & InStats )
: Stats ( InStats )
2020-09-01 14:07:48 -04:00
{
CacheLruHead . LruNext = & CacheLruTail ;
CacheLruTail . LruPrev = & CacheLruHead ;
}
FFileIoStoreBlockCache : : ~ FFileIoStoreBlockCache ( )
{
FCachedBlock * CachedBlock = CacheLruHead . LruNext ;
while ( CachedBlock ! = & CacheLruTail )
{
FCachedBlock * Next = CachedBlock - > LruNext ;
delete CachedBlock ;
CachedBlock = Next ;
}
FMemory : : Free ( CacheMemory ) ;
}
void FFileIoStoreBlockCache : : Initialize ( uint64 InCacheMemorySize , uint64 InReadBufferSize )
{
ReadBufferSize = InReadBufferSize ;
uint64 CacheBlockCount = InCacheMemorySize / InReadBufferSize ;
if ( CacheBlockCount )
{
InCacheMemorySize = CacheBlockCount * InReadBufferSize ;
CacheMemory = reinterpret_cast < uint8 * > ( FMemory : : Malloc ( InCacheMemorySize ) ) ;
FCachedBlock * Prev = & CacheLruHead ;
for ( uint64 CacheBlockIndex = 0 ; CacheBlockIndex < CacheBlockCount ; + + CacheBlockIndex )
{
FCachedBlock * CachedBlock = new FCachedBlock ( ) ;
CachedBlock - > Key = uint64 ( - 1 ) ;
CachedBlock - > Buffer = CacheMemory + CacheBlockIndex * InReadBufferSize ;
Prev - > LruNext = CachedBlock ;
CachedBlock - > LruPrev = Prev ;
Prev = CachedBlock ;
}
Prev - > LruNext = & CacheLruTail ;
CacheLruTail . LruPrev = Prev ;
}
}
bool FFileIoStoreBlockCache : : Read ( FFileIoStoreReadRequest * Block )
{
2021-08-17 09:13:59 -04:00
if ( ! CacheMemory )
2020-09-01 14:07:48 -04:00
{
return false ;
}
check ( Block - > Buffer ) ;
2021-06-15 16:38:03 -04:00
FCachedBlock * CachedBlock = CachedBlocks . FindRef ( Block - > Key . Hash ) ;
2020-09-01 14:07:48 -04:00
if ( ! CachedBlock )
{
2021-11-22 16:44:27 -05:00
Stats . OnBlockCacheMiss ( ReadBufferSize ) ;
2020-09-01 14:07:48 -04:00
return false ;
}
2021-08-17 09:13:59 -04:00
CachedBlock - > LruPrev - > LruNext = CachedBlock - > LruNext ;
CachedBlock - > LruNext - > LruPrev = CachedBlock - > LruPrev ;
CachedBlock - > LruPrev = & CacheLruHead ;
CachedBlock - > LruNext = CacheLruHead . LruNext ;
CachedBlock - > LruPrev - > LruNext = CachedBlock ;
CachedBlock - > LruNext - > LruPrev = CachedBlock ;
2020-09-01 14:07:48 -04:00
check ( CachedBlock - > Buffer ) ;
2021-11-22 16:44:27 -05:00
Stats . OnBlockCacheHit ( ReadBufferSize ) ;
2020-09-01 14:07:48 -04:00
FMemory : : Memcpy ( Block - > Buffer - > Memory , CachedBlock - > Buffer , ReadBufferSize ) ;
2021-06-15 16:38:03 -04:00
2020-09-01 14:07:48 -04:00
return true ;
}
void FFileIoStoreBlockCache : : Store ( const FFileIoStoreReadRequest * Block )
{
2021-08-17 09:13:59 -04:00
bool bIsCacheableBlock = CacheMemory ! = nullptr & & Block - > BytesUsed < Block - > Size ;
2020-09-01 14:07:48 -04:00
if ( ! bIsCacheableBlock )
{
return ;
}
check ( Block - > Buffer ) ;
check ( Block - > Buffer - > Memory ) ;
2021-06-15 16:38:03 -04:00
FCachedBlock * BlockToReplace = CacheLruTail . LruPrev ;
if ( BlockToReplace = = & CacheLruHead )
2020-09-01 14:07:48 -04:00
{
2021-06-15 16:38:03 -04:00
return ;
2020-09-01 14:07:48 -04:00
}
check ( BlockToReplace ) ;
2021-06-15 16:38:03 -04:00
CachedBlocks . Remove ( BlockToReplace - > Key ) ;
BlockToReplace - > Key = Block - > Key . Hash ;
BlockToReplace - > LruPrev - > LruNext = BlockToReplace - > LruNext ;
BlockToReplace - > LruNext - > LruPrev = BlockToReplace - > LruPrev ;
BlockToReplace - > LruPrev = & CacheLruHead ;
BlockToReplace - > LruNext = CacheLruHead . LruNext ;
BlockToReplace - > LruPrev - > LruNext = BlockToReplace ;
BlockToReplace - > LruNext - > LruPrev = BlockToReplace ;
2020-09-01 14:07:48 -04:00
check ( BlockToReplace - > Buffer ) ;
FMemory : : Memcpy ( BlockToReplace - > Buffer , Block - > Buffer - > Memory , ReadBufferSize ) ;
2021-11-22 16:44:27 -05:00
Stats . OnBlockCacheStore ( ReadBufferSize ) ;
2021-06-15 16:38:03 -04:00
CachedBlocks . Add ( BlockToReplace - > Key , BlockToReplace ) ;
2020-09-01 14:07:48 -04:00
}
2021-11-22 16:44:27 -05:00
# define UE_FILEIOSTORE_DETAILED_QUEUE_COUNTERS_ENABLED 0
# if UE_FILEIOSTORE_DETAILED_QUEUE_COUNTERS_ENABLED
TRACE_DECLARE_INT_COUNTER ( IoDispatcherLatencyCircuitBreaks , TEXT ( " IoDispatcher/LatencyCircuitBreaks " ) ) ;
TRACE_DECLARE_INT_COUNTER ( IoDispatcherSeekDistanceCircuitBreaks , TEXT ( " IoDispatcher/SeekDistanceCircuitBreaks " ) ) ;
TRACE_DECLARE_INT_COUNTER ( IoDispatcherNumPriorityQueues , TEXT ( " IoDispatcher/NumPriorityQueues " ) ) ;
# endif
2021-05-27 13:40:37 -04:00
bool FFileIoStoreOffsetSortedRequestQueue : : RequestSortPredicate ( const FFileIoStoreReadRequestSortKey & A , const FFileIoStoreReadRequestSortKey & B )
{
if ( A . Handle = = B . Handle )
{
return A . Offset < B . Offset ;
}
return A . Handle < B . Handle ;
}
FFileIoStoreOffsetSortedRequestQueue : : FFileIoStoreOffsetSortedRequestQueue ( int32 InPriority )
: Priority ( InPriority )
{
}
TArray < FFileIoStoreReadRequest * > FFileIoStoreOffsetSortedRequestQueue : : StealRequests ( )
{
RequestsBySequence . Clear ( ) ;
PeekRequestIndex = INDEX_NONE ;
return MoveTemp ( Requests ) ;
}
// This could be potentially optimized if the higher level keeps track of which requests it changes the priority of, or even just the old priorty levels
TArray < FFileIoStoreReadRequest * > FFileIoStoreOffsetSortedRequestQueue : : RemoveMisprioritizedRequests ( )
{
PeekRequestIndex = INDEX_NONE ;
TArray < FFileIoStoreReadRequest * > RequestsToReturn ;
for ( int32 i = Requests . Num ( ) - 1 ; i > = 0 ; - - i )
{
if ( Requests [ i ] - > Priority ! = Priority )
{
RequestsToReturn . Add ( Requests [ i ] ) ;
RequestsBySequence . Remove ( Requests [ i ] ) ;
Requests . RemoveAt ( i , 1 , false ) ;
}
}
return RequestsToReturn ;
}
FFileIoStoreReadRequest * FFileIoStoreOffsetSortedRequestQueue : : GetNextInternal ( FFileIoStoreReadRequestSortKey LastSortKey , bool bPop )
{
if ( Requests . Num ( ) = = 0 )
{
return nullptr ;
}
int32 RequestIndex = INDEX_NONE ;
if ( PeekRequestIndex ! = INDEX_NONE )
{
RequestIndex = PeekRequestIndex ;
}
else
{
bool bHeadRequestTooOld = false ;
if ( GIoDispatcherRequestLatencyCircuitBreakerMS > 0 )
{
// If our oldest request has been unserviced for too long, grab that instead of the next sequential read
uint64 ThresholdCycles = uint64 ( ( GIoDispatcherRequestLatencyCircuitBreakerMS * 1000.0 ) / FPlatformTime : : GetSecondsPerCycle64 ( ) ) ;
bHeadRequestTooOld = ( FPlatformTime : : Cycles64 ( ) - RequestsBySequence . PeekHead ( ) - > CreationTime ) > = ThresholdCycles ;
2021-11-22 16:44:27 -05:00
# if UE_FILEIOSTORE_DETAILED_QUEUE_COUNTERS_ENABLED
2021-05-27 13:40:37 -04:00
if ( bPop )
{
TRACE_COUNTER_INCREMENT ( IoDispatcherLatencyCircuitBreaks ) ;
}
2021-11-22 16:44:27 -05:00
# endif
2021-05-27 13:40:37 -04:00
}
const bool bChooseByOffset =
LastSortKey . Handle ! = 0
& & ! bHeadRequestTooOld
& & ( GIoDispatcherMaintainSortingOnPriorityChange | | LastSortKey . Priority = = Priority ) ;
if ( bChooseByOffset )
{
// Pick the request with the closest offset to the last thing that we read
RequestIndex = Algo : : LowerBoundBy ( Requests , LastSortKey , RequestSortProjection , RequestSortPredicate ) ;
if ( Requests . IsValidIndex ( RequestIndex ) ) // If all requests are before LastOffset we get back out-of-bounds
{
if ( Requests [ RequestIndex ] - > FileHandle ! = LastSortKey . Handle )
{
// Changing file handle so switch back to the oldest outstanding request
RequestIndex = INDEX_NONE ;
}
else if ( GIoDispatcherMaxForwardSeekKB > 0 & & ( LastSortKey . Offset - Requests [ RequestIndex ] - > Offset ) > uint64 ( GIoDispatcherMaxForwardSeekKB ) * 1024 )
{
// Large forward seek so switch back to the oldest outstanding request
RequestIndex = INDEX_NONE ;
2021-11-22 16:44:27 -05:00
# if UE_FILEIOSTORE_DETAILED_QUEUE_COUNTERS_ENABLED
2021-05-27 13:40:37 -04:00
if ( bPop )
{
TRACE_COUNTER_INCREMENT ( IoDispatcherSeekDistanceCircuitBreaks ) ;
}
2021-11-22 16:44:27 -05:00
# endif
2021-05-27 13:40:37 -04:00
}
}
}
if ( ! Requests . IsValidIndex ( RequestIndex ) )
{
RequestIndex = Requests . Find ( RequestsBySequence . PeekHead ( ) ) ;
check ( Requests [ RequestIndex ] = = RequestsBySequence . PeekHead ( ) ) ;
}
}
check ( Requests . IsValidIndex ( RequestIndex ) ) ;
FFileIoStoreReadRequest * Request = Requests [ RequestIndex ] ;
if ( bPop )
{
Requests . RemoveAt ( RequestIndex ) ;
RequestsBySequence . Remove ( Request ) ;
PeekRequestIndex = INDEX_NONE ;
}
else
{
PeekRequestIndex = RequestIndex ;
}
return Request ;
}
FFileIoStoreReadRequest * FFileIoStoreOffsetSortedRequestQueue : : Pop ( FFileIoStoreReadRequestSortKey LastSortKey )
{
return GetNextInternal ( LastSortKey , true ) ;
}
void FFileIoStoreOffsetSortedRequestQueue : : Push ( FFileIoStoreReadRequest * Request )
{
// Insert sorted by file handle & offset
int32 InsertIndex = Algo : : UpperBoundBy ( Requests , RequestSortProjection ( Request ) , RequestSortProjection , RequestSortPredicate ) ;
Requests . Insert ( Request , InsertIndex ) ;
// Insert sorted by age
RequestsBySequence . Add ( Request ) ;
PeekRequestIndex = INDEX_NONE ;
}
2021-10-12 21:21:22 -04:00
void FFileIoStoreOffsetSortedRequestQueue : : CancelRequestsWithFileHandle ( uint64 FileHandle )
{
for ( FFileIoStoreReadRequest * Request : Requests )
{
if ( Request - > FileHandle = = FileHandle )
{
Request - > bCancelled = true ;
}
}
}
2021-05-27 13:40:37 -04:00
void FFileIoStoreRequestQueue : : UpdateSortRequestsByOffset ( )
{
// Must hold CriticalSection here
if ( bSortRequestsByOffset = = bool ( GIoDispatcherSortRequestsByOffset ) )
{
return ;
}
bSortRequestsByOffset = bool ( GIoDispatcherSortRequestsByOffset ) ;
if ( bSortRequestsByOffset )
{
// Split things into separate heaps
for ( FFileIoStoreReadRequest * Request : Heap )
{
Push ( * Request ) ;
}
Heap . Empty ( ) ;
}
else
{
// Put things back into the main heap
TArray < FFileIoStoreReadRequest * > AllRequests ;
for ( FFileIoStoreOffsetSortedRequestQueue & SubQueue : SortedPriorityQueues )
{
AllRequests . Append ( SubQueue . StealRequests ( ) ) ;
}
Algo : : SortBy ( AllRequests , [ ] ( FFileIoStoreReadRequest * Request ) { return Request - > Sequence ; } ) ;
for ( FFileIoStoreReadRequest * Request : AllRequests )
{
Push ( * Request ) ;
}
check ( Algo : : AllOf ( SortedPriorityQueues , [ ] ( const FFileIoStoreOffsetSortedRequestQueue & Q ) { return Q . IsEmpty ( ) ; } ) ) ;
SortedPriorityQueues . Empty ( ) ;
}
}
2020-11-24 18:42:39 -04:00
FFileIoStoreReadRequest * FFileIoStoreRequestQueue : : Pop ( )
2020-09-01 14:07:48 -04:00
{
2021-05-27 13:40:37 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( RequestQueuePop ) ;
2020-11-24 18:42:39 -04:00
FScopeLock _ ( & CriticalSection ) ;
2021-05-27 13:40:37 -04:00
UpdateSortRequestsByOffset ( ) ;
FFileIoStoreReadRequest * Result = nullptr ;
if ( bSortRequestsByOffset )
2020-09-01 14:07:48 -04:00
{
2021-05-27 13:40:37 -04:00
if ( SortedPriorityQueues . Num ( ) = = 0 )
{
return nullptr ;
}
FFileIoStoreOffsetSortedRequestQueue & SubQueue = SortedPriorityQueues . Last ( ) ;
check ( ! SubQueue . IsEmpty ( ) ) ;
Result = SubQueue . Pop ( LastSortKey ) ;
check ( Result ) ;
LastSortKey = Result ;
if ( SubQueue . IsEmpty ( ) )
{
SortedPriorityQueues . Pop ( ) ;
// SubQueue is invalid here
2021-11-22 16:44:27 -05:00
# if UE_FILEIOSTORE_DETAILED_QUEUE_COUNTERS_ENABLED
2021-05-27 13:40:37 -04:00
TRACE_COUNTER_DECREMENT ( IoDispatcherNumPriorityQueues ) ;
2021-11-22 16:44:27 -05:00
# endif
2021-05-27 13:40:37 -04:00
}
2020-09-01 14:07:48 -04:00
}
2021-05-27 13:40:37 -04:00
else
{
if ( Heap . Num ( ) = = 0 )
{
return nullptr ;
}
Heap . HeapPop ( Result , QueueSortFunc , false ) ;
}
2021-04-29 19:32:06 -04:00
check ( Result - > QueueStatus = = FFileIoStoreReadRequest : : QueueStatus_InQueue ) ;
Result - > QueueStatus = FFileIoStoreReadRequest : : QueueStatus_Started ;
2020-11-24 18:42:39 -04:00
return Result ;
2020-09-01 14:07:48 -04:00
}
2021-05-27 13:40:37 -04:00
void FFileIoStoreRequestQueue : : PushToPriorityQueues ( FFileIoStoreReadRequest * Request )
2020-09-01 14:07:48 -04:00
{
2021-05-27 13:40:37 -04:00
int32 QueueIndex = Algo : : LowerBoundBy ( SortedPriorityQueues , Request - > Priority , QueuePriorityProjection , TLess < int32 > ( ) ) ;
if ( ! SortedPriorityQueues . IsValidIndex ( QueueIndex ) | | SortedPriorityQueues [ QueueIndex ] . GetPriority ( ) ! = Request - > Priority )
{
SortedPriorityQueues . Insert ( FFileIoStoreOffsetSortedRequestQueue ( Request - > Priority ) , QueueIndex ) ;
2021-11-22 16:44:27 -05:00
# if UE_FILEIOSTORE_DETAILED_QUEUE_COUNTERS_ENABLED
2021-05-27 13:40:37 -04:00
TRACE_COUNTER_INCREMENT ( IoDispatcherNumPriorityQueues ) ;
2021-11-22 16:44:27 -05:00
# endif
2021-05-27 13:40:37 -04:00
}
check ( Algo : : IsSortedBy ( SortedPriorityQueues , QueuePriorityProjection , TLess < int32 > ( ) ) ) ;
FFileIoStoreOffsetSortedRequestQueue & Queue = SortedPriorityQueues [ QueueIndex ] ;
check ( Queue . GetPriority ( ) = = Request - > Priority ) ;
Queue . Push ( Request ) ;
2020-11-24 18:42:39 -04:00
}
2021-05-27 13:40:37 -04:00
void FFileIoStoreRequestQueue : : Push ( FFileIoStoreReadRequest & Request )
2020-11-24 18:42:39 -04:00
{
2021-05-27 13:40:37 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( RequestQueuePush ) ;
2020-11-24 18:42:39 -04:00
FScopeLock _ ( & CriticalSection ) ;
2021-05-27 13:40:37 -04:00
UpdateSortRequestsByOffset ( ) ;
check ( Request . QueueStatus ! = FFileIoStoreReadRequest : : QueueStatus_InQueue ) ;
Request . QueueStatus = FFileIoStoreReadRequest : : QueueStatus_InQueue ;
2021-05-31 16:35:03 -04:00
2021-05-27 13:40:37 -04:00
if ( bSortRequestsByOffset )
2020-09-01 14:07:48 -04:00
{
2021-05-27 13:40:37 -04:00
PushToPriorityQueues ( & Request ) ;
}
else
{
Heap . HeapPush ( & Request , QueueSortFunc ) ;
}
}
void FFileIoStoreRequestQueue : : Push ( FFileIoStoreReadRequestList & Requests )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( RequestQueuePush ) ;
FScopeLock _ ( & CriticalSection ) ;
UpdateSortRequestsByOffset ( ) ;
for ( auto It = Requests . Steal ( ) ; It ; + + It )
{
check ( It - > QueueStatus ! = FFileIoStoreReadRequest : : QueueStatus_InQueue ) ;
It - > QueueStatus = FFileIoStoreReadRequest : : QueueStatus_InQueue ;
if ( bSortRequestsByOffset )
{
PushToPriorityQueues ( * It ) ;
}
else
{
Heap . HeapPush ( * It , QueueSortFunc ) ;
}
2020-09-01 14:07:48 -04:00
}
2020-11-24 18:42:39 -04:00
}
void FFileIoStoreRequestQueue : : UpdateOrder ( )
{
2020-12-11 14:21:20 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( RequestQueueUpdateOrder ) ;
2020-11-24 18:42:39 -04:00
FScopeLock _ ( & CriticalSection ) ;
2021-05-27 13:40:37 -04:00
UpdateSortRequestsByOffset ( ) ;
if ( bSortRequestsByOffset )
{
TArray < FFileIoStoreReadRequest * > Requests ;
for ( FFileIoStoreOffsetSortedRequestQueue & SubQueue : SortedPriorityQueues )
{
TArray < FFileIoStoreReadRequest * > RequestsRemoved = SubQueue . RemoveMisprioritizedRequests ( ) ;
Requests . Append ( RequestsRemoved ) ;
}
// Pop/Peek rely on empty queues being culled
SortedPriorityQueues . RemoveAll ( [ ] ( FFileIoStoreOffsetSortedRequestQueue & SubQueue ) { return SubQueue . IsEmpty ( ) ; } ) ;
Algo : : SortBy ( Requests , [ ] ( FFileIoStoreReadRequest * Request ) { return Request - > Sequence ; } ) ;
for ( FFileIoStoreReadRequest * Request : Requests )
{
PushToPriorityQueues ( Request ) ;
}
}
else
{
Heap . Heapify ( QueueSortFunc ) ;
}
2020-09-01 14:07:48 -04:00
}
2021-04-29 19:32:06 -04:00
void FFileIoStoreRequestQueue : : Lock ( )
{
CriticalSection . Lock ( ) ;
}
void FFileIoStoreRequestQueue : : Unlock ( )
{
CriticalSection . Unlock ( ) ;
}
void FFileIoStoreRequestQueue : : CancelRequestsWithFileHandle ( const uint64 FileHandle )
{
FScopeLock _ ( & CriticalSection ) ;
2021-10-12 21:21:22 -04:00
if ( bSortRequestsByOffset )
2021-04-29 19:32:06 -04:00
{
2021-10-12 21:21:22 -04:00
for ( FFileIoStoreOffsetSortedRequestQueue & SubQueue : SortedPriorityQueues )
2021-04-29 19:32:06 -04:00
{
2021-10-12 21:21:22 -04:00
SubQueue . CancelRequestsWithFileHandle ( FileHandle ) ;
}
}
else
{
for ( FFileIoStoreReadRequest * Request : Heap )
{
if ( Request - > FileHandle = = FileHandle )
{
Request - > bCancelled = true ;
}
2021-04-29 19:32:06 -04:00
}
}
}
2021-11-22 16:44:27 -05:00
FFileIoStoreReader : : FFileIoStoreReader ( IPlatformFileIoStore & InPlatformImpl , FFileIoStoreStats & InStats )
2019-12-13 11:07:03 -05:00
: PlatformImpl ( InPlatformImpl )
2021-11-22 16:44:27 -05:00
, Stats ( InStats )
2019-12-13 11:07:03 -05:00
{
}
2021-04-29 19:32:06 -04:00
FFileIoStoreReader : : ~ FFileIoStoreReader ( )
{
Close ( ) ;
}
2021-11-22 16:44:27 -05:00
uint64 FFileIoStoreReader : : GetTocAllocatedSize ( ) const
{
return TocImperfectHashMapFallback . GetAllocatedSize ( ) +
PerfectHashMap . TocOffsetAndLengths . GetAllocatedSize ( ) +
PerfectHashMap . TocChunkIds . GetAllocatedSize ( ) +
PerfectHashMap . TocChunkHashSeeds . GetAllocatedSize ( ) +
ContainerFile . CompressionBlocks . GetAllocatedSize ( ) +
ContainerFile . BlockSignatureHashes . GetAllocatedSize ( ) ;
}
2021-11-30 09:00:43 -05:00
FIoStatus FFileIoStoreReader : : Initialize ( const TCHAR * InTocFilePath , int32 InOrder )
2019-12-13 11:07:03 -05:00
{
2021-11-30 09:00:43 -05:00
FStringView ContainerPathView ( InTocFilePath ) ;
if ( ! ContainerPathView . EndsWith ( TEXT ( " .utoc " ) ) )
{
return FIoStatusBuilder ( EIoErrorCode : : FileOpenFailed ) < < TEXT ( " Expected .utoc extension on container path ' " ) < < InTocFilePath < < TEXT ( " ' " ) ;
}
FStringView BasePathView = ContainerPathView . LeftChop ( 5 ) ;
2022-01-26 19:09:35 -05:00
ContainerFile . FilePath = BasePathView ;
2021-11-30 09:00:43 -05:00
2019-12-13 11:07:03 -05:00
IPlatformFile & Ipf = FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) ;
2021-11-30 09:00:43 -05:00
UE_LOG ( LogIoDispatcher , Display , TEXT ( " Reading toc: %s " ) , InTocFilePath ) ;
2020-04-22 06:25:12 -04:00
2020-08-10 10:05:42 -04:00
TUniquePtr < FIoStoreTocResource > TocResourcePtr = MakeUnique < FIoStoreTocResource > ( ) ;
FIoStoreTocResource & TocResource = * TocResourcePtr ;
2021-11-30 09:00:43 -05:00
FIoStatus Status = FIoStoreTocResource : : Read ( InTocFilePath , EIoStoreTocReadOptions : : Default , TocResource ) ;
2020-04-22 06:25:12 -04:00
if ( ! Status . IsOk ( ) )
2019-12-13 11:07:03 -05:00
{
2020-04-22 06:25:12 -04:00
return Status ;
2019-12-13 11:07:03 -05:00
}
2021-01-08 19:56:07 -04:00
ContainerFile . PartitionSize = TocResource . Header . PartitionSize ;
ContainerFile . Partitions . SetNum ( TocResource . Header . PartitionCount ) ;
for ( uint32 PartitionIndex = 0 ; PartitionIndex < TocResource . Header . PartitionCount ; + + PartitionIndex )
{
FFileIoStoreContainerFilePartition & Partition = ContainerFile . Partitions [ PartitionIndex ] ;
TStringBuilder < 256 > ContainerFilePath ;
2021-11-30 09:00:43 -05:00
ContainerFilePath . Append ( BasePathView ) ;
2021-01-08 19:56:07 -04:00
if ( PartitionIndex > 0 )
{
ContainerFilePath . Appendf ( TEXT ( " _s%d " ) , PartitionIndex ) ;
}
ContainerFilePath . Append ( TEXT ( " .ucas " ) ) ;
Partition . FilePath = ContainerFilePath ;
if ( ! PlatformImpl . OpenContainer ( * ContainerFilePath , Partition . FileHandle , Partition . FileSize ) )
{
return FIoStatusBuilder ( EIoErrorCode : : FileOpenFailed ) < < TEXT ( " Failed to open IoStore container file ' " ) < < * ContainerFilePath < < TEXT ( " ' " ) ;
}
Partition . ContainerFileIndex = GlobalPartitionIndex + + ;
}
2019-12-13 11:07:03 -05:00
2021-11-07 23:43:01 -05:00
if ( GIoDispatcherTocsEnablePerfectHashing & & ! TocResource . ChunkPerfectHashSeeds . IsEmpty ( ) )
2019-12-13 11:07:03 -05:00
{
2021-10-12 21:21:22 -04:00
for ( int32 ChunkIndexWithoutPerfectHash : TocResource . ChunkIndicesWithoutPerfectHash )
{
TocImperfectHashMapFallback . Add ( TocResource . ChunkIds [ ChunkIndexWithoutPerfectHash ] , TocResource . ChunkOffsetLengths [ ChunkIndexWithoutPerfectHash ] ) ;
}
PerfectHashMap . TocChunkHashSeeds = MoveTemp ( TocResource . ChunkPerfectHashSeeds ) ;
2021-08-26 07:34:45 -04:00
PerfectHashMap . TocOffsetAndLengths = MoveTemp ( TocResource . ChunkOffsetLengths ) ;
2021-11-18 14:37:34 -05:00
PerfectHashMap . TocChunkIds = MoveTemp ( TocResource . ChunkIds ) ;
2021-08-26 07:34:45 -04:00
bHasPerfectHashMap = true ;
}
else
{
2021-11-30 09:00:43 -05:00
UE_LOG ( LogIoDispatcher , Warning , TEXT ( " Falling back to imperfect hashmap for container '%s' " ) , InTocFilePath ) ;
2021-08-26 07:34:45 -04:00
for ( uint32 ChunkIndex = 0 ; ChunkIndex < TocResource . Header . TocEntryCount ; + + ChunkIndex )
{
TocImperfectHashMapFallback . Add ( TocResource . ChunkIds [ ChunkIndex ] , TocResource . ChunkOffsetLengths [ ChunkIndex ] ) ;
}
bHasPerfectHashMap = false ;
2020-04-01 05:00:26 -04:00
}
2021-01-08 19:56:07 -04:00
2020-06-23 18:40:00 -04:00
ContainerFile . CompressionMethods = MoveTemp ( TocResource . CompressionMethods ) ;
ContainerFile . CompressionBlockSize = TocResource . Header . CompressionBlockSize ;
ContainerFile . CompressionBlocks = MoveTemp ( TocResource . CompressionBlocks ) ;
ContainerFile . ContainerFlags = TocResource . Header . ContainerFlags ;
ContainerFile . EncryptionKeyGuid = TocResource . Header . EncryptionKeyGuid ;
ContainerFile . BlockSignatureHashes = MoveTemp ( TocResource . ChunkBlockSignatures ) ;
2021-04-29 19:32:06 -04:00
ContainerFile . ContainerInstanceId = + + GlobalContainerInstanceId ;
2020-06-23 18:40:00 -04:00
2021-11-22 16:44:27 -05:00
Stats . OnTocMounted ( GetTocAllocatedSize ( ) ) ;
2021-08-26 07:34:45 -04:00
2021-11-30 09:00:54 -05:00
UE_LOG ( LogIoDispatcher , Display , TEXT ( " Toc signature hash: %s " ) , * TocResource . SignatureHash . ToString ( ) ) ;
2020-06-23 18:40:00 -04:00
ContainerId = TocResource . Header . ContainerId ;
2021-01-19 04:39:56 -04:00
Order = InOrder ;
2019-12-13 11:07:03 -05:00
return FIoStatus : : Ok ;
}
2021-04-29 19:32:06 -04:00
FIoStatus FFileIoStoreReader : : Close ( )
{
if ( bClosed )
{
return FIoStatus : : Ok ;
}
for ( FFileIoStoreContainerFilePartition & Partition : ContainerFile . Partitions )
{
PlatformImpl . CloseContainer ( Partition . FileHandle ) ;
}
2021-11-22 16:44:27 -05:00
Stats . OnTocUnmounted ( GetTocAllocatedSize ( ) ) ;
2021-08-26 07:34:45 -04:00
PerfectHashMap . TocChunkHashSeeds . Empty ( ) ;
2021-11-18 14:37:34 -05:00
PerfectHashMap . TocChunkIds . Empty ( ) ;
2021-08-26 07:34:45 -04:00
PerfectHashMap . TocOffsetAndLengths . Empty ( ) ;
TocImperfectHashMapFallback . Empty ( ) ;
2021-04-29 19:32:06 -04:00
ContainerFile = FFileIoStoreContainerFile ( ) ;
ContainerId = FIoContainerId ( ) ;
Order = INDEX_NONE ;
bClosed = true ;
return FIoStatus : : Ok ;
}
2021-08-26 07:34:45 -04:00
const FIoOffsetAndLength * FFileIoStoreReader : : FindChunkInternal ( const FIoChunkId & ChunkId ) const
{
if ( bHasPerfectHashMap )
{
// See FIoStoreWriterImpl::GeneratePerfectHashes
2021-11-18 14:37:34 -05:00
const uint32 ChunkCount = PerfectHashMap . TocChunkIds . Num ( ) ;
2021-08-26 07:34:45 -04:00
if ( ! ChunkCount )
{
return nullptr ;
}
2021-10-12 21:21:22 -04:00
const uint32 SeedCount = PerfectHashMap . TocChunkHashSeeds . Num ( ) ;
uint32 SeedIndex = FIoStoreTocResource : : HashChunkIdWithSeed ( 0 , ChunkId ) % SeedCount ;
2021-08-26 07:34:45 -04:00
const int32 Seed = PerfectHashMap . TocChunkHashSeeds [ SeedIndex ] ;
if ( Seed = = 0 )
{
return nullptr ;
}
uint32 Slot ;
if ( Seed < 0 )
{
2021-10-12 21:21:22 -04:00
uint32 SeedAsIndex = static_cast < uint32 > ( - Seed - 1 ) ;
if ( SeedAsIndex < ChunkCount )
{
Slot = static_cast < uint32 > ( SeedAsIndex ) ;
}
else
{
// Entry without perfect hash
return TocImperfectHashMapFallback . Find ( ChunkId ) ;
}
2021-08-26 07:34:45 -04:00
}
else
{
Slot = FIoStoreTocResource : : HashChunkIdWithSeed ( static_cast < uint32 > ( Seed ) , ChunkId ) % ChunkCount ;
}
2021-11-18 14:37:34 -05:00
if ( PerfectHashMap . TocChunkIds [ Slot ] = = ChunkId )
2021-08-26 07:34:45 -04:00
{
return & PerfectHashMap . TocOffsetAndLengths [ Slot ] ;
}
return nullptr ;
}
else
{
return TocImperfectHashMapFallback . Find ( ChunkId ) ;
}
}
2019-12-13 11:07:03 -05:00
bool FFileIoStoreReader : : DoesChunkExist ( const FIoChunkId & ChunkId ) const
{
2021-04-29 19:32:06 -04:00
check ( ! bClosed ) ;
2021-08-26 07:34:45 -04:00
return FindChunkInternal ( ChunkId ) ! = nullptr ;
2019-12-13 11:07:03 -05:00
}
TIoStatusOr < uint64 > FFileIoStoreReader : : GetSizeForChunk ( const FIoChunkId & ChunkId ) const
{
2021-04-29 19:32:06 -04:00
check ( ! bClosed ) ;
2021-08-26 07:34:45 -04:00
const FIoOffsetAndLength * OffsetAndLength = FindChunkInternal ( ChunkId ) ;
if ( OffsetAndLength )
2019-12-13 11:07:03 -05:00
{
return OffsetAndLength - > GetLength ( ) ;
}
else
{
return FIoStatus ( EIoErrorCode : : NotFound ) ;
}
}
2020-04-01 05:00:26 -04:00
const FIoOffsetAndLength * FFileIoStoreReader : : Resolve ( const FIoChunkId & ChunkId ) const
2019-12-13 11:07:03 -05:00
{
2021-04-29 19:32:06 -04:00
check ( ! bClosed ) ;
2021-08-26 07:34:45 -04:00
return FindChunkInternal ( ChunkId ) ;
2019-12-13 11:07:03 -05:00
}
2021-01-08 19:56:07 -04:00
IMappedFileHandle * FFileIoStoreReader : : GetMappedContainerFileHandle ( uint64 TocOffset )
2019-12-13 11:07:03 -05:00
{
2021-04-29 19:32:06 -04:00
check ( ! bClosed ) ;
2021-01-08 19:56:07 -04:00
int32 PartitionIndex = int32 ( TocOffset / ContainerFile . PartitionSize ) ;
FFileIoStoreContainerFilePartition & Partition = ContainerFile . Partitions [ PartitionIndex ] ;
if ( ! Partition . MappedFileHandle )
2020-04-01 05:00:26 -04:00
{
IPlatformFile & Ipf = FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) ;
2021-01-08 19:56:07 -04:00
Partition . MappedFileHandle . Reset ( Ipf . OpenMapped ( * Partition . FilePath ) ) ;
2020-04-01 05:00:26 -04:00
}
2021-01-08 19:56:07 -04:00
check ( Partition . FileSize > 0 ) ;
return new FMappedFileProxy ( Partition . MappedFileHandle . Get ( ) , Partition . FileSize ) ;
2020-04-01 05:00:26 -04:00
}
2021-09-28 04:00:33 -04:00
TIoStatusOr < FIoContainerHeader > FFileIoStoreReader : : ReadContainerHeader ( ) const
{
LLM_SCOPE ( ELLMTag : : AsyncLoading ) ;
TRACE_CPUPROFILER_EVENT_SCOPE ( ReadContainerHeader ) ;
FIoChunkId HeaderChunkId = CreateIoChunkId ( ContainerId . Value ( ) , 0 , EIoChunkType : : ContainerHeader ) ;
const FIoOffsetAndLength * OffsetAndLength = FindChunkInternal ( HeaderChunkId ) ;
if ( ! OffsetAndLength )
{
2021-12-16 19:09:32 -05:00
return FIoStatus ( FIoStatusBuilder ( EIoErrorCode : : NotFound ) < < TEXT ( " Container header chunk not found " ) ) ;
2021-09-28 04:00:33 -04:00
}
const uint64 CompressionBlockSize = ContainerFile . CompressionBlockSize ;
const uint64 Offset = OffsetAndLength - > GetOffset ( ) ;
const uint64 Size = OffsetAndLength - > GetLength ( ) ;
const uint64 RequestEndOffset = Offset + Size ;
const int32 RequestBeginBlockIndex = int32 ( Offset / CompressionBlockSize ) ;
const int32 RequestEndBlockIndex = int32 ( ( RequestEndOffset - 1 ) / CompressionBlockSize ) ;
// Assumes that the container header is uncompressed and placed in its own blocks in the same partition without padding
const FIoStoreTocCompressedBlockEntry * CompressionBlockEntry = & ContainerFile . CompressionBlocks [ RequestBeginBlockIndex ] ;
const int32 PartitionIndex = int32 ( CompressionBlockEntry - > GetOffset ( ) / ContainerFile . PartitionSize ) ;
const FFileIoStoreContainerFilePartition & Partition = ContainerFile . Partitions [ PartitionIndex ] ;
const uint64 RawOffset = CompressionBlockEntry - > GetOffset ( ) % ContainerFile . PartitionSize ;
2022-01-10 13:43:28 -05:00
# if !UE_BUILD_SHIPPING
2022-01-28 13:51:28 -05:00
// Check for flag - compressed containers still have CompressionBlockSize != 0 and CompressionMethod "None".
if ( EnumHasAnyFlags ( ContainerFile . ContainerFlags , EIoContainerFlags : : Compressed ) )
{
FileCache_PostIoStoreCompressionBlockSize ( CompressionBlockSize , Partition . FilePath ) ;
}
2022-01-10 13:43:28 -05:00
# endif
2021-09-28 04:00:33 -04:00
FIoBuffer IoBuffer ( Align ( Size , FAES : : AESBlockSize ) ) ;
IPlatformFile & Ipf = FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) ;
TUniquePtr < IFileHandle > ContainerFileHandle ( Ipf . OpenRead ( * Partition . FilePath ) ) ;
if ( ! ContainerFileHandle )
{
2021-12-16 19:09:32 -05:00
return FIoStatus ( FIoStatusBuilder ( EIoErrorCode : : FileOpenFailed ) < < TEXT ( " Failed to open container file " ) < < Partition . FilePath ) ;
2021-09-28 04:00:33 -04:00
}
{
TRACE_CPUPROFILER_EVENT_SCOPE ( ReadFromContainerFile ) ;
if ( ! ContainerFileHandle - > Seek ( RawOffset ) )
{
2021-12-16 19:09:32 -05:00
return FIoStatus ( FIoStatusBuilder ( EIoErrorCode : : ReadError ) < < FString : : Printf ( TEXT ( " Failed seeking to offset %llu in container file " ) , RawOffset ) ) ;
2021-09-28 04:00:33 -04:00
}
if ( ! ContainerFileHandle - > Read ( IoBuffer . Data ( ) , IoBuffer . DataSize ( ) ) )
{
2021-12-16 19:09:32 -05:00
return FIoStatus ( FIoStatusBuilder ( EIoErrorCode : : ReadError ) < < FString : : Printf ( TEXT ( " Failed reading %llu bytes at offset %llu " ) , IoBuffer . DataSize ( ) , RawOffset ) ) ;
2021-09-28 04:00:33 -04:00
}
}
const bool bSigned = EnumHasAnyFlags ( ContainerFile . ContainerFlags , EIoContainerFlags : : Signed ) ;
const bool bEncrypted = ContainerFile . EncryptionKey . IsValid ( ) ;
if ( bSigned | | bEncrypted )
{
uint8 * BlockData = IoBuffer . Data ( ) ;
for ( int32 CompressedBlockIndex = RequestBeginBlockIndex ; CompressedBlockIndex < = RequestEndBlockIndex ; + + CompressedBlockIndex )
{
CompressionBlockEntry = & ContainerFile . CompressionBlocks [ CompressedBlockIndex ] ;
check ( ContainerFile . CompressionMethods [ CompressionBlockEntry - > GetCompressionMethodIndex ( ) ] . IsNone ( ) ) ;
const uint64 BlockSize = Align ( CompressionBlockEntry - > GetCompressedSize ( ) , FAES : : AESBlockSize ) ;
if ( bSigned )
{
const FSHAHash & SignatureHash = ContainerFile . BlockSignatureHashes [ CompressedBlockIndex ] ;
FSHAHash BlockHash ;
FSHA1 : : HashBuffer ( BlockData , BlockSize , BlockHash . Hash ) ;
if ( SignatureHash ! = BlockHash )
{
2021-12-16 19:09:32 -05:00
return FIoStatus ( FIoStatusBuilder ( EIoErrorCode : : SignatureError ) < < TEXT ( " Signature error detected when reading container header " ) ) ;
2021-09-28 04:00:33 -04:00
}
}
if ( bEncrypted )
{
FAES : : DecryptData ( BlockData , uint32 ( BlockSize ) , ContainerFile . EncryptionKey ) ;
}
BlockData + = BlockSize ;
}
}
FMemoryReaderView Ar ( MakeArrayView ( IoBuffer . Data ( ) , static_cast < int32 > ( IoBuffer . DataSize ( ) ) ) ) ;
FIoContainerHeader ContainerHeader ;
Ar < < ContainerHeader ;
2021-10-12 21:21:22 -04:00
if ( Ar . IsError ( ) )
{
UE_LOG ( LogIoDispatcher , Warning , TEXT ( " Invalid container header in file '%s' " ) , * ContainerFile . FilePath ) ;
ContainerHeader = FIoContainerHeader ( ) ;
}
2021-09-28 04:00:33 -04:00
return ContainerHeader ;
}
2021-11-07 23:43:01 -05:00
void FFileIoStoreReader : : ReopenAllFileHandles ( )
{
for ( FFileIoStoreContainerFilePartition & Partition : ContainerFile . Partitions )
{
PlatformImpl . CloseContainer ( Partition . FileHandle ) ;
PlatformImpl . OpenContainer ( * Partition . FilePath , Partition . FileHandle , Partition . FileSize ) ;
}
}
2020-12-11 14:21:20 -04:00
FFileIoStoreResolvedRequest : : FFileIoStoreResolvedRequest (
FIoRequestImpl & InDispatcherRequest ,
const FFileIoStoreContainerFile & InContainerFile ,
uint64 InResolvedOffset ,
uint64 InResolvedSize )
2021-04-29 19:32:06 -04:00
: DispatcherRequest ( & InDispatcherRequest )
2020-12-11 14:21:20 -04:00
, ContainerFile ( InContainerFile )
, ResolvedOffset ( InResolvedOffset )
, ResolvedSize ( InResolvedSize )
{
}
2021-01-08 19:56:07 -04:00
void FFileIoStoreResolvedRequest : : AddReadRequestLink ( FFileIoStoreReadRequestLink * ReadRequestLink )
2020-12-11 14:21:20 -04:00
{
2021-01-08 19:56:07 -04:00
check ( ! ReadRequestLink - > Next ) ;
2020-12-11 14:21:20 -04:00
if ( ReadRequestsTail )
{
2021-01-08 19:56:07 -04:00
ReadRequestsTail - > Next = ReadRequestLink ;
2020-12-11 14:21:20 -04:00
}
else
{
2021-01-08 19:56:07 -04:00
ReadRequestsHead = ReadRequestLink ;
2020-12-11 14:21:20 -04:00
}
2021-01-08 19:56:07 -04:00
ReadRequestsTail = ReadRequestLink ;
2020-12-11 14:21:20 -04:00
}
FFileIoStoreRequestTracker : : FFileIoStoreRequestTracker ( FFileIoStoreRequestAllocator & InRequestAllocator , FFileIoStoreRequestQueue & InRequestQueue )
: RequestAllocator ( InRequestAllocator )
, RequestQueue ( InRequestQueue )
{
}
FFileIoStoreRequestTracker : : ~ FFileIoStoreRequestTracker ( )
{
}
FFileIoStoreCompressedBlock * FFileIoStoreRequestTracker : : FindOrAddCompressedBlock ( FFileIoStoreBlockKey Key , bool & bOutWasAdded )
{
bOutWasAdded = false ;
FFileIoStoreCompressedBlock * & Result = CompressedBlocksMap . FindOrAdd ( Key ) ;
if ( ! Result )
{
Result = RequestAllocator . AllocCompressedBlock ( ) ;
Result - > Key = Key ;
bOutWasAdded = true ;
}
return Result ;
}
FFileIoStoreReadRequest * FFileIoStoreRequestTracker : : FindOrAddRawBlock ( FFileIoStoreBlockKey Key , bool & bOutWasAdded )
{
bOutWasAdded = false ;
FFileIoStoreReadRequest * & Result = RawBlocksMap . FindOrAdd ( Key ) ;
if ( ! Result )
{
Result = RequestAllocator . AllocReadRequest ( ) ;
Result - > Key = Key ;
bOutWasAdded = true ;
}
return Result ;
}
void FFileIoStoreRequestTracker : : RemoveRawBlock ( const FFileIoStoreReadRequest * RawBlock )
{
if ( ! RawBlock - > bCancelled )
{
RawBlocksMap . Remove ( RawBlock - > Key ) ;
}
}
void FFileIoStoreRequestTracker : : AddReadRequestsToResolvedRequest ( FFileIoStoreCompressedBlock * CompressedBlock , FFileIoStoreResolvedRequest & ResolvedRequest )
{
//TRACE_CPUPROFILER_EVENT_SCOPE(AddReadRequestsToResolvedRequest);
bool bUpdateQueueOrder = false ;
+ + ResolvedRequest . UnfinishedReadsCount ;
for ( FFileIoStoreReadRequest * ReadRequest : CompressedBlock - > RawBlocks )
{
2021-01-08 19:56:07 -04:00
FFileIoStoreReadRequestLink * Link = RequestAllocator . AllocRequestLink ( ReadRequest ) ;
+ + ReadRequest - > RefCount ;
ResolvedRequest . AddReadRequestLink ( Link ) ;
2020-12-11 14:21:20 -04:00
if ( ResolvedRequest . GetPriority ( ) > ReadRequest - > Priority )
{
ReadRequest - > Priority = ResolvedRequest . GetPriority ( ) ;
bUpdateQueueOrder = true ;
}
}
if ( bUpdateQueueOrder )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( RequestTrackerAddIoRequestUpdateOrder ) ;
RequestQueue . UpdateOrder ( ) ;
}
}
void FFileIoStoreRequestTracker : : AddReadRequestsToResolvedRequest ( const FFileIoStoreReadRequestList & Requests , FFileIoStoreResolvedRequest & ResolvedRequest )
{
2021-01-08 19:56:07 -04:00
//TRACE_CPUPROFILER_EVENT_SCOPE(RequestTrackerAddIoRequest);
2021-05-27 13:40:37 -04:00
for ( FFileIoStoreReadRequest * Request : Requests )
2020-12-11 14:21:20 -04:00
{
+ + ResolvedRequest . UnfinishedReadsCount ;
2021-05-27 13:40:37 -04:00
FFileIoStoreReadRequestLink * Link = RequestAllocator . AllocRequestLink ( Request ) ;
+ + Request - > RefCount ;
2021-01-08 19:56:07 -04:00
ResolvedRequest . AddReadRequestLink ( Link ) ;
2021-05-27 13:40:37 -04:00
check ( ResolvedRequest . GetPriority ( ) = = Request - > Priority ) ;
2020-12-11 14:21:20 -04:00
}
}
void FFileIoStoreRequestTracker : : RemoveCompressedBlock ( const FFileIoStoreCompressedBlock * CompressedBlock )
{
if ( ! CompressedBlock - > bCancelled )
{
CompressedBlocksMap . Remove ( CompressedBlock - > Key ) ;
}
}
2021-04-29 19:32:06 -04:00
bool FFileIoStoreRequestTracker : : CancelIoRequest ( FFileIoStoreResolvedRequest & ResolvedRequest )
2020-12-11 14:21:20 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( RequestTrackerCancelIoRequest ) ;
2021-04-29 19:32:06 -04:00
check ( ! ResolvedRequest . bCancelled ) ;
bool bShouldComplete = true ;
RequestQueue . Lock ( ) ;
2021-01-08 19:56:07 -04:00
FFileIoStoreReadRequestLink * Link = ResolvedRequest . ReadRequestsHead ;
2020-12-11 14:21:20 -04:00
while ( Link )
{
2021-01-08 19:56:07 -04:00
FFileIoStoreReadRequest & ReadRequest = Link - > ReadRequest ;
2020-12-11 14:21:20 -04:00
Link = Link - > Next ;
2021-04-29 19:32:06 -04:00
if ( ReadRequest . bCancelled )
{
continue ;
}
if ( ReadRequest . QueueStatus = = FFileIoStoreReadRequest : : QueueStatus_Started )
{
bShouldComplete = false ;
continue ;
}
2020-12-11 14:21:20 -04:00
bool bCancelReadRequest = true ;
2021-01-08 19:56:07 -04:00
for ( FFileIoStoreCompressedBlock * CompressedBlock : ReadRequest . CompressedBlocks )
2020-12-11 14:21:20 -04:00
{
2021-04-29 19:32:06 -04:00
if ( CompressedBlock - > bCancelled )
{
continue ;
}
2020-12-11 14:21:20 -04:00
bool bCancelCompressedBlock = true ;
for ( FFileIoStoreBlockScatter & Scatter : CompressedBlock - > ScatterList )
{
if ( Scatter . Size > 0 & & Scatter . Request ! = & ResolvedRequest )
{
bCancelCompressedBlock = false ;
bCancelReadRequest = false ;
}
2021-04-29 19:32:06 -04:00
else
{
Scatter . Size = 0 ;
}
2020-12-11 14:21:20 -04:00
}
if ( bCancelCompressedBlock )
{
CompressedBlock - > bCancelled = true ;
CompressedBlocksMap . Remove ( CompressedBlock - > Key ) ;
}
}
if ( bCancelReadRequest )
{
2021-01-08 19:56:07 -04:00
if ( ! ReadRequest . ImmediateScatter . Request )
2020-12-11 14:21:20 -04:00
{
2021-01-08 19:56:07 -04:00
RawBlocksMap . Remove ( ReadRequest . Key ) ;
2020-12-11 14:21:20 -04:00
}
2021-01-08 19:56:07 -04:00
ReadRequest . bCancelled = true ;
2021-04-29 19:32:06 -04:00
# if DO_CHECK
for ( FFileIoStoreCompressedBlock * CompressedBlock : ReadRequest . CompressedBlocks )
2020-12-11 14:21:20 -04:00
{
2021-04-29 19:32:06 -04:00
check ( CompressedBlock - > bCancelled ) ;
for ( FFileIoStoreBlockScatter & Scatter : CompressedBlock - > ScatterList )
{
check ( ! Scatter . Request - > DispatcherRequest | | Scatter . Request - > DispatcherRequest - > IsCancelled ( ) ) ;
}
2020-12-11 14:21:20 -04:00
}
2021-04-29 19:32:06 -04:00
# endif
2020-12-11 14:21:20 -04:00
}
}
2021-04-29 19:32:06 -04:00
RequestQueue . Unlock ( ) ;
return bShouldComplete ;
2020-12-11 14:21:20 -04:00
}
void FFileIoStoreRequestTracker : : UpdatePriorityForIoRequest ( FFileIoStoreResolvedRequest & ResolvedRequest )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( RequestTrackerUpdatePriorityForIoRequest ) ;
bool bUpdateOrder = false ;
2021-01-08 19:56:07 -04:00
FFileIoStoreReadRequestLink * Link = ResolvedRequest . ReadRequestsHead ;
2020-12-11 14:21:20 -04:00
while ( Link )
{
2021-01-08 19:56:07 -04:00
FFileIoStoreReadRequest & ReadRequest = Link - > ReadRequest ;
2020-12-11 14:21:20 -04:00
Link = Link - > Next ;
2021-01-08 19:56:07 -04:00
if ( ResolvedRequest . GetPriority ( ) > ReadRequest . Priority )
2020-12-11 14:21:20 -04:00
{
2021-01-08 19:56:07 -04:00
ReadRequest . Priority = ResolvedRequest . GetPriority ( ) ;
2020-12-11 14:21:20 -04:00
bUpdateOrder = true ;
}
}
if ( bUpdateOrder )
{
RequestQueue . UpdateOrder ( ) ;
}
}
2021-01-08 19:56:07 -04:00
void FFileIoStoreRequestTracker : : ReleaseIoRequestReferences ( FFileIoStoreResolvedRequest & ResolvedRequest )
{
FFileIoStoreReadRequestLink * Link = ResolvedRequest . ReadRequestsHead ;
while ( Link )
{
FFileIoStoreReadRequestLink * Next = Link - > Next ;
check ( Link - > ReadRequest . RefCount > 0 ) ;
if ( - - Link - > ReadRequest . RefCount = = 0 )
{
for ( FFileIoStoreCompressedBlock * CompressedBlock : Link - > ReadRequest . CompressedBlocks )
{
check ( CompressedBlock - > RefCount > 0 ) ;
if ( - - CompressedBlock - > RefCount = = 0 )
{
RequestAllocator . Free ( CompressedBlock ) ;
}
}
RequestAllocator . Free ( & Link - > ReadRequest ) ;
}
RequestAllocator . Free ( Link ) ;
Link = Next ;
}
ResolvedRequest . ReadRequestsHead = nullptr ;
ResolvedRequest . ReadRequestsTail = nullptr ;
2021-04-29 19:32:06 -04:00
RequestAllocator . Free ( & ResolvedRequest ) ;
2021-01-08 19:56:07 -04:00
}
2021-11-07 23:43:01 -05:00
int64 FFileIoStoreRequestTracker : : GetLiveReadRequestsCount ( ) const
{
return RequestAllocator . GetLiveReadRequestsCount ( ) ;
}
2021-09-15 02:54:32 -04:00
FFileIoStore : : FFileIoStore ( TUniquePtr < IPlatformFileIoStore > & & InPlatformImpl )
2021-11-22 16:44:27 -05:00
: BlockCache ( Stats )
, BufferAllocator ( Stats )
, RequestTracker ( RequestAllocator , RequestQueue )
2021-09-15 02:54:32 -04:00
, PlatformImpl ( MoveTemp ( InPlatformImpl ) )
2020-04-01 05:00:26 -04:00
{
}
FFileIoStore : : ~ FFileIoStore ( )
{
delete Thread ;
2020-09-01 14:07:48 -04:00
}
2021-01-19 04:39:56 -04:00
void FFileIoStore : : Initialize ( TSharedRef < const FIoDispatcherBackendContext > InContext )
2020-09-01 14:07:48 -04:00
{
2021-01-19 04:39:56 -04:00
check ( ! Thread ) ;
2021-06-22 00:27:54 -04:00
2021-01-19 04:39:56 -04:00
BackendContext = InContext ;
bIsMultithreaded = InContext - > bIsMultiThreaded ;
2020-09-01 14:07:48 -04:00
ReadBufferSize = ( GIoDispatcherBufferSizeKB > 0 ? uint64 ( GIoDispatcherBufferSizeKB ) < < 10 : 256 < < 10 ) ;
uint64 BufferMemorySize = uint64 ( GIoDispatcherBufferMemoryMB ) < < 20ull ;
uint64 BufferSize = uint64 ( GIoDispatcherBufferSizeKB ) < < 10ull ;
uint32 BufferAlignment = uint32 ( GIoDispatcherBufferAlignment ) ;
BufferAllocator . Initialize ( BufferMemorySize , BufferSize , BufferAlignment ) ;
uint64 CacheMemorySize = uint64 ( GIoDispatcherCacheSizeMB ) < < 20ull ;
BlockCache . Initialize ( CacheMemorySize , BufferSize ) ;
2021-09-15 02:54:32 -04:00
PlatformImpl - > Initialize ( {
& BackendContext - > WakeUpDispatcherThreadDelegate ,
& RequestAllocator ,
& BufferAllocator ,
2021-11-22 16:44:27 -05:00
& BlockCache ,
& Stats
2021-09-15 02:54:32 -04:00
} ) ;
2021-01-19 04:39:56 -04:00
2020-09-01 14:07:48 -04:00
uint64 DecompressionContextCount = uint64 ( GIoDispatcherDecompressionWorkerCount > 0 ? GIoDispatcherDecompressionWorkerCount : 4 ) ;
for ( uint64 ContextIndex = 0 ; ContextIndex < DecompressionContextCount ; + + ContextIndex )
{
FFileIoStoreCompressionContext * Context = new FFileIoStoreCompressionContext ( ) ;
Context - > Next = FirstFreeCompressionContext ;
FirstFreeCompressionContext = Context ;
}
Thread = FRunnableThread : : Create ( this , TEXT ( " IoService " ) , 0 , TPri_AboveNormal ) ;
2019-12-13 11:07:03 -05:00
}
2021-11-30 09:00:43 -05:00
TIoStatusOr < FIoContainerHeader > FFileIoStore : : Mount ( const TCHAR * InTocPath , int32 Order , const FGuid & EncryptionKeyGuid , const FAES : : FAESKey & EncryptionKey )
2019-12-13 11:07:03 -05:00
{
2021-11-22 16:44:27 -05:00
TUniquePtr < FFileIoStoreReader > Reader ( new FFileIoStoreReader ( * PlatformImpl , Stats ) ) ;
2021-11-30 09:00:43 -05:00
FIoStatus IoStatus = Reader - > Initialize ( InTocPath , Order ) ;
2020-04-22 06:25:12 -04:00
if ( ! IoStatus . IsOk ( ) )
{
return IoStatus ;
}
2020-05-05 03:49:22 -04:00
if ( Reader - > IsEncrypted ( ) )
{
2020-10-29 13:38:15 -04:00
if ( Reader - > GetEncryptionKeyGuid ( ) = = EncryptionKeyGuid & & EncryptionKey . IsValid ( ) )
2020-05-05 03:49:22 -04:00
{
Reader - > SetEncryptionKey ( EncryptionKey ) ;
}
else
{
2020-10-29 13:38:15 -04:00
return FIoStatus ( EIoErrorCode : : InvalidEncryptionKey , * FString : : Printf ( TEXT ( " Invalid encryption key '%s' (container '%s', encryption key '%s') " ) ,
2021-11-30 09:00:43 -05:00
* EncryptionKeyGuid . ToString ( ) , InTocPath , * Reader - > GetEncryptionKeyGuid ( ) . ToString ( ) ) ) ;
2020-05-05 03:49:22 -04:00
}
}
2021-09-28 04:00:33 -04:00
TIoStatusOr < FIoContainerHeader > ContainerHeaderReadResult = Reader - > ReadContainerHeader ( ) ;
FIoContainerHeader ContainerHeader ;
if ( ContainerHeaderReadResult . IsOk ( ) )
{
ContainerHeader = ContainerHeaderReadResult . ConsumeValueOrDie ( ) ;
}
else if ( EIoErrorCode : : NotFound ! = ContainerHeaderReadResult . Status ( ) . GetErrorCode ( ) )
{
return ContainerHeaderReadResult ;
}
2020-04-22 06:25:12 -04:00
int32 InsertionIndex ;
2019-12-13 11:07:03 -05:00
{
FWriteScopeLock _ ( IoStoreReadersLock ) ;
2021-04-29 19:32:06 -04:00
InsertionIndex = Algo : : UpperBound ( IoStoreReaders , Reader , [ ] ( const TUniquePtr < FFileIoStoreReader > & A , const TUniquePtr < FFileIoStoreReader > & B )
2020-04-22 06:25:12 -04:00
{
if ( A - > GetOrder ( ) ! = B - > GetOrder ( ) )
{
return A - > GetOrder ( ) > B - > GetOrder ( ) ;
}
2021-04-29 19:32:06 -04:00
return A - > GetContainerInstanceId ( ) > B - > GetContainerInstanceId ( ) ;
2020-04-22 06:25:12 -04:00
} ) ;
2021-04-29 19:32:06 -04:00
IoStoreReaders . Insert ( MoveTemp ( Reader ) , InsertionIndex ) ;
2021-11-30 09:00:43 -05:00
UE_LOG ( LogIoDispatcher , Display , TEXT ( " Mounting container '%s' in location slot %d " ) , InTocPath , InsertionIndex ) ;
2021-01-19 04:39:56 -04:00
}
2021-09-28 04:00:33 -04:00
return ContainerHeader ;
2019-12-13 11:07:03 -05:00
}
2021-11-30 09:00:43 -05:00
bool FFileIoStore : : Unmount ( const TCHAR * InTocPath )
2021-04-29 19:32:06 -04:00
{
FWriteScopeLock _ ( IoStoreReadersLock ) ;
for ( int32 Idx = 0 ; Idx < IoStoreReaders . Num ( ) ; + + Idx )
{
2021-11-30 09:00:43 -05:00
if ( IoStoreReaders [ Idx ] - > GetContainerFile ( ) . FilePath = = InTocPath )
2021-04-29 19:32:06 -04:00
{
2021-11-30 09:00:43 -05:00
UE_LOG ( LogIoDispatcher , Display , TEXT ( " Unmounting container '%s' " ) , InTocPath ) ;
2021-04-29 19:32:06 -04:00
// Cancel pending I/O requests trying to read from the container
for ( const FFileIoStoreContainerFilePartition & Partition : IoStoreReaders [ Idx ] - > GetContainerFile ( ) . Partitions )
{
RequestQueue . CancelRequestsWithFileHandle ( Partition . FileHandle ) ;
}
FIoContainerId ContainerId = IoStoreReaders [ Idx ] - > GetContainerId ( ) ;
IoStoreReaders . RemoveAt ( Idx ) ;
2021-09-28 04:00:33 -04:00
return true ;
2021-04-29 19:32:06 -04:00
}
}
2021-11-30 09:00:43 -05:00
UE_LOG ( LogIoDispatcher , Display , TEXT ( " Failed to unmount container '%s' " ) , InTocPath ) ;
2021-04-29 19:32:06 -04:00
2021-09-28 04:00:33 -04:00
return false ;
2021-04-29 19:32:06 -04:00
}
2021-01-19 04:39:56 -04:00
bool FFileIoStore : : Resolve ( FIoRequestImpl * Request )
2019-12-13 11:07:03 -05:00
{
FReadScopeLock _ ( IoStoreReadersLock ) ;
2021-04-29 19:32:06 -04:00
for ( const TUniquePtr < FFileIoStoreReader > & Reader : IoStoreReaders )
2019-12-13 11:07:03 -05:00
{
2020-12-11 14:21:20 -04:00
if ( const FIoOffsetAndLength * OffsetAndLength = Reader - > Resolve ( Request - > ChunkId ) )
2019-12-13 11:07:03 -05:00
{
2020-12-11 14:21:20 -04:00
uint64 RequestedOffset = Request - > Options . GetOffset ( ) ;
uint64 ResolvedOffset = OffsetAndLength - > GetOffset ( ) + RequestedOffset ;
uint64 ResolvedSize = 0 ;
if ( RequestedOffset < = OffsetAndLength - > GetLength ( ) )
2020-04-01 05:00:26 -04:00
{
2020-12-11 14:21:20 -04:00
ResolvedSize = FMath : : Min ( Request - > Options . GetSize ( ) , OffsetAndLength - > GetLength ( ) - RequestedOffset ) ;
2020-04-01 05:00:26 -04:00
}
2021-01-08 19:56:07 -04:00
FFileIoStoreResolvedRequest * ResolvedRequest = RequestAllocator . AllocResolvedRequest (
2020-12-11 14:21:20 -04:00
* Request ,
Reader - > GetContainerFile ( ) ,
ResolvedOffset ,
ResolvedSize ) ;
Request - > BackendData = ResolvedRequest ;
if ( ResolvedSize > 0 )
2019-12-13 11:07:03 -05:00
{
2020-09-01 14:07:48 -04:00
FFileIoStoreReadRequestList CustomRequests ;
2021-09-15 02:54:32 -04:00
if ( PlatformImpl - > CreateCustomRequests ( * ResolvedRequest , CustomRequests ) )
2020-09-01 14:07:48 -04:00
{
2021-11-22 16:44:27 -05:00
Stats . OnReadRequestsQueued ( CustomRequests ) ;
2020-12-11 14:21:20 -04:00
RequestTracker . AddReadRequestsToResolvedRequest ( CustomRequests , * ResolvedRequest ) ;
2020-11-24 18:42:39 -04:00
RequestQueue . Push ( CustomRequests ) ;
2020-09-01 14:07:48 -04:00
OnNewPendingRequestsAdded ( ) ;
}
else
{
2020-12-11 14:21:20 -04:00
ReadBlocks ( * ResolvedRequest ) ;
2020-09-01 14:07:48 -04:00
}
2019-12-13 11:07:03 -05:00
}
2020-12-11 14:21:20 -04:00
else
{
// Nothing to read
CompleteDispatcherRequest ( ResolvedRequest ) ;
2021-04-29 19:32:06 -04:00
RequestTracker . ReleaseIoRequestReferences ( * ResolvedRequest ) ;
2020-12-11 14:21:20 -04:00
}
2019-12-13 11:07:03 -05:00
2021-01-19 04:39:56 -04:00
return true ;
2019-12-13 11:07:03 -05:00
}
}
2021-01-19 04:39:56 -04:00
return false ;
2019-12-13 11:07:03 -05:00
}
2020-12-11 14:21:20 -04:00
void FFileIoStore : : CancelIoRequest ( FIoRequestImpl * Request )
{
if ( Request - > BackendData )
{
FFileIoStoreResolvedRequest * ResolvedRequest = static_cast < FFileIoStoreResolvedRequest * > ( Request - > BackendData ) ;
2021-04-29 19:32:06 -04:00
bool bShouldComplete = RequestTracker . CancelIoRequest ( * ResolvedRequest ) ;
if ( bShouldComplete )
{
ResolvedRequest - > bCancelled = true ;
CompleteDispatcherRequest ( ResolvedRequest ) ;
}
2020-12-11 14:21:20 -04:00
}
}
void FFileIoStore : : UpdatePriorityForIoRequest ( FIoRequestImpl * Request )
{
if ( Request - > BackendData )
{
FFileIoStoreResolvedRequest * ResolvedRequest = static_cast < FFileIoStoreResolvedRequest * > ( Request - > BackendData ) ;
RequestTracker . UpdatePriorityForIoRequest ( * ResolvedRequest ) ;
}
}
2019-12-13 11:07:03 -05:00
bool FFileIoStore : : DoesChunkExist ( const FIoChunkId & ChunkId ) const
{
FReadScopeLock _ ( IoStoreReadersLock ) ;
2021-04-29 19:32:06 -04:00
for ( const TUniquePtr < FFileIoStoreReader > & Reader : IoStoreReaders )
2019-12-13 11:07:03 -05:00
{
if ( Reader - > DoesChunkExist ( ChunkId ) )
{
return true ;
}
}
return false ;
}
TIoStatusOr < uint64 > FFileIoStore : : GetSizeForChunk ( const FIoChunkId & ChunkId ) const
{
FReadScopeLock _ ( IoStoreReadersLock ) ;
2021-04-29 19:32:06 -04:00
for ( const TUniquePtr < FFileIoStoreReader > & Reader : IoStoreReaders )
2019-12-13 11:07:03 -05:00
{
TIoStatusOr < uint64 > ReaderResult = Reader - > GetSizeForChunk ( ChunkId ) ;
if ( ReaderResult . IsOk ( ) )
{
return ReaderResult ;
}
}
return FIoStatus ( EIoErrorCode : : NotFound ) ;
}
2020-04-01 05:00:26 -04:00
FAutoConsoleTaskPriority CPrio_IoDispatcherTaskPriority (
TEXT ( " TaskGraph.TaskPriorities.IoDispatcherAsyncTasks " ) ,
TEXT ( " Task and thread priority for IoDispatcher decompression. " ) ,
ENamedThreads : : BackgroundThreadPriority , // if we have background priority task threads, then use them...
ENamedThreads : : NormalTaskPriority , // .. at normal task priority
ENamedThreads : : NormalTaskPriority // if we don't have background threads, then use normal priority threads at normal task priority instead
) ;
ENamedThreads : : Type FFileIoStore : : FDecompressAsyncTask : : GetDesiredThread ( )
2019-12-13 11:07:03 -05:00
{
2020-04-01 05:00:26 -04:00
return CPrio_IoDispatcherTaskPriority . Get ( ) ;
}
void FFileIoStore : : ScatterBlock ( FFileIoStoreCompressedBlock * CompressedBlock , bool bIsAsync )
{
2020-06-23 18:40:00 -04:00
LLM_SCOPE ( ELLMTag : : FileSystem ) ;
2020-04-01 05:00:26 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( IoDispatcherScatter ) ;
2020-12-11 14:21:20 -04:00
check ( ! CompressedBlock - > bFailed ) ;
2020-04-01 05:00:26 -04:00
FFileIoStoreCompressionContext * CompressionContext = CompressedBlock - > CompressionContext ;
check ( CompressionContext ) ;
uint8 * CompressedBuffer ;
2020-11-24 18:42:39 -04:00
if ( CompressedBlock - > RawBlocks . Num ( ) > 1 )
2019-12-13 11:07:03 -05:00
{
2020-04-01 05:00:26 -04:00
check ( CompressedBlock - > CompressedDataBuffer ) ;
CompressedBuffer = CompressedBlock - > CompressedDataBuffer ;
2020-01-28 06:54:05 -05:00
}
2020-04-01 05:00:26 -04:00
else
2020-01-28 06:54:05 -05:00
{
2020-11-24 18:42:39 -04:00
FFileIoStoreReadRequest * RawBlock = CompressedBlock - > RawBlocks [ 0 ] ;
2020-04-01 05:00:26 -04:00
check ( CompressedBlock - > RawOffset > = RawBlock - > Offset ) ;
uint64 OffsetInBuffer = CompressedBlock - > RawOffset - RawBlock - > Offset ;
CompressedBuffer = RawBlock - > Buffer - > Memory + OffsetInBuffer ;
}
2020-06-23 18:40:00 -04:00
if ( CompressedBlock - > SignatureHash )
{
FSHAHash BlockHash ;
2020-08-11 01:36:57 -04:00
FSHA1 : : HashBuffer ( CompressedBuffer , CompressedBlock - > RawSize , BlockHash . Hash ) ;
2020-06-23 18:40:00 -04:00
if ( * CompressedBlock - > SignatureHash ! = BlockHash )
{
FIoSignatureError Error ;
{
FReadScopeLock _ ( IoStoreReadersLock ) ;
2021-04-29 19:32:06 -04:00
for ( const TUniquePtr < FFileIoStoreReader > & Reader : IoStoreReaders )
{
if ( CompressedBlock - > Key . FileIndex = = Reader - > GetContainerInstanceId ( ) )
{
Error . ContainerName = FPaths : : GetBaseFilename ( Reader - > GetContainerFile ( ) . FilePath ) ;
}
}
2020-06-23 18:40:00 -04:00
Error . BlockIndex = CompressedBlock - > Key . BlockIndex ;
Error . ExpectedHash = * CompressedBlock - > SignatureHash ;
Error . ActualHash = BlockHash ;
}
UE_LOG ( LogIoDispatcher , Warning , TEXT ( " Signature error detected in container '%s' at block index '%d' " ) , * Error . ContainerName , Error . BlockIndex ) ;
2021-01-19 04:39:56 -04:00
check ( BackendContext ) ;
if ( BackendContext - > SignatureErrorDelegate . IsBound ( ) )
2020-06-23 18:40:00 -04:00
{
2021-01-19 04:39:56 -04:00
BackendContext - > SignatureErrorDelegate . Broadcast ( Error ) ;
2020-06-23 18:40:00 -04:00
}
}
}
2020-09-24 00:43:27 -04:00
if ( ! CompressedBlock - > bFailed )
2020-05-05 03:49:22 -04:00
{
2020-09-24 00:43:27 -04:00
if ( CompressedBlock - > EncryptionKey . IsValid ( ) )
2019-12-13 11:07:03 -05:00
{
2020-09-24 00:43:27 -04:00
FAES : : DecryptData ( CompressedBuffer , CompressedBlock - > RawSize , CompressedBlock - > EncryptionKey ) ;
2019-12-13 11:07:03 -05:00
}
2020-09-24 00:43:27 -04:00
uint8 * UncompressedBuffer ;
if ( CompressedBlock - > CompressionMethod . IsNone ( ) )
{
UncompressedBuffer = CompressedBuffer ;
}
else
{
if ( CompressionContext - > UncompressedBufferSize < CompressedBlock - > UncompressedSize )
{
FMemory : : Free ( CompressionContext - > UncompressedBuffer ) ;
CompressionContext - > UncompressedBuffer = reinterpret_cast < uint8 * > ( FMemory : : Malloc ( CompressedBlock - > UncompressedSize ) ) ;
CompressionContext - > UncompressedBufferSize = CompressedBlock - > UncompressedSize ;
}
UncompressedBuffer = CompressionContext - > UncompressedBuffer ;
2020-04-01 05:00:26 -04:00
2020-09-24 00:43:27 -04:00
bool bFailed = ! FCompression : : UncompressMemory ( CompressedBlock - > CompressionMethod , UncompressedBuffer , int32 ( CompressedBlock - > UncompressedSize ) , CompressedBuffer , int32 ( CompressedBlock - > CompressedSize ) ) ;
if ( bFailed )
{
UE_LOG ( LogIoDispatcher , Warning , TEXT ( " Failed decompressing block " ) ) ;
CompressedBlock - > bFailed = true ;
}
}
2020-04-01 05:00:26 -04:00
2020-09-24 00:43:27 -04:00
for ( FFileIoStoreBlockScatter & Scatter : CompressedBlock - > ScatterList )
{
2021-04-29 19:32:06 -04:00
if ( Scatter . Size )
{
2021-08-23 10:49:29 -04:00
check ( Scatter . DstOffset + Scatter . Size < = Scatter . Request - > GetBuffer ( ) . DataSize ( ) ) ;
check ( Scatter . SrcOffset + Scatter . Size < = CompressedBlock - > UncompressedSize ) ;
FMemory : : Memcpy ( Scatter . Request - > GetBuffer ( ) . Data ( ) + Scatter . DstOffset , UncompressedBuffer + Scatter . SrcOffset , Scatter . Size ) ;
2021-04-29 19:32:06 -04:00
}
2020-09-24 00:43:27 -04:00
}
2020-01-28 06:54:05 -05:00
}
2020-04-01 05:00:26 -04:00
if ( bIsAsync )
2020-01-28 06:54:05 -05:00
{
2020-04-01 05:00:26 -04:00
FScopeLock Lock ( & DecompressedBlocksCritical ) ;
CompressedBlock - > Next = FirstDecompressedBlock ;
FirstDecompressedBlock = CompressedBlock ;
2020-01-28 06:54:05 -05:00
2021-01-19 04:39:56 -04:00
BackendContext - > WakeUpDispatcherThreadDelegate . Execute ( ) ;
2020-04-01 05:00:26 -04:00
}
}
2020-01-28 06:54:05 -05:00
2020-12-11 14:21:20 -04:00
void FFileIoStore : : CompleteDispatcherRequest ( FFileIoStoreResolvedRequest * ResolvedRequest )
2020-11-24 18:42:39 -04:00
{
2021-01-08 19:56:07 -04:00
check ( ResolvedRequest ) ;
2021-04-29 19:32:06 -04:00
check ( ResolvedRequest - > DispatcherRequest ) ;
FIoRequestImpl * DispatcherRequest = ResolvedRequest - > DispatcherRequest ;
ResolvedRequest - > DispatcherRequest = nullptr ;
2020-12-11 14:21:20 -04:00
if ( ResolvedRequest - > bFailed )
{
DispatcherRequest - > SetFailed ( ) ;
}
DispatcherRequest - > BackendData = nullptr ;
2020-11-24 18:42:39 -04:00
if ( ! CompletedRequestsTail )
{
2020-12-11 14:21:20 -04:00
CompletedRequestsHead = CompletedRequestsTail = DispatcherRequest ;
2020-11-24 18:42:39 -04:00
}
else
{
2020-12-11 14:21:20 -04:00
CompletedRequestsTail - > NextRequest = DispatcherRequest ;
CompletedRequestsTail = DispatcherRequest ;
2020-11-24 18:42:39 -04:00
}
CompletedRequestsTail - > NextRequest = nullptr ;
}
2020-04-01 05:00:26 -04:00
void FFileIoStore : : FinalizeCompressedBlock ( FFileIoStoreCompressedBlock * CompressedBlock )
{
2021-11-22 16:44:27 -05:00
Stats . OnDecompressComplete ( CompressedBlock ) ;
2021-05-31 16:35:03 -04:00
2020-11-24 18:42:39 -04:00
if ( CompressedBlock - > RawBlocks . Num ( ) > 1 )
2020-04-01 05:00:26 -04:00
{
2020-12-11 14:21:20 -04:00
check ( CompressedBlock - > CompressedDataBuffer | | CompressedBlock - > bCancelled | | CompressedBlock - > bFailed ) ;
if ( CompressedBlock - > CompressedDataBuffer )
{
FMemory : : Free ( CompressedBlock - > CompressedDataBuffer ) ;
}
2019-12-13 11:07:03 -05:00
}
2020-01-28 06:54:05 -05:00
else
{
2020-11-24 18:42:39 -04:00
FFileIoStoreReadRequest * RawBlock = CompressedBlock - > RawBlocks [ 0 ] ;
2021-01-08 19:56:07 -04:00
check ( RawBlock - > BufferRefCount > 0 ) ;
if ( - - RawBlock - > BufferRefCount = = 0 )
2020-01-28 06:54:05 -05:00
{
2020-12-11 14:21:20 -04:00
check ( RawBlock - > Buffer | | RawBlock - > bCancelled ) ;
if ( RawBlock - > Buffer )
{
FreeBuffer ( * RawBlock - > Buffer ) ;
2021-01-08 19:56:07 -04:00
RawBlock - > Buffer = nullptr ;
2020-12-11 14:21:20 -04:00
}
2020-04-01 05:00:26 -04:00
}
}
2020-12-11 14:21:20 -04:00
check ( CompressedBlock - > CompressionContext | | CompressedBlock - > bCancelled | | CompressedBlock - > bFailed ) ;
if ( CompressedBlock - > CompressionContext )
{
FreeCompressionContext ( CompressedBlock - > CompressionContext ) ;
}
2021-01-08 19:56:07 -04:00
for ( int32 ScatterIndex = 0 , ScatterCount = CompressedBlock - > ScatterList . Num ( ) ; ScatterIndex < ScatterCount ; + + ScatterIndex )
2020-04-01 05:00:26 -04:00
{
2021-01-08 19:56:07 -04:00
FFileIoStoreBlockScatter & Scatter = CompressedBlock - > ScatterList [ ScatterIndex ] ;
2021-11-22 16:44:27 -05:00
Stats . OnBytesScattered ( Scatter . Size ) ;
2020-09-24 00:43:27 -04:00
Scatter . Request - > bFailed | = CompressedBlock - > bFailed ;
2021-04-29 19:32:06 -04:00
check ( ! CompressedBlock - > bCancelled | | ! Scatter . Request - > DispatcherRequest | | Scatter . Request - > DispatcherRequest - > IsCancelled ( ) ) ;
2020-09-01 14:07:48 -04:00
check ( Scatter . Request - > UnfinishedReadsCount > 0 ) ;
if ( - - Scatter . Request - > UnfinishedReadsCount = = 0 )
{
2021-04-29 19:32:06 -04:00
if ( ! Scatter . Request - > bCancelled )
{
CompleteDispatcherRequest ( Scatter . Request ) ;
}
RequestTracker . ReleaseIoRequestReferences ( * Scatter . Request ) ;
2020-09-01 14:07:48 -04:00
}
2020-04-01 05:00:26 -04:00
}
}
2020-09-01 14:07:48 -04:00
FIoRequestImpl * FFileIoStore : : GetCompletedRequests ( )
2020-04-01 05:00:26 -04:00
{
2020-06-23 18:40:00 -04:00
LLM_SCOPE ( ELLMTag : : FileSystem ) ;
2020-09-01 14:07:48 -04:00
//TRACE_CPUPROFILER_EVENT_SCOPE(GetCompletedRequests);
2020-04-01 05:00:26 -04:00
2020-09-01 14:07:48 -04:00
if ( ! bIsMultithreaded )
2020-04-01 05:00:26 -04:00
{
2021-09-15 02:54:32 -04:00
while ( PlatformImpl - > StartRequests ( RequestQueue ) ) ;
2020-09-01 14:07:48 -04:00
}
2020-04-01 05:00:26 -04:00
2020-09-01 14:07:48 -04:00
FFileIoStoreReadRequestList CompletedRequests ;
2021-09-15 02:54:32 -04:00
PlatformImpl - > GetCompletedRequests ( CompletedRequests ) ;
2021-11-22 16:44:27 -05:00
Stats . OnReadRequestsCompleted ( CompletedRequests ) ;
2021-05-27 13:40:37 -04:00
for ( auto It = CompletedRequests . Steal ( ) ; It ; + + It )
2020-09-01 14:07:48 -04:00
{
2021-05-27 13:40:37 -04:00
FFileIoStoreReadRequest * CompletedRequest = * It ;
2020-09-01 14:07:48 -04:00
if ( ! CompletedRequest - > ImmediateScatter . Request )
2020-08-11 01:36:57 -04:00
{
2020-12-11 14:21:20 -04:00
check ( CompletedRequest - > Buffer | | CompletedRequest - > bCancelled ) ;
RequestTracker . RemoveRawBlock ( CompletedRequest ) ;
2020-11-24 18:42:39 -04:00
2020-09-01 14:07:48 -04:00
//TRACE_CPUPROFILER_EVENT_SCOPE(ProcessCompletedBlock);
for ( FFileIoStoreCompressedBlock * CompressedBlock : CompletedRequest - > CompressedBlocks )
2020-04-01 05:00:26 -04:00
{
2020-09-24 00:43:27 -04:00
CompressedBlock - > bFailed | = CompletedRequest - > bFailed ;
2021-04-29 19:32:06 -04:00
CompressedBlock - > bCancelled | = CompletedRequest - > bCancelled ;
2020-11-24 18:42:39 -04:00
if ( CompressedBlock - > RawBlocks . Num ( ) > 1 )
2020-04-01 05:00:26 -04:00
{
2020-09-01 14:07:48 -04:00
//TRACE_CPUPROFILER_EVENT_SCOPE(HandleComplexBlock);
2020-12-11 14:21:20 -04:00
if ( ! ( CompressedBlock - > bCancelled | CompressedBlock - > bFailed ) )
2020-09-01 14:07:48 -04:00
{
2020-12-11 14:21:20 -04:00
check ( CompletedRequest - > Buffer ) ;
if ( ! CompressedBlock - > CompressedDataBuffer )
{
CompressedBlock - > CompressedDataBuffer = reinterpret_cast < uint8 * > ( FMemory : : Malloc ( CompressedBlock - > RawSize ) ) ;
}
2020-09-01 14:07:48 -04:00
2020-12-11 14:21:20 -04:00
uint8 * Src = CompletedRequest - > Buffer - > Memory ;
uint8 * Dst = CompressedBlock - > CompressedDataBuffer ;
uint64 CopySize = CompletedRequest - > Size ;
int64 CompletedBlockOffsetInBuffer = int64 ( CompletedRequest - > Offset ) - int64 ( CompressedBlock - > RawOffset ) ;
if ( CompletedBlockOffsetInBuffer < 0 )
{
Src - = CompletedBlockOffsetInBuffer ;
CopySize + = CompletedBlockOffsetInBuffer ;
}
else
{
Dst + = CompletedBlockOffsetInBuffer ;
}
uint64 CompressedBlockRawEndOffset = CompressedBlock - > RawOffset + CompressedBlock - > RawSize ;
uint64 CompletedBlockEndOffset = CompletedRequest - > Offset + CompletedRequest - > Size ;
if ( CompletedBlockEndOffset > CompressedBlockRawEndOffset )
{
CopySize - = CompletedBlockEndOffset - CompressedBlockRawEndOffset ;
}
FMemory : : Memcpy ( Dst , Src , CopySize ) ;
2020-09-01 14:07:48 -04:00
}
2021-01-08 19:56:07 -04:00
check ( CompletedRequest - > BufferRefCount > 0 ) ;
if ( - - CompletedRequest - > BufferRefCount = = 0 )
{
if ( CompletedRequest - > Buffer )
{
FreeBuffer ( * CompletedRequest - > Buffer ) ;
CompletedRequest - > Buffer = nullptr ;
}
}
2020-04-01 05:00:26 -04:00
}
2020-08-11 01:36:57 -04:00
2020-09-01 14:07:48 -04:00
check ( CompressedBlock - > UnfinishedRawBlocksCount > 0 ) ;
if ( - - CompressedBlock - > UnfinishedRawBlocksCount = = 0 )
2020-08-11 01:36:57 -04:00
{
2021-11-22 16:44:27 -05:00
Stats . OnDecompressQueued ( CompressedBlock ) ;
2020-12-11 14:21:20 -04:00
RequestTracker . RemoveCompressedBlock ( CompressedBlock ) ;
2020-09-01 14:07:48 -04:00
if ( ! ReadyForDecompressionTail )
{
ReadyForDecompressionHead = ReadyForDecompressionTail = CompressedBlock ;
}
else
{
ReadyForDecompressionTail - > Next = CompressedBlock ;
ReadyForDecompressionTail = CompressedBlock ;
}
CompressedBlock - > Next = nullptr ;
2020-08-11 01:36:57 -04:00
}
}
2020-04-01 05:00:26 -04:00
}
2020-09-01 14:07:48 -04:00
else
2020-08-11 01:36:57 -04:00
{
2020-09-01 14:07:48 -04:00
check ( ! CompletedRequest - > Buffer ) ;
2021-11-22 16:44:27 -05:00
Stats . OnBytesScattered ( CompletedRequest - > ImmediateScatter . Size ) ;
2020-12-11 14:21:20 -04:00
FFileIoStoreResolvedRequest * CompletedResolvedRequest = CompletedRequest - > ImmediateScatter . Request ;
CompletedResolvedRequest - > bFailed | = CompletedRequest - > bFailed ;
2021-04-29 19:32:06 -04:00
check ( ! CompletedRequest - > bCancelled | | ! CompletedResolvedRequest - > DispatcherRequest | | CompletedResolvedRequest - > DispatcherRequest - > IsCancelled ( ) ) ;
2020-12-11 14:21:20 -04:00
check ( CompletedResolvedRequest - > UnfinishedReadsCount > 0 ) ;
if ( - - CompletedResolvedRequest - > UnfinishedReadsCount = = 0 )
2020-09-01 14:07:48 -04:00
{
2021-04-29 19:32:06 -04:00
if ( ! CompletedResolvedRequest - > bCancelled )
{
CompleteDispatcherRequest ( CompletedResolvedRequest ) ;
}
RequestTracker . ReleaseIoRequestReferences ( * CompletedResolvedRequest ) ;
2020-09-01 14:07:48 -04:00
}
2020-08-11 01:36:57 -04:00
}
2020-04-01 05:00:26 -04:00
}
FFileIoStoreCompressedBlock * BlockToReap ;
{
FScopeLock Lock ( & DecompressedBlocksCritical ) ;
BlockToReap = FirstDecompressedBlock ;
FirstDecompressedBlock = nullptr ;
}
while ( BlockToReap )
{
FFileIoStoreCompressedBlock * Next = BlockToReap - > Next ;
FinalizeCompressedBlock ( BlockToReap ) ;
BlockToReap = Next ;
}
FFileIoStoreCompressedBlock * BlockToDecompress = ReadyForDecompressionHead ;
while ( BlockToDecompress )
{
FFileIoStoreCompressedBlock * Next = BlockToDecompress - > Next ;
2020-12-11 14:21:20 -04:00
if ( BlockToDecompress - > bFailed | BlockToDecompress - > bCancelled )
{
FinalizeCompressedBlock ( BlockToDecompress ) ;
BlockToDecompress = Next ;
continue ;
}
2020-04-01 05:00:26 -04:00
BlockToDecompress - > CompressionContext = AllocCompressionContext ( ) ;
if ( ! BlockToDecompress - > CompressionContext )
{
break ;
}
2021-08-23 10:49:29 -04:00
for ( const FFileIoStoreBlockScatter & Scatter : BlockToDecompress - > ScatterList )
{
if ( Scatter . Size )
{
FIoRequestImpl * DispatcherRequest = Scatter . Request - > DispatcherRequest ;
check ( DispatcherRequest ) ;
if ( ! DispatcherRequest - > HasBuffer ( ) )
{
DispatcherRequest - > CreateBuffer ( Scatter . Request - > ResolvedSize ) ;
}
}
}
2020-06-23 18:40:00 -04:00
// Scatter block asynchronous when the block is compressed, encrypted or signed
const bool bScatterAsync = bIsMultithreaded & & ( ! BlockToDecompress - > CompressionMethod . IsNone ( ) | | BlockToDecompress - > EncryptionKey . IsValid ( ) | | BlockToDecompress - > SignatureHash ) ;
if ( bScatterAsync )
2020-04-01 05:00:26 -04:00
{
2020-06-23 18:40:00 -04:00
TGraphTask < FDecompressAsyncTask > : : CreateTask ( ) . ConstructAndDispatchWhenReady ( * this , BlockToDecompress ) ;
2020-04-01 05:00:26 -04:00
}
else
{
2020-06-23 18:40:00 -04:00
ScatterBlock ( BlockToDecompress , false ) ;
FinalizeCompressedBlock ( BlockToDecompress ) ;
2020-04-01 05:00:26 -04:00
}
BlockToDecompress = Next ;
}
ReadyForDecompressionHead = BlockToDecompress ;
if ( ! ReadyForDecompressionHead )
{
ReadyForDecompressionTail = nullptr ;
}
2020-09-01 14:07:48 -04:00
FIoRequestImpl * Result = CompletedRequestsHead ;
CompletedRequestsHead = CompletedRequestsTail = nullptr ;
return Result ;
2020-04-01 05:00:26 -04:00
}
TIoStatusOr < FIoMappedRegion > FFileIoStore : : OpenMapped ( const FIoChunkId & ChunkId , const FIoReadOptions & Options )
{
if ( ! FPlatformProperties : : SupportsMemoryMappedFiles ( ) )
{
return FIoStatus ( EIoErrorCode : : Unknown , TEXT ( " Platform does not support memory mapped files " ) ) ;
}
if ( Options . GetTargetVa ( ) ! = nullptr )
{
return FIoStatus ( EIoErrorCode : : InvalidParameter , TEXT ( " Invalid read options " ) ) ;
}
IPlatformFile & Ipf = FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) ;
2020-04-22 06:25:12 -04:00
FReadScopeLock _ ( IoStoreReadersLock ) ;
2021-04-29 19:32:06 -04:00
for ( TUniquePtr < FFileIoStoreReader > & Reader : IoStoreReaders )
2020-04-01 05:00:26 -04:00
{
if ( const FIoOffsetAndLength * OffsetAndLength = Reader - > Resolve ( ChunkId ) )
{
uint64 ResolvedOffset = OffsetAndLength - > GetOffset ( ) ;
uint64 ResolvedSize = FMath : : Min ( Options . GetSize ( ) , OffsetAndLength - > GetLength ( ) ) ;
const FFileIoStoreContainerFile & ContainerFile = Reader - > GetContainerFile ( ) ;
2020-04-22 06:25:12 -04:00
int32 BlockIndex = int32 ( ResolvedOffset / ContainerFile . CompressionBlockSize ) ;
const FIoStoreTocCompressedBlockEntry & CompressionBlockEntry = ContainerFile . CompressionBlocks [ BlockIndex ] ;
2020-06-23 18:40:00 -04:00
const int64 BlockOffset = ( int64 ) CompressionBlockEntry . GetOffset ( ) ;
2020-04-22 06:25:12 -04:00
check ( BlockOffset > 0 & & IsAligned ( BlockOffset , FPlatformProperties : : GetMemoryMappingAlignment ( ) ) ) ;
2020-04-01 05:00:26 -04:00
2021-01-08 19:56:07 -04:00
IMappedFileHandle * MappedFileHandle = Reader - > GetMappedContainerFileHandle ( BlockOffset ) ;
IMappedFileRegion * MappedFileRegion = MappedFileHandle - > MapRegion ( BlockOffset + Options . GetOffset ( ) , ResolvedSize ) ;
2020-11-24 18:42:39 -04:00
if ( MappedFileRegion ! = nullptr )
{
check ( IsAligned ( MappedFileRegion - > GetMappedPtr ( ) , FPlatformProperties : : GetMemoryMappingAlignment ( ) ) ) ;
return FIoMappedRegion { MappedFileHandle , MappedFileRegion } ;
}
else
{
return FIoStatus ( EIoErrorCode : : ReadError ) ;
}
2020-01-28 06:54:05 -05:00
}
}
2019-12-13 11:07:03 -05:00
2020-04-22 06:25:12 -04:00
// We didn't find any entry for the ChunkId.
return FIoStatus ( EIoErrorCode : : NotFound ) ;
2020-04-01 05:00:26 -04:00
}
2021-11-07 23:43:01 -05:00
void FFileIoStore : : ReopenAllFileHandles ( )
{
UE_CLOG ( RequestTracker . GetLiveReadRequestsCount ( ) , LogIoDispatcher , Warning , TEXT ( " Calling ReopenAllFileHandles with read requests in flight " ) ) ;
FWriteScopeLock _ ( IoStoreReadersLock ) ;
for ( const TUniquePtr < FFileIoStoreReader > & Reader : IoStoreReaders )
{
Reader - > ReopenAllFileHandles ( ) ;
}
}
2020-09-01 14:07:48 -04:00
void FFileIoStore : : OnNewPendingRequestsAdded ( )
{
if ( bIsMultithreaded )
{
2021-09-15 02:54:32 -04:00
PlatformImpl - > ServiceNotify ( ) ;
2020-09-01 14:07:48 -04:00
}
}
2020-12-11 14:21:20 -04:00
void FFileIoStore : : ReadBlocks ( FFileIoStoreResolvedRequest & ResolvedRequest )
2020-04-01 05:00:26 -04:00
{
/*TStringBuilder<256> ScopeName;
ScopeName . Appendf ( TEXT ( " ReadBlock %d " ) , BlockIndex ) ;
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT ( * ScopeName ) ; */
2020-12-11 14:21:20 -04:00
const FFileIoStoreContainerFile & ContainerFile = ResolvedRequest . GetContainerFile ( ) ;
2020-04-22 06:25:12 -04:00
const uint64 CompressionBlockSize = ContainerFile . CompressionBlockSize ;
const uint64 RequestEndOffset = ResolvedRequest . ResolvedOffset + ResolvedRequest . ResolvedSize ;
int32 RequestBeginBlockIndex = int32 ( ResolvedRequest . ResolvedOffset / CompressionBlockSize ) ;
int32 RequestEndBlockIndex = int32 ( ( RequestEndOffset - 1 ) / CompressionBlockSize ) ;
2020-04-01 05:00:26 -04:00
2020-09-01 14:07:48 -04:00
FFileIoStoreReadRequestList NewBlocks ;
2020-04-01 05:00:26 -04:00
2020-04-22 06:25:12 -04:00
uint64 RequestStartOffsetInBlock = ResolvedRequest . ResolvedOffset - RequestBeginBlockIndex * CompressionBlockSize ;
uint64 RequestRemainingBytes = ResolvedRequest . ResolvedSize ;
uint64 OffsetInRequest = 0 ;
for ( int32 CompressedBlockIndex = RequestBeginBlockIndex ; CompressedBlockIndex < = RequestEndBlockIndex ; + + CompressedBlockIndex )
2020-01-28 06:54:05 -05:00
{
2020-04-22 06:25:12 -04:00
FFileIoStoreBlockKey CompressedBlockKey ;
2021-04-29 19:32:06 -04:00
CompressedBlockKey . FileIndex = ResolvedRequest . GetContainerFile ( ) . ContainerInstanceId ;
2020-04-22 06:25:12 -04:00
CompressedBlockKey . BlockIndex = CompressedBlockIndex ;
2020-12-11 14:21:20 -04:00
bool bCompressedBlockWasAdded ;
FFileIoStoreCompressedBlock * CompressedBlock = RequestTracker . FindOrAddCompressedBlock ( CompressedBlockKey , bCompressedBlockWasAdded ) ;
check ( CompressedBlock ) ;
2021-04-29 19:32:06 -04:00
check ( ! CompressedBlock - > bCancelled ) ;
2020-12-11 14:21:20 -04:00
if ( bCompressedBlockWasAdded )
2020-11-24 18:42:39 -04:00
{
2020-12-11 14:21:20 -04:00
CompressedBlock - > EncryptionKey = ContainerFile . EncryptionKey ;
2020-04-22 06:25:12 -04:00
const FIoStoreTocCompressedBlockEntry & CompressionBlockEntry = ContainerFile . CompressionBlocks [ CompressedBlockIndex ] ;
2020-08-11 01:36:57 -04:00
CompressedBlock - > UncompressedSize = CompressionBlockEntry . GetUncompressedSize ( ) ;
CompressedBlock - > CompressedSize = CompressionBlockEntry . GetCompressedSize ( ) ;
2020-06-23 18:40:00 -04:00
CompressedBlock - > CompressionMethod = ContainerFile . CompressionMethods [ CompressionBlockEntry . GetCompressionMethodIndex ( ) ] ;
2020-12-11 14:21:20 -04:00
CompressedBlock - > SignatureHash = EnumHasAnyFlags ( ContainerFile . ContainerFlags , EIoContainerFlags : : Signed ) ? & ContainerFile . BlockSignatureHashes [ CompressedBlockIndex ] : nullptr ;
2021-01-08 19:56:07 -04:00
CompressedBlock - > RawSize = Align ( CompressionBlockEntry . GetCompressedSize ( ) , FAES : : AESBlockSize ) ; // The raw blocks size is always aligned to AES blocks size;
int32 PartitionIndex = int32 ( CompressionBlockEntry . GetOffset ( ) / ContainerFile . PartitionSize ) ;
const FFileIoStoreContainerFilePartition & Partition = ContainerFile . Partitions [ PartitionIndex ] ;
uint64 PartitionRawOffset = CompressionBlockEntry . GetOffset ( ) % ContainerFile . PartitionSize ;
CompressedBlock - > RawOffset = PartitionRawOffset ;
const uint32 RawBeginBlockIndex = uint32 ( PartitionRawOffset / ReadBufferSize ) ;
const uint32 RawEndBlockIndex = uint32 ( ( PartitionRawOffset + CompressedBlock - > RawSize - 1 ) / ReadBufferSize ) ;
2020-04-22 06:25:12 -04:00
const uint32 RawBlockCount = RawEndBlockIndex - RawBeginBlockIndex + 1 ;
check ( RawBlockCount > 0 ) ;
for ( uint32 RawBlockIndex = RawBeginBlockIndex ; RawBlockIndex < = RawEndBlockIndex ; + + RawBlockIndex )
2020-04-01 05:00:26 -04:00
{
2020-04-22 06:25:12 -04:00
FFileIoStoreBlockKey RawBlockKey ;
RawBlockKey . BlockIndex = RawBlockIndex ;
2021-01-08 19:56:07 -04:00
RawBlockKey . FileIndex = Partition . ContainerFileIndex ;
2020-04-01 05:00:26 -04:00
2020-12-11 14:21:20 -04:00
bool bRawBlockWasAdded ;
FFileIoStoreReadRequest * RawBlock = RequestTracker . FindOrAddRawBlock ( RawBlockKey , bRawBlockWasAdded ) ;
check ( RawBlock ) ;
2021-04-29 19:32:06 -04:00
check ( ! RawBlock - > bCancelled ) ;
2020-12-11 14:21:20 -04:00
if ( bRawBlockWasAdded )
2020-04-01 05:00:26 -04:00
{
2020-12-11 14:21:20 -04:00
RawBlock - > Priority = ResolvedRequest . GetPriority ( ) ;
2021-01-08 19:56:07 -04:00
RawBlock - > FileHandle = Partition . FileHandle ;
2020-04-22 06:25:12 -04:00
RawBlock - > Offset = RawBlockIndex * ReadBufferSize ;
2021-01-08 19:56:07 -04:00
uint64 ReadSize = FMath : : Min ( Partition . FileSize , RawBlock - > Offset + ReadBufferSize ) - RawBlock - > Offset ;
2020-04-22 06:25:12 -04:00
RawBlock - > Size = ReadSize ;
2020-09-01 14:07:48 -04:00
NewBlocks . Add ( RawBlock ) ;
2020-04-01 05:00:26 -04:00
}
2021-08-17 09:13:59 -04:00
RawBlock - > BytesUsed + =
uint32 ( FMath : : Min ( CompressedBlock - > RawOffset + CompressedBlock - > RawSize , RawBlock - > Offset + RawBlock - > Size ) -
FMath : : Max ( CompressedBlock - > RawOffset , RawBlock - > Offset ) ) ;
2020-11-24 18:42:39 -04:00
CompressedBlock - > RawBlocks . Add ( RawBlock ) ;
2020-04-22 06:25:12 -04:00
+ + CompressedBlock - > UnfinishedRawBlocksCount ;
2021-01-08 19:56:07 -04:00
+ + CompressedBlock - > RefCount ;
RawBlock - > CompressedBlocks . Add ( CompressedBlock ) ;
+ + RawBlock - > BufferRefCount ;
2020-04-01 05:00:26 -04:00
}
}
2020-08-11 01:36:57 -04:00
check ( CompressedBlock - > UncompressedSize > RequestStartOffsetInBlock ) ;
uint64 RequestSizeInBlock = FMath : : Min < uint64 > ( CompressedBlock - > UncompressedSize - RequestStartOffsetInBlock , RequestRemainingBytes ) ;
2021-08-23 10:49:29 -04:00
check ( OffsetInRequest + RequestSizeInBlock < = ResolvedRequest . ResolvedSize ) ;
2020-08-11 01:36:57 -04:00
check ( RequestStartOffsetInBlock + RequestSizeInBlock < = CompressedBlock - > UncompressedSize ) ;
2020-04-22 06:25:12 -04:00
FFileIoStoreBlockScatter & Scatter = CompressedBlock - > ScatterList . AddDefaulted_GetRef ( ) ;
2020-12-11 14:21:20 -04:00
Scatter . Request = & ResolvedRequest ;
2020-04-22 06:25:12 -04:00
Scatter . DstOffset = OffsetInRequest ;
Scatter . SrcOffset = RequestStartOffsetInBlock ;
Scatter . Size = RequestSizeInBlock ;
RequestRemainingBytes - = RequestSizeInBlock ;
OffsetInRequest + = RequestSizeInBlock ;
RequestStartOffsetInBlock = 0 ;
2019-12-13 11:07:03 -05:00
2020-12-11 14:21:20 -04:00
RequestTracker . AddReadRequestsToResolvedRequest ( CompressedBlock , ResolvedRequest ) ;
2020-11-24 18:42:39 -04:00
}
2020-09-01 14:07:48 -04:00
if ( ! NewBlocks . IsEmpty ( ) )
2020-04-01 05:00:26 -04:00
{
2021-11-22 16:44:27 -05:00
Stats . OnReadRequestsQueued ( NewBlocks ) ;
2020-11-24 18:42:39 -04:00
RequestQueue . Push ( NewBlocks ) ;
2020-09-01 14:07:48 -04:00
OnNewPendingRequestsAdded ( ) ;
2020-04-01 05:00:26 -04:00
}
}
2020-09-01 14:07:48 -04:00
void FFileIoStore : : FreeBuffer ( FFileIoStoreBuffer & Buffer )
2020-04-01 05:00:26 -04:00
{
2020-09-01 14:07:48 -04:00
BufferAllocator . FreeBuffer ( & Buffer ) ;
2021-09-15 02:54:32 -04:00
PlatformImpl - > ServiceNotify ( ) ;
2020-04-01 05:00:26 -04:00
}
FFileIoStoreCompressionContext * FFileIoStore : : AllocCompressionContext ( )
{
FFileIoStoreCompressionContext * Result = FirstFreeCompressionContext ;
if ( Result )
{
FirstFreeCompressionContext = FirstFreeCompressionContext - > Next ;
}
return Result ;
}
void FFileIoStore : : FreeCompressionContext ( FFileIoStoreCompressionContext * CompressionContext )
{
CompressionContext - > Next = FirstFreeCompressionContext ;
FirstFreeCompressionContext = CompressionContext ;
}
bool FFileIoStore : : Init ( )
{
return true ;
}
void FFileIoStore : : Stop ( )
{
bStopRequested = true ;
2021-09-15 02:54:32 -04:00
PlatformImpl - > ServiceNotify ( ) ;
2020-04-01 05:00:26 -04:00
}
uint32 FFileIoStore : : Run ( )
{
while ( ! bStopRequested )
{
2021-09-15 02:54:32 -04:00
if ( ! PlatformImpl - > StartRequests ( RequestQueue ) )
2020-04-22 06:25:12 -04:00
{
2021-09-15 02:54:32 -04:00
PlatformImpl - > ServiceWait ( ) ;
2020-04-22 06:25:12 -04:00
}
2020-04-01 05:00:26 -04:00
}
return 0 ;
2019-12-13 11:07:03 -05:00
}
2021-01-19 04:39:56 -04:00
2021-12-15 03:24:48 -05:00
TSharedRef < FFileIoStore > CreateIoDispatcherFileBackend ( )
2021-01-19 04:39:56 -04:00
{
2021-11-30 09:01:21 -05:00
bool bCheckForPlatformImplementation = true ;
if ( ! FGenericPlatformProcess : : SupportsMultithreading ( ) )
{
bCheckForPlatformImplementation = false ;
}
# if !UE_BUILD_SHIPPING
if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " forcegenericio " ) ) )
{
bCheckForPlatformImplementation = false ;
}
# endif
2021-09-15 02:54:32 -04:00
if ( bCheckForPlatformImplementation )
{
2021-10-04 16:32:08 -04:00
if ( FModuleManager : : Get ( ) . ModuleExists ( ANSI_TO_TCHAR ( PLATFORM_IODISPATCHER_MODULE ) ) )
2021-09-15 02:54:32 -04:00
{
2021-10-04 16:32:08 -04:00
IPlatformFileIoStoreModule * PlatformModule = FModuleManager : : LoadModulePtr < IPlatformFileIoStoreModule > ( ANSI_TO_TCHAR ( PLATFORM_IODISPATCHER_MODULE ) ) ;
2021-09-15 02:54:32 -04:00
if ( PlatformModule )
{
TUniquePtr < IPlatformFileIoStore > PlatformImpl = PlatformModule - > CreatePlatformFileIoStore ( ) ;
if ( PlatformImpl . IsValid ( ) )
{
return MakeShared < FFileIoStore > ( MoveTemp ( PlatformImpl ) ) ;
}
}
}
# if PLATFORM_IMPLEMENTS_IO
{
TUniquePtr < IPlatformFileIoStore > PlatformImpl = CreatePlatformFileIoStore ( ) ;
if ( PlatformImpl . IsValid ( ) )
{
return MakeShared < FFileIoStore > ( MoveTemp ( PlatformImpl ) ) ;
}
}
# endif
}
return MakeShared < FFileIoStore > ( MakeUnique < FGenericFileIoStoreImpl > ( ) ) ;
2021-05-31 16:35:03 -04:00
}
2021-06-07 20:09:45 -04:00
uint32 FFileIoStore : : GetThreadId ( ) const
{
return Thread ? Thread - > GetThreadID ( ) : 0 ;
}
2021-05-31 16:35:03 -04:00
CSV_DEFINE_CATEGORY ( IoDispatcherFileBackend , true ) ;
2021-06-22 00:27:54 -04:00
CSV_DEFINE_CATEGORY ( IoDispatcherFileBackendVerbose , false ) ;
2021-05-31 16:35:03 -04:00
// These stats go to both insights and csv by default
// TODO: Ideally these should go to insights even if CSV is not capturing, but not be doubled-up if both CSV and Insights are capturing
// TODO: It would also be nice to send these to insights as int64 without unit conversion where appropriate
// IoDispatcher thread
2021-06-22 00:27:54 -04:00
CSV_DEFINE_STAT ( IoDispatcherFileBackend , FrameBytesScatteredKB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackend , QueuedFilesystemReadMB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , QueuedFilesystemReads ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , QueuedUncompressBlocks ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , QueuedUncompressInMB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , QueuedUncompressOutMB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBytesReadKB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBytesUncompressedInKB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBytesUncompressedOutKB ) ;
2021-05-31 16:35:03 -04:00
2021-06-22 00:27:54 -04:00
// FileIoStore thread
CSV_DEFINE_STAT ( IoDispatcherFileBackend , FrameFilesystemBytesReadKB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackend , FrameSequentialReads ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackend , FrameSeeks ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameFilesystemReads ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameForwardSeeks ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBackwardSeeks ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameHandleChangeSeeks ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameSeekDistanceMB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBlockCacheStores ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBlockCacheStoresKB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBlockCacheHits ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBlockCacheHitKB ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBlockCacheMisses ) ;
CSV_DEFINE_STAT ( IoDispatcherFileBackendVerbose , FrameBlockCacheMissKB ) ;
2021-05-31 16:35:03 -04:00
2021-11-22 16:44:27 -05:00
# if UE_FILEIOSTORE_STATS_ENABLED
2021-05-31 16:35:03 -04:00
2021-11-22 16:44:27 -05:00
FFileIoStoreStats : : FFileIoStoreStats ( )
# if COUNTERSTRACE_ENABLED
: QueuedReadRequestsSizeCounter ( TEXT ( " FileIoStore/QueuedReadRequestsSize " ) , TraceCounterDisplayHint_Memory )
, CompletedReadRequestsSizeCounter ( TEXT ( " FileIoStore/CompletedReadRequestsSize " ) , TraceCounterDisplayHint_Memory )
, QueuedCompressedSizeCounter ( TEXT ( " FileIoStore/QueuedCompressedSize " ) , TraceCounterDisplayHint_Memory )
, QueuedUncompressedSizeCounter ( TEXT ( " FileIoStore/QueuedUncompressedSize " ) , TraceCounterDisplayHint_Memory )
, CompletedCompressedSizeCounter ( TEXT ( " FileIoStore/CompletedCompressedSize " ) , TraceCounterDisplayHint_Memory )
, CompletedUncompressedSizeCounter ( TEXT ( " FileIoStore/CompletedUncompressedSize " ) , TraceCounterDisplayHint_Memory )
, FileSystemSeeksTotalDistanceCounter ( TEXT ( " FileIoStore/FileSystemSeeksTotalDistance " ) , TraceCounterDisplayHint_Memory )
, FileSystemSeeksForwardCountCounter ( TEXT ( " FileIoStore/FileSystemSeeksForwardCount " ) , TraceCounterDisplayHint_None )
, FileSystemSeeksBackwardCountCounter ( TEXT ( " FileIoStore/FileSystemSeeksBackwardCount " ) , TraceCounterDisplayHint_None )
, FileSystemSeeksChangeHandleCountCounter ( TEXT ( " FileIoStore/FileSystemSeeksChangeHandleCount " ) , TraceCounterDisplayHint_None )
, FileSystemCompletedRequestsSizeCounter ( TEXT ( " FileIoStore/FileSystemCompletedRequestsSize " ) , TraceCounterDisplayHint_Memory )
, BlockCacheStoredSizeCounter ( TEXT ( " FileIoStore/BlockCacheStoredSize " ) , TraceCounterDisplayHint_Memory )
, BlockCacheHitSizeCounter ( TEXT ( " FileIoStore/BlockCacheHitSize " ) , TraceCounterDisplayHint_Memory )
, BlockCacheMissedSizeCounter ( TEXT ( " FileIoStore/BlockCacheMissedSize " ) , TraceCounterDisplayHint_Memory )
, ScatteredSizeCounter ( TEXT ( " FileIoStore/ScatteredSize " ) , TraceCounterDisplayHint_Memory )
, TocMemoryCounter ( TEXT ( " FileIoStore/TocMemory " ) , TraceCounterDisplayHint_Memory )
, AvailableBuffersCounter ( TEXT ( " FileIoStore/AvailableBuffers " ) , TraceCounterDisplayHint_None )
2021-05-31 16:35:03 -04:00
# endif
2021-06-03 18:48:17 -04:00
{
# if CSV_PROFILER
2021-11-22 16:44:27 -05:00
TickerHandle = FTSTicker : : GetCoreTicker ( ) . AddTicker ( FTickerDelegate : : CreateRaw ( this , & FFileIoStoreStats : : CsvTick ) ) ;
2021-06-03 18:48:17 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
FFileIoStoreStats : : ~ FFileIoStoreStats ( )
2021-06-03 18:48:17 -04:00
{
# if CSV_PROFILER
2021-08-16 11:09:22 -04:00
FTSTicker : : GetCoreTicker ( ) . RemoveTicker ( TickerHandle ) ;
2021-06-03 18:48:17 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
bool FFileIoStoreStats : : CsvTick ( float DeltaTime )
2021-06-03 18:48:17 -04:00
{
# if CSV_PROFILER
CSV_CUSTOM_STAT_DEFINED ( QueuedFilesystemReadMB , BytesToApproxMB ( QueuedFilesystemReadBytes ) , ECsvCustomStatOp : : Set ) ;
CSV_CUSTOM_STAT_DEFINED ( QueuedFilesystemReads , ( int32 ) QueuedFilesystemReads , ECsvCustomStatOp : : Set ) ;
CSV_CUSTOM_STAT_DEFINED ( QueuedUncompressBlocks , int32 ( QueuedUncompressBlocks ) , ECsvCustomStatOp : : Set ) ;
CSV_CUSTOM_STAT_DEFINED ( QueuedUncompressInMB , BytesToApproxMB ( QueuedUncompressBytesIn ) , ECsvCustomStatOp : : Set ) ;
CSV_CUSTOM_STAT_DEFINED ( QueuedUncompressOutMB , BytesToApproxMB ( QueuedUncompressBytesOut ) , ECsvCustomStatOp : : Set ) ;
# endif
return true ;
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnReadRequestsQueued ( const FFileIoStoreReadRequestList & Requests )
2021-05-31 16:35:03 -04:00
{
uint64 TotalBytes = 0 ;
int32 NumReads = 0 ;
for ( const FFileIoStoreReadRequest * Request : Requests )
{
+ + NumReads ;
TotalBytes + = Request - > Size ;
}
# if CSV_PROFILER
2021-11-22 16:44:27 -05:00
QueuedFilesystemReadBytes + = TotalBytes ;
2021-06-03 18:48:17 -04:00
QueuedFilesystemReads + = NumReads ;
2021-05-31 16:35:03 -04:00
# endif
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
QueuedReadRequestsSizeCounter . Add ( TotalBytes ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnFilesystemReadStarted ( const FFileIoStoreReadRequest * Request )
2021-05-31 16:35:03 -04:00
{
CSV_CUSTOM_STAT_DEFINED ( FrameFilesystemReads , 1 , ECsvCustomStatOp : : Accumulate ) ;
2021-11-22 16:44:27 -05:00
if ( LastHandle ! = Request - > FileHandle )
2021-05-31 16:35:03 -04:00
{
OnHandleChangeSeek ( ) ;
}
2021-11-22 16:44:27 -05:00
else if ( LastOffset = = Request - > Offset )
2021-05-31 16:35:03 -04:00
{
OnSequentialRead ( ) ;
}
else
{
2021-11-22 16:44:27 -05:00
OnSeek ( LastOffset , Request - > Offset ) ;
2021-05-31 16:35:03 -04:00
}
2021-11-22 16:44:27 -05:00
LastOffset = Request - > Offset + Request - > Size ;
LastHandle = Request - > FileHandle ;
CSV_CUSTOM_STAT_DEFINED ( FrameFilesystemReads , 1 , ECsvCustomStatOp : : Accumulate ) ;
}
void FFileIoStoreStats : : OnFilesystemReadsStarted ( const FFileIoStoreReadRequestList & Requests )
{
int64 TotalBytes = 0 ;
int32 NumReads = 0 ;
for ( const FFileIoStoreReadRequest * Request : Requests )
{
if ( LastHandle ! = Request - > FileHandle )
{
OnHandleChangeSeek ( ) ;
}
else if ( LastOffset = = Request - > Offset )
{
OnSequentialRead ( ) ;
}
else
{
OnSeek ( LastOffset , Request - > Offset ) ;
}
LastOffset = Request - > Offset + Request - > Size ;
LastHandle = Request - > FileHandle ;
+ + NumReads ;
TotalBytes + = Request - > Size ;
}
CSV_CUSTOM_STAT_DEFINED ( FrameFilesystemReads , NumReads , ECsvCustomStatOp : : Accumulate ) ;
}
void FFileIoStoreStats : : OnFilesystemReadCompleted ( const FFileIoStoreReadRequest * CompletedRequest )
{
CSV_CUSTOM_STAT_DEFINED ( FrameFilesystemBytesReadKB , BytesToApproxKB ( CompletedRequest - > Size ) , ECsvCustomStatOp : : Accumulate ) ;
# if COUNTERSTRACE_ENABLED
FileSystemCompletedRequestsSizeCounter . Add ( CompletedRequest - > Size ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnFilesystemReadsCompleted ( const FFileIoStoreReadRequestList & CompletedRequests )
2021-05-31 16:35:03 -04:00
{
int64 TotalBytes = 0 ;
int32 NumReads = 0 ;
for ( const FFileIoStoreReadRequest * Request : CompletedRequests )
{
+ + NumReads ;
TotalBytes + = Request - > Size ;
}
2021-11-22 16:44:27 -05:00
CSV_CUSTOM_STAT_DEFINED ( FrameFilesystemBytesReadKB , BytesToApproxKB ( TotalBytes ) , ECsvCustomStatOp : : Accumulate ) ;
# if COUNTERSTRACE_ENABLED
FileSystemCompletedRequestsSizeCounter . Add ( TotalBytes ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnReadRequestsCompleted ( const FFileIoStoreReadRequestList & CompletedRequests )
2021-05-31 16:35:03 -04:00
{
2021-11-22 16:44:27 -05:00
int64 TotalBytes = 0 ;
int32 NumReads = 0 ;
for ( const FFileIoStoreReadRequest * Request : CompletedRequests )
{
+ + NumReads ;
TotalBytes + = Request - > Size ;
}
2021-05-31 16:35:03 -04:00
# if CSV_PROFILER
2021-11-22 16:44:27 -05:00
QueuedFilesystemReadBytes - = TotalBytes ;
QueuedFilesystemReads - = NumReads ;
2021-05-31 16:35:03 -04:00
# endif
2021-11-22 16:44:27 -05:00
CSV_CUSTOM_STAT_DEFINED ( FrameBytesReadKB , BytesToApproxKB ( TotalBytes ) , ECsvCustomStatOp : : Accumulate ) ; // TODO: Send to insights if CSV is disabled
2021-05-31 16:35:03 -04:00
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
QueuedReadRequestsSizeCounter . Subtract ( TotalBytes ) ;
CompletedReadRequestsSizeCounter . Add ( TotalBytes ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnDecompressQueued ( const FFileIoStoreCompressedBlock * CompressedBlock )
2021-05-31 16:35:03 -04:00
{
# if CSV_PROFILER
2021-06-03 18:48:17 -04:00
+ + QueuedUncompressBlocks ;
2021-11-22 16:44:27 -05:00
QueuedUncompressBytesIn + = CompressedBlock - > CompressedSize ;
QueuedUncompressBytesOut + = CompressedBlock - > UncompressedSize ;
2021-05-31 16:35:03 -04:00
# endif
2021-06-22 00:27:54 -04:00
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
QueuedCompressedSizeCounter . Add ( CompressedBlock - > CompressedSize ) ;
QueuedUncompressedSizeCounter . Add ( CompressedBlock - > UncompressedSize ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnDecompressComplete ( const FFileIoStoreCompressedBlock * CompressedBlock )
2021-05-31 16:35:03 -04:00
{
# if CSV_PROFILER
2021-06-03 18:48:17 -04:00
- - QueuedUncompressBlocks ;
2021-11-22 16:44:27 -05:00
QueuedUncompressBytesIn - = CompressedBlock - > CompressedSize ;
QueuedUncompressBytesOut - = CompressedBlock - > UncompressedSize ;
2021-05-31 16:35:03 -04:00
# endif
2021-11-22 16:44:27 -05:00
CSV_CUSTOM_STAT_DEFINED ( FrameBytesUncompressedInKB , BytesToApproxKB ( CompressedBlock - > CompressedSize ) , ECsvCustomStatOp : : Accumulate ) ;
CSV_CUSTOM_STAT_DEFINED ( FrameBytesUncompressedOutKB , BytesToApproxKB ( CompressedBlock - > UncompressedSize ) , ECsvCustomStatOp : : Accumulate ) ;
2021-05-31 16:35:03 -04:00
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
QueuedCompressedSizeCounter . Subtract ( CompressedBlock - > CompressedSize ) ;
QueuedUncompressedSizeCounter . Subtract ( CompressedBlock - > UncompressedSize ) ;
2021-06-22 00:27:54 -04:00
2021-11-22 16:44:27 -05:00
CompletedCompressedSizeCounter . Add ( CompressedBlock - > CompressedSize ) ;
CompletedUncompressedSizeCounter . Add ( CompressedBlock - > UncompressedSize ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnBytesScattered ( int64 NumBytes )
2021-05-31 16:35:03 -04:00
{
CSV_CUSTOM_STAT_DEFINED ( FrameBytesScatteredKB , BytesToApproxKB ( NumBytes ) , ECsvCustomStatOp : : Accumulate ) ;
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
ScatteredSizeCounter . Add ( NumBytes ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnSequentialRead ( )
2021-05-31 16:35:03 -04:00
{
CSV_CUSTOM_STAT_DEFINED ( FrameSequentialReads , 1 , ECsvCustomStatOp : : Accumulate ) ;
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnSeek ( uint64 PrevOffset , uint64 NewOffset )
2021-05-31 16:35:03 -04:00
{
if ( NewOffset > PrevOffset )
{
int64 Delta = NewOffset - PrevOffset ;
CSV_CUSTOM_STAT_DEFINED ( FrameForwardSeeks , 1 , ECsvCustomStatOp : : Accumulate ) ;
CSV_CUSTOM_STAT_DEFINED ( FrameSeekDistanceMB , BytesToApproxMB ( Delta ) , ECsvCustomStatOp : : Accumulate ) ;
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
FileSystemSeeksTotalDistanceCounter . Add ( Delta ) ;
FileSystemSeeksForwardCountCounter . Increment ( ) ;
# endif
2021-05-31 16:35:03 -04:00
}
else
{
int64 Delta = PrevOffset - NewOffset ;
CSV_CUSTOM_STAT_DEFINED ( FrameBackwardSeeks , 1 , ECsvCustomStatOp : : Accumulate ) ;
CSV_CUSTOM_STAT_DEFINED ( FrameSeekDistanceMB , BytesToApproxMB ( Delta ) , ECsvCustomStatOp : : Accumulate ) ;
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
FileSystemSeeksTotalDistanceCounter . Add ( Delta ) ;
FileSystemSeeksBackwardCountCounter . Increment ( ) ;
# endif
2021-05-31 16:35:03 -04:00
}
CSV_CUSTOM_STAT_DEFINED ( FrameSeeks , 1 , ECsvCustomStatOp : : Accumulate ) ;
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnHandleChangeSeek ( )
2021-05-31 16:35:03 -04:00
{
CSV_CUSTOM_STAT_DEFINED ( FrameHandleChangeSeeks , 1 , ECsvCustomStatOp : : Accumulate ) ;
CSV_CUSTOM_STAT_DEFINED ( FrameSeeks , 1 , ECsvCustomStatOp : : Accumulate ) ;
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
FileSystemSeeksChangeHandleCountCounter . Increment ( ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnBlockCacheStore ( uint64 NumBytes )
2021-05-31 16:35:03 -04:00
{
CSV_CUSTOM_STAT_DEFINED ( FrameBlockCacheStores , 1 , ECsvCustomStatOp : : Accumulate ) ;
CSV_CUSTOM_STAT_DEFINED ( FrameBlockCacheStoresKB , BytesToApproxKB ( NumBytes ) , ECsvCustomStatOp : : Accumulate ) ;
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
BlockCacheStoredSizeCounter . Add ( NumBytes ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnBlockCacheHit ( uint64 NumBytes )
2021-05-31 16:35:03 -04:00
{
CSV_CUSTOM_STAT_DEFINED ( FrameBlockCacheHits , 1 , ECsvCustomStatOp : : Accumulate ) ;
CSV_CUSTOM_STAT_DEFINED ( FrameBlockCacheHitKB , BytesToApproxKB ( NumBytes ) , ECsvCustomStatOp : : Accumulate ) ;
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
BlockCacheHitSizeCounter . Add ( NumBytes ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnBlockCacheMiss ( uint64 NumBytes )
2021-05-31 16:35:03 -04:00
{
CSV_CUSTOM_STAT_DEFINED ( FrameBlockCacheMisses , 1 , ECsvCustomStatOp : : Accumulate ) ;
CSV_CUSTOM_STAT_DEFINED ( FrameBlockCacheMissKB , BytesToApproxKB ( NumBytes ) , ECsvCustomStatOp : : Accumulate ) ;
2021-11-22 16:44:27 -05:00
# if COUNTERSTRACE_ENABLED
BlockCacheMissedSizeCounter . Add ( NumBytes ) ;
2021-05-31 16:35:03 -04:00
# endif
}
2021-11-22 16:44:27 -05:00
void FFileIoStoreStats : : OnTocMounted ( uint64 AllocatedSize )
{
# if COUNTERSTRACE_ENABLED
TocMemoryCounter . Add ( AllocatedSize ) ;
# endif
}
void FFileIoStoreStats : : OnTocUnmounted ( uint64 AllocatedSize )
{
# if COUNTERSTRACE_ENABLED
TocMemoryCounter . Subtract ( AllocatedSize ) ;
# endif
}
void FFileIoStoreStats : : OnBufferReleased ( )
{
# if COUNTERSTRACE_ENABLED
AvailableBuffersCounter . Increment ( ) ;
# endif
}
void FFileIoStoreStats : : OnBufferAllocated ( )
{
# if COUNTERSTRACE_ENABLED
AvailableBuffersCounter . Decrement ( ) ;
# endif
}
# endif