Beispiel #1
0
    using std::endl;
    using std::string;
    using std::vector;

    namespace {
        mongo::AtomicUInt64 mmfNextId(0);
    }

    static size_t fetchMinOSPageSizeBytes() {
        SYSTEM_INFO si;
        GetSystemInfo(&si);
        size_t minOSPageSizeBytes = si.dwPageSize;
        minOSPageSizeBytesTest(minOSPageSizeBytes);
        return minOSPageSizeBytes;
    }
    const size_t g_minOSPageSizeBytes = fetchMinOSPageSizeBytes();

    // MapViewMutex
    //
    // Protects:
    //   1. Ensures all MapViewOfFile/UnMapViewOfFile operations are serialized to reduce chance of
    //    "address in use" errors (error code 487)
    // -   These errors can still occur if the memory is used for other purposes
    //     (stack storage, heap)
    //   2. Prevents calls to VirtualProtect while we remapping files.
    // Lock Ordering:
    //  - If taken, must be after previewViews._m to prevent deadlocks
    mutex mapViewMutex;

    MAdvise::MAdvise(void *,unsigned, Advice) { }
    MAdvise::~MAdvise() { }
Beispiel #2
0
namespace mongo {
    static size_t fetchMinOSPageSizeBytes() {
        size_t minOSPageSizeBytes = sysconf( _SC_PAGESIZE );
        minOSPageSizeBytesTest(minOSPageSizeBytes);
        return minOSPageSizeBytes;
    }
    const size_t g_minOSPageSizeBytes = fetchMinOSPageSizeBytes();
        
    

    MemoryMappedFile::MemoryMappedFile() : _uniqueId(mmfNextId.fetchAndAdd(1)) {
        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

    namespace {
        void* _pageAlign( void* p ) {
            return (void*)((int64_t)p & ~(g_minOSPageSizeBytes-1));
        }

        class PageAlignTest : public StartupTest {
        public:
            void run() {
                {
                    int64_t x = g_minOSPageSizeBytes + 123;
                    void* y = _pageAlign( reinterpret_cast<void*>( x ) );
                    invariant( g_minOSPageSizeBytes == reinterpret_cast<size_t>(y) );
                }
                {
                    int64_t a = static_cast<uint64_t>( numeric_limits<int>::max() );
                    a = a / g_minOSPageSizeBytes;
                    a = a * g_minOSPageSizeBytes;
                    // a should now be page aligned

                    // b is not page aligned
                    int64_t b = a + 123;

                    void* y = _pageAlign( reinterpret_cast<void*>( b ) );
                    invariant( a == reinterpret_cast<int64_t>(y) );
                }

            }
        } pageAlignTest;
    }

#if defined(__sunos__)
    MAdvise::MAdvise(void *,unsigned, Advice) { }
    MAdvise::~MAdvise() { }
#else
    MAdvise::MAdvise(void *p, unsigned len, Advice a) {

        _p = _pageAlign( p );

        _len = len + static_cast<unsigned>( reinterpret_cast<size_t>(p) -
                                            reinterpret_cast<size_t>(_p)  );

        int advice = 0;
        switch ( a ) {
        case Sequential:
            advice = MADV_SEQUENTIAL;
            break;
        case Random:
            advice = MADV_RANDOM;
            break;
        }

        if ( madvise(_p,_len,advice ) ) {
            error() << "madvise failed: " << errnoWithDescription();
        }

    }
    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) {
#if defined(__sunos__) // SERVER-8795
        LockMongoFilesExclusive lockMongoFiles;
#endif

        // 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;

        bool useFsync = sync && !ProcessInfo::preferMsyncOverFSync();

        if ( useFsync ?
            fsync(fd) != 0 :
            msync(viewForFlushing(), len, sync ? MS_SYNC : MS_ASYNC) ) {
            // msync failed, this is very bad
            log() << (useFsync ? "fsync failed: " : "msync failed: ") << errnoWithDescription()
                  << " file: " << filename() << endl;
            dataSyncFailedHandler();
        }
    }

    class PosixFlushable : public MemoryMappedFile::Flushable {
    public:
        PosixFlushable( MemoryMappedFile* theFile, void* view , HANDLE fd , long len)
            : _theFile( theFile ), _view( view ), _fd(fd), _len(len), _id(_theFile->getUniqueId()) {
        }

        void flush() {
            if ( _view == NULL || _fd == 0 )
                return;

            if ( ProcessInfo::preferMsyncOverFSync() ?
                msync(_view, _len, MS_SYNC ) == 0 :
                fsync(_fd) == 0 ) {
                return;
            }

            if ( errno == EBADF ) {
                // ok, we were unlocked, so this file was closed
                return;
            }

            // some error, lets see if we're supposed to exist
            LockMongoFilesShared mmfilesLock;
            std::set<MongoFile*> mmfs = MongoFile::getAllFiles();
            std::set<MongoFile*>::const_iterator it = mmfs.find(_theFile);
            if ( (it == mmfs.end()) || ((*it)->getUniqueId() != _id) ) {
                log() << "msync failed with: " << errnoWithDescription()
                      << " but file doesn't exist anymore, so ignoring";
                // this was deleted while we were unlocked
                return;
            }

            // we got an error, and we still exist, so this is bad, we fail
            log() << "msync " << errnoWithDescription() << endl;
            dataSyncFailedHandler();
        }

        MemoryMappedFile* _theFile;
        void * _view;
        HANDLE _fd;
        long _len;
        const uint64_t _id;
    };

    MemoryMappedFile::Flushable * MemoryMappedFile::prepareFlush() {
        return new PosixFlushable( this, viewForFlushing(), fd, len);
    }


} // namespace mongo
Beispiel #3
0
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