- Notifications
You must be signed in to change notification settings - Fork 260
/
Copy pathmmap.hpp
136 lines (113 loc) · 5.39 KB
/
mmap.hpp
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
#pragma once
#include<sys/stat.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<string>
#include<fstream>
#include<iostream>
classMemoryMapped {
public:
enum CacheHint { Normal, SequentialScan, RandomAccess };
enum MapRange { WholeFile = 0 };
MemoryMapped() : _filesize( 0 ), _hint( Normal ),
_mappedBytes( 0 ), _file( 0 ), _mappedView ( NULL ) { }
/// open file, mappedBytes = 0 maps the whole file
MemoryMapped( const std::string& filename, size_t mappedBytes = WholeFile,
CacheHint hint = Normal ) : _filesize( 0 ), _hint( hint ),
_mappedBytes( mappedBytes ), _file( 0 ), _mappedView ( NULL ) {
open( filename.c_str(), mappedBytes, hint );
}
/// open file, mappedBytes = 0 maps the whole file
MemoryMapped( const std::string& filename, size_t mappedBytes = WholeFile,
bool create_first = false, CacheHint hint = Normal ) : _filesize( 0 ), _hint( hint ),
_mappedBytes( mappedBytes ), _file( 0 ), _mappedView ( NULL ) {
bool made = true;
if ( create_first ) {
made = make_empty_file( filename, mappedBytes );
}
if ( made ) {
open( filename.c_str(), mappedBytes, _hint );
}
}
~MemoryMapped() { close(); }
boolopen( constchar * filename, size_t mappedBytes = WholeFile,
CacheHint hint = Normal ) {
if ( isValid() ) returnfalse;
_file = 0;
_filesize = 0;
_hint = hint;
_mappedView = NULL;
_file = ::open( filename, O_RDWR | O_LARGEFILE );
if ( _file == -1 ) { _file = 0; returnfalse; }
structstat64 statInfo;
if ( fstat64( _file, &statInfo ) < 0 ) { returnfalse; }
_filesize = statInfo.st_size;
remap( 0, mappedBytes ); // initial mapping
if ( !_mappedView ) { returnfalse; }
returntrue; // everything's fine
}
voidclose() {
if ( _mappedView ) { ::munmap(_mappedView, _filesize); _mappedView = NULL; }
if ( _file ) { ::close(_file); _file = 0; }
_filesize = 0;
}
void * ptr( uint64_t ofs ) {
uint8_t * p = ( uint8_t * )_mappedView;
uint8_t * p_ofs = p + ofs;
return p_ofs;
}
uint8_t * u8_ptr( uint64_t ofs ) { return (uint8_t *)ptr( ofs ); }
uint16_t * u16_ptr( uint64_t ofs ) { return (uint16_t *)ptr( ofs * 2 ); }
uint32_t * u32_ptr( uint64_t ofs ) { return (uint32_t *)ptr( ofs * 4 ); }
uint64_t * u64_ptr( uint64_t ofs ) { return (uint64_t *)ptr( ofs * 8 ); }
uint64_t& operator[]( uint64_t idx ) { return *u64_ptr( idx ); }
std::string to_string( void ) { returnstd::string( ( constchar * )u8_ptr( 0 ), mappedSize() ); }
boolisValid() const { return _mappedView != NULL; }
uint64_tsize() const { return _filesize; }
size_tmappedSize() const { return _mappedBytes; }
/// replace mapping by a new one of the same file, offset MUST be a multiple of the page size
boolremap( uint64_t offset, size_t mappedBytes ) {
if ( !_file ) { returnfalse; }
if ( mappedBytes == WholeFile ) { mappedBytes = _filesize; }
if ( _mappedView ) { ::munmap( _mappedView, _mappedBytes ); _mappedView = NULL; }
if ( offset > _filesize ) { returnfalse; }
if ( offset + mappedBytes > _filesize ) { mappedBytes = size_t( _filesize - offset ); }
_mappedView = ::mmap64( NULL, mappedBytes, PROT_READ|PROT_WRITE, MAP_SHARED, _file, offset );
if ( _mappedView == MAP_FAILED ) { _mappedBytes = 0; _mappedView = NULL; returnfalse; }
_mappedBytes = mappedBytes;
// tweak performance
int linuxHint = 0;
switch ( _hint )
{
case Normal: linuxHint = MADV_NORMAL; break;
case SequentialScan: linuxHint = MADV_SEQUENTIAL; break;
case RandomAccess: linuxHint = MADV_RANDOM; break;
default: break;
}
linuxHint |= MADV_WILLNEED; // assume that file will be accessed soon
linuxHint |= MADV_HUGEPAGE; // assume that file will be large
::madvise( _mappedView, _mappedBytes, linuxHint );
returntrue;
}
private:
MemoryMapped( const MemoryMapped& ); /// don't copy object
MemoryMapped& operator=( const MemoryMapped& ); /// don't copy object
staticintgetpagesize() { returnsysconf(_SC_PAGESIZE); }
boolmake_empty_file( const std::string& filename, uint64_t file_size ) {
try {
std::ofstream ofs( filename, std::ios::binary | std::ios::out );
ofs.seekp( file_size - 1 );
ofs.write( "", 1 );
returntrue;
} catch ( ... ) {
returnfalse;
}
}
uint64_t _filesize; /// file size
CacheHint _hint; /// caching strategy
size_t _mappedBytes; /// mapped size
typedefint FileHandle; /// define handle
FileHandle _file; /// file handle
void* _mappedView; /// pointer to the file contents mapped into memory
};