Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
IPlatformFileCachedWrapper.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Misc/AssertionMacros.h"
7#include "HAL/UnrealMemory.h"
8#include "Templates/UnrealTemplate.h"
9#include "Math/UnrealMathUtility.h"
10#include "Serialization/Archive.h"
11#include "Containers/UnrealString.h"
12#include "Misc/Parse.h"
13#include "Logging/LogMacros.h"
14#include "Misc/DateTime.h"
15#include "GenericPlatform/GenericPlatformFile.h"
16#include "HAL/IPlatformFileLogWrapper.h"
17#include "Templates/UniquePtr.h"
18
19class IAsyncReadFileHandle;
20
22{
23public:
24 FCachedFileHandle(IFileHandle* InFileHandle, bool bInReadable, bool bInWritable)
26 , FilePos(InFileHandle->Tell())
28 , FileSize(InFileHandle->Size())
29 , bWritable(bInWritable)
30 , bReadable(bInReadable)
31 , CurrentCache(0)
32 {
34 }
35
37 {
38 }
39
40
41 virtual int64 Tell() override
42 {
43 return FilePos;
44 }
45
46 virtual bool Seek(int64 NewPosition) override
47 {
48 if (NewPosition < 0 || NewPosition > FileSize)
49 {
50 return false;
51 }
52 FilePos=NewPosition;
53 return true;
54 }
55
56 virtual bool SeekFromEnd(int64 NewPositionRelativeToEnd = 0) override
57 {
58 return Seek(FileSize - NewPositionRelativeToEnd);
59 }
60
61 virtual bool Read(uint8* Destination, int64 BytesToRead) override
62 {
63 if (!bReadable || BytesToRead < 0 || (BytesToRead + FilePos > FileSize))
64 {
65 return false;
66 }
67
68 if (BytesToRead == 0)
69 {
70 return true;
71 }
72
73 bool Result = false;
74 if (BytesToRead > BufferCacheSize) // reading more than we cache
75 {
76 // if the file position is within the cache, copy out the remainder of the cache
77 int32 CacheIndex=GetCacheIndex(FilePos);
78 if (CacheIndex < CacheCount)
79 {
80 int64 CopyBytes = CacheEnd[CacheIndex]-FilePos;
81 FMemory::Memcpy(Destination, BufferCache[CacheIndex]+(FilePos-CacheStart[CacheIndex]), CopyBytes);
82 FilePos += CopyBytes;
83 BytesToRead -= CopyBytes;
84 Destination += CopyBytes;
85 }
86
88 {
89 Result = InnerRead(Destination, BytesToRead);
90 }
91 if (Result)
92 {
93 FilePos += BytesToRead;
94 }
95 }
96 else
97 {
98 Result = true;
99
100 while (BytesToRead && Result)
101 {
102 uint32 CacheIndex=GetCacheIndex(FilePos);
103 if (CacheIndex > CacheCount)
104 {
105 // need to update the cache
106 uint64 AlignedFilePos=FilePos&BufferSizeMask; // Aligned Version
107 uint64 SizeToRead=FMath::Min<uint64>(BufferCacheSize, FileSize-AlignedFilePos);
108 InnerSeek(AlignedFilePos);
109 Result = InnerRead(BufferCache[CurrentCache], SizeToRead);
110
111 if (Result)
112 {
113 CacheStart[CurrentCache] = AlignedFilePos;
114 CacheEnd[CurrentCache] = AlignedFilePos+SizeToRead;
115 CacheIndex = CurrentCache;
116 // move to next cache for update
117 CurrentCache++;
119 }
120 }
121
122 // copy from the cache to the destination
123 if (Result)
124 {
125 // Analyzer doesn't see this - if this code ever changes make sure there are no buffer overruns!
126 CA_ASSUME(CacheIndex < CacheCount);
127 uint64 CorrectedBytesToRead=FMath::Min<uint64>(BytesToRead, CacheEnd[CacheIndex]-FilePos);
128 FMemory::Memcpy(Destination, BufferCache[CacheIndex]+(FilePos-CacheStart[CacheIndex]), CorrectedBytesToRead);
129 FilePos += CorrectedBytesToRead;
130 Destination += CorrectedBytesToRead;
131 BytesToRead -= CorrectedBytesToRead;
132 }
133 }
134 }
135 return Result;
136 }
137
138 virtual bool Write(const uint8* Source, int64 BytesToWrite) override
139 {
140 if (!bWritable || BytesToWrite < 0)
141 {
142 return false;
143 }
144
145 if (BytesToWrite == 0)
146 {
147 return true;
148 }
149
151 bool Result = FileHandle->Write(Source, BytesToWrite);
152 if (Result)
153 {
154 FilePos += BytesToWrite;
155 FileSize = FMath::Max<int64>(FilePos, FileSize);
158 }
159 return Result;
160 }
161
162 virtual int64 Size() override
163 {
164 return FileSize;
165 }
166
167 virtual bool Flush(const bool bFullFlush = false) override
168 {
169 if (bWritable)
170 {
171 return FileHandle->Flush(bFullFlush);
172 }
173 return false;
174 }
175
176 virtual bool Truncate(int64 NewSize) override
177 {
178 if (bWritable)
179 {
180 if (FileHandle->Truncate(NewSize))
181 {
183 FilePos = TellPos = FileHandle->Tell();
184 FileSize = FileHandle->Size();
185 return true;
186 }
187 }
188 return false;
189 }
190
191 virtual void ShrinkBuffers() override
192 {
193 FileHandle->ShrinkBuffers();
194 }
195
196private:
197
198 static constexpr uint32 BufferCacheSize = 64 * 1024; // Seems to be the magic number for best perf
199 static constexpr uint64 BufferSizeMask = ~((uint64)BufferCacheSize-1);
200 static constexpr uint32 CacheCount = 2;
201
202 bool InnerSeek(uint64 Pos)
203 {
204 if (Pos==TellPos)
205 {
206 return true;
207 }
208 bool bOk=FileHandle->Seek(Pos);
209 if (bOk)
210 {
211 TellPos=Pos;
212 }
213 return bOk;
214 }
215 bool InnerRead(uint8* Dest, uint64 BytesToRead)
216 {
217 if (FileHandle->Read(Dest, BytesToRead))
218 {
219 TellPos += BytesToRead;
220 return true;
221 }
222 return false;
223 }
224 int32 GetCacheIndex(int64 Pos) const
225 {
226 for (uint32 i=0; i<UE_ARRAY_COUNT(CacheStart); ++i)
227 {
228 if (Pos >= CacheStart[i] && Pos < CacheEnd[i])
229 {
230 return i;
231 }
232 }
233 return CacheCount+1;
234 }
236 {
237 for (uint32 i=0; i<CacheCount; ++i)
238 {
239 CacheStart[i] = CacheEnd[i] = -1;
240 }
241 }
242
244 int64 FilePos; /* Desired position in the file stream, this can be different to FilePos due to the cache */
245 int64 TellPos; /* Actual position in the file, this can be different to FilePos */
246 int64 FileSize;
253};
254
256{
258public:
259 static const TCHAR* GetTypeName()
260 {
261 return TEXT("CachedReadFile");
262 }
263
265 : LowerLevel(nullptr)
266 {
267 }
268
269 //~ For visibility of overloads we don't override
270 using IPlatformFile::IterateDirectory;
271 using IPlatformFile::IterateDirectoryRecursively;
272 using IPlatformFile::IterateDirectoryStat;
273 using IPlatformFile::IterateDirectoryStatRecursively;
274
275 virtual bool Initialize(IPlatformFile* Inner, const TCHAR* CommandLineParam) override
276 {
277 // Inner is required.
278 check(Inner != nullptr);
279 LowerLevel = Inner;
280 return !!LowerLevel;
281 }
282 virtual bool ShouldBeUsed(IPlatformFile* Inner, const TCHAR* CmdLine) const override
283 {
284#ifndef PLATFORM_PROVIDES_FILE_CACHE
285#define PLATFORM_PROVIDES_FILE_CACHE 0
286#endif
287 // Default to false on platforms that already do platform file level caching
288 bool bResult = !PLATFORM_PROVIDES_FILE_CACHE && !PLATFORM_WINDOWS && FPlatformProperties::RequiresCookedData();
289
290 // Allow a choice between shorter load times or less memory on desktop platforms.
291 // Note: this cannot be in config since they aren't read at that point.
293 {
294 if (FParse::Param(CmdLine, TEXT("NoCachedReadFile")))
295 {
296 bResult = false;
297 }
298 else if (FParse::Param(CmdLine, TEXT("CachedReadFile")))
299 {
300 bResult = true;
301 }
302
303 UE_LOG(LogPlatformFile, Verbose, TEXT("%s cached read wrapper"), bResult ? TEXT("Using") : TEXT("Not using"));
304 }
305#endif
306 return bResult;
307 }
309 {
310 return LowerLevel;
311 }
312 virtual void SetLowerLevel(IPlatformFile* NewLowerLevel) override
313 {
314 LowerLevel = NewLowerLevel;
315 }
316 virtual const TCHAR* GetName() const override
317 {
319 }
320 virtual bool FileExists(const TCHAR* Filename) override
321 {
322 return LowerLevel->FileExists(Filename);
323 }
324 virtual int64 FileSize(const TCHAR* Filename) override
325 {
326 return LowerLevel->FileSize(Filename);
327 }
328 virtual bool DeleteFile(const TCHAR* Filename) override
329 {
330 return LowerLevel->DeleteFile(Filename);
331 }
332 virtual bool IsReadOnly(const TCHAR* Filename) override
333 {
334 return LowerLevel->IsReadOnly(Filename);
335 }
336 virtual bool MoveFile(const TCHAR* To, const TCHAR* From) override
337 {
338 return LowerLevel->MoveFile(To, From);
339 }
340 virtual bool SetReadOnly(const TCHAR* Filename, bool bNewReadOnlyValue) override
341 {
342 return LowerLevel->SetReadOnly(Filename, bNewReadOnlyValue);
343 }
344 virtual FDateTime GetTimeStamp(const TCHAR* Filename) override
345 {
346 return LowerLevel->GetTimeStamp(Filename);
347 }
348 virtual void SetTimeStamp(const TCHAR* Filename, FDateTime DateTime) override
349 {
350 LowerLevel->SetTimeStamp(Filename, DateTime);
351 }
352 virtual FDateTime GetAccessTimeStamp(const TCHAR* Filename) override
353 {
355 }
356 virtual FString GetFilenameOnDisk(const TCHAR* Filename) override
357 {
358 return LowerLevel->GetFilenameOnDisk(Filename);
359 }
360 virtual IFileHandle* OpenRead(const TCHAR* Filename, bool bAllowWrite) override
361 {
362 IFileHandle* InnerHandle=LowerLevel->OpenRead(Filename, bAllowWrite);
363 if (!InnerHandle)
364 {
365 return nullptr;
366 }
367 return new FCachedFileHandle(InnerHandle, true, false);
368 }
369 virtual IFileHandle* OpenWrite(const TCHAR* Filename, bool bAppend = false, bool bAllowRead = false) override
370 {
371 IFileHandle* InnerHandle=LowerLevel->OpenWrite(Filename, bAppend, bAllowRead);
372 if (!InnerHandle)
373 {
374 return nullptr;
375 }
376 return new FCachedFileHandle(InnerHandle, bAllowRead, true);
377 }
378 virtual bool DirectoryExists(const TCHAR* Directory) override
379 {
380 return LowerLevel->DirectoryExists(Directory);
381 }
382 virtual bool CreateDirectory(const TCHAR* Directory) override
383 {
384 return LowerLevel->CreateDirectory(Directory);
385 }
386 virtual bool DeleteDirectory(const TCHAR* Directory) override
387 {
388 return LowerLevel->DeleteDirectory(Directory);
389 }
390 virtual FFileStatData GetStatData(const TCHAR* FilenameOrDirectory) override
391 {
392 return LowerLevel->GetStatData(FilenameOrDirectory);
393 }
394 virtual bool IterateDirectory(const TCHAR* Directory, IPlatformFile::FDirectoryVisitor& Visitor) override
395 {
396 return LowerLevel->IterateDirectory(Directory, Visitor);
397 }
398 virtual bool IterateDirectoryRecursively(const TCHAR* Directory, IPlatformFile::FDirectoryVisitor& Visitor) override
399 {
400 return LowerLevel->IterateDirectoryRecursively(Directory, Visitor);
401 }
402 virtual bool IterateDirectoryStat(const TCHAR* Directory, IPlatformFile::FDirectoryStatVisitor& Visitor) override
403 {
404 return LowerLevel->IterateDirectoryStat(Directory, Visitor);
405 }
406 virtual bool IterateDirectoryStatRecursively(const TCHAR* Directory, IPlatformFile::FDirectoryStatVisitor& Visitor) override
407 {
409 }
410 virtual void FindFiles(TArray<FString>& FoundFiles, const TCHAR* Directory, const TCHAR* FileExtension)
411 {
412 return LowerLevel->FindFiles(FoundFiles, Directory, FileExtension);
413 }
414 virtual void FindFilesRecursively(TArray<FString>& FoundFiles, const TCHAR* Directory, const TCHAR* FileExtension)
415 {
416 return LowerLevel->FindFilesRecursively(FoundFiles, Directory, FileExtension);
417 }
418 virtual bool DeleteDirectoryRecursively(const TCHAR* Directory) override
419 {
421 }
422 virtual bool CopyFile(const TCHAR* To, const TCHAR* From, EPlatformFileRead ReadFlags = EPlatformFileRead::None, EPlatformFileWrite WriteFlags = EPlatformFileWrite::None) override
423 {
424 return LowerLevel->CopyFile(To, From, ReadFlags, WriteFlags);
425 }
426 virtual bool CreateDirectoryTree(const TCHAR* Directory) override
427 {
428 return LowerLevel->CreateDirectoryTree(Directory);
429 }
430 virtual bool CopyDirectoryTree(const TCHAR* DestinationDirectory, const TCHAR* Source, bool bOverwriteAllExisting) override
431 {
432 return LowerLevel->CopyDirectoryTree(DestinationDirectory, Source, bOverwriteAllExisting);
433 }
434 virtual FString ConvertToAbsolutePathForExternalAppForRead( const TCHAR* Filename ) override
435 {
437 }
438 virtual FString ConvertToAbsolutePathForExternalAppForWrite( const TCHAR* Filename ) override
439 {
441 }
442 virtual bool SendMessageToServer(const TCHAR* Message, IFileServerMessageHandler* Handler) override
443 {
444 return LowerLevel->SendMessageToServer(Message, Handler);
445 }
446 virtual IAsyncReadFileHandle* OpenAsyncRead(const TCHAR* Filename) override
447 {
448 return LowerLevel->OpenAsyncRead(Filename);
449 }
450 virtual IMappedFileHandle* OpenMapped(const TCHAR* Filename) override
451 {
452 return LowerLevel->OpenMapped(Filename);
453 }
454 virtual void SetAsyncMinimumPriority(EAsyncIOPriorityAndFlags MinPriority) override
455 {
457 }
458
459};
#define check(expr)
#define CA_ASSUME(Expr)
EAsyncIOPriorityAndFlags
Definition Enums.h:5594
EPlatformFileRead
EPlatformFileWrite
#define PLATFORM_PROVIDES_FILE_CACHE
#define PLATFORM_WINDOWS
Definition Platform.h:4
#define TEXT(x)
Definition Platform.h:1108
#define PLATFORM_DESKTOP
Definition Platform.h:6
#define UE_ARRAY_COUNT(array)
virtual bool Write(const uint8 *Source, int64 BytesToWrite) override
bool InnerRead(uint8 *Dest, uint64 BytesToRead)
uint8 BufferCache[CacheCount][BufferCacheSize]
static constexpr uint64 BufferSizeMask
virtual bool SeekFromEnd(int64 NewPositionRelativeToEnd=0) override
virtual int64 Size() override
static constexpr uint32 CacheCount
virtual int64 Tell() override
virtual bool Flush(const bool bFullFlush=false) override
virtual void ShrinkBuffers() override
static constexpr uint32 BufferCacheSize
int32 GetCacheIndex(int64 Pos) const
virtual bool Seek(int64 NewPosition) override
FCachedFileHandle(IFileHandle *InFileHandle, bool bInReadable, bool bInWritable)
TUniquePtr< IFileHandle > FileHandle
virtual bool Truncate(int64 NewSize) override
virtual bool Read(uint8 *Destination, int64 BytesToRead) override
virtual bool SendMessageToServer(const TCHAR *Message, IFileServerMessageHandler *Handler) override
IPlatformFile * GetLowerLevel() override
virtual bool FileExists(const TCHAR *Filename) override
virtual FString ConvertToAbsolutePathForExternalAppForRead(const TCHAR *Filename) override
virtual bool Initialize(IPlatformFile *Inner, const TCHAR *CommandLineParam) override
virtual IFileHandle * OpenWrite(const TCHAR *Filename, bool bAppend=false, bool bAllowRead=false) override
virtual FString GetFilenameOnDisk(const TCHAR *Filename) override
virtual FDateTime GetAccessTimeStamp(const TCHAR *Filename) override
virtual void SetTimeStamp(const TCHAR *Filename, FDateTime DateTime) override
virtual bool SetReadOnly(const TCHAR *Filename, bool bNewReadOnlyValue) override
virtual FDateTime GetTimeStamp(const TCHAR *Filename) override
virtual bool IterateDirectoryStatRecursively(const TCHAR *Directory, IPlatformFile::FDirectoryStatVisitor &Visitor) override
virtual bool ShouldBeUsed(IPlatformFile *Inner, const TCHAR *CmdLine) const override
virtual bool DeleteDirectoryRecursively(const TCHAR *Directory) override
virtual void SetAsyncMinimumPriority(EAsyncIOPriorityAndFlags MinPriority) override
virtual FFileStatData GetStatData(const TCHAR *FilenameOrDirectory) override
virtual void FindFiles(TArray< FString > &FoundFiles, const TCHAR *Directory, const TCHAR *FileExtension)
virtual bool DeleteDirectory(const TCHAR *Directory) override
virtual bool IterateDirectoryRecursively(const TCHAR *Directory, IPlatformFile::FDirectoryVisitor &Visitor) override
virtual bool IterateDirectory(const TCHAR *Directory, IPlatformFile::FDirectoryVisitor &Visitor) override
virtual bool DirectoryExists(const TCHAR *Directory) override
virtual IAsyncReadFileHandle * OpenAsyncRead(const TCHAR *Filename) override
virtual const TCHAR * GetName() const override
virtual IFileHandle * OpenRead(const TCHAR *Filename, bool bAllowWrite) override
virtual IMappedFileHandle * OpenMapped(const TCHAR *Filename) override
virtual bool IsReadOnly(const TCHAR *Filename) override
virtual FString ConvertToAbsolutePathForExternalAppForWrite(const TCHAR *Filename) override
virtual void SetLowerLevel(IPlatformFile *NewLowerLevel) override
virtual void FindFilesRecursively(TArray< FString > &FoundFiles, const TCHAR *Directory, const TCHAR *FileExtension)
virtual int64 FileSize(const TCHAR *Filename) override
virtual bool CopyDirectoryTree(const TCHAR *DestinationDirectory, const TCHAR *Source, bool bOverwriteAllExisting) override
virtual bool IterateDirectoryStat(const TCHAR *Directory, IPlatformFile::FDirectoryStatVisitor &Visitor) override
virtual bool CreateDirectoryTree(const TCHAR *Directory) override
virtual int64 Tell()=0
virtual int64 Size()
virtual IFileHandle * OpenWrite(const TCHAR *Filename, bool bAppend=false, bool bAllowRead=false)=0
virtual FFileStatData GetStatData(const TCHAR *FilenameOrDirectory)=0
virtual bool DeleteDirectoryRecursively(const TCHAR *Directory)
virtual IMappedFileHandle * OpenMapped(const TCHAR *Filename)
virtual FString ConvertToAbsolutePathForExternalAppForWrite(const TCHAR *Filename)
virtual bool IterateDirectoryStat(const TCHAR *Directory, FDirectoryStatVisitor &Visitor)=0
virtual FString ConvertToAbsolutePathForExternalAppForRead(const TCHAR *Filename)
virtual IFileHandle * OpenRead(const TCHAR *Filename, bool bAllowWrite=false)=0
virtual bool CopyDirectoryTree(const TCHAR *DestinationDirectory, const TCHAR *Source, bool bOverwriteAllExisting)
virtual void SetAsyncMinimumPriority(EAsyncIOPriorityAndFlags MinPriority)
virtual bool IterateDirectory(const TCHAR *Directory, FDirectoryVisitor &Visitor)=0
virtual bool IterateDirectoryStatRecursively(const TCHAR *Directory, FDirectoryStatVisitor &Visitor)
virtual bool IsReadOnly(const TCHAR *Filename)=0
virtual bool DeleteDirectory(const TCHAR *Directory)=0
virtual void SetTimeStamp(const TCHAR *Filename, FDateTime DateTime)=0
virtual bool DirectoryExists(const TCHAR *Directory)=0
virtual bool CreateDirectoryTree(const TCHAR *Directory)
virtual bool IterateDirectoryRecursively(const TCHAR *Directory, FDirectoryVisitor &Visitor)
virtual bool SetReadOnly(const TCHAR *Filename, bool bNewReadOnlyValue)=0
virtual IAsyncReadFileHandle * OpenAsyncRead(const TCHAR *Filename)
virtual bool FileExists(const TCHAR *Filename)=0
virtual int64 FileSize(const TCHAR *Filename)=0
virtual bool SendMessageToServer(const TCHAR *Message, IFileServerMessageHandler *Handler)
virtual FString GetFilenameOnDisk(const TCHAR *Filename)=0
virtual FDateTime GetTimeStamp(const TCHAR *Filename)=0
virtual FDateTime GetAccessTimeStamp(const TCHAR *Filename)=0
static FORCEINLINE void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition Parse.h:20