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 class MAdvise {
00025 void *_p;
00026 unsigned _len;
00027 public:
00028 enum Advice { Sequential=1 };
00029 MAdvise(void *p, unsigned len, Advice a);
00030 ~MAdvise();
00031 };
00032
00033
00034 class MongoFile : boost::noncopyable {
00035 public:
00037 class Flushable {
00038 public:
00039 virtual ~Flushable() {}
00040 virtual void flush() = 0;
00041 };
00042
00043 virtual ~MongoFile() {}
00044
00045 enum Options {
00046 SEQUENTIAL = 1,
00047 READONLY = 2
00048 };
00049
00053 template < class F >
00054 static void forEach( F fun );
00055
00058 static set<MongoFile*>& getAllFiles() { return mmfiles; }
00059
00060
00061 static void (*notifyPreFlush)();
00062 static void (*notifyPostFlush)();
00063
00064 static int flushAll( bool sync );
00065 static long long totalMappedLength();
00066 static void closeAllFiles( stringstream &message );
00067
00068 #if defined(_DEBUG)
00069 static void markAllWritable();
00070 static void unmarkAllWritable();
00071 #else
00072 static void markAllWritable() { }
00073 static void unmarkAllWritable() { }
00074 #endif
00075
00076 static bool exists(boost::filesystem::path p) { return boost::filesystem::exists(p); }
00077
00078 virtual bool isMongoMMF() { return false; }
00079
00080 string filename() const { return _filename; }
00081 void setFilename(string fn);
00082
00083 private:
00084 string _filename;
00085 static int _flushAll( bool sync );
00086 protected:
00087 virtual void close() = 0;
00088 virtual void flush(bool sync) = 0;
00093 virtual Flushable * prepareFlush() = 0;
00094
00095 void created();
00096
00097
00098
00099
00100
00101
00102 void destroyed();
00103
00104 virtual unsigned long long length() const = 0;
00105
00106
00107 virtual void _lock() {}
00108 virtual void _unlock() {}
00109
00110 static set<MongoFile*> mmfiles;
00111 public:
00112 static map<string,MongoFile*> pathToFile;
00113
00114
00115 static RWLockRecursive mmmutex;
00116 };
00117
00124 class MongoFileFinder : boost::noncopyable {
00125 public:
00126 MongoFileFinder() : _lk(MongoFile::mmmutex) { }
00127
00131 MongoFile* findByPath(string path) {
00132 map<string,MongoFile*>::iterator i = MongoFile::pathToFile.find(path);
00133 return i == MongoFile::pathToFile.end() ? NULL : i->second;
00134 }
00135
00136 private:
00137 RWLockRecursive::Shared _lk;
00138 };
00139
00140 struct MongoFileAllowWrites {
00141 MongoFileAllowWrites() {
00142 MongoFile::markAllWritable();
00143 }
00144 ~MongoFileAllowWrites() {
00145 MongoFile::unmarkAllWritable();
00146 }
00147 };
00148
00149 class MemoryMappedFile : public MongoFile {
00150 protected:
00151 virtual void* viewForFlushing() {
00152 if( views.size() == 0 )
00153 return 0;
00154 assert( views.size() == 1 );
00155 return views[0];
00156 }
00157 public:
00158 MemoryMappedFile();
00159
00160 virtual ~MemoryMappedFile() {
00161 RWLockRecursive::Exclusive lk(mmmutex);
00162 close();
00163 }
00164
00165 virtual void close();
00166
00167
00168 void* map(const char *filename);
00169
00171 void* mapWithOptions(const char *filename, int options);
00172
00173
00174
00175
00176
00177 void* map(const char *filename, unsigned long long &length, int options = 0 );
00178
00179
00180
00181
00182 void* create(string filename, unsigned long long len, bool zero);
00183
00184 void flush(bool sync);
00185 virtual Flushable * prepareFlush();
00186
00187 long shortLength() const { return (long) len; }
00188 unsigned long long length() const { return len; }
00189
00193 void* createReadOnlyMap();
00194 void* createPrivateMap();
00195
00197 static void makeWritable(void *, unsigned len)
00198 #if defined(_WIN32)
00199 ;
00200 #else
00201 { }
00202 #endif
00203
00204 private:
00205 static void updateLength( const char *filename, unsigned long long &length );
00206
00207 HANDLE fd;
00208 HANDLE maphandle;
00209 vector<void *> views;
00210 unsigned long long len;
00211
00212 #ifdef _WIN32
00213 boost::shared_ptr<mutex> _flushMutex;
00214 void clearWritableBits(void *privateView);
00215 public:
00216 static const unsigned ChunkSize = 64 * 1024 * 1024;
00217 static const unsigned NChunks = 1024 * 1024;
00218 #else
00219 void clearWritableBits(void *privateView) { }
00220 #endif
00221
00222 protected:
00223
00224 virtual void _lock();
00225 virtual void _unlock();
00226
00228 void* remapPrivateView(void *oldPrivateAddr);
00229 };
00230
00231 typedef MemoryMappedFile MMF;
00232
00234 template < class F >
00235 inline void MongoFile::forEach( F p ) {
00236 RWLockRecursive::Shared lklk(mmmutex);
00237 for ( set<MongoFile*>::iterator i = mmfiles.begin(); i != mmfiles.end(); i++ )
00238 p(*i);
00239 }
00240
00241 #if defined(_WIN32)
00242 class ourbitset {
00243 volatile unsigned bits[MemoryMappedFile::NChunks];
00244 public:
00245 ourbitset() {
00246 memset((void*) bits, 0, sizeof(bits));
00247 }
00248 bool get(unsigned i) const {
00249 unsigned x = i / 32;
00250 assert( x < MemoryMappedFile::NChunks );
00251 return (bits[x] & (1 << (i%32))) != 0;
00252 }
00253 void set(unsigned i) {
00254 unsigned x = i / 32;
00255 wassert( x < (MemoryMappedFile::NChunks*2/3) );
00256 assert( x < MemoryMappedFile::NChunks );
00257 bits[x] |= (1 << (i%32));
00258 }
00259 void clear(unsigned i) {
00260 unsigned x = i / 32;
00261 assert( x < MemoryMappedFile::NChunks );
00262 bits[x] &= ~(1 << (i%32));
00263 }
00264 };
00265 extern ourbitset writable;
00266 void makeChunkWritable(size_t chunkno);
00267 inline void MemoryMappedFile::makeWritable(void *_p, unsigned len) {
00268 size_t p = (size_t) _p;
00269 unsigned a = p/ChunkSize;
00270 unsigned b = (p+len)/ChunkSize;
00271 for( unsigned i = a; i <= b; i++ ) {
00272 if( !writable.get(i) ) {
00273 makeChunkWritable(i);
00274 }
00275 }
00276 }
00277
00278 #endif
00279
00280 }