2009-01-29 23:22:59 +01:00
|
|
|
// mmap_win.cpp
|
|
|
|
|
2009-10-27 20:58:27 +01:00
|
|
|
/* Copyright 2009 10gen Inc.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2009-01-29 23:22:59 +01:00
|
|
|
|
2010-04-27 21:27:52 +02:00
|
|
|
#include "pch.h"
|
2009-01-29 23:22:59 +01:00
|
|
|
#include "mmap.h"
|
2010-06-05 01:14:59 +02:00
|
|
|
#include "text.h"
|
2009-07-27 19:50:25 +02:00
|
|
|
#include <windows.h>
|
2009-01-30 00:38:35 +01:00
|
|
|
|
2009-01-29 23:22:59 +01:00
|
|
|
namespace mongo {
|
|
|
|
|
2011-01-05 18:18:19 +01:00
|
|
|
mutex mapViewMutex("mapView");
|
|
|
|
|
2010-08-30 17:30:06 +02:00
|
|
|
MemoryMappedFile::MemoryMappedFile()
|
2011-01-04 06:40:41 +01:00
|
|
|
: _flushMutex(new mutex("flushMutex")) {
|
2009-01-29 23:22:59 +01:00
|
|
|
fd = 0;
|
|
|
|
maphandle = 0;
|
2010-01-15 21:31:51 +01:00
|
|
|
len = 0;
|
2009-01-29 23:22:59 +01:00
|
|
|
created();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MemoryMappedFile::close() {
|
2010-10-01 22:14:36 +02:00
|
|
|
for( vector<void*>::iterator i = views.begin(); i != views.end(); i++ ) {
|
|
|
|
UnmapViewOfFile(*i);
|
2010-09-27 18:35:22 +02:00
|
|
|
}
|
2010-10-01 22:14:36 +02:00
|
|
|
views.clear();
|
2009-01-29 23:22:59 +01:00
|
|
|
if ( maphandle )
|
|
|
|
CloseHandle(maphandle);
|
|
|
|
maphandle = 0;
|
|
|
|
if ( fd )
|
|
|
|
CloseHandle(fd);
|
|
|
|
fd = 0;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-09-09 13:12:17 +02:00
|
|
|
unsigned long long mapped = 0;
|
2009-01-29 23:22:59 +01:00
|
|
|
|
2010-11-27 21:25:08 +01:00
|
|
|
void* MemoryMappedFile::remapPrivateView(void *oldPrivateAddr) {
|
2011-01-05 18:18:19 +01:00
|
|
|
// the mutex is to assure we get the same address on the remap
|
|
|
|
scoped_lock lk(mapViewMutex);
|
|
|
|
|
2010-11-27 21:40:57 +01:00
|
|
|
bool ok = UnmapViewOfFile(oldPrivateAddr);
|
2010-12-16 15:31:02 +01:00
|
|
|
assert(ok);
|
|
|
|
|
|
|
|
// we want the new address to be the same as the old address in case things keep pointers around (as namespaceindex does).
|
2011-01-04 06:40:41 +01:00
|
|
|
void *p = MapViewOfFileEx(maphandle, FILE_MAP_COPY, 0, 0,
|
2010-12-16 15:31:02 +01:00
|
|
|
/*dwNumberOfBytesToMap 0 means to eof*/0 /*len*/,
|
|
|
|
oldPrivateAddr);
|
2011-01-05 18:18:19 +01:00
|
|
|
|
2010-12-16 15:31:02 +01:00
|
|
|
assert(p);
|
|
|
|
assert(p == oldPrivateAddr);
|
|
|
|
return p;
|
2010-11-27 21:40:57 +01:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void* MemoryMappedFile::createPrivateMap() {
|
2010-09-14 21:38:14 +02:00
|
|
|
assert( maphandle );
|
2011-01-05 18:18:19 +01:00
|
|
|
scoped_lock lk(mapViewMutex);
|
2010-09-14 21:38:14 +02:00
|
|
|
void *p = MapViewOfFile(maphandle, FILE_MAP_COPY, /*f ofs hi*/0, /*f ofs lo*/ 0, /*dwNumberOfBytesToMap 0 means to eof*/0);
|
|
|
|
if ( p == 0 ) {
|
|
|
|
DWORD e = GetLastError();
|
2011-01-06 20:54:47 +01:00
|
|
|
log() << "createPrivateMap failed " << filename() << " " << errnoWithDescription(e) << endl;
|
2010-09-14 21:38:14 +02:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
else {
|
2010-11-16 22:40:56 +01:00
|
|
|
views.push_back(p);
|
|
|
|
}
|
2010-09-14 21:38:14 +02:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2010-10-01 22:14:36 +02:00
|
|
|
void* MemoryMappedFile::createReadOnlyMap() {
|
|
|
|
assert( maphandle );
|
2011-01-05 18:18:19 +01:00
|
|
|
scoped_lock lk(mapViewMutex);
|
2010-10-01 22:14:36 +02:00
|
|
|
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();
|
2010-12-30 21:34:30 +01:00
|
|
|
log() << "FILE_MAP_READ MapViewOfFile failed " << filename() << " " << errnoWithDescription(e) << endl;
|
2010-10-01 22:14:36 +02:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
else {
|
2010-10-04 22:46:17 +02:00
|
|
|
views.push_back(p);
|
|
|
|
}
|
2010-10-01 22:14:36 +02:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2010-09-09 13:12:17 +02:00
|
|
|
void* MemoryMappedFile::map(const char *filenameIn, unsigned long long &length, int options) {
|
2010-12-30 21:34:30 +01:00
|
|
|
setFilename(filenameIn);
|
2009-02-11 17:28:49 +01:00
|
|
|
/* big hack here: Babble uses db names with colons. doesn't seem to work on windows. temporary perhaps. */
|
|
|
|
char filename[256];
|
2010-05-10 17:26:08 +02:00
|
|
|
strncpy(filename, filenameIn, 255);
|
2009-02-11 17:28:49 +01:00
|
|
|
filename[255] = 0;
|
2011-01-04 06:40:41 +01:00
|
|
|
{
|
2009-03-19 13:36:24 +01:00
|
|
|
size_t len = strlen( filename );
|
2011-01-04 06:40:41 +01:00
|
|
|
for ( size_t i=len-1; i>=0; i-- ) {
|
2009-03-19 13:36:24 +01:00
|
|
|
if ( filename[i] == '/' ||
|
2011-01-04 06:40:41 +01:00
|
|
|
filename[i] == '\\' )
|
2009-03-19 13:36:24 +01:00
|
|
|
break;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-03-19 13:36:24 +01:00
|
|
|
if ( filename[i] == ':' )
|
|
|
|
filename[i] = '_';
|
2009-02-11 17:28:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-29 23:22:59 +01:00
|
|
|
updateLength( filename, length );
|
|
|
|
|
2010-09-19 23:32:06 +02:00
|
|
|
{
|
|
|
|
DWORD createOptions = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
if ( options & SEQUENTIAL )
|
|
|
|
createOptions |= FILE_FLAG_SEQUENTIAL_SCAN;
|
|
|
|
DWORD rw = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
fd = CreateFile(
|
|
|
|
toNativeString(filename).c_str(),
|
|
|
|
rw, // desired access
|
2010-12-23 00:01:30 +01:00
|
|
|
FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
|
2010-09-19 23:32:06 +02:00
|
|
|
NULL, // security
|
|
|
|
OPEN_ALWAYS, // create disposition
|
|
|
|
createOptions , // flags
|
|
|
|
NULL); // hTempl
|
|
|
|
if ( fd == INVALID_HANDLE_VALUE ) {
|
2010-12-15 02:23:17 +01:00
|
|
|
DWORD e = GetLastError();
|
|
|
|
log() << "Create/OpenFile failed " << filename << " errno:" << e << endl;
|
2010-09-19 23:32:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2009-01-29 23:22:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
mapped += length;
|
|
|
|
|
2010-09-19 23:32:06 +02:00
|
|
|
{
|
|
|
|
DWORD flProtect = PAGE_READWRITE; //(options & READONLY)?PAGE_READONLY:PAGE_READWRITE;
|
2011-01-04 06:40:41 +01:00
|
|
|
maphandle = CreateFileMapping(fd, NULL, flProtect,
|
|
|
|
length >> 32 /*maxsizehigh*/,
|
|
|
|
(unsigned) length /*maxsizelow*/,
|
|
|
|
NULL/*lpName*/);
|
2010-09-19 23:32:06 +02:00
|
|
|
if ( maphandle == NULL ) {
|
|
|
|
DWORD e = GetLastError(); // log() call was killing lasterror before we get to that point in the stream
|
|
|
|
log() << "CreateFileMapping failed " << filename << ' ' << errnoWithDescription(e) << endl;
|
|
|
|
return 0;
|
|
|
|
}
|
2009-01-29 23:22:59 +01:00
|
|
|
}
|
|
|
|
|
2010-10-01 22:14:36 +02:00
|
|
|
void *view = 0;
|
2010-09-13 23:16:42 +02:00
|
|
|
{
|
2011-01-05 18:18:19 +01:00
|
|
|
scoped_lock lk(mapViewMutex);
|
2010-09-13 23:16:42 +02:00
|
|
|
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);
|
|
|
|
}
|
2009-01-29 23:22:59 +01:00
|
|
|
if ( view == 0 ) {
|
2010-09-13 14:29:18 +02:00
|
|
|
DWORD e = GetLastError();
|
|
|
|
log() << "MapViewOfFile failed " << filename << " " << errnoWithDescription(e) << endl;
|
2009-01-29 23:22:59 +01:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
else {
|
2010-10-04 22:46:17 +02:00
|
|
|
views.push_back(view);
|
|
|
|
}
|
2009-10-27 19:25:45 +01:00
|
|
|
len = length;
|
2010-09-27 18:35:22 +02:00
|
|
|
|
2009-01-29 23:22:59 +01:00
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
2010-07-26 22:06:49 +02:00
|
|
|
class WindowsFlushable : public MemoryMappedFile::Flushable {
|
|
|
|
public:
|
2010-08-30 17:50:18 +02:00
|
|
|
WindowsFlushable( void * view , HANDLE fd , string filename , boost::shared_ptr<mutex> flushMutex )
|
|
|
|
: _view(view) , _fd(fd) , _filename(filename) , _flushMutex(flushMutex)
|
|
|
|
{}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
void flush() {
|
|
|
|
if (!_view || !_fd)
|
2010-07-26 22:06:49 +02:00
|
|
|
return;
|
|
|
|
|
2010-08-30 17:50:18 +02:00
|
|
|
scoped_lock lk(*_flushMutex);
|
2010-08-30 17:30:06 +02:00
|
|
|
|
2010-07-26 22:06:49 +02:00
|
|
|
bool success = FlushViewOfFile(_view, 0); // 0 means whole mapping
|
2011-01-04 06:40:41 +01:00
|
|
|
if (!success) {
|
2010-07-26 22:06:49 +02:00
|
|
|
int err = GetLastError();
|
|
|
|
out() << "FlushViewOfFile failed " << err << " file: " << _filename << endl;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-07-26 22:06:49 +02:00
|
|
|
success = FlushFileBuffers(_fd);
|
2011-01-04 06:40:41 +01:00
|
|
|
if (!success) {
|
2010-07-26 22:06:49 +02:00
|
|
|
int err = GetLastError();
|
|
|
|
out() << "FlushFileBuffers failed " << err << " file: " << _filename << endl;
|
|
|
|
}
|
2010-03-10 03:46:47 +01:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-07-26 22:06:49 +02:00
|
|
|
void * _view;
|
|
|
|
HANDLE _fd;
|
|
|
|
string _filename;
|
2010-08-30 17:50:18 +02:00
|
|
|
boost::shared_ptr<mutex> _flushMutex;
|
2010-07-26 22:06:49 +02:00
|
|
|
};
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-07-26 22:06:49 +02:00
|
|
|
void MemoryMappedFile::flush(bool sync) {
|
|
|
|
uassert(13056, "Async flushing not supported on windows", sync);
|
2010-10-01 22:14:36 +02:00
|
|
|
if( !views.empty() ) {
|
2010-12-30 21:34:30 +01:00
|
|
|
WindowsFlushable f( views[0] , fd , filename() , _flushMutex);
|
2010-10-01 22:14:36 +02:00
|
|
|
f.flush();
|
|
|
|
}
|
2010-03-10 03:46:47 +01:00
|
|
|
}
|
2010-06-24 17:03:57 +02:00
|
|
|
|
2010-10-01 22:14:36 +02:00
|
|
|
MemoryMappedFile::Flushable * MemoryMappedFile::prepareFlush() {
|
2010-12-30 21:34:30 +01:00
|
|
|
return new WindowsFlushable( views.empty() ? 0 : views[0] , fd , filename() , _flushMutex );
|
2010-07-26 22:06:49 +02:00
|
|
|
}
|
2010-06-24 17:03:57 +02:00
|
|
|
void MemoryMappedFile::_lock() {}
|
|
|
|
void MemoryMappedFile::_unlock() {}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|