00001 // File: $Id$ 00002 // Author: K. John Wu <John.Wu at acm.org> 00003 // Lawrence Berkeley National Laboratory 00004 // Copyright 2000-2011 University of California 00005 #ifndef IBIS_FILEMANAGER_H 00006 #define IBIS_FILEMANAGER_H 00007 00008 00009 00010 00011 00012 00013 00014 00015 #include "util.h" 00016 00017 #include <set> // std::set 00018 #include <map> // std::map 00019 #include <math.h> // sqrt 00020 00024 class FASTBIT_CXX_DLLSPEC ibis::fileManager { 00025 public: 00026 00030 enum ACCESS_PREFERENCE { 00031 MMAP_LARGE_FILES, // files > minMapSize are mapped if possible 00032 PREFER_READ, // read the whole file into memory 00033 PREFER_MMAP // try to use mmap if possible 00034 }; 00035 00036 template<typename T> 00037 int getFile(const char* name, array_t<T>& arr, 00038 ACCESS_PREFERENCE pref=MMAP_LARGE_FILES); 00039 template<typename T> 00040 int tryGetFile(const char* name, array_t<T>& arr, 00041 ACCESS_PREFERENCE pref=MMAP_LARGE_FILES); 00042 00044 void printStatus(std::ostream& out) const; 00046 void flushFile(const char* name); 00048 void flushDir(const char* name); 00050 void clear(); 00051 00053 static fileManager& instance(); 00055 static time_t iBeat() {return hbeat++;} 00057 const double& pageCount() const {return page_count;} 00059 static uint32_t pageSize() {return pagesize;} 00060 inline void recordPages(off_t start, off_t stop); 00061 static inline void increaseUse(size_t inc, const char* evt); 00062 static inline void decreaseUse(size_t dec, const char* evt); 00064 void signalMemoryAvailable() const; 00065 00067 class cleaner { 00068 public: 00069 virtual void operator()() const = 0; 00070 virtual ~cleaner() {}; 00071 }; 00072 void addCleaner(const cleaner* cl); 00073 void removeCleaner(const cleaner* cl); 00074 00075 class roFile; // forward declaration of fileManager::roFile 00076 class storage; // forward declaration of fileManager::storage 00077 #if defined(HAVE_FILE_MAP) 00078 class rofSegment; // forward declaration of fileManager::rofSegment 00079 #endif 00080 friend class roFile; 00081 friend class storage; 00082 int getFile(const char* name, storage** st, 00083 ACCESS_PREFERENCE pref=MMAP_LARGE_FILES); 00084 int tryGetFile(const char* name, storage** st, 00085 ACCESS_PREFERENCE pref=MMAP_LARGE_FILES); 00086 static storage* getFileSegment(const char* name, const int fdes, 00087 const off_t b, const off_t e); 00088 00090 inline void gainReadAccess(const char* mesg) const; 00092 inline void releaseAccess(const char* mesg) const; 00095 class readLock { 00096 public: 00097 readLock(const char* m) : mesg(m) { 00098 ibis::fileManager::instance().gainReadAccess(m); 00099 } 00100 ~readLock() { 00101 ibis::fileManager::instance().releaseAccess(mesg); 00102 } 00103 private: 00104 const char* mesg; // mesg identifies the holder of the lock 00105 }; 00106 00108 static uint64_t currentCacheSize() {return maxBytes;} 00110 static int adjustCacheSize(uint64_t); 00112 static uint64_t bytesInUse() {return ibis::fileManager::totalBytes();} 00114 static uint64_t bytesFree(); 00115 00119 template <typename T> 00120 class buffer { 00121 public: 00123 buffer(size_t sz=0); 00125 ~buffer(); 00126 00128 T& operator[](size_t i) {return buf[i];} 00130 const T& operator[](size_t i) const {return buf[i];} 00132 T* address() const {return buf;} 00134 size_t size() const {return nbuf;} 00136 size_t resize(size_t sz=0); 00138 void swap(buffer<T>& other) throw () { 00139 T* btmp = buf; 00140 buf = other.buf; 00141 other.buf = btmp; 00142 size_t ntmp = nbuf; 00143 nbuf = other.nbuf; 00144 other.nbuf = ntmp; 00145 } 00146 00147 private: 00148 T* buf; 00149 size_t nbuf; 00150 00151 buffer(const buffer<T>&); 00152 buffer<T>& operator=(const buffer<T>&); 00153 }; // buffer 00154 00155 protected: 00156 fileManager(); // get its input parameter from ibis::gParameters() 00157 ~fileManager(); // it exists forever 00158 00159 void recordFile(roFile*); // record a new storage 00160 00161 // parameters for controlling the resource usage 00163 static ibis::util::sharedInt64 totalBytes; 00165 static uint64_t maxBytes; 00167 static unsigned int maxOpenFiles; 00168 00169 // not implemented, to prevent compiler from generating these functions 00170 fileManager(const fileManager& rhs); 00171 fileManager& operator=(const fileManager& rhs); 00172 00173 private: 00174 typedef std::map< const char*, roFile*, 00175 std::less< const char* > > fileList; 00176 typedef std::set< const cleaner* > cleanerList; 00177 typedef std::set< const char*, std::less< const char* > > nameList; 00178 fileList mapped; // files that are memory mapped 00179 fileList incore; // files that have been read into the main memory 00180 nameList reading;// files that are being read by the function getFile 00181 cleanerList cleaners; // list of external cleaners 00183 double page_count; 00185 uint32_t minMapSize; 00187 uint32_t nwaiting; 00189 pthread_cond_t readCond; 00190 00191 mutable pthread_rwlock_t lock; // the multiple read single write lock 00192 mutable pthread_mutex_t mutex; // control access to incore and mapped 00193 mutable pthread_cond_t cond; // conditional variable -- unload(), etc.. 00194 00195 static time_t hbeat; // a simple counter, no mutex lock 00197 static uint32_t pagesize; 00198 00199 int unload(size_t size); // try to unload size bytes 00200 void invokeCleaners() const;// invoke external cleaners 00201 inline void gainWriteAccess(const char* m) const; 00202 00203 class writeLock; 00204 class softWriteLock; 00205 friend class writeLock; 00206 friend class softWriteLock; 00207 }; // class fileManager 00208 00219 class FASTBIT_CXX_DLLSPEC ibis::fileManager::storage { 00220 public: 00221 storage(); 00222 explicit storage(size_t n); // allocate n bytes 00223 virtual ~storage() {clear();} 00224 00225 storage(const char* fname, const off_t begin, const off_t end); 00226 storage(const int fdes, const off_t begin, const off_t end); 00227 storage(const char* begin, const char* end); 00228 storage(const storage& rhs); 00229 storage& operator=(const storage& rhs); 00230 void copy(const storage& rhs); 00231 00234 const char* filename() const {return name;} 00235 00237 bool empty() const {return (m_begin == 0 || m_begin >= m_end);} 00239 size_t size() const { 00240 return (m_begin!=0 && m_begin<m_end ? m_end-m_begin : 0);} 00242 size_t bytes() const { 00243 return (m_begin!=0 && m_begin<m_end ? m_end-m_begin : 0);} 00246 void enlarge(size_t nelm=0); 00247 00249 char* begin() {return m_begin;} 00251 const char* end() const {return m_end;} 00253 const char* begin() const {return m_begin;} 00255 char operator[](size_t i) const {return m_begin[i];} 00256 00257 virtual void beginUse(); 00258 virtual void endUse(); 00260 unsigned inUse() const {return nref();} 00262 unsigned pastUse() const {return nacc;} 00263 00265 virtual bool isFileMap() const {return false;} 00266 // IO functions 00267 virtual void printStatus(std::ostream& out) const; 00268 off_t read(const char* fname, const off_t begin, const off_t end); 00269 off_t read(const int fdes, const off_t begin, const off_t end); 00270 void write(const char* file) const; 00271 00272 inline void swap(storage& rhs) throw (); 00273 // // compares storage objects according to starting addresses 00274 // struct less : std::binary_function< storage*, storage*, bool > { 00275 // bool operator()(const storage* x, const storage* y) const { 00276 // return (x->begin() < y->begin()); 00277 // } 00278 // }; 00279 00280 protected: 00281 char* name; 00282 char* m_begin; 00283 char* m_end; 00284 unsigned nacc; 00285 00286 ibis::util::sharedInt32 nref; 00287 00288 virtual void clear(); // free memory/close file 00289 }; // class fileManager::storage 00290 00299 class FASTBIT_CXX_DLLSPEC ibis::fileManager::roFile 00300 : public ibis::fileManager::storage { 00301 public: 00302 virtual ~roFile() {clear();} 00303 00304 // functions for recording access statistics 00305 virtual void beginUse(); 00306 virtual void endUse(); 00307 // is the read-only file mapped ? 00308 virtual bool isFileMap() const {return (mapped != 0);} 00309 00310 // IO functions 00311 virtual void printStatus(std::ostream& out) const; 00312 void read(const char* file); 00313 #if defined(HAVE_FILE_MAP) 00314 void mapFile(const char* file); 00315 #endif 00316 00317 // // compares storage objects according to file names 00318 // struct less : std::binary_function< roFile*, roFile*, bool > { 00319 // bool operator()(const roFile* x, const roFile* y) const { 00320 // return strcmp(x->filename(), y->filename()) < 0; 00321 // } 00322 // }; 00323 protected: 00324 roFile(); 00325 // Read the whole file into memory. 00326 void doRead(const char* file); 00327 // Read the specified segment of the file into memory. 00328 void doRead(const char* file, off_t b, off_t e); 00329 #if defined(HAVE_FILE_MAP) 00330 void doMap(const char* file, off_t b, off_t e, int opt=0); 00331 #endif 00332 00336 float score() const { 00337 float sc = FLT_MAX; 00338 time_t now = time(0); 00339 if (opened >= now) { 00340 sc = static_cast<float>(1e-4 * size() + nacc); 00341 } 00342 else if (lastUse >= now) { 00343 sc = static_cast<float>(sqrt(5e-6*size()) + nacc + 00344 (now - opened)); 00345 } 00346 else { 00347 sc = static_cast<float>((sqrt(1e-6*size() + now - opened) + 00348 (static_cast<double>(nacc) / 00349 (now - opened))) / (now - lastUse)); 00350 } 00351 return sc; 00352 } 00353 00354 friend class ibis::fileManager; 00355 virtual void clear(); // free memory/close file 00356 00357 void printBody(std::ostream& out) const; 00358 00359 private: 00360 time_t opened; // time first created, presumably when the file was opened 00361 time_t lastUse; // time of last use 00362 unsigned mapped; // 0 not a mapped file, otherwise yes 00363 00364 #if defined(_WIN32) && defined(_MSC_VER) 00365 HANDLE fdescriptor; // HANDLE to the open file 00366 HANDLE fmap; // HANDLE to the mapping object 00367 LPVOID map_begin; // actual address returned by MapViewOfFile 00368 #elif (HAVE_MMAP+0 > 0) 00369 int fdescriptor; // descriptor of the open file 00370 size_t fsize; // the size of the mapped portion of file 00371 void *map_begin; // actual address returned by mmap 00372 #endif 00373 00374 // not implemented, to prevent automatic generation 00375 roFile(const roFile&); 00376 roFile& operator=(const roFile&); 00377 }; // class fileManager::roFile 00378 00379 #if defined(HAVE_FILE_MAP) 00380 00381 00382 00383 class FASTBIT_CXX_DLLSPEC ibis::fileManager::rofSegment 00384 : public ibis::fileManager::roFile { 00385 public: 00386 rofSegment(const char *fn, off_t b, off_t e); 00387 virtual ~rofSegment() {}; 00388 virtual void printStatus(std::ostream& out) const; 00389 00390 private: 00391 rofSegment(); // no default constructor 00392 rofSegment(const rofSegment&); // no copy constructor 00393 rofSegment& operator=(const rofSegment&); // no assignment operator 00394 00395 std::string filename_; // name of the file 00396 off_t begin_, end_; // the start and the end address of the file map 00397 }; // ibis::fileManager::rofSegment 00398 #endif 00399 00401 class ibis::fileManager::writeLock { 00402 public: 00403 writeLock(const char* m) : mesg(m) 00404 {ibis::fileManager::instance().gainWriteAccess(mesg);} 00405 ~writeLock() {ibis::fileManager::instance().releaseAccess(mesg);} 00406 private: 00407 const char* mesg; 00408 00409 writeLock(const writeLock&); 00410 writeLock& operator=(const writeLock&); 00411 }; // ibis::fileManager::writeLock 00412 00414 class ibis::fileManager::softWriteLock { 00415 public: 00416 softWriteLock(const char* m); 00417 ~softWriteLock(); 00420 bool isLocked() const {return(locked_==0);} 00421 00422 private: 00423 const char* mesg; 00424 const int locked_; 00425 00426 softWriteLock(const softWriteLock&); 00427 softWriteLock& operator=(const softWriteLock&); 00428 }; // ibis::fileManager::softWriteLock 00429 00430 inline uint64_t ibis::fileManager::bytesFree() { 00431 if (maxBytes == 0) 00432 ibis::fileManager::instance(); 00433 return (maxBytes > ibis::fileManager::totalBytes() ? 00434 maxBytes - ibis::fileManager::totalBytes() : 0); 00435 } // ibis::fileManager::bytesFree 00436 00437 inline void ibis::fileManager::releaseAccess(const char* mesg) const { 00438 int ierr = pthread_rwlock_unlock(&lock); 00439 if (0 == ierr) { 00440 LOGGER(ibis::gVerbose > 9) 00441 << "fileManager::releaseAccess on " 00442 << static_cast<const void*>(&lock) << " for " << mesg; 00443 } 00444 else { 00445 LOGGER(ibis::gVerbose >= 0) 00446 << "Warning -- fileManager::releaseAccess on " 00447 << static_cast<const void*>(&lock) << " for " << mesg 00448 << " failed with the error code " << ierr << " -- " 00449 << strerror(ierr); 00450 } 00451 } // ibis::fileManager::releaseAccess 00452 00453 inline void ibis::fileManager::gainReadAccess(const char* mesg) const { 00454 int ierr = pthread_rwlock_rdlock(&lock); 00455 if (0 == ierr) { 00456 LOGGER(ibis::gVerbose > 9) 00457 << "fileManager::gainReadAccess on " 00458 << static_cast<const void*>(&lock) << " for " << mesg; 00459 } 00460 else { 00461 LOGGER(ibis::gVerbose >= 0) 00462 << "Warning -- fileManager::gainReadAccess on " 00463 << static_cast<const void*>(&lock) << " for " << mesg 00464 << " failed with the error code " << ierr << " -- " 00465 << strerror(ierr); 00466 } 00467 } // ibis::fileManager::gainReadAccess 00468 00469 inline void ibis::fileManager::gainWriteAccess(const char* mesg) const { 00470 int ierr = pthread_rwlock_wrlock(&lock); 00471 if (0 == ierr) { 00472 LOGGER(ibis::gVerbose > 9) 00473 << "fileManager::gainWriteAccess on " 00474 << static_cast<const void*>(&lock) << " for " << mesg; 00475 } 00476 else { 00477 LOGGER(ibis::gVerbose >= 0) 00478 << "Warning -- fileManager::gainWriteAccess on " 00479 << static_cast<const void*>(&lock) << " for " << mesg 00480 << " failed with the error code " << ierr << " -- " 00481 << strerror(ierr); 00482 } 00483 } // ibis::fileManager::gainWriteAccess 00484 00488 inline void ibis::fileManager::recordPages(off_t start, off_t stop) { 00489 if (start < stop) { 00490 start -= (start % pagesize); 00491 if (stop % pagesize) 00492 stop += pagesize - stop % pagesize; 00493 page_count += static_cast<double>((stop - start) / pagesize); 00494 } 00495 } // ibis::fileManager::recordPages 00496 00497 inline void 00498 ibis::fileManager::increaseUse(size_t inc, const char* evt) { 00499 ibis::fileManager::totalBytes += inc; 00500 LOGGER(inc > 0 && evt != 0 && *evt != 0 && ibis::gVerbose > 9) 00501 << evt << " added " << inc << " bytes to increase totalBytes to " 00502 << ibis::fileManager::totalBytes(); 00503 } // ibis::fileManager::increaseUse 00504 00505 inline void 00506 ibis::fileManager::decreaseUse(size_t dec, const char* evt) { 00507 ibis::fileManager::totalBytes -= dec; 00508 LOGGER(dec > 0 && evt != 0 && *evt != 0 && ibis::gVerbose > 9) 00509 << evt << " removed " << dec << " bytes to decrease totalBytes to " 00510 << ibis::fileManager::totalBytes(); 00511 } // ibis::fileManager::decreaseUse 00512 00522 inline void 00523 ibis::fileManager::storage::swap(ibis::fileManager::storage& rhs) throw () { 00524 {char* tmp = name; name = rhs.name; rhs.name = tmp;} 00525 {char* tmp = m_begin; m_begin = rhs.m_begin; rhs.m_begin = tmp;} 00526 {char* tmp = m_end; m_end = rhs.m_end; rhs.m_end = tmp;} 00527 {unsigned itmp = nacc; nacc = rhs.nacc; rhs.nacc = itmp;} 00528 //nref.swap(rhs.nref); 00529 } // ibis::fileManager::storage::swap 00530 #endif // IBIS_FILEMANAGER_H
![]() |