// @file mongommf.cpp /** * Copyright (C) 2010 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ /* this module adds some of our layers atop memory mapped files - specifically our handling of private views & such if you don't care about journaling/durability (temp sort files & such) use MemoryMappedFile class, not this. */ #include "pch.h" #include "mongommf.h" namespace mongo { /** for durability support we want to be able to map pointers to specific MongoMMF objects. */ class PointerToMMF { public: PointerToMMF() : _m("PointerFinder") { } /** register view. threadsafe */ void add(void *view, MongoMMF *f) { mutex::scoped_lock lk(_m); _views[view] = f; } /** de-register view. threadsafe */ void remove(void *view) { mutex::scoped_lock lk(_m); _views.erase(view); } MongoMMF* _find(void *p, /*out*/ size_t& ofs) { std::map< void*, MongoMMF* >::iterator i = _views.upper_bound(((char *)p)+1); i--; bool ok = i != _views.end(); if( ok ) { MongoMMF *mmf = i->second; assert( mmf ); size_t o = ((char *)p) - ((char*)i->first); if( o < mmf->length() ) { ofs = o; return mmf; } } return 0; } /** find associated MMF object for a given pointer. threadsafe @param ofs out returns offset into the view of the pointer, if found. @return the MongoMMF to which this pointer belongs. null if not found. */ MongoMMF* find(void *p, /*out*/ size_t& ofs) { mutex::scoped_lock lk(_m); return _find(p, ofs); } private: map _views; mutex _m; }; static PointerToMMF ourPrivateViews; static PointerToMMF ourReadViews; /// _DEBUG build use only (other than existance) /*static*/ void* MongoMMF::switchToPrivateView(void *readonly_ptr) { assert( durable ); assert( debug ); void *p = readonly_ptr; { size_t ofs; MongoMMF *mmf = ourReadViews.find(p, ofs); if( mmf ) { return ((char *)mmf->_view_private) + ofs; } } { size_t ofs; MongoMMF *mmf = ourPrivateViews.find(readonly_ptr, 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() << "error switchToPrivateView " << p << endl; return p; } /* switch to _view_write. normally, this is a bad idea since your changes will not show up in _view_private if there have been changes there; thus the leading underscore as a tad of a "warning". but useful when done with some care, such as during initialization. */ /*static*/ void* MongoMMF::_switchToWritableView(void *p) { RARELY log() << "todo dur not done switchtowritable" << endl; if( debug ) return switchToPrivateView(p); return p; } bool MongoMMF::open(string fname, bool sequentialHint) { _view_write = mapWithOptions(fname.c_str(), sequentialHint ? SEQUENTIAL : 0); // temp : _view_private pending more work! _view_private = _view_write; if( _view_write ) { if( durable ) { ourPrivateViews.add(_view_private, this); if( debug ) { _view_readonly = MemoryMappedFile::createReadOnlyMap(); ourReadViews.add(_view_readonly, this); } } return true; } return false; } bool MongoMMF::create(string fname, unsigned long long& len, bool sequentialHint) { _view_write = map(fname.c_str(), len, sequentialHint ? SEQUENTIAL : 0); // temp : _view_private pending more work! not implemented yet. _view_private = _view_write; if( _view_write ) { if( durable ) { ourPrivateViews.add(_view_private, this); if( debug ) { _view_readonly = MemoryMappedFile::createReadOnlyMap(); ourReadViews.add(_view_readonly, this); } } return true; } return false; } /* we will re-map the private few frequently, thus the use of MoveableBuffer */ MoveableBuffer MongoMMF::getView() { if( durable && debug ) return _view_readonly; return _view_private; } MongoMMF::MongoMMF() { _view_write = _view_private = _view_readonly = 0; } MongoMMF::~MongoMMF() { close(); } /*virtual*/ void MongoMMF::close() { if( durable ) { ourPrivateViews.remove(_view_private); if( debug ) { ourReadViews.remove(_view_readonly); } } _view_write = _view_private = _view_readonly = 0; MemoryMappedFile::close(); } }