Skip to content

Commit 6530ec3

Browse files
Add alternative methods for reading files
Using mmap only seems to be very slow with some NAS
1 parent fce3a36 commit 6530ec3

File tree

8 files changed

+241
-12
lines changed

8 files changed

+241
-12
lines changed

Source/CLI/Global.cpp

+43
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,40 @@ int global::SetHash(bool Value)
242242
return 0;
243243
}
244244

245+
//---------------------------------------------------------------------------
246+
int global::SetFileOpenMethod(const char* Value)
247+
{
248+
if (strcmp(Value, "mmap") == 0)
249+
{
250+
FileOpenMethod = filemap::method::mmap;
251+
return 0;
252+
}
253+
if (strcmp(Value, "fstream") == 0)
254+
{
255+
FileOpenMethod = filemap::method::fstream;
256+
return 0;
257+
}
258+
if (strcmp(Value, "fopen") == 0)
259+
{
260+
FileOpenMethod = filemap::method::fopen;
261+
return 0;
262+
}
263+
if (strcmp(Value, "open") == 0)
264+
{
265+
FileOpenMethod = filemap::method::open;
266+
return 0;
267+
}
268+
#if defined(_WIN32) || defined(_WINDOWS)
269+
if (strcmp(Value, "createfile") == 0)
270+
{
271+
FileOpenMethod = filemap::method::createfile;
272+
return 0;
273+
}
274+
#endif //defined(_WIN32) || defined(_WINDOWS)
275+
cerr << "Error: unknown io value '" << Value << "'." << endl;
276+
return 1;
277+
}
278+
245279
//---------------------------------------------------------------------------
246280
int global::SetAll(bool Value)
247281
{
@@ -432,6 +466,7 @@ int global::ManageCommandLine(const char* argv[], int argc)
432466
IgnoreLicenseKey = !License.IsSupported_License();
433467
SubLicenseId = 0;
434468
SubLicenseDur = 1;
469+
FileOpenMethod = filemap::method::mmap;
435470
ShowLicenseKey = false;
436471
StoreLicenseKey = false;
437472
DisplayCommand = false;
@@ -748,6 +783,14 @@ int global::ManageCommandLine(const char* argv[], int argc)
748783
if (auto Value = SetAcceptFiles())
749784
return Value;
750785
}
786+
else if (strcmp(argv[i], "--io") == 0)
787+
{
788+
if (i + 1 == argc)
789+
return Error_Missing(argv[i]);
790+
int Value = SetFileOpenMethod(argv[++i]);
791+
if (Value)
792+
return Value;
793+
}
751794
else if (!strcmp(argv[i], "-framerate"))
752795
{
753796
if (OptionsForOtherFiles)

Source/CLI/Global.h

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class global
3838
string LicenseKey;
3939
uint64_t SubLicenseId;
4040
uint64_t SubLicenseDur;
41+
filemap::method FileOpenMethod;
4142
bool IgnoreLicenseKey;
4243
bool ShowLicenseKey;
4344
bool StoreLicenseKey;
@@ -100,6 +101,7 @@ class global
100101
int SetFrameMd5An(bool Value);
101102
int SetFrameMd5FileName(const char* FileName);
102103
int SetHash(bool Value);
104+
int SetFileOpenMethod(const char* Value);
103105
int SetAll(bool Value);
104106

105107
private:

Source/CLI/Main.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ int ParseFile_Uncompressed(parse_info& ParseInfo, size_t Files_Pos)
481481
}
482482

483483
//---------------------------------------------------------------------------
484-
int ParseFile_Compressed(parse_info& ParseInfo)
484+
int ParseFile_Compressed(parse_info& ParseInfo, const string* FileOpenName)
485485
{
486486
// Init
487487
string OutputDirectoryName;
@@ -522,6 +522,8 @@ int ParseFile_Compressed(parse_info& ParseInfo)
522522
matroska* M = new matroska(OutputDirectoryName, &Global.Mode, Ask_Callback, Thread_Pool, &Global.Errors);
523523
M->Quiet = Global.Quiet;
524524
M->NoOutputCheck = NoOutputCheck;
525+
M->OpenName = FileOpenName;
526+
M->OpenStyle = Global.FileOpenMethod;
525527
if (ParseInfo.ParseFile_Input(*M))
526528
{
527529
ReturnValue = 1;
@@ -591,7 +593,7 @@ int ParseFile(size_t Files_Pos)
591593
return 1;
592594

593595
// Compressed content
594-
if (int Value = ParseFile_Compressed(ParseInfo))
596+
if (int Value = ParseFile_Compressed(ParseInfo, ParseInfo.Name))
595597
return Value;
596598
if (ParseInfo.IsDetected)
597599
return 0;
@@ -755,6 +757,7 @@ int main(int argc, const char* argv[])
755757
if (!Value)
756758
{
757759
// Configure for a 2nd pass
760+
auto FileOpenName = Global.OutputFileName;
758761
ParseInfo.Name = NULL;
759762
Global.OutputFileName = Global.Inputs[0];
760763
if (!Global.Actions[Action_Hash]) // If hashes are present in the file, output is checked by using hashes
@@ -772,7 +775,7 @@ int main(int argc, const char* argv[])
772775
// Parse (check mode)
773776
Global.Actions.set(Action_QuickCheckAfterEncode, !Global.Actions[Action_Check]);
774777
Global.Actions.set(Action_Decode, false); // Override config
775-
Value = ParseFile_Compressed(ParseInfo);
778+
Value = ParseFile_Compressed(ParseInfo, &FileOpenName);
776779
if (!Value && !ParseInfo.IsDetected)
777780
{
778781
cout << '\n' << "Error: " << Global.OutputFileName << endl;

Source/Lib/Compressed/Matroska/Matroska.cpp

+18-2
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,16 @@ void matroska::ParseBuffer()
359359
// Check if we can indicate the system that we'll not need anymore memory below this value, without indicating it too much
360360
if (Buffer_Offset > Buffer_Offset_LowerLimit + 1024 * 1024 && Buffer_Offset < Buffer.Size()) // TODO: when multi-threaded frame decoding is implemented, we need to check that all thread don't need anymore memory below this value
361361
{
362-
FileMap->Remap();
362+
FileMap->Remap(Buffer_Offset, Buffer_Offset + 256 * 1024 * 1024);
363363
Buffer = *FileMap;
364+
if (OpenStyle == filemap::method::mmap)
365+
{
364366
if (ReversibilityData)
365367
ReversibilityData->SetBaseData(Buffer.Data());
366368
for (const auto& TrackInfo_Current : TrackInfo)
367369
if (TrackInfo_Current && TrackInfo_Current->ReversibilityData)
368370
TrackInfo_Current->ReversibilityData->SetBaseData(Buffer.Data());
371+
}
369372
Buffer_Offset_LowerLimit = Buffer_Offset;
370373
}
371374

@@ -376,7 +379,7 @@ void matroska::ParseBuffer()
376379
Buffer_Offset = Cluster_Offset;
377380
Cluster_Level = (size_t)-1;
378381

379-
FileMap->Remap();
382+
FileMap->Remap(Buffer_Offset, 256 * 1024 * 1024);
380383
Buffer = *FileMap;
381384
if (ReversibilityData)
382385
ReversibilityData->SetBaseData(Buffer.Data());
@@ -850,6 +853,19 @@ void matroska::Segment_Cluster()
850853
Errors->Error(IO_FileChecker, error::type::Undecodable, (error::generic::code)filechecker_issue::undecodable::Format_Undetected, string());
851854
if (ReversibilityData && !FrameWriter_Template->Compound)
852855
InitOutput_Find();
856+
857+
Actions[Action_Hash] = false;
858+
859+
if (!FileMap2)
860+
{
861+
FileMap2 = FileMap;
862+
if (OpenStyle != filemap::method::mmap && OpenName)
863+
{
864+
FileMap = new filemap;
865+
FileMap->Open_ReadMode(*OpenName, OpenStyle, 0, 256 * 1024 * 1024);
866+
Buffer = *FileMap;
867+
}
868+
}
853869
}
854870

855871
//---------------------------------------------------------------------------

Source/Lib/Utils/FileIO/FileIO.cpp

+152-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
#include "Lib/Utils/FileIO/FileIO.h"
1212
#include <iostream>
1313
#include <sstream>
14+
#include <fstream>
1415
#if defined(_WIN32) || defined(_WINDOWS)
1516
#include "windows.h"
17+
#include <stdio.h>
18+
#include <fcntl.h>
1619
#include <io.h> // File existence
1720
#include <direct.h> // Directory creation
1821
#define access _access_s
@@ -29,10 +32,106 @@
2932
//---------------------------------------------------------------------------
3033

3134
//---------------------------------------------------------------------------
32-
int filemap::Open_ReadMode(const char* FileName)
35+
struct private_buffered
36+
{
37+
union f
38+
{
39+
FILE* File;
40+
ifstream* Ifstream;
41+
int Int;
42+
#if defined(_WIN32) || defined(_WINDOWS)
43+
HANDLE Handle;
44+
#endif
45+
};
46+
f F;
47+
size_t Data_Shift = 0;
48+
size_t MaxSize = 0;
49+
};
50+
51+
//---------------------------------------------------------------------------
52+
int filemap::Open_ReadMode(const char* FileName, method NewStyle, size_t Begin, size_t End)
3353
{
3454
Close();
3555

56+
if (NewStyle != method::mmap)
57+
{
58+
Method = NewStyle;
59+
private_buffered* P = new private_buffered;
60+
P->MaxSize = End - Begin;
61+
size_t FileSize;
62+
63+
switch (Method)
64+
{
65+
default: // case style::fstream:
66+
{
67+
auto F = new ifstream(FileName, ios::binary);
68+
F->seekg(0, F->end);
69+
FileSize = F->tellg();
70+
F->seekg(Begin, F->beg);
71+
P->F.Ifstream = F;
72+
break;
73+
}
74+
case method::fopen:
75+
{
76+
struct stat Fstat;
77+
if (stat(FileName, &Fstat))
78+
return 1;
79+
FileSize = Fstat.st_size;
80+
auto F = fopen(FileName, "rb");
81+
P->F.File = F;
82+
break;
83+
}
84+
case method::open:
85+
{
86+
struct stat Fstat;
87+
if (stat(FileName, &Fstat))
88+
return 1;
89+
FileSize = Fstat.st_size;
90+
#if defined(_WIN32) || defined(_WINDOWS)
91+
auto F = _open(FileName, _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, _S_IREAD);
92+
#else //defined(_WIN32) || defined(_WINDOWS)
93+
auto F = open(FileName, O_RDONLY);
94+
#endif //defined(_WIN32) || defined(_WINDOWS)
95+
if (F == -1)
96+
return 1;
97+
P->F.Int = F;
98+
break;
99+
}
100+
#if defined(_WIN32) || defined(_WINDOWS)
101+
case method::createfile:
102+
{
103+
DWORD FileSizeHigh;
104+
auto NewFile = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
105+
auto FileSizeLow = GetFileSize(NewFile, &FileSizeHigh);
106+
if ((FileSizeLow != INVALID_FILE_SIZE || GetLastError() == NO_ERROR) // If no error (special case with 32-bit max value)
107+
&& (!FileSizeHigh || sizeof(size_t) >= 8)) // Mapping 4+ GiB files is not supported in 32-bit mode
108+
{
109+
FileSize = ((size_t)FileSizeHigh) << 32 | FileSizeLow;
110+
}
111+
else
112+
return 1;
113+
if (Begin)
114+
{
115+
LARGE_INTEGER GoTo;
116+
GoTo.QuadPart = Begin;
117+
if (!SetFilePointerEx(NewFile, GoTo, nullptr, 0))
118+
return 1;
119+
P->Data_Shift = Begin;
120+
}
121+
P->F.Handle = NewFile;
122+
break;
123+
}
124+
#endif //defined(_WIN32) || defined(_WINDOWS)
125+
}
126+
127+
auto Buffer = new uint8_t[P->MaxSize];
128+
P->Data_Shift -= P->MaxSize;
129+
AssignBase(Buffer - P->Data_Shift, FileSize);
130+
Private2 = (decltype(Private2))P;
131+
132+
return Remap(Begin, End);
133+
}
134+
36135
size_t NewSize;
37136
#if defined(_WIN32) || defined(_WINDOWS)
38137
auto NewFile = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
@@ -99,12 +198,63 @@ inline int munmap_const(const void* addr, size_t length)
99198
#pragma GCC diagnostic pop
100199
#endif
101200
#endif
102-
int filemap::Remap()
201+
int filemap::Remap(size_t Begin, size_t End)
103202
{
104203
// Special case for 0-byte files
105204
if (Empty())
106205
return 0;
107206

207+
if (Method != method::mmap)
208+
{
209+
auto P = (private_buffered*)Private2;
210+
auto Buffer = Data() + P->Data_Shift;
211+
auto Buffer_MaxSize = P->MaxSize;
212+
Begin -= P->Data_Shift;
213+
if (!End)
214+
End = Size();
215+
End -= P->Data_Shift;
216+
auto Buffer_Middle = Buffer + Begin;
217+
auto Buffer_Middle_Size = Buffer_MaxSize - Begin;
218+
memmove((void*)Buffer, (void*)Buffer_Middle, Buffer_Middle_Size);
219+
P->Data_Shift += Begin;
220+
AssignKeepSizeBase(Buffer - P->Data_Shift);
221+
Buffer += Buffer_Middle_Size;
222+
Buffer_MaxSize -= Buffer_Middle_Size;
223+
224+
switch (Method)
225+
{
226+
default: // case style::fstream:
227+
{
228+
auto F = P->F.Ifstream;
229+
F->read((char*)Buffer, Buffer_MaxSize);
230+
break;
231+
}
232+
case method::fopen:
233+
{
234+
auto F = P->F.File;
235+
if (fread((char*)Buffer, Buffer_MaxSize, 1, F) != 1)
236+
return 1;
237+
break;
238+
}
239+
case method::open:
240+
{
241+
auto F = P->F.Int;
242+
read(F, (void*)Buffer, Buffer_MaxSize);
243+
break;
244+
}
245+
#if defined(_WIN32) || defined(_WINDOWS)
246+
case method::createfile:
247+
{
248+
auto F = P->F.Handle;
249+
ReadFile(F, (LPVOID)Buffer, (DWORD)Buffer_MaxSize, nullptr, 0);
250+
break;
251+
}
252+
#endif //defined(_WIN32) || defined(_WINDOWS)
253+
}
254+
255+
return 0;
256+
}
257+
108258
// Close previous map
109259
if (Data())
110260
{

Source/Lib/Utils/FileIO/FileIO.h

+15-4
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,30 @@ class filemap : public buffer_view
2323
~filemap() { Close(); }
2424

2525
// Actions
26-
int Open_ReadMode(const char* FileName);
27-
int Open_ReadMode(const string& FileName) { return Open_ReadMode(FileName.c_str()); }
26+
enum class method
27+
{
28+
mmap,
29+
fstream,
30+
fopen,
31+
open,
32+
#if defined(_WIN32) || defined(_WINDOWS)
33+
createfile,
34+
#endif //defined(_WIN32) || defined(_WINDOWS)
35+
};
36+
int Open_ReadMode(const char* FileName, method NewMethod = {}, size_t Begin = {}, size_t End = {});
37+
int Open_ReadMode(const string& FileName, method NewMethod = {}, size_t Begin = {}, size_t End = {}) { return Open_ReadMode(FileName.c_str(), NewMethod, Begin, End); }
2838
bool IsOpen() { return Private == (decltype(Private))-1 ? false : true; }
29-
int Remap();
39+
int Remap(size_t Begin = 0, size_t End = 0);
3040
int Close();
3141

3242
private:
3343
#if defined(_WIN32) || defined(_WINDOWS)
3444
void* Private = (void*)-1;
35-
void* Private2 = (void*)-1;
3645
#else //defined(_WIN32) || defined(_WINDOWS)
3746
int Private = (int)-1;
3847
#endif //defined(_WIN32) || defined(_WINDOWS)
48+
void* Private2 = (void*)-1;
49+
method Method = {};
3950
};
4051

4152
class file

Source/Lib/Utils/FileIO/Input_Base.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ input_base::~input_base()
3838
bool input_base::Parse(filemap* FileMap_Source, const buffer_view& Buffer_Source, size_t FileSize_Source)
3939
{
4040
FileMap = FileMap_Source;
41+
FileMap2 = nullptr;
4142
FileSize = FileSize_Source == (size_t)-1 ? Buffer_Source.Size() : FileSize_Source;
4243
Buffer = Buffer_Source;
4344
HashComputed = false;

0 commit comments

Comments
 (0)