void operator () (MongoFile *mf) { if( mf->isMongoMMF() ) { MongoMMF *mmf = (MongoMMF*) mf; const unsigned char *p = (const unsigned char *) mmf->getView(); const unsigned char *w = (const unsigned char *) mmf->view_write(); if (!p || !w) return; // File not fully opened yet _bytes += mmf->length(); assert( mmf->length() == (unsigned) mmf->length() ); { scoped_lock lk( privateViews._mutex() ); // see setNoJournal if (memcmp(p, w, (unsigned) mmf->length()) == 0) return; // next file } unsigned low = 0xffffffff; unsigned high = 0; log() << "DurParanoid mismatch in " << mmf->filename() << endl; int logged = 0; unsigned lastMismatch = 0xffffffff; for( unsigned i = 0; i < mmf->length(); i++ ) { if( p[i] != w[i] ) { if( lastMismatch != 0xffffffff && lastMismatch+1 != i ) log() << endl; // separate blocks of mismatches lastMismatch= i; if( ++logged < 60 ) { if( logged == 1 ) log() << "ofs % 628 = 0x" << hex << (i%628) << endl; // for .ns files to find offset in record stringstream ss; ss << "mismatch ofs:" << hex << i << "\tfilemap:" << setw(2) << (unsigned) w[i] << "\tprivmap:" << setw(2) << (unsigned) p[i]; if( p[i] > 32 && p[i] <= 126 ) ss << '\t' << p[i]; log() << ss.str() << endl; } if( logged == 60 ) log() << "..." << endl; if( i < low ) low = i; if( i > high ) high = i; } } if( low != 0xffffffff ) { std::stringstream ss; ss << "journal error warning views mismatch " << mmf->filename() << ' ' << (hex) << low << ".." << high << " len:" << high-low+1; log() << ss.str() << endl; log() << "priv loc: " << (void*)(p+low) << ' ' << endl; set<WriteIntent>& b = commitJob.writes(); (void)b; // mark as unused. Useful for inspection in debugger // should we abort() here so this isn't unnoticed in some circumstances? massert(13599, "Written data does not match in-memory view. Missing WriteIntent?", false); } } }
/** (SLOW) diagnostic to check that the private view and the non-private view are in sync. */ static void debugValidateMapsMatch() { if( !DebugValidateMapsMatch ) return; Timer t; set<MongoFile*>& files = MongoFile::getAllFiles(); for( set<MongoFile*>::iterator i = files.begin(); i != files.end(); i++ ) { MongoFile *mf = *i; if( mf->isMongoMMF() ) { MongoMMF *mmf = (MongoMMF*) mf; const char *p = (const char *) mmf->getView(); const char *w = (const char *) mmf->view_write(); unsigned low = 0xffffffff; unsigned high = 0; for( unsigned i = 0; i < mmf->length(); i++ ) { if( p[i] != w[i] ) { log() << i << '\t' << (int) p[i] << '\t' << (int) w[i] << endl; if( i < low ) low = i; if( i > high ) high = i; } } if( low != 0xffffffff ) { std::stringstream ss; ss << "dur error warning views mismatch " << mmf->filename() << ' ' << (hex) << low << ".." << high << " len:" << high-low+1; log() << ss.str() << endl; log() << "priv loc: " << (void*)(p+low) << endl; vector<WriteIntent>& w = commitJob.writes(); (void)w; // mark as unused. Useful for inspection in debugger breakpoint(); } } } log() << "debugValidateMapsMatch " << t.millis() << "ms " << endl; }
__declspec(noinline) void makeChunkWritable(size_t chunkno) { scoped_lock lk(mapViewMutex); if( writable.get(chunkno) ) // double check lock return; // remap all maps in this chunk. common case is a single map, but could have more than one with smallfiles or .ns files size_t chunkStart = chunkno * MemoryMappedFile::ChunkSize; size_t chunkNext = chunkStart + MemoryMappedFile::ChunkSize; scoped_lock lk2(privateViews._mutex()); map<void*,MongoMMF*>::iterator i = privateViews.finditer_inlock((void*) (chunkNext-1)); while( 1 ) { const pair<void*,MongoMMF*> x = *(--i); MongoMMF *mmf = x.second; if( mmf == 0 ) break; size_t viewStart = (size_t) x.first; size_t viewEnd = (size_t) (viewStart + mmf->length()); if( viewEnd <= chunkStart ) break; size_t protectStart = max(viewStart, chunkStart); dassert(protectStart<chunkNext); size_t protectEnd = min(viewEnd, chunkNext); size_t protectSize = protectEnd - protectStart; dassert(protectSize>0&&protectSize<=MemoryMappedFile::ChunkSize); DWORD oldProtection; bool ok = VirtualProtect( reinterpret_cast<void*>( protectStart ), protectSize, PAGE_WRITECOPY, &oldProtection ); if ( !ok ) { DWORD dosError = GetLastError(); log() << "VirtualProtect for " << mmf->filename() << " chunk " << chunkno << " failed with " << errnoWithDescription( dosError ) << " (chunk size is " << protectSize << ", address is " << hex << protectStart << dec << ")" << " in mongo::makeChunkWritable, terminating" << endl; fassertFailed( 16362 ); } } writable.set(chunkno); }
/*static*/ void* MongoMMF::switchToPrivateView(void *readonly_ptr) { assert( cmdLine.dur ); assert( testIntent ); void *p = readonly_ptr; { size_t ofs=0; MongoMMF *mmf = ourReadViews.find(p, ofs); if( mmf ) { void *res = ((char *)mmf->_view_private) + ofs; return res; } } { size_t ofs=0; MongoMMF *mmf = privateViews.find(p, ofs); if( mmf ) { log() << "dur: perf warning p=" << p << " is already in the writable view of " << mmf->filename() << endl; return p; } } // did you call writing() with a pointer that isn't into a datafile? log() << "dur error switchToPrivateView " << p << endl; return p; }