-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path_gr_mmio.h
315 lines (298 loc) · 10.6 KB
/
_gr_mmio.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#pragma once
// Copyright David Lawrence Bien 1997 - 2021.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt).
// _gr_mmio.h
// graph I/O through mapped memory.
// dbien: 21APR2020
#include <fcntl.h>
#include "_compat.h"
#ifndef WIN32
#include <unistd.h>
#include <sys/mman.h>
#endif //!WIN32
#include "_gr_inc.h"
#include "_fdobjs.h"
__DGRAPH_BEGIN_NAMESPACE
// Specialize for mmout - default version just writes raw memory:
template < class t_TyWrite >
__INLINE size_t
_StRawWriteGraphEl( void * _pvWrite, ssize_t _sstLeft, t_TyWrite const & _rEl )
{
if ( sizeof( _rEl ) )
{
if ( sizeof( _rEl ) <= _sstLeft )
memcpy( _pvWrite, &_rEl, sizeof( _rEl ) );
return sizeof( _rEl );
}
}
// Specialize for mmin - default version just reads raw memory:
template < class t_TyRead >
__INLINE size_t
_StRawReadGraphEl( const void * _pvRead, ssize_t _sstLeft, t_TyRead & _rEl )
{
if ( sizeof( _rEl ) )
{
__THROWPT( e_ttFileInput );
if ( _sstLeft < sizeof( _rEl ) )
THROWNAMEDEXCEPTION( "EOF reading element." );
memcpy( &_rEl, _pvRead, sizeof( _rEl ) );
return sizeof( _rEl );
}
}
struct _mm_RawElIO
{
template < class t_TyEl >
size_t StWrite( void * _pvWrite, ssize_t _sstLeft, t_TyEl const & _rel )
{
return _StRawWriteGraphEl( _pvWrite, _sstLeft, _rel );
}
template < class t_TyEl >
size_t StRead( const void * _pvRead, ssize_t _sstLeft, t_TyEl & _rel )
{
return _StRawReadGraphEl( _pvRead, _sstLeft, _rel );
}
};
template < class t_TyOutputNodeEl,
class t_TyOutputLinkEl = t_TyOutputNodeEl,
size_t t_knGrowFileByBytes = 65536 >
struct _mmout_object
{
typedef int _TyInitArg;
typedef vtySeekOffset _TyStreamPos;
typedef t_TyOutputNodeEl _TyIONodeEl;
typedef t_TyOutputLinkEl _TyIOLinkEl;
static const size_t s_knGrowFileByBytes = t_knGrowFileByBytes;
vtyFileHandle m_hFile{vkhInvalidFileHandle}; // This object doesn't own the lifetime of the open file.
FileMappingObj m_fmoFile; // We do own the lifetime of our mapping however.
//uint8_t * m_pbyMappedBegin{(uint8_t*)vkpvNullMapping};
uint8_t * m_pbyMappedCur{(uint8_t*)vkpvNullMapping};
uint8_t * m_pbyMappedEnd{(uint8_t*)vkpvNullMapping};
t_TyOutputNodeEl m_one;
t_TyOutputLinkEl m_ole;
_mmout_object( _mmout_object const & ) = delete;
_mmout_object() = delete;
_mmout_object( int _hFile,
t_TyOutputNodeEl const & _rone,
t_TyOutputLinkEl const & _role )
: m_hFile( _hFile ),
m_one( _rone ),
m_ole( _role )
{
_OpenMap();
}
_mmout_object( int _hFile,
t_TyOutputNodeEl && _rrone,
t_TyOutputLinkEl && _rrole )
: m_hFile( _hFile ),
m_one( std::move( _rrone ) ),
m_ole( std::move( _rrole ) )
{
_OpenMap();
}
~_mmout_object() noexcept(false)
{
Assert( m_fmoFile.FIsOpen() && ( vkhInvalidFileHandle != m_hFile ) );
if ( !m_fmoFile.FIsOpen() || ( vkhInvalidFileHandle == m_hFile ) )
return;
bool fInUnwinding = !!std::uncaught_exceptions();
void * pvMappedSave = m_fmoFile.Pv();
int iCloseFileMapping = m_fmoFile.Close();
vtyErrNo errCloseFileMapping = !iCloseFileMapping ? vkerrNullErrNo : GetLastErrNo();
vtyErrNo errTruncate = vkerrNullErrNo;
if ( vkhInvalidFileHandle != m_hFile )
{
// We need to truncate the file to m_cpxMappedCur - m_pvMapped bytes.
size_t stSizeTruncate = m_pbyMappedCur - (uint8_t*)pvMappedSave;
int iTruncate = FileSetSize(m_hFile, stSizeTruncate);
errTruncate = !iTruncate ? vkerrNullErrNo : GetLastErrNo();
}
vtyErrNo errFirst;
unsigned nError;
if ( ( (nError = 1), ( vkerrNullErrNo != ( errFirst = errTruncate ) ) ) ||
( (nError = 2), ( vkerrNullErrNo != ( errFirst = errCloseFileMapping ) ) ) )
{
// Ensure that the errno is represented in the last error:
SetLastErrNo( errFirst );
if ( !fInUnwinding )
{
const char * pcThrow;
switch( nError )
{
case 1: pcThrow = "Error encountered truncating m_hFile[0x%zx]"; break;
case 2: pcThrow = "Error encountered closing file mapping m_hFile[0x%zx]"; break;
default: pcThrow = "Wh-what?! m_hFile[0x%zx]"; break;
}
THROWNAMEDEXCEPTIONERRNO( errFirst, pcThrow, (size_t)m_hFile );
}
}
if ( !fInUnwinding )
__THROWPT_DTOR( e_ttFileOutput | e_ttFatal, fInUnwinding );
}
_TyStreamPos TellP() const
{
return m_pbyMappedCur - (uint8_t*)m_fmoFile.Pv();
}
void SeekP( _TyStreamPos _sp )
{
// We will let the caller set the position anywhere at all.
m_pbyMappedCur = (uint8_t*)m_fmoFile.Pv() + _sp;
}
void Write( const void * _pv, size_t _st )
{
if ( ssize_t( _st ) > ( m_pbyMappedEnd - m_pbyMappedCur ) )
_GrowMap( ssize_t(_st) - ( m_pbyMappedEnd - m_pbyMappedCur ) );
memcpy( m_pbyMappedCur, _pv, _st );
m_pbyMappedCur += _st;
}
template < class t_TyEl >
void WriteNodeEl( t_TyEl const & _rel )
{
ssize_t sstLeft = ( m_pbyMappedEnd - m_pbyMappedCur );
size_t stNeed = m_one.StWrite( m_pbyMappedCur, sstLeft, _rel );
if ( stNeed > sstLeft )
{
_GrowMap( stNeed - sstLeft );
size_t stNeed2 = m_one.StWrite( m_pbyMappedCur, ( m_pbyMappedEnd - m_pbyMappedCur ), _rel );
Assert( stNeed == stNeed2 );
}
m_pbyMappedCur += stNeed;
}
template < class t_TyEl >
void WriteLinkEl( t_TyEl const & _rel )
{
ssize_t sstLeft = ( m_pbyMappedEnd - m_pbyMappedCur );
size_t stNeed = m_ole.StWrite( m_pbyMappedCur, sstLeft, _rel );
if ( stNeed > sstLeft )
{
_GrowMap( stNeed - sstLeft );
size_t stNeed2 = m_ole.StWrite( m_pbyMappedCur, ( m_pbyMappedEnd - m_pbyMappedCur ), _rel );
Assert( stNeed == stNeed2 );
}
m_pbyMappedCur += stNeed;
}
protected:
void _OpenMap()
{
int iResult = FileSetSize( m_hFile, s_knGrowFileByBytes ); // Set initial size.
__THROWPT( e_ttFileOutput | e_ttFatal );
if ( !!iResult )
THROWNAMEDEXCEPTIONERRNO(GetLastErrNo(), "FileSetSize() m_hFile[0x%zx]", (size_t)m_hFile);
m_fmoFile.SetHMMFile( MapReadWriteHandle( m_hFile ) );
__THROWPT( e_ttFileOutput | e_ttFatal );
if ( !m_fmoFile.FIsOpen() )
THROWNAMEDEXCEPTIONERRNO(GetLastErrNo(), "Mapping failed m_hFile[0x%zx]", (size_t)m_hFile);
m_pbyMappedCur = (uint8_t*)m_fmoFile.Pv();
m_pbyMappedEnd = m_pbyMappedCur + s_knGrowFileByBytes;
}
void _GrowMap( size_t _stByAtLeast )
{
VerifyThrow( m_fmoFile.FIsOpen() && ( vkhInvalidFileHandle != m_hFile ) );
size_t stGrowBy = ( ( ( _stByAtLeast - 1 ) / s_knGrowFileByBytes ) + 1 ) * s_knGrowFileByBytes;
size_t stMapped = m_pbyMappedEnd - (uint8_t*)m_fmoFile.Pv();
size_t stCurOffset = m_pbyMappedCur - (uint8_t*)m_fmoFile.Pv();
m_pbyMappedCur = (uint8_t*)vkpvNullMapping;
m_pbyMappedEnd = (uint8_t*)vkpvNullMapping;
(void)m_fmoFile.Close();
int iFileSetSize = FileSetSize(m_hFile, stMapped + stGrowBy);
__THROWPT( e_ttFileOutput | e_ttFatal );
if (-1 == iFileSetSize)
THROWNAMEDEXCEPTIONERRNO( GetLastErrNo(), "FileSetSize() failed for m_hFile[0x%zx].", (size_t)m_hFile );
m_fmoFile.SetHMMFile( MapReadWriteHandle( m_hFile ) );
__THROWPT( e_ttFileOutput | e_ttFatal );
if ( !m_fmoFile.FIsOpen() )
THROWNAMEDEXCEPTIONERRNO(GetLastErrNo(), "Remapping the failed for m_hFile[0x%zx].", (size_t)m_hFile );
m_pbyMappedEnd = (uint8_t*)m_fmoFile.Pv() + stMapped;
m_pbyMappedCur = (uint8_t*)m_fmoFile.Pv() + stCurOffset;
}
};
template < class t_TyInputNodeEl,
class t_TyInputLinkEl = t_TyInputNodeEl >
struct _mmin_object
{
typedef int _TyInitArg;
typedef vtySeekOffset _TyStreamPos;
typedef t_TyInputNodeEl _TyIONodeEl;
typedef t_TyInputLinkEl _TyIOLinkEl;
vtyFileHandle m_hFile{vkhInvalidFileHandle}; // This object doesn't own the lifetime of the open file.
FileMappingObj m_fmoFile; // We own the mapping.
const uint8_t * m_pbyMappedCur{(uint8_t*)vkpvNullMapping};
const uint8_t * m_pbyMappedEnd{(uint8_t*)vkpvNullMapping};
t_TyInputNodeEl m_ine;
t_TyInputLinkEl m_ile;
_mmin_object( _mmin_object const & ) = delete;
_mmin_object() = delete;
_mmin_object( int _hFile,
t_TyInputNodeEl const & _rine,
t_TyInputLinkEl const & _rile )
: m_hFile( _hFile ),
m_ine( _rine ),
m_ile( _rile )
{
_OpenMap();
}
_mmin_object( int _hFile,
t_TyInputNodeEl && _rrine,
t_TyInputLinkEl && _rrile )
: m_hFile( _hFile ),
m_ine( std::move( _rrine ) ),
m_ile( std::move( _rrile ) )
{
_OpenMap();
}
_TyStreamPos TellG() const
{
return m_pbyMappedCur - (uint8_t*)m_fmoFile.Pv();
}
void SeekG( _TyStreamPos _sp )
{
// We allow seeking beyond the end - but Read will throw if we try to read there.
m_pbyMappedCur = (uint8_t*)m_fmoFile.Pv() + _sp;
}
void Read( void * _pv, size_t _st )
{
__THROWPT( e_ttFileInput ); // should be able to recover from this.
if ( ssize_t(_st) > ( m_pbyMappedEnd - m_pbyMappedCur ) )
THROWNAMEDEXCEPTION( "EOF.");
memcpy( _pv, m_pbyMappedCur, _st );
m_pbyMappedCur += _st;
}
template < class t_TyEl >
void ReadNodeEl( t_TyEl & _rel )
{
ssize_t sstLeft = m_pbyMappedEnd - m_pbyMappedCur;
size_t stRead = m_ine.StRead( m_pbyMappedCur, sstLeft, _rel ); // throws on EOF.
m_pbyMappedCur += stRead;
}
template < class t_TyEl >
void ReadLinkEl( t_TyEl & _rel )
{
ssize_t sstLeft = m_pbyMappedEnd - m_pbyMappedCur;
size_t stRead = m_ile.StRead( m_pbyMappedCur, sstLeft, _rel ); // throws on EOF.
m_pbyMappedCur += stRead;
}
protected:
void _OpenMap()
{
VerifyThrow( vkhInvalidFileHandle != m_hFile );
// Now get the size of the file and then map it.
vtyHandleAttr attrFile;
int iResult = GetHandleAttrs( m_hFile, attrFile );
if (-1 == iResult)
THROWNAMEDEXCEPTIONERRNO(GetLastErrNo(), "GetHandleAttrs() failed for m_hFile[0x%zx].", (size_t)m_hFile);
uint64_t u64Size = GetSize_HandleAttr( attrFile );
if (0 == u64Size )
THROWNAMEDEXCEPTION("Can't map an empty m_hFile[0x%zx].", (size_t)m_hFile);
__THROWPT( e_ttFileInput | e_ttFatal );
if ( !FIsRegularFile_HandleAttr( attrFile ) )
THROWNAMEDEXCEPTION("m_hFile[0x%zx] is not a regular file.", (size_t)m_hFile);
m_fmoFile.SetHMMFile( MapReadOnlyHandle( m_hFile, nullptr ) );
__THROWPT( e_ttFileInput | e_ttFatal );
if ( !m_fmoFile.FIsOpen() )
THROWNAMEDEXCEPTIONERRNO(GetLastErrNo(), "MapReadOnlyHandle() failed to map m_hFile[0x%zx], size [%llu].", (size_t)m_hFile, u64Size);
m_pbyMappedCur = (const uint8_t*)m_fmoFile.Pv();
m_pbyMappedEnd = m_pbyMappedCur + u64Size;
}
};
__DGRAPH_END_NAMESPACE