|
MongoDB
2.0.3
|
00001 // mmap.h 00002 00003 /* Copyright 2009 10gen Inc. 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 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(); // destructor resets the range to MADV_NORMAL 00031 }; 00032 00033 /* the administrative-ish stuff here */ 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, // hint - e.g. FILE_FLAG_SEQUENTIAL_SCAN on windows 00047 READONLY = 2 // not contractually guaranteed, but if specified the impl has option to fault writes 00048 }; 00049 00053 template < class F > 00054 static void forEach( F fun ); 00055 00058 static set<MongoFile*>& getAllFiles() { return mmfiles; } 00059 00060 // callbacks if you need them 00061 static void (*notifyPreFlush)(); 00062 static void (*notifyPostFlush)(); 00063 00064 static int flushAll( bool sync ); // returns n flushed 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 ); // returns n flushed 00086 protected: 00087 virtual void close() = 0; 00088 virtual void flush(bool sync) = 0; 00093 virtual Flushable * prepareFlush() = 0; 00094 00095 void created(); /* subclass must call after create */ 00096 00097 /* subclass must call in destructor (or at close). 00098 removes this from pathToFile and other maps 00099 safe to call more than once, albeit might be wasted work 00100 ideal to call close to the close, if the close is well before object destruction 00101 */ 00102 void destroyed(); 00103 00104 virtual unsigned long long length() const = 0; 00105 00106 // only supporting on posix mmap 00107 virtual void _lock() {} 00108 virtual void _unlock() {} 00109 00110 static set<MongoFile*> mmfiles; 00111 public: 00112 static map<string,MongoFile*> pathToFile; 00113 00114 // lock order: lock dbMutex before this if you lock both 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 // Throws exception if file doesn't exist. (dm may2010: not sure if this is always true?) 00168 void* map(const char *filename); 00169 00171 void* mapWithOptions(const char *filename, int options); 00172 00173 /* Creates with length if DNE, otherwise uses existing file length, 00174 passed length. 00175 @param options MongoFile::Options bits 00176 */ 00177 void* map(const char *filename, unsigned long long &length, int options = 0 ); 00178 00179 /* Create. Must not exist. 00180 @param zero fill file with zeros when true 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 // only posix mmap implementations will support this 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]; // volatile as we are doing double check locking 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) ); // warn if getting close to limit 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 } // namespace mongo
1.8.0