2010-10-01 22:14:36 +02:00
|
|
|
// @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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* 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 {
|
|
|
|
|
2010-11-13 23:42:41 +01:00
|
|
|
/** 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<void*, MongoMMF*> _views;
|
|
|
|
mutex _m;
|
|
|
|
};
|
|
|
|
|
|
|
|
static PointerToMMF ourPrivateViews;
|
|
|
|
static PointerToMMF ourReadViews; /// _DEBUG build use only (other than existance)
|
2010-10-04 20:02:52 +02:00
|
|
|
|
2010-11-14 00:32:41 +01:00
|
|
|
namespace dur {
|
|
|
|
MongoMMF* pointerToMMF(void *p, size_t& ofs) {
|
|
|
|
return ourPrivateViews.find(p, ofs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-04 20:02:52 +02:00
|
|
|
/*static*/ void* MongoMMF::switchToPrivateView(void *readonly_ptr) {
|
2010-10-01 22:14:36 +02:00
|
|
|
assert( durable );
|
|
|
|
assert( debug );
|
|
|
|
|
2010-11-13 23:42:41 +01:00
|
|
|
void *p = readonly_ptr;
|
2010-10-01 22:14:36 +02:00
|
|
|
|
2010-11-13 23:42:41 +01:00
|
|
|
{
|
2010-11-14 00:32:41 +01:00
|
|
|
size_t ofs=0;
|
2010-11-13 23:42:41 +01:00
|
|
|
MongoMMF *mmf = ourReadViews.find(p, ofs);
|
|
|
|
if( mmf ) {
|
2010-11-04 22:43:02 +01:00
|
|
|
return ((char *)mmf->_view_private) + ofs;
|
2010-10-01 22:14:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-13 23:42:41 +01:00
|
|
|
{
|
2010-11-14 00:32:41 +01:00
|
|
|
size_t ofs=0;
|
|
|
|
MongoMMF *mmf = ourPrivateViews.find(p, ofs);
|
2010-11-13 23:42:41 +01:00
|
|
|
if( mmf ) {
|
|
|
|
log() << "dur: perf warning p=" << p << " is already in the writable view of " << mmf->filename() << endl;
|
2010-10-01 22:14:36 +02:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
2010-11-13 23:42:41 +01:00
|
|
|
|
|
|
|
// did you call writing() with a pointer that isn't into a datafile?
|
|
|
|
log() << "error switchToPrivateView " << p << endl;
|
|
|
|
return p;
|
2010-10-01 22:14:36 +02:00
|
|
|
}
|
2010-10-04 20:02:52 +02:00
|
|
|
|
2010-11-04 22:43:02 +01:00
|
|
|
/* 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
|
2010-10-04 21:02:15 +02:00
|
|
|
as a tad of a "warning". but useful when done with some care, such as during
|
|
|
|
initialization.
|
2010-10-04 20:02:52 +02:00
|
|
|
*/
|
2010-10-04 21:02:15 +02:00
|
|
|
/*static*/ void* MongoMMF::_switchToWritableView(void *p) {
|
2010-10-04 20:02:52 +02:00
|
|
|
RARELY log() << "todo dur not done switchtowritable" << endl;
|
2010-11-13 23:42:41 +01:00
|
|
|
if( debug )
|
|
|
|
return switchToPrivateView(p);
|
2010-10-04 20:02:52 +02:00
|
|
|
return p;
|
|
|
|
}
|
2010-10-01 22:14:36 +02:00
|
|
|
|
2010-10-13 19:06:49 +02:00
|
|
|
bool MongoMMF::open(string fname, bool sequentialHint) {
|
2010-11-04 22:43:02 +01:00
|
|
|
_view_write = mapWithOptions(fname.c_str(), sequentialHint ? SEQUENTIAL : 0);
|
|
|
|
// temp : _view_private pending more work!
|
|
|
|
_view_private = _view_write;
|
|
|
|
if( _view_write ) {
|
2010-10-01 22:14:36 +02:00
|
|
|
if( durable ) {
|
2010-11-13 23:42:41 +01:00
|
|
|
ourPrivateViews.add(_view_private, this);
|
|
|
|
if( debug ) {
|
|
|
|
_view_readonly = MemoryMappedFile::createReadOnlyMap();
|
|
|
|
ourReadViews.add(_view_readonly, this);
|
|
|
|
}
|
2010-10-01 22:14:36 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-10-13 19:06:49 +02:00
|
|
|
bool MongoMMF::create(string fname, unsigned long long& len, bool sequentialHint) {
|
2010-11-04 22:43:02 +01:00
|
|
|
_view_write = map(fname.c_str(), len, sequentialHint ? SEQUENTIAL : 0);
|
2010-11-13 23:42:41 +01:00
|
|
|
// temp : _view_private pending more work! not implemented yet.
|
2010-11-04 22:43:02 +01:00
|
|
|
_view_private = _view_write;
|
|
|
|
if( _view_write ) {
|
2010-10-01 22:14:36 +02:00
|
|
|
if( durable ) {
|
2010-11-13 23:42:41 +01:00
|
|
|
ourPrivateViews.add(_view_private, this);
|
|
|
|
if( debug ) {
|
|
|
|
_view_readonly = MemoryMappedFile::createReadOnlyMap();
|
|
|
|
ourReadViews.add(_view_readonly, this);
|
|
|
|
}
|
2010-10-01 22:14:36 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we will re-map the private few frequently, thus the use of MoveableBuffer */
|
|
|
|
MoveableBuffer MongoMMF::getView() {
|
|
|
|
if( durable && debug )
|
2010-11-04 22:43:02 +01:00
|
|
|
return _view_readonly;
|
|
|
|
return _view_private;
|
2010-10-01 22:14:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MongoMMF::MongoMMF() {
|
2010-11-04 22:43:02 +01:00
|
|
|
_view_write = _view_private = _view_readonly = 0;
|
2010-10-01 22:14:36 +02:00
|
|
|
}
|
|
|
|
|
2010-10-04 22:46:17 +02:00
|
|
|
MongoMMF::~MongoMMF() {
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/ void MongoMMF::close() {
|
2010-11-13 23:42:41 +01:00
|
|
|
if( durable ) {
|
|
|
|
ourPrivateViews.remove(_view_private);
|
|
|
|
if( debug ) {
|
|
|
|
ourReadViews.remove(_view_readonly);
|
|
|
|
}
|
2010-10-01 22:14:36 +02:00
|
|
|
}
|
2010-11-04 22:43:02 +01:00
|
|
|
_view_write = _view_private = _view_readonly = 0;
|
2010-10-04 22:46:17 +02:00
|
|
|
MemoryMappedFile::close();
|
2010-10-01 22:14:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|