summaryrefslogtreecommitdiff
path: root/util/mmap.h
diff options
context:
space:
mode:
Diffstat (limited to 'util/mmap.h')
-rw-r--r--util/mmap.h289
1 files changed, 173 insertions, 116 deletions
diff --git a/util/mmap.h b/util/mmap.h
index c954ef7..2ef4176 100644
--- a/util/mmap.h
+++ b/util/mmap.h
@@ -16,20 +16,63 @@
*/
#pragma once
+#include <boost/thread/xtime.hpp>
+#include "concurrency/rwlock.h"
namespace mongo {
-
+
/* the administrative-ish stuff here */
- class MongoFile : boost::noncopyable {
-
+ class MongoFile : boost::noncopyable {
public:
/** Flushable has to fail nicely if the underlying object gets killed */
class Flushable {
public:
- virtual ~Flushable(){}
+ virtual ~Flushable() {}
virtual void flush() = 0;
};
-
+
+ virtual ~MongoFile() {}
+
+ enum Options {
+ SEQUENTIAL = 1, // hint - e.g. FILE_FLAG_SEQUENTIAL_SCAN on windows
+ READONLY = 2 // not contractually guaranteed, but if specified the impl has option to fault writes
+ };
+
+ /** @param fun is called for each MongoFile.
+ calledl from within a mutex that MongoFile uses. so be careful not to deadlock.
+ */
+ template < class F >
+ static void forEach( F fun );
+
+ /** note: you need to be in mmmutex when using this. forEach (above) handles that for you automatically. */
+ static set<MongoFile*>& getAllFiles() { return mmfiles; }
+
+ // callbacks if you need them
+ static void (*notifyPreFlush)();
+ static void (*notifyPostFlush)();
+
+ static int flushAll( bool sync ); // returns n flushed
+ static long long totalMappedLength();
+ static void closeAllFiles( stringstream &message );
+
+#if defined(_DEBUG)
+ static void markAllWritable();
+ static void unmarkAllWritable();
+#else
+ static void markAllWritable() { }
+ static void unmarkAllWritable() { }
+#endif
+
+ static bool exists(boost::filesystem::path p) { return boost::filesystem::exists(p); }
+
+ virtual bool isMongoMMF() { return false; }
+
+ string filename() const { return _filename; }
+ void setFilename(string fn);
+
+ private:
+ string _filename;
+ static int _flushAll( bool sync ); // returns n flushed
protected:
virtual void close() = 0;
virtual void flush(bool sync) = 0;
@@ -38,164 +81,178 @@ namespace mongo {
* Flushable has to fail nicely if the underlying object gets killed
*/
virtual Flushable * prepareFlush() = 0;
-
+
void created(); /* subclass must call after create */
- void destroyed(); /* subclass must call in destructor */
+
+ /* subclass must call in destructor (or at close).
+ removes this from pathToFile and other maps
+ safe to call more than once, albeit might be wasted work
+ ideal to call close to the close, if the close is well before object destruction
+ */
+ void destroyed();
+
+ virtual unsigned long long length() const = 0;
// only supporting on posix mmap
virtual void _lock() {}
virtual void _unlock() {}
+ static set<MongoFile*> mmfiles;
public:
- virtual ~MongoFile() {}
- virtual long length() = 0;
-
- enum Options {
- SEQUENTIAL = 1 // hint - e.g. FILE_FLAG_SEQUENTIAL_SCAN on windows
- };
-
- static int flushAll( bool sync ); // returns n flushed
- static long long totalMappedLength();
- static void closeAllFiles( stringstream &message );
+ static map<string,MongoFile*> pathToFile;
+ static RWLock mmmutex;
+ };
- // Locking allows writes. Reads are always allowed
- static void lockAll();
- static void unlockAll();
+ /** look up a MMF by filename. scoped mutex locking convention.
+ example:
+ MMFFinderByName finder;
+ MongoMMF *a = finder.find("file_name_a");
+ MongoMMF *b = finder.find("file_name_b");
+ */
+ class MongoFileFinder : boost::noncopyable {
+ public:
+ MongoFileFinder() : _lk(MongoFile::mmmutex,false) { }
- /* can be "overriden" if necessary */
- static bool exists(boost::filesystem::path p) {
- return boost::filesystem::exists(p);
+ /** @return The MongoFile object associated with the specified file name. If no file is open
+ with the specified name, returns null.
+ */
+ MongoFile* findByPath(string path) {
+ map<string,MongoFile*>::iterator i = MongoFile::pathToFile.find(path);
+ return i == MongoFile::pathToFile.end() ? NULL : i->second;
}
- };
-
-#ifndef _DEBUG
- // no-ops in production
- inline void MongoFile::lockAll() {}
- inline void MongoFile::unlockAll() {}
-#endif
+ private:
+ rwlock _lk;
+ };
struct MongoFileAllowWrites {
- MongoFileAllowWrites(){
- MongoFile::lockAll();
+ MongoFileAllowWrites() {
+ MongoFile::markAllWritable();
}
- ~MongoFileAllowWrites(){
- MongoFile::unlockAll();
+ ~MongoFileAllowWrites() {
+ MongoFile::unmarkAllWritable();
}
};
- /** template for what a new storage engine's class definition must implement
- PRELIMINARY - subject to change.
- */
- class StorageContainerTemplate : public MongoFile {
- protected:
- virtual void close();
- virtual void flush(bool sync);
- public:
- virtual long length();
-
- /** pointer to a range of space in this storage unit */
- class Pointer {
- public:
- /** retried address of buffer at offset 'offset' withing the storage unit. returned range is a contiguous
- buffer reflecting what is in storage. caller will not read or write past 'len'.
-
- note calls may be received that are at different points in a range and different lengths. however
- for now assume that on writes, if a call is made, previously returned addresses are no longer valid. i.e.
- p = at(10000, 500);
- q = at(10000, 600);
- after the second call it is ok if p is invalid.
- */
- void* at(int offset, int len);
-
- /** indicate that we wrote to the range (from a previous at() call) and that it needs
- flushing to disk.
- */
- void written(int offset, int len);
-
- bool isNull() const;
- };
-
- /** commit written() calls from above. */
- void commit();
-
- Pointer open(const char *filename);
- Pointer open(const char *_filename, long &length, int options=0);
- };
-
class MemoryMappedFile : public MongoFile {
public:
- class Pointer {
- char *_base;
- public:
- Pointer() : _base(0) { }
- Pointer(void *p) : _base((char*) p) { }
- void* at(int offset, int maxLen) { return _base + offset; }
- void grow(int offset, int len) { /* no action required with mem mapped file */ }
- bool isNull() const { return _base == 0; }
- };
-
MemoryMappedFile();
- ~MemoryMappedFile() {
- destroyed();
+
+ virtual ~MemoryMappedFile() {
+ destroyed(); // cleans up from the master list of mmaps
close();
}
- void close();
-
- // Throws exception if file doesn't exist. (dm may2010: not sure if this is always true?)
- void* map( const char *filename );
- /*To replace map():
-
- Pointer open( const char *filename ) {
- void *p = map(filename);
- uassert(13077, "couldn't open/map file", p);
- return Pointer(p);
- }*/
+ virtual void close();
+
+ // Throws exception if file doesn't exist. (dm may2010: not sure if this is always true?)
+ void* map(const char *filename);
+ void* mapWithOptions(const char *filename, int options);
/* Creates with length if DNE, otherwise uses existing file length,
passed length.
+ @param options MongoFile::Options bits
*/
- void* map(const char *filename, long &length, int options = 0 );
+ void* map(const char *filename, unsigned long long &length, int options = 0 );
+
+ /* Create. Must not exist.
+ @param zero fill file with zeros when true
+ */
+ void* create(string filename, unsigned long long len, bool zero);
void flush(bool sync);
virtual Flushable * prepareFlush();
- /*void* viewOfs() {
- return view;
- }*/
+ long shortLength() const { return (long) len; }
+ unsigned long long length() const { return len; }
- long length() {
- return len;
- }
+ /** create a new view with the specified properties.
+ automatically cleaned up upon close/destruction of the MemoryMappedFile object.
+ */
+ void* createReadOnlyMap();
+ void* createPrivateMap();
- string filename() const { return _filename; }
+ /** make the private map range writable (necessary for our windows implementation) */
+ static void makeWritable(void *, unsigned len)
+#if defined(_WIN32)
+ ;
+#else
+ { }
+#endif
private:
- static void updateLength( const char *filename, long &length );
-
+ static void updateLength( const char *filename, unsigned long long &length );
+
HANDLE fd;
HANDLE maphandle;
- void *view;
- long len;
- string _filename;
+ vector<void *> views;
+ unsigned long long len;
+
+#ifdef _WIN32
+ boost::shared_ptr<mutex> _flushMutex;
+ void clearWritableBits(void *privateView);
+ public:
+ static const unsigned ChunkSize = 64 * 1024 * 1024;
+ static const unsigned NChunks = 1024 * 1024;
+#else
+ void clearWritableBits(void *privateView) { }
+#endif
protected:
// only posix mmap implementations will support this
virtual void _lock();
virtual void _unlock();
+ /** close the current private view and open a new replacement */
+ void* remapPrivateView(void *oldPrivateAddr);
};
- void printMemInfo( const char * where );
+ typedef MemoryMappedFile MMF;
-#include "ramstore.h"
+ /** p is called from within a mutex that MongoFile uses. so be careful not to deadlock. */
+ template < class F >
+ inline void MongoFile::forEach( F p ) {
+ rwlock lk( mmmutex , false );
+ for ( set<MongoFile*>::iterator i = mmfiles.begin(); i != mmfiles.end(); i++ )
+ p(*i);
+ }
+
+#if defined(_WIN32)
+ class ourbitset {
+ volatile unsigned bits[MemoryMappedFile::NChunks]; // volatile as we are doing double check locking
+ public:
+ ourbitset() {
+ memset((void*) bits, 0, sizeof(bits));
+ }
+ bool get(unsigned i) const {
+ unsigned x = i / 32;
+ assert( x < MemoryMappedFile::NChunks );
+ return bits[x] & (1 << (i%32));
+ }
+ void set(unsigned i) {
+ unsigned x = i / 32;
+ assert( x < MemoryMappedFile::NChunks );
+ bits[x] |= (1 << (i%32));
+ }
+ void clear(unsigned i) {
+ unsigned x = i / 32;
+ assert( x < MemoryMappedFile::NChunks );
+ bits[x] &= ~(1 << (i%32));
+ }
+ };
+ extern ourbitset writable;
+ void makeChunkWritable(size_t chunkno);
+ inline void MemoryMappedFile::makeWritable(void *_p, unsigned len) {
+ size_t p = (size_t) _p;
+ unsigned a = p/ChunkSize;
+ unsigned b = (p+len)/ChunkSize;
+ for( unsigned i = a; i <= b; i++ ) {
+ if( !writable.get(i) ) {
+ makeChunkWritable(i);
+ }
+ }
+ }
-//#define _RAMSTORE
-#if defined(_RAMSTORE)
- typedef RamStoreFile MMF;
-#else
- typedef MemoryMappedFile MMF;
#endif
} // namespace mongo