diff options
Diffstat (limited to 'src/mongo/util/mmap_win.cpp')
-rw-r--r-- | src/mongo/util/mmap_win.cpp | 765 |
1 files changed, 371 insertions, 394 deletions
diff --git a/src/mongo/util/mmap_win.cpp b/src/mongo/util/mmap_win.cpp index 8ce10b5241e..d72f10ab72d 100644 --- a/src/mongo/util/mmap_win.cpp +++ b/src/mongo/util/mmap_win.cpp @@ -42,497 +42,474 @@ namespace mongo { - using std::endl; - using std::string; - using std::vector; +using std::endl; +using std::string; +using std::vector; - namespace { - mongo::AtomicUInt64 mmfNextId(0); - } +namespace { +mongo::AtomicUInt64 mmfNextId(0); +} - static size_t fetchMinOSPageSizeBytes() { - SYSTEM_INFO si; - GetSystemInfo(&si); - size_t minOSPageSizeBytes = si.dwPageSize; - minOSPageSizeBytesTest(minOSPageSizeBytes); - return minOSPageSizeBytes; - } - const size_t g_minOSPageSizeBytes = fetchMinOSPageSizeBytes(); - - // MapViewMutex - // - // Protects: - // 1. Ensures all MapViewOfFile/UnMapViewOfFile operations are serialized to reduce chance of - // "address in use" errors (error code 487) - // - These errors can still occur if the memory is used for other purposes - // (stack storage, heap) - // 2. Prevents calls to VirtualProtect while we remapping files. - // Lock Ordering: - // - If taken, must be after previewViews._m to prevent deadlocks - mutex mapViewMutex("mapView"); - - MAdvise::MAdvise(void *,unsigned, Advice) { } - MAdvise::~MAdvise() { } - - const unsigned long long memoryMappedFileLocationFloor = 256LL * 1024LL * 1024LL * 1024LL; - static unsigned long long _nextMemoryMappedFileLocation = memoryMappedFileLocationFloor; - - // nextMemoryMappedFileLocationMutex - // - // Protects: - // Windows 64-bit specific allocation of virtual memory regions for - // placing memory mapped files in memory - // Lock Ordering: - // No restrictions - static SimpleMutex _nextMemoryMappedFileLocationMutex("nextMemoryMappedFileLocationMutex"); - - unsigned long long AlignNumber(unsigned long long number, unsigned long long granularity) - { - return (number + granularity - 1) & ~(granularity - 1); +static size_t fetchMinOSPageSizeBytes() { + SYSTEM_INFO si; + GetSystemInfo(&si); + size_t minOSPageSizeBytes = si.dwPageSize; + minOSPageSizeBytesTest(minOSPageSizeBytes); + return minOSPageSizeBytes; +} +const size_t g_minOSPageSizeBytes = fetchMinOSPageSizeBytes(); + +// MapViewMutex +// +// Protects: +// 1. Ensures all MapViewOfFile/UnMapViewOfFile operations are serialized to reduce chance of +// "address in use" errors (error code 487) +// - These errors can still occur if the memory is used for other purposes +// (stack storage, heap) +// 2. Prevents calls to VirtualProtect while we remapping files. +// Lock Ordering: +// - If taken, must be after previewViews._m to prevent deadlocks +mutex mapViewMutex("mapView"); + +MAdvise::MAdvise(void*, unsigned, Advice) {} +MAdvise::~MAdvise() {} + +const unsigned long long memoryMappedFileLocationFloor = 256LL * 1024LL * 1024LL * 1024LL; +static unsigned long long _nextMemoryMappedFileLocation = memoryMappedFileLocationFloor; + +// nextMemoryMappedFileLocationMutex +// +// Protects: +// Windows 64-bit specific allocation of virtual memory regions for +// placing memory mapped files in memory +// Lock Ordering: +// No restrictions +static SimpleMutex _nextMemoryMappedFileLocationMutex("nextMemoryMappedFileLocationMutex"); + +unsigned long long AlignNumber(unsigned long long number, unsigned long long granularity) { + return (number + granularity - 1) & ~(granularity - 1); +} + +static void* getNextMemoryMappedFileLocation(unsigned long long mmfSize) { + if (4 == sizeof(void*)) { + return 0; } + SimpleMutex::scoped_lock lk(_nextMemoryMappedFileLocationMutex); - static void* getNextMemoryMappedFileLocation(unsigned long long mmfSize) { - if (4 == sizeof(void*)) { - return 0; - } - SimpleMutex::scoped_lock lk(_nextMemoryMappedFileLocationMutex); + static unsigned long long granularity = 0; - static unsigned long long granularity = 0; + if (0 == granularity) { + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + granularity = static_cast<unsigned long long>(systemInfo.dwAllocationGranularity); + } - if (0 == granularity) { - SYSTEM_INFO systemInfo; - GetSystemInfo(&systemInfo); - granularity = static_cast<unsigned long long>(systemInfo.dwAllocationGranularity); - } + unsigned long long thisMemoryMappedFileLocation = _nextMemoryMappedFileLocation; - unsigned long long thisMemoryMappedFileLocation = _nextMemoryMappedFileLocation; + int current_retry = 1; - int current_retry = 1; + while (true) { + MEMORY_BASIC_INFORMATION memInfo; - while (true) { - MEMORY_BASIC_INFORMATION memInfo; - - if (VirtualQuery(reinterpret_cast<LPCVOID>(thisMemoryMappedFileLocation), - &memInfo, sizeof(memInfo)) == 0) { - DWORD gle = GetLastError(); - - // If we exceed the limits of Virtual Memory - // - 8TB before Windows 8.1/2012 R2, 128 TB after - // restart scanning from our memory mapped floor once more - // This is a linear scan of regions, not of every VM page - if (gle == ERROR_INVALID_PARAMETER && current_retry == 1) { - thisMemoryMappedFileLocation = memoryMappedFileLocationFloor; - ++current_retry; - continue; - } + if (VirtualQuery(reinterpret_cast<LPCVOID>(thisMemoryMappedFileLocation), + &memInfo, + sizeof(memInfo)) == 0) { + DWORD gle = GetLastError(); - log() << "VirtualQuery of " << thisMemoryMappedFileLocation - << " failed with error " << errnoWithDescription(gle); - fassertFailed(17484); + // If we exceed the limits of Virtual Memory + // - 8TB before Windows 8.1/2012 R2, 128 TB after + // restart scanning from our memory mapped floor once more + // This is a linear scan of regions, not of every VM page + if (gle == ERROR_INVALID_PARAMETER && current_retry == 1) { + thisMemoryMappedFileLocation = memoryMappedFileLocationFloor; + ++current_retry; + continue; } - // Free memory regions that we can use for memory map files - // 1. Marked MEM_FREE, not MEM_RESERVE - // 2. Marked as PAGE_NOACCESS, not anything else - if (memInfo.Protect == PAGE_NOACCESS && - memInfo.State == MEM_FREE && - memInfo.RegionSize > mmfSize) - break; - - thisMemoryMappedFileLocation = reinterpret_cast<unsigned long long>(memInfo.BaseAddress) - + memInfo.RegionSize; + log() << "VirtualQuery of " << thisMemoryMappedFileLocation << " failed with error " + << errnoWithDescription(gle); + fassertFailed(17484); } - _nextMemoryMappedFileLocation = thisMemoryMappedFileLocation - + AlignNumber(mmfSize, granularity); - - return reinterpret_cast<void*>(static_cast<uintptr_t>(thisMemoryMappedFileLocation)); - } + // Free memory regions that we can use for memory map files + // 1. Marked MEM_FREE, not MEM_RESERVE + // 2. Marked as PAGE_NOACCESS, not anything else + if (memInfo.Protect == PAGE_NOACCESS && memInfo.State == MEM_FREE && + memInfo.RegionSize > mmfSize) + break; - MemoryMappedFile::MemoryMappedFile() - : _uniqueId(mmfNextId.fetchAndAdd(1)) { - fd = 0; - maphandle = 0; - len = 0; - created(); + thisMemoryMappedFileLocation = + reinterpret_cast<unsigned long long>(memInfo.BaseAddress) + memInfo.RegionSize; } - void MemoryMappedFile::close() { - LockMongoFilesShared::assertExclusivelyLocked(); + _nextMemoryMappedFileLocation = + thisMemoryMappedFileLocation + AlignNumber(mmfSize, granularity); - // Prevent flush and close from concurrently running - boost::lock_guard<boost::mutex> lk(_flushMutex); + return reinterpret_cast<void*>(static_cast<uintptr_t>(thisMemoryMappedFileLocation)); +} - { - scoped_lock lk(mapViewMutex); +MemoryMappedFile::MemoryMappedFile() : _uniqueId(mmfNextId.fetchAndAdd(1)) { + fd = 0; + maphandle = 0; + len = 0; + created(); +} - for (vector<void*>::iterator i = views.begin(); i != views.end(); i++) { - UnmapViewOfFile(*i); - } - } +void MemoryMappedFile::close() { + LockMongoFilesShared::assertExclusivelyLocked(); - views.clear(); - if ( maphandle ) - CloseHandle(maphandle); - maphandle = 0; - if ( fd ) - CloseHandle(fd); - fd = 0; - destroyed(); // cleans up from the master list of mmaps - } + // Prevent flush and close from concurrently running + boost::lock_guard<boost::mutex> lk(_flushMutex); - unsigned long long mapped = 0; + { + scoped_lock lk(mapViewMutex); - void* MemoryMappedFile::createReadOnlyMap() { - verify( maphandle ); + for (vector<void*>::iterator i = views.begin(); i != views.end(); i++) { + UnmapViewOfFile(*i); + } + } - scoped_lock lk(mapViewMutex); + views.clear(); + if (maphandle) + CloseHandle(maphandle); + maphandle = 0; + if (fd) + CloseHandle(fd); + fd = 0; + destroyed(); // cleans up from the master list of mmaps +} - void* readOnlyMapAddress = NULL; - int current_retry = 0; +unsigned long long mapped = 0; - while (true) { +void* MemoryMappedFile::createReadOnlyMap() { + verify(maphandle); - LPVOID thisAddress = getNextMemoryMappedFileLocation(len); + scoped_lock lk(mapViewMutex); - 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 + void* readOnlyMapAddress = NULL; + int current_retry = 0; - if (0 == readOnlyMapAddress) { - DWORD dosError = GetLastError(); + while (true) { + LPVOID thisAddress = getNextMemoryMappedFileLocation(len); - ++current_retry; + 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 we failed to allocate a memory mapped file, try again in case we picked - // an address that Windows is also trying to use for some other VM allocations - if (dosError == ERROR_INVALID_ADDRESS && current_retry < 5) { - continue; - } + if (0 == readOnlyMapAddress) { + DWORD dosError = GetLastError(); - log() << "MapViewOfFileEx for " << filename() - << " at address " << thisAddress - << " failed with error " << errnoWithDescription(dosError) - << " (file size is " << len << ")" - << " in MemoryMappedFile::createReadOnlyMap" - << endl; + ++current_retry; - fassertFailed(16165); + // If we failed to allocate a memory mapped file, try again in case we picked + // an address that Windows is also trying to use for some other VM allocations + if (dosError == ERROR_INVALID_ADDRESS && current_retry < 5) { + continue; } - break; + log() << "MapViewOfFileEx for " << filename() << " at address " << thisAddress + << " failed with error " << errnoWithDescription(dosError) << " (file size is " + << len << ")" + << " in MemoryMappedFile::createReadOnlyMap" << endl; + + fassertFailed(16165); } - views.push_back( readOnlyMapAddress ); - return readOnlyMapAddress; + break; } - void* MemoryMappedFile::map(const char *filenameIn, unsigned long long &length, int options) { - verify( fd == 0 && len == 0 ); // can't open more than once - setFilename(filenameIn); - FileAllocator::get()->allocateAsap( filenameIn, length ); - /* big hack here: Babble uses db names with colons. doesn't seem to work on windows. temporary perhaps. */ - char filename[256]; - strncpy(filename, filenameIn, 255); - filename[255] = 0; - { - size_t len = strlen( filename ); - for ( size_t i=len-1; i>=0; i-- ) { - if ( filename[i] == '/' || - filename[i] == '\\' ) - break; + views.push_back(readOnlyMapAddress); + return readOnlyMapAddress; +} - if ( filename[i] == ':' ) - filename[i] = '_'; - } +void* MemoryMappedFile::map(const char* filenameIn, unsigned long long& length, int options) { + verify(fd == 0 && len == 0); // can't open more than once + setFilename(filenameIn); + FileAllocator::get()->allocateAsap(filenameIn, length); + /* big hack here: Babble uses db names with colons. doesn't seem to work on windows. temporary perhaps. */ + char filename[256]; + strncpy(filename, filenameIn, 255); + filename[255] = 0; + { + size_t len = strlen(filename); + for (size_t i = len - 1; i >= 0; i--) { + if (filename[i] == '/' || filename[i] == '\\') + break; + + if (filename[i] == ':') + filename[i] = '_'; } + } - updateLength( filename, length ); + updateLength(filename, length); - { - DWORD createOptions = FILE_ATTRIBUTE_NORMAL; - if ( options & SEQUENTIAL ) - createOptions |= FILE_FLAG_SEQUENTIAL_SCAN; - DWORD rw = GENERIC_READ | GENERIC_WRITE; - fd = CreateFileW( - toWideString(filename).c_str(), - rw, // desired access - FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode - NULL, // security - OPEN_ALWAYS, // create disposition - createOptions , // flags - NULL); // hTempl - if ( fd == INVALID_HANDLE_VALUE ) { - DWORD dosError = GetLastError(); - log() << "CreateFileW for " << filename - << " failed with " << errnoWithDescription( dosError ) - << " (file size is " << length << ")" - << " in MemoryMappedFile::map" - << endl; - return 0; - } + { + DWORD createOptions = FILE_ATTRIBUTE_NORMAL; + if (options & SEQUENTIAL) + createOptions |= FILE_FLAG_SEQUENTIAL_SCAN; + DWORD rw = GENERIC_READ | GENERIC_WRITE; + fd = CreateFileW(toWideString(filename).c_str(), + rw, // desired access + FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode + NULL, // security + OPEN_ALWAYS, // create disposition + createOptions, // flags + NULL); // hTempl + if (fd == INVALID_HANDLE_VALUE) { + DWORD dosError = GetLastError(); + log() << "CreateFileW for " << filename << " failed with " + << errnoWithDescription(dosError) << " (file size is " << length << ")" + << " in MemoryMappedFile::map" << endl; + return 0; } + } - mapped += length; + mapped += length; - { - DWORD flProtect = PAGE_READWRITE; //(options & READONLY)?PAGE_READONLY:PAGE_READWRITE; - maphandle = CreateFileMappingW(fd, NULL, flProtect, - length >> 32 /*maxsizehigh*/, - (unsigned) length /*maxsizelow*/, - NULL/*lpName*/); - if ( maphandle == NULL ) { - DWORD dosError = GetLastError(); - log() << "CreateFileMappingW for " << filename - << " failed with " << errnoWithDescription( dosError ) - << " (file size is " << length << ")" - << " in MemoryMappedFile::map" - << endl; - close(); - fassertFailed( 16225 ); - } + { + DWORD flProtect = PAGE_READWRITE; //(options & READONLY)?PAGE_READONLY:PAGE_READWRITE; + maphandle = CreateFileMappingW(fd, + NULL, + flProtect, + length >> 32 /*maxsizehigh*/, + (unsigned)length /*maxsizelow*/, + NULL /*lpName*/); + if (maphandle == NULL) { + DWORD dosError = GetLastError(); + log() << "CreateFileMappingW for " << filename << " failed with " + << errnoWithDescription(dosError) << " (file size is " << length << ")" + << " in MemoryMappedFile::map" << endl; + close(); + fassertFailed(16225); } + } - void *view = 0; - { - scoped_lock lk(mapViewMutex); - DWORD access = ( options & READONLY ) ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS; - - int current_retry = 0; - while (true) { + void* view = 0; + { + scoped_lock lk(mapViewMutex); + DWORD access = (options & READONLY) ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS; - LPVOID thisAddress = getNextMemoryMappedFileLocation(length); + int current_retry = 0; + while (true) { + 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 + 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 - if (view == 0) { - DWORD dosError = GetLastError(); + if (view == 0) { + DWORD dosError = GetLastError(); - ++current_retry; + ++current_retry; - // If we failed to allocate a memory mapped file, try again in case we picked - // an address that Windows is also trying to use for some other VM allocations - if (dosError == ERROR_INVALID_ADDRESS && current_retry < 5) { - continue; - } + // If we failed to allocate a memory mapped file, try again in case we picked + // an address that Windows is also trying to use for some other VM allocations + if (dosError == ERROR_INVALID_ADDRESS && current_retry < 5) { + continue; + } #ifndef _WIN64 - // Warn user that if they are running a 32-bit app on 64-bit Windows - if (dosError == ERROR_NOT_ENOUGH_MEMORY) { - BOOL wow64Process; - BOOL retWow64 = IsWow64Process(GetCurrentProcess(), &wow64Process); - if (retWow64 && wow64Process) { - log() << "This is a 32-bit MongoDB binary running on a 64-bit" - " operating system that has run out of virtual memory for" - " databases. Switch to a 64-bit build of MongoDB to open" - " the databases."; - } + // Warn user that if they are running a 32-bit app on 64-bit Windows + if (dosError == ERROR_NOT_ENOUGH_MEMORY) { + BOOL wow64Process; + BOOL retWow64 = IsWow64Process(GetCurrentProcess(), &wow64Process); + if (retWow64 && wow64Process) { + log() << "This is a 32-bit MongoDB binary running on a 64-bit" + " operating system that has run out of virtual memory for" + " databases. Switch to a 64-bit build of MongoDB to open" + " the databases."; } + } #endif - log() << "MapViewOfFileEx for " << filename - << " at address " << thisAddress - << " failed with " << errnoWithDescription(dosError) - << " (file size is " << length << ")" - << " in MemoryMappedFile::map" - << endl; - - close(); - fassertFailed(16166); - } + log() << "MapViewOfFileEx for " << filename << " at address " << thisAddress + << " failed with " << errnoWithDescription(dosError) << " (file size is " + << length << ")" + << " in MemoryMappedFile::map" << endl; - break; + close(); + fassertFailed(16166); } - } - views.push_back(view); - len = length; - return view; + break; + } } - extern mutex mapViewMutex; - - void* MemoryMappedFile::createPrivateMap() { - verify( maphandle ); - - scoped_lock lk(mapViewMutex); + views.push_back(view); + len = length; + return view; +} - LPVOID thisAddress = getNextMemoryMappedFileLocation( len ); +extern mutex mapViewMutex; - void* privateMapAddress = NULL; - int current_retry = 0; +void* MemoryMappedFile::createPrivateMap() { + verify(maphandle); - while (true) { + scoped_lock lk(mapViewMutex); - 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 + LPVOID thisAddress = getNextMemoryMappedFileLocation(len); - if (privateMapAddress == 0) { - DWORD dosError = GetLastError(); + void* privateMapAddress = NULL; + int current_retry = 0; - ++current_retry; + while (true) { + 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 we failed to allocate a memory mapped file, try again in case we picked - // an address that Windows is also trying to use for some other VM allocations - if (dosError == ERROR_INVALID_ADDRESS && current_retry < 5) { - continue; - } + if (privateMapAddress == 0) { + DWORD dosError = GetLastError(); - log() << "MapViewOfFileEx for " << filename() - << " failed with error " << errnoWithDescription(dosError) - << " (file size is " << len << ")" - << " in MemoryMappedFile::createPrivateMap" - << endl; + ++current_retry; - fassertFailed(16167); + // If we failed to allocate a memory mapped file, try again in case we picked + // an address that Windows is also trying to use for some other VM allocations + if (dosError == ERROR_INVALID_ADDRESS && current_retry < 5) { + continue; } - break; + log() << "MapViewOfFileEx for " << filename() << " failed with error " + << errnoWithDescription(dosError) << " (file size is " << len << ")" + << " in MemoryMappedFile::createPrivateMap" << endl; + + fassertFailed(16167); } - views.push_back( privateMapAddress ); - return privateMapAddress; + break; } - void* MemoryMappedFile::remapPrivateView(void *oldPrivateAddr) { - LockMongoFilesExclusive lockMongoFiles; + views.push_back(privateMapAddress); + return privateMapAddress; +} - privateViews.clearWritableBits(oldPrivateAddr, len); +void* MemoryMappedFile::remapPrivateView(void* oldPrivateAddr) { + LockMongoFilesExclusive lockMongoFiles; - scoped_lock lk(mapViewMutex); + privateViews.clearWritableBits(oldPrivateAddr, len); - if( !UnmapViewOfFile(oldPrivateAddr) ) { - DWORD dosError = GetLastError(); - log() << "UnMapViewOfFile for " << filename() - << " failed with error " << errnoWithDescription( dosError ) - << " in MemoryMappedFile::remapPrivateView" - << endl; - fassertFailed( 16168 ); - } + scoped_lock lk(mapViewMutex); - 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 ( 0 == newPrivateView ) { - DWORD dosError = GetLastError(); - log() << "MapViewOfFileEx for " << filename() - << " failed with error " << errnoWithDescription( dosError ) - << " (file size is " << len << ")" - << " in MemoryMappedFile::remapPrivateView" - << endl; - } - fassert( 16148, newPrivateView == oldPrivateAddr ); - return newPrivateView; + if (!UnmapViewOfFile(oldPrivateAddr)) { + DWORD dosError = GetLastError(); + log() << "UnMapViewOfFile for " << filename() << " failed with error " + << errnoWithDescription(dosError) << " in MemoryMappedFile::remapPrivateView" << endl; + fassertFailed(16168); } - class WindowsFlushable : public MemoryMappedFile::Flushable { - public: - WindowsFlushable( MemoryMappedFile* theFile, - void * view, - HANDLE fd, - const uint64_t id, - const std::string& filename, - boost::mutex& flushMutex ) - : _theFile(theFile), _view(view), _fd(fd), _id(id), _filename(filename), - _flushMutex(flushMutex) - {} - - void flush() { - if (!_view || !_fd) - return; + 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 (0 == newPrivateView) { + DWORD dosError = GetLastError(); + log() << "MapViewOfFileEx for " << filename() << " failed with error " + << errnoWithDescription(dosError) << " (file size is " << len << ")" + << " in MemoryMappedFile::remapPrivateView" << endl; + } + fassert(16148, newPrivateView == oldPrivateAddr); + return newPrivateView; +} - { - LockMongoFilesShared mmfilesLock; +class WindowsFlushable : public MemoryMappedFile::Flushable { +public: + WindowsFlushable(MemoryMappedFile* theFile, + void* view, + HANDLE fd, + const uint64_t id, + const std::string& filename, + boost::mutex& flushMutex) + : _theFile(theFile), + _view(view), + _fd(fd), + _id(id), + _filename(filename), + _flushMutex(flushMutex) {} + + void flush() { + if (!_view || !_fd) + return; - std::set<MongoFile*> mmfs = MongoFile::getAllFiles(); - std::set<MongoFile*>::const_iterator it = mmfs.find(_theFile); - if ( it == mmfs.end() || (*it)->getUniqueId() != _id ) { - // this was deleted while we were unlocked - return; - } + { + LockMongoFilesShared mmfilesLock; - // Hold the flush mutex to ensure the file is not closed during flush - _flushMutex.lock(); + std::set<MongoFile*> mmfs = MongoFile::getAllFiles(); + std::set<MongoFile*>::const_iterator it = mmfs.find(_theFile); + if (it == mmfs.end() || (*it)->getUniqueId() != _id) { + // this was deleted while we were unlocked + return; } - boost::lock_guard<boost::mutex> lk(_flushMutex, boost::adopt_lock_t()); - - int loopCount = 0; - bool success = false; - bool timeout = false; - int dosError = ERROR_SUCCESS; - const int maximumTimeInSeconds = 60 * 15; - Timer t; - while ( !success && !timeout ) { - ++loopCount; - success = FALSE != FlushViewOfFile( _view, 0 ); - if ( !success ) { - dosError = GetLastError(); - if ( dosError != ERROR_LOCK_VIOLATION ) { - break; - } - timeout = t.seconds() > maximumTimeInSeconds; - } - } - if ( success && loopCount > 1 ) { - log() << "FlushViewOfFile for " << _filename - << " succeeded after " << loopCount - << " attempts taking " << t.millis() - << "ms" << endl; - } - else if ( !success ) { - log() << "FlushViewOfFile for " << _filename - << " failed with error " << dosError - << " after " << loopCount - << " attempts taking " << t.millis() - << "ms" << endl; - // Abort here to avoid data corruption - fassert(16387, false); - } + // Hold the flush mutex to ensure the file is not closed during flush + _flushMutex.lock(); + } - success = FALSE != FlushFileBuffers(_fd); + boost::lock_guard<boost::mutex> lk(_flushMutex, boost::adopt_lock_t()); + + int loopCount = 0; + bool success = false; + bool timeout = false; + int dosError = ERROR_SUCCESS; + const int maximumTimeInSeconds = 60 * 15; + Timer t; + while (!success && !timeout) { + ++loopCount; + success = FALSE != FlushViewOfFile(_view, 0); if (!success) { - int err = GetLastError(); - log() << "FlushFileBuffers failed: " << errnoWithDescription( err ) - << " file: " << _filename << endl; - dataSyncFailedHandler(); + dosError = GetLastError(); + if (dosError != ERROR_LOCK_VIOLATION) { + break; + } + timeout = t.seconds() > maximumTimeInSeconds; } } + if (success && loopCount > 1) { + log() << "FlushViewOfFile for " << _filename << " succeeded after " << loopCount + << " attempts taking " << t.millis() << "ms" << endl; + } else if (!success) { + log() << "FlushViewOfFile for " << _filename << " failed with error " << dosError + << " after " << loopCount << " attempts taking " << t.millis() << "ms" << endl; + // Abort here to avoid data corruption + fassert(16387, false); + } - MemoryMappedFile* _theFile; // this may be deleted while we are running - void * _view; - HANDLE _fd; - const uint64_t _id; - string _filename; - boost::mutex& _flushMutex; - }; - - void MemoryMappedFile::flush(bool sync) { - uassert(13056, "Async flushing not supported on windows", sync); - if( !views.empty() ) { - WindowsFlushable f(this, viewForFlushing(), fd, _uniqueId, filename(), _flushMutex); - f.flush(); + success = FALSE != FlushFileBuffers(_fd); + if (!success) { + int err = GetLastError(); + log() << "FlushFileBuffers failed: " << errnoWithDescription(err) + << " file: " << _filename << endl; + dataSyncFailedHandler(); } } - MemoryMappedFile::Flushable * MemoryMappedFile::prepareFlush() { - return new WindowsFlushable(this, viewForFlushing(), fd, _uniqueId, - filename(), _flushMutex); + MemoryMappedFile* _theFile; // this may be deleted while we are running + void* _view; + HANDLE _fd; + const uint64_t _id; + string _filename; + boost::mutex& _flushMutex; +}; + +void MemoryMappedFile::flush(bool sync) { + uassert(13056, "Async flushing not supported on windows", sync); + if (!views.empty()) { + WindowsFlushable f(this, viewForFlushing(), fd, _uniqueId, filename(), _flushMutex); + f.flush(); } +} +MemoryMappedFile::Flushable* MemoryMappedFile::prepareFlush() { + return new WindowsFlushable(this, viewForFlushing(), fd, _uniqueId, filename(), _flushMutex); +} } |