summaryrefslogtreecommitdiff
path: root/src/mongo/util/mmap_posix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/mmap_posix.cpp')
-rw-r--r--src/mongo/util/mmap_posix.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/mongo/util/mmap_posix.cpp b/src/mongo/util/mmap_posix.cpp
new file mode 100644
index 00000000000..7eb5f062045
--- /dev/null
+++ b/src/mongo/util/mmap_posix.cpp
@@ -0,0 +1,221 @@
+// mmap_posix.cpp
+
+/* 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.
+ */
+
+#include "pch.h"
+#include "mmap.h"
+#include "file_allocator.h"
+#include "../db/d_concurrency.h"
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "../util/processinfo.h"
+#include "mongoutils/str.h"
+using namespace mongoutils;
+
+namespace mongo {
+ static size_t fetchMinOSPageSizeBytes() {
+ size_t minOSPageSizeBytes = sysconf( _SC_PAGESIZE );
+ minOSPageSizeBytesTest(minOSPageSizeBytes);
+ return minOSPageSizeBytes;
+ }
+ const size_t g_minOSPageSizeBytes = fetchMinOSPageSizeBytes();
+
+ MemoryMappedFile::MemoryMappedFile() {
+ fd = 0;
+ maphandle = 0;
+ len = 0;
+ created();
+ }
+
+ void MemoryMappedFile::close() {
+ LockMongoFilesShared::assertExclusivelyLocked();
+ for( vector<void*>::iterator i = views.begin(); i != views.end(); i++ ) {
+ munmap(*i,len);
+ }
+ views.clear();
+
+ if ( fd )
+ ::close(fd);
+ fd = 0;
+ destroyed(); // cleans up from the master list of mmaps
+ }
+
+#ifndef O_NOATIME
+#define O_NOATIME (0)
+#endif
+
+#ifndef MAP_NORESERVE
+#define MAP_NORESERVE (0)
+#endif
+
+#if defined(__sunos__)
+ MAdvise::MAdvise(void *,unsigned, Advice) { }
+ MAdvise::~MAdvise() { }
+#else
+ MAdvise::MAdvise(void *p, unsigned len, Advice a) {
+
+ _p = (void*)((long)p & ~(g_minOSPageSizeBytes-1));
+
+ _len = len +((unsigned long long)p-(unsigned long long)_p);
+
+ int advice = 0;
+ switch ( a ) {
+ case Sequential: advice = MADV_SEQUENTIAL; break;
+ case Random: advice = MADV_RANDOM; break;
+ default: verify(0);
+ }
+
+ if ( madvise(_p,_len,advice ) ) {
+ error() << "madvise failed: " << errnoWithDescription() << endl;
+ }
+
+ }
+ MAdvise::~MAdvise() {
+ madvise(_p,_len,MADV_NORMAL);
+ }
+#endif
+
+ void* MemoryMappedFile::map(const char *filename, unsigned long long &length, int options) {
+ // length may be updated by callee.
+ setFilename(filename);
+ FileAllocator::get()->allocateAsap( filename, length );
+ len = length;
+
+ massert( 10446 , str::stream() << "mmap: can't map area of size 0 file: " << filename, length > 0 );
+
+ fd = open(filename, O_RDWR | O_NOATIME);
+ if ( fd <= 0 ) {
+ log() << "couldn't open " << filename << ' ' << errnoWithDescription() << endl;
+ fd = 0; // our sentinel for not opened
+ return 0;
+ }
+
+ unsigned long long filelen = lseek(fd, 0, SEEK_END);
+ uassert(10447, str::stream() << "map file alloc failed, wanted: " << length << " filelen: " << filelen << ' ' << sizeof(size_t), filelen == length );
+ lseek( fd, 0, SEEK_SET );
+
+ void * view = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if ( view == MAP_FAILED ) {
+ error() << " mmap() failed for " << filename << " len:" << length << " " << errnoWithDescription() << endl;
+ if ( errno == ENOMEM ) {
+ if( sizeof(void*) == 4 )
+ error() << "mmap failed with out of memory. You are using a 32-bit build and probably need to upgrade to 64" << endl;
+ else
+ error() << "mmap failed with out of memory. (64 bit build)" << endl;
+ }
+ return 0;
+ }
+
+
+#if defined(__sunos__)
+#warning madvise not supported on solaris yet
+#else
+ if ( options & SEQUENTIAL ) {
+ if ( madvise( view , length , MADV_SEQUENTIAL ) ) {
+ warning() << "map: madvise failed for " << filename << ' ' << errnoWithDescription() << endl;
+ }
+ }
+#endif
+
+ views.push_back( view );
+
+ return view;
+ }
+
+ void* MemoryMappedFile::createReadOnlyMap() {
+ void * x = mmap( /*start*/0 , len , PROT_READ , MAP_SHARED , fd , 0 );
+ if( x == MAP_FAILED ) {
+ if ( errno == ENOMEM ) {
+ if( sizeof(void*) == 4 )
+ error() << "mmap ro failed with out of memory. You are using a 32-bit build and probably need to upgrade to 64" << endl;
+ else
+ error() << "mmap ro failed with out of memory. (64 bit build)" << endl;
+ }
+ return 0;
+ }
+ return x;
+ }
+
+ void* MemoryMappedFile::createPrivateMap() {
+ void * x = mmap( /*start*/0 , len , PROT_READ|PROT_WRITE , MAP_PRIVATE|MAP_NORESERVE , fd , 0 );
+ if( x == MAP_FAILED ) {
+ if ( errno == ENOMEM ) {
+ if( sizeof(void*) == 4 ) {
+ error() << "mmap private failed with out of memory. You are using a 32-bit build and probably need to upgrade to 64" << endl;
+ }
+ else {
+ error() << "mmap private failed with out of memory. (64 bit build)" << endl;
+ }
+ }
+ else {
+ error() << "mmap private failed " << errnoWithDescription() << endl;
+ }
+ return 0;
+ }
+
+ views.push_back(x);
+ return x;
+ }
+
+ void* MemoryMappedFile::remapPrivateView(void *oldPrivateAddr) {
+ // don't unmap, just mmap over the old region
+ void * x = mmap( oldPrivateAddr, len , PROT_READ|PROT_WRITE , MAP_PRIVATE|MAP_NORESERVE|MAP_FIXED , fd , 0 );
+ if( x == MAP_FAILED ) {
+ int err = errno;
+ error() << "13601 Couldn't remap private view: " << errnoWithDescription(err) << endl;
+ log() << "aborting" << endl;
+ printMemInfo();
+ abort();
+ }
+ verify( x == oldPrivateAddr );
+ return x;
+ }
+
+ void MemoryMappedFile::flush(bool sync) {
+ if ( views.empty() || fd == 0 )
+ return;
+ if ( msync(viewForFlushing(), len, sync ? MS_SYNC : MS_ASYNC) )
+ problem() << "msync " << errnoWithDescription() << endl;
+ }
+
+ class PosixFlushable : public MemoryMappedFile::Flushable {
+ public:
+ PosixFlushable( void * view , HANDLE fd , long len )
+ : _view( view ) , _fd( fd ) , _len(len) {
+ }
+
+ void flush() {
+ if ( _view && _fd )
+ if ( msync(_view, _len, MS_SYNC ) )
+ problem() << "msync " << errnoWithDescription() << endl;
+
+ }
+
+ void * _view;
+ HANDLE _fd;
+ long _len;
+ };
+
+ MemoryMappedFile::Flushable * MemoryMappedFile::prepareFlush() {
+ return new PosixFlushable( viewForFlushing() , fd , len );
+ }
+
+
+} // namespace mongo
+