00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #pragma once
00019 #include <boost/thread/xtime.hpp>
00020 #include "concurrency/rwlock.h"
00021
00022 namespace mongo {
00023
00024
00025 class MongoFile : boost::noncopyable {
00026 public:
00028 class Flushable {
00029 public:
00030 virtual ~Flushable() {}
00031 virtual void flush() = 0;
00032 };
00033
00034 virtual ~MongoFile() {}
00035
00036 enum Options {
00037 SEQUENTIAL = 1,
00038 READONLY = 2
00039 };
00040
00044 template < class F >
00045 static void forEach( F fun );
00046
00048 static set<MongoFile*>& getAllFiles() { return mmfiles; }
00049
00050
00051 static void (*notifyPreFlush)();
00052 static void (*notifyPostFlush)();
00053
00054 static int flushAll( bool sync );
00055 static long long totalMappedLength();
00056 static void closeAllFiles( stringstream &message );
00057
00058 #if defined(_DEBUG)
00059 static void markAllWritable();
00060 static void unmarkAllWritable();
00061 #else
00062 static void markAllWritable() { }
00063 static void unmarkAllWritable() { }
00064 #endif
00065
00066 static bool exists(boost::filesystem::path p) { return boost::filesystem::exists(p); }
00067
00068 virtual bool isMongoMMF() { return false; }
00069
00070 string filename() const { return _filename; }
00071 void setFilename(string fn);
00072
00073 private:
00074 string _filename;
00075 static int _flushAll( bool sync );
00076 protected:
00077 virtual void close() = 0;
00078 virtual void flush(bool sync) = 0;
00083 virtual Flushable * prepareFlush() = 0;
00084
00085 void created();
00086
00087
00088
00089
00090
00091
00092 void destroyed();
00093
00094 virtual unsigned long long length() const = 0;
00095
00096
00097 virtual void _lock() {}
00098 virtual void _unlock() {}
00099
00100 static set<MongoFile*> mmfiles;
00101 public:
00102 static map<string,MongoFile*> pathToFile;
00103 static RWLock mmmutex;
00104 };
00105
00112 class MongoFileFinder : boost::noncopyable {
00113 public:
00114 MongoFileFinder() : _lk(MongoFile::mmmutex,false) { }
00115
00119 MongoFile* findByPath(string path) {
00120 map<string,MongoFile*>::iterator i = MongoFile::pathToFile.find(path);
00121 return i == MongoFile::pathToFile.end() ? NULL : i->second;
00122 }
00123
00124 private:
00125 rwlock _lk;
00126 };
00127
00128 struct MongoFileAllowWrites {
00129 MongoFileAllowWrites() {
00130 MongoFile::markAllWritable();
00131 }
00132 ~MongoFileAllowWrites() {
00133 MongoFile::unmarkAllWritable();
00134 }
00135 };
00136
00137 class MemoryMappedFile : public MongoFile {
00138 public:
00139 MemoryMappedFile();
00140
00141 virtual ~MemoryMappedFile() {
00142 destroyed();
00143 close();
00144 }
00145
00146 virtual void close();
00147
00148
00149 void* map(const char *filename);
00150 void* mapWithOptions(const char *filename, int options);
00151
00152
00153
00154
00155
00156 void* map(const char *filename, unsigned long long &length, int options = 0 );
00157
00158
00159
00160
00161 void* create(string filename, unsigned long long len, bool zero);
00162
00163 void flush(bool sync);
00164 virtual Flushable * prepareFlush();
00165
00166 long shortLength() const { return (long) len; }
00167 unsigned long long length() const { return len; }
00168
00172 void* createReadOnlyMap();
00173 void* createPrivateMap();
00174
00176 static void makeWritable(void *, unsigned len)
00177 #if defined(_WIN32)
00178 ;
00179 #else
00180 { }
00181 #endif
00182
00183 private:
00184 static void updateLength( const char *filename, unsigned long long &length );
00185
00186 HANDLE fd;
00187 HANDLE maphandle;
00188 vector<void *> views;
00189 unsigned long long len;
00190
00191 #ifdef _WIN32
00192 boost::shared_ptr<mutex> _flushMutex;
00193 void clearWritableBits(void *privateView);
00194 public:
00195 static const unsigned ChunkSize = 64 * 1024 * 1024;
00196 static const unsigned NChunks = 1024 * 1024;
00197 #else
00198 void clearWritableBits(void *privateView) { }
00199 #endif
00200
00201 protected:
00202
00203 virtual void _lock();
00204 virtual void _unlock();
00205
00207 void* remapPrivateView(void *oldPrivateAddr);
00208 };
00209
00210 typedef MemoryMappedFile MMF;
00211
00213 template < class F >
00214 inline void MongoFile::forEach( F p ) {
00215 rwlock lk( mmmutex , false );
00216 for ( set<MongoFile*>::iterator i = mmfiles.begin(); i != mmfiles.end(); i++ )
00217 p(*i);
00218 }
00219
00220 #if defined(_WIN32)
00221 class ourbitset {
00222 volatile unsigned bits[MemoryMappedFile::NChunks];
00223 public:
00224 ourbitset() {
00225 memset((void*) bits, 0, sizeof(bits));
00226 }
00227 bool get(unsigned i) const {
00228 unsigned x = i / 32;
00229 assert( x < MemoryMappedFile::NChunks );
00230 return bits[x] & (1 << (i%32));
00231 }
00232 void set(unsigned i) {
00233 unsigned x = i / 32;
00234 assert( x < MemoryMappedFile::NChunks );
00235 bits[x] |= (1 << (i%32));
00236 }
00237 void clear(unsigned i) {
00238 unsigned x = i / 32;
00239 assert( x < MemoryMappedFile::NChunks );
00240 bits[x] &= ~(1 << (i%32));
00241 }
00242 };
00243 extern ourbitset writable;
00244 void makeChunkWritable(size_t chunkno);
00245 inline void MemoryMappedFile::makeWritable(void *_p, unsigned len) {
00246 size_t p = (size_t) _p;
00247 unsigned a = p/ChunkSize;
00248 unsigned b = (p+len)/ChunkSize;
00249 for( unsigned i = a; i <= b; i++ ) {
00250 if( !writable.get(i) ) {
00251 makeChunkWritable(i);
00252 }
00253 }
00254 }
00255
00256 #endif
00257
00258 }