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