Skip to content
Browse files

SERVER-5663, SERVER-2942 MapViewOfFileEx backport

Backport the fixes for Windows memory-mapped files made in
2.1.x into the 2.0.x branch.  Stop using VirtualProtect in
remapPrivateView, use UnmapViewOfFile and MapViewOfFileEx
to refresh the private view of the memory-mapped file.
Place memory-mapped files at a high address in 64-bit to
get out of the way of allocations made by Windows.
  • Loading branch information...
1 parent 4ada6df commit 881d6229e1ab58695959862a76f3175e142af84e @tadmarshall tadmarshall committed
Showing with 109 additions and 67 deletions.
  1. +41 −38 db/mongommf.cpp
  2. +11 −11 util/mmap.h
  3. +57 −18 util/mmap_win.cpp
View
79 db/mongommf.cpp
@@ -88,19 +88,25 @@ namespace mongo {
void* MemoryMappedFile::createPrivateMap() {
assert( maphandle );
scoped_lock lk(mapViewMutex);
- void *p = MapViewOfFile(maphandle, FILE_MAP_READ, 0, 0, 0);
- if ( p == 0 ) {
- DWORD e = GetLastError();
- log() << "createPrivateMap failed " << filename() << " " <<
- errnoWithDescription(e) << " filelen:" << len <<
- ((sizeof(void*) == 4 ) ? " (32 bit build)" : "") <<
- endl;
+ LPVOID thisAddress = getNextMemoryMappedFileLocation( len );
+ void* privateMapAddress = MapViewOfFileEx(
+ maphandle, // file mapping handle
+ FILE_MAP_READ, // access
+ 0, 0, // file offset, high and low
+ 0, // bytes to map, 0 == all
+ thisAddress ); // address to place file
+ if ( privateMapAddress == 0 ) {
+ DWORD dosError = GetLastError();
+ log() << "MapViewOfFileEx for " << filename()
+ << " failed with " << errnoWithDescription( dosError )
+ << " (file size is " << len << ")"
+ << " in MemoryMappedFile::createPrivateMap, terminating"
+ << endl;
+ ::abort();
}
- else {
- clearWritableBits(p);
- views.push_back(p);
- }
- return p;
+ clearWritableBits( privateMapAddress );
+ views.push_back( privateMapAddress );
+ return privateMapAddress;
}
void* MemoryMappedFile::remapPrivateView(void *oldPrivateAddr) {
@@ -109,37 +115,34 @@ namespace mongo {
// the mapViewMutex is to assure we get the same address on the remap
scoped_lock lk(mapViewMutex);
+ RWLockRecursive::Exclusive lockMongoFiles(mmmutex);
+
clearWritableBits(oldPrivateAddr);
-#if 1
- // https://jira.mongodb.org/browse/SERVER-2942
- DWORD old;
- bool ok = VirtualProtect(oldPrivateAddr, (SIZE_T) len, PAGE_READONLY, &old);
- if( !ok ) {
- DWORD e = GetLastError();
- log() << "VirtualProtect failed in remapPrivateView " << filename() << hex << oldPrivateAddr << ' ' << len << ' ' << errnoWithDescription(e) << endl;
- assert(false);
- }
- return oldPrivateAddr;
-#else
if( !UnmapViewOfFile(oldPrivateAddr) ) {
- DWORD e = GetLastError();
- log() << "UnMapViewOfFile failed " << filename() << ' ' << errnoWithDescription(e) << endl;
- assert(false);
+ DWORD dosError = GetLastError();
+ log() << "UnMapViewOfFile for " << filename()
+ << " failed with " << errnoWithDescription( dosError )
+ << " in MemoryMappedFile::remapPrivateView, terminating"
+ << endl;
+ ::abort();
}
- // we want the new address to be the same as the old address in case things keep pointers around (as namespaceindex does).
- void *p = MapViewOfFileEx(maphandle, FILE_MAP_READ, 0, 0,
- /*dwNumberOfBytesToMap 0 means to eof*/0 /*len*/,
- oldPrivateAddr);
-
- if ( p == 0 ) {
- DWORD e = GetLastError();
- log() << "MapViewOfFileEx failed " << filename() << " " << errnoWithDescription(e) << endl;
- assert(p);
+ void* newPrivateView = MapViewOfFileEx(
+ maphandle, // file mapping handle
+ FILE_MAP_READ, // access
+ 0, 0, // file offset, high and low
+ 0, // bytes to map, 0 == all
+ oldPrivateAddr ); // we want the same address we had before
+ if ( oldPrivateAddr != newPrivateView ) {
+ DWORD dosError = GetLastError();
+ log() << "MapViewOfFileEx for " << filename()
+ << " failed with " << errnoWithDescription( dosError )
+ << " (file size is " << len << ")"
+ << " in MemoryMappedFile::remapPrivateView, terminating"
+ << endl;
+ ::abort();
}
- assert(p == oldPrivateAddr);
- return p;
-#endif
+ return newPrivateView;
}
#endif
View
22 util/mmap.h
@@ -263,18 +263,18 @@ namespace mongo {
}
};
extern ourbitset writable;
- void makeChunkWritable(size_t chunkno);
- inline void MemoryMappedFile::makeWritable(void *_p, unsigned len) {
- size_t p = (size_t) _p;
- unsigned a = p/ChunkSize;
- unsigned b = (p+len)/ChunkSize;
- for( unsigned i = a; i <= b; i++ ) {
- if( !writable.get(i) ) {
- makeChunkWritable(i);
- }
- }
+ void makeChunkWritable(size_t chunkno);
+ inline void MemoryMappedFile::makeWritable(void *_p, unsigned len) {
+ size_t p = (size_t) _p;
+ unsigned a = p/ChunkSize;
+ unsigned b = (p+len)/ChunkSize;
+ for( unsigned i = a; i <= b; i++ ) {
+ if( !writable.get(i) ) {
+ makeChunkWritable(i);
+ }
+ }
}
-
+ extern void* getNextMemoryMappedFileLocation( unsigned long long mmfSize );
#endif
} // namespace mongo
View
75 util/mmap_win.cpp
@@ -30,6 +30,26 @@ namespace mongo {
MAdvise::MAdvise(void *,unsigned, Advice) { }
MAdvise::~MAdvise() { }
+ static unsigned long long _nextMemoryMappedFileLocation = 256LL * 1024LL * 1024LL * 1024LL;
+ static SimpleMutex _nextMemoryMappedFileLocationMutex( "nextMemoryMappedFileLocationMutex" );
+
+ void* getNextMemoryMappedFileLocation( unsigned long long mmfSize ) {
+ if ( 4 == sizeof(void*) ) {
+ return 0;
+ }
+ SimpleMutex::scoped_lock lk( _nextMemoryMappedFileLocationMutex );
+ static unsigned long long granularity = 0;
+ if ( 0 == granularity ) {
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo( &systemInfo );
+ granularity = static_cast<unsigned long long>( systemInfo.dwAllocationGranularity );
+ }
+ unsigned long long thisMemoryMappedFileLocation = _nextMemoryMappedFileLocation;
+ mmfSize = ( mmfSize + granularity - 1) & ~( granularity - 1 );
+ _nextMemoryMappedFileLocation += mmfSize;
+ return reinterpret_cast<void*>( static_cast<uintptr_t>( thisMemoryMappedFileLocation ) );
+ }
+
/** notification on unmapping so we can clear writable bits */
void MemoryMappedFile::clearWritableBits(void *p) {
for( unsigned i = ((size_t)p)/ChunkSize; i <= (((size_t)p)+len)/ChunkSize; i++ ) {
@@ -67,15 +87,24 @@ namespace mongo {
void* MemoryMappedFile::createReadOnlyMap() {
assert( maphandle );
scoped_lock lk(mapViewMutex);
- void *p = MapViewOfFile(maphandle, FILE_MAP_READ, /*f ofs hi*/0, /*f ofs lo*/ 0, /*dwNumberOfBytesToMap 0 means to eof*/0);
- if ( p == 0 ) {
- DWORD e = GetLastError();
- log() << "FILE_MAP_READ MapViewOfFile failed " << filename() << " " << errnoWithDescription(e) << endl;
+ LPVOID thisAddress = getNextMemoryMappedFileLocation( len );
+ void* readOnlyMapAddress = MapViewOfFileEx(
+ maphandle, // file mapping handle
+ FILE_MAP_READ, // access
+ 0, 0, // file offset, high and low
+ 0, // bytes to map, 0 == all
+ thisAddress ); // address to place file
+ if ( 0 == readOnlyMapAddress ) {
+ DWORD dosError = GetLastError();
+ log() << "MapViewOfFileEx for " << filename()
+ << " failed with " << errnoWithDescription( dosError )
+ << " (file size is " << len << ")"
+ << " in MemoryMappedFile::createReadOnlyMap, terminating"
+ << endl;
+ ::abort();
}
- else {
- views.push_back(p);
- }
- return p;
+ views.push_back( readOnlyMapAddress );
+ return readOnlyMapAddress;
}
void* MemoryMappedFile::map(const char *filenameIn, unsigned long long &length, int options) {
@@ -138,18 +167,28 @@ namespace mongo {
void *view = 0;
{
scoped_lock lk(mapViewMutex);
- DWORD access = (options&READONLY)? FILE_MAP_READ : FILE_MAP_ALL_ACCESS;
- view = MapViewOfFile(maphandle, access, /*f ofs hi*/0, /*f ofs lo*/ 0, /*dwNumberOfBytesToMap 0 means to eof*/0);
- }
- if ( view == 0 ) {
- DWORD e = GetLastError();
- log() << "MapViewOfFile failed " << filename << " " << errnoWithDescription(e) <<
- ((sizeof(void*)==4)?" (32 bit build)":"") << endl;
- close();
+ DWORD access = ( options & READONLY ) ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS;
+ LPVOID thisAddress = getNextMemoryMappedFileLocation( length );
+ view = MapViewOfFileEx(
+ maphandle, // file mapping handle
+ access, // access
+ 0, 0, // file offset, high and low
+ 0, // bytes to map, 0 == all
+ thisAddress ); // address to place file
}
- else {
- views.push_back(view);
+ {
+ if ( view == 0 ) {
+ DWORD dosError = GetLastError();
+ log() << "MapViewOfFileEx for " << filename
+ << " failed with " << errnoWithDescription( dosError )
+ << " (file size is " << length << ")"
+ << " in MemoryMappedFile::map, terminating"
+ << endl;
+ close();
+ ::abort();
+ }
}
+ views.push_back(view);
len = length;
return view;

0 comments on commit 881d622

Please sign in to comment.
Something went wrong with that request. Please try again.