00001
00002
00003
00004
00005 #ifndef IBIS_FILEMANAGER_H
00006 #define IBIS_FILEMANAGER_H
00015 #include "util.h"
00016
00017 #include <set>
00018 #include <map>
00019 #include <math.h>
00020
00024 class ibis::fileManager {
00025 public:
00026
00030 enum ACCESS_PREFERENCE {
00031 MMAP_LARGE_FILES,
00032 PREFER_READ,
00033 PREFER_MMAP
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 time_t iBeat() const {return _hbeat++;}
00057 const double& pageCount() const {return page_count;}
00059 static uint32_t pageSize() {return pagesize;}
00063 inline void recordPages(off_t start, off_t stop);
00064 static inline void increaseUse(size_t inc, const char* evt);
00065 static inline void decreaseUse(size_t dec, const char* evt);
00067 void signalMemoryAvailable() const;
00068
00070 class cleaner {
00071 public:
00072 virtual void operator()() const = 0;
00073 virtual ~cleaner() {};
00074 };
00075 void addCleaner(const cleaner* cl);
00076 void removeCleaner(const cleaner* cl);
00077
00078 class roFile;
00079 class storage;
00080 #if defined(HAVE_FILE_MAP)
00081 class rofSegment;
00082 #endif
00083 friend class roFile;
00084 friend class storage;
00085 int getFile(const char* name, storage** st,
00086 ACCESS_PREFERENCE pref=MMAP_LARGE_FILES);
00087 int tryGetFile(const char* name, storage** st,
00088 ACCESS_PREFERENCE pref=MMAP_LARGE_FILES);
00089 storage* getFileSegment(const char* name, off_t b, off_t e);
00090
00092 inline void gainReadAccess(const char* mesg) const;
00094 inline void releaseAccess(const char* mesg) const;
00097 class readLock {
00098 public:
00099 readLock(const char* m) : mesg(m) {
00100 ibis::fileManager::instance().gainReadAccess(m);
00101 }
00102 ~readLock() {
00103 ibis::fileManager::instance().releaseAccess(mesg);
00104 }
00105 private:
00106 const char* mesg;
00107 };
00108
00110 static uint64_t currentCacheSize() {return maxBytes;}
00112 static int adjustCacheSize(uint64_t);
00114 static uint64_t bytesInUse() {return ibis::fileManager::totalBytes();}
00116 static uint64_t bytesFree();
00117
00121 template <typename T>
00122 class buffer {
00123 public:
00125 buffer(size_t sz=0);
00127 ~buffer();
00128
00130 T& operator[](size_t i) {return buf[i];}
00132 const T& operator[](size_t i) const {return buf[i];}
00134 T* address() const {return buf;}
00136 size_t size() const {return nbuf;}
00138 size_t resize(size_t sz=0);
00140 void swap(buffer<T>& other) throw () {
00141 T* btmp = buf;
00142 buf = other.buf;
00143 other.buf = btmp;
00144 size_t ntmp = nbuf;
00145 nbuf = other.nbuf;
00146 other.nbuf = ntmp;
00147 }
00148
00149 private:
00150 T* buf;
00151 size_t nbuf;
00152
00153 buffer(const buffer<T>&);
00154 buffer<T>& operator=(const buffer<T>&);
00155 };
00156
00157 protected:
00158 fileManager();
00159 ~fileManager();
00160
00161 void recordFile(roFile*);
00162
00163
00165 static ibis::util::sharedInt64 totalBytes;
00167 static uint64_t maxBytes;
00169 static unsigned int maxOpenFiles;
00170
00171
00172 fileManager(const fileManager& rhs);
00173 fileManager& operator=(const fileManager& rhs);
00174
00175 private:
00176 typedef std::map< const char*, roFile*,
00177 std::less< const char* > > fileList;
00178 typedef std::set< const cleaner* > cleanerList;
00179 typedef std::set< const char*, std::less< const char* > > nameList;
00180 fileList mapped;
00181 fileList incore;
00182 nameList reading;
00183 cleanerList cleaners;
00184 mutable time_t _hbeat;
00186 double page_count;
00188 static uint32_t pagesize;
00190 uint32_t minMapSize;
00192 uint32_t nwaiting;
00194 pthread_cond_t readCond;
00195
00196 mutable pthread_rwlock_t lock;
00197 mutable pthread_mutex_t mutex;
00198 mutable pthread_cond_t cond;
00199
00200 int unload(size_t size);
00201 void invokeCleaners() const;
00202 inline void gainWriteAccess(const char* m) const;
00204 class writeLock {
00205 public:
00206 writeLock(const fileManager* fm, const char* m) :
00207 manager(fm), mesg(m) {manager->gainWriteAccess(mesg);}
00208 ~writeLock() {manager->releaseAccess(mesg);}
00209 private:
00210 const fileManager* manager;
00211 const char* mesg;
00212
00213 writeLock(const writeLock&);
00214 writeLock& operator=(const writeLock&);
00215 };
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 friend class writeLock;
00252 };
00253
00264 class ibis::fileManager::storage {
00265 public:
00266 storage() : name(0), m_begin(0), m_end(0), nacc(0), nref() {};
00267 explicit storage(size_t n);
00268 virtual ~storage() {clear();}
00269
00271 storage(const int fdes, const off_t begin, const off_t end);
00272
00273 storage(const storage& rhs);
00274 storage& operator=(const storage& rhs);
00275 void copy(const storage& rhs);
00277 storage(const char* begin, const char* end);
00278
00282 bool unnamed() {return (name == 0);}
00283 const char* filename() const {return name;}
00284
00286 bool empty() const {return (m_begin == 0 || m_begin >= m_end);}
00288 size_t size() const {
00289 return (m_begin != 0 && m_begin >= m_end ? 0 : m_end - m_begin);}
00291 size_t bytes() const {return (m_begin >= m_end ? 0 : m_end - m_begin);}
00294 void enlarge(size_t nelm=0);
00295
00297 char* begin() {return m_begin;}
00299 const char* end() const {return m_end;}
00301 const char* begin() const {return m_begin;}
00303 char operator[](size_t i) const {return m_begin[i];}
00304
00306 virtual void beginUse() {
00307 ++ nref;
00308 }
00310 virtual void endUse() {
00311 -- nref;
00312 ++ nacc;
00313 }
00314 unsigned inUse() const {
00315 return nref();
00316 }
00317 unsigned pastUse() const {
00318 return nacc;
00319 }
00320
00322 virtual bool isFileMap() const {return false;}
00323
00324 virtual void printStatus(std::ostream& out) const;
00326 off_t read(const int fdes, const off_t begin, const off_t end);
00328 void write(const char* file) const;
00329
00330 inline void swap(storage& rhs) throw ();
00331
00332
00333
00334
00335
00336
00337
00338 protected:
00339 char* name;
00340 char* m_begin;
00341 char* m_end;
00342 unsigned nacc;
00343
00344 ibis::util::sharedInt32 nref;
00345
00346 virtual void clear();
00347 };
00348
00357 class ibis::fileManager::roFile : public ibis::fileManager::storage {
00358 public:
00359 virtual ~roFile() {clear();}
00360
00361
00362 virtual void beginUse();
00363 virtual void endUse();
00364
00365 virtual bool isFileMap() const {return (mapped != 0);}
00366
00367
00368 virtual void printStatus(std::ostream& out) const;
00369 void read(const char* file);
00370 #if defined(HAVE_FILE_MAP)
00371 void mapFile(const char* file);
00372 #endif
00373
00374
00375
00376
00377
00378
00379
00380 protected:
00381 roFile() : storage(), opened(0), lastUse(0), mapped(0) {
00382 #if defined(_WIN32) && defined(_MSC_VER)
00383 fdescriptor = INVALID_HANDLE_VALUE;
00384 fmap = INVALID_HANDLE_VALUE;
00385 map_begin = 0;
00386 #elif (HAVE_MMAP+0 > 0)
00387 fdescriptor = -1;
00388 fsize = 0;
00389 map_begin = 0;
00390 #endif
00391 };
00392
00393
00394 void doRead(const char* file);
00395
00396 void doRead(const char* file, off_t b, off_t e);
00397 #if defined(HAVE_FILE_MAP)
00398 void doMap(const char* file, off_t b, off_t e, int opt=0);
00399 #endif
00400
00404 float score() const {
00405 float sc = FLT_MAX;
00406 time_t now = time(0);
00407 if (opened >= now) {
00408 sc = static_cast<float>(1e-4 * size() + nacc);
00409 }
00410 else if (lastUse >= now) {
00411 sc = static_cast<float>(sqrt(5e-6*size()) + nacc +
00412 (now - opened));
00413 }
00414 else {
00415 sc = static_cast<float>((sqrt(1e-6*size() + now - opened) +
00416 (static_cast<double>(nacc) /
00417 (now - opened))) / (now - lastUse));
00418 }
00419 return sc;
00420 }
00421
00422 friend class ibis::fileManager;
00423 virtual void clear();
00424
00425 void printBody(std::ostream& out) const;
00426
00427 private:
00428 time_t opened;
00429 time_t lastUse;
00430 unsigned mapped;
00431
00432 #if defined(_WIN32) && defined(_MSC_VER)
00433 HANDLE fdescriptor;
00434 HANDLE fmap;
00435 LPVOID map_begin;
00436 #elif (HAVE_MMAP+0 > 0)
00437 int fdescriptor;
00438 size_t fsize;
00439 void *map_begin;
00440 #endif
00441
00442
00443 roFile(const roFile&);
00444 roFile& operator=(const roFile&);
00445 };
00446
00447 #if defined(HAVE_FILE_MAP)
00451 class ibis::fileManager::rofSegment : public ibis::fileManager::roFile {
00452 public:
00453 rofSegment(const char *fn, off_t b, off_t e);
00454 virtual ~rofSegment() {};
00455 virtual void printStatus(std::ostream& out) const;
00456
00457 private:
00458 rofSegment();
00459 rofSegment(const rofSegment&);
00460 rofSegment& operator=(const rofSegment&);
00461
00462 std::string filename_;
00463 off_t begin_, end_;
00464 };
00465 #endif
00466
00467 inline uint64_t ibis::fileManager::bytesFree() {
00468 if (maxBytes == 0)
00469 ibis::fileManager::instance();
00470 return (maxBytes > ibis::fileManager::totalBytes() ?
00471 maxBytes - ibis::fileManager::totalBytes() : 0);
00472 }
00473
00474 inline void ibis::fileManager::releaseAccess(const char* mesg) const {
00475 int ierr = pthread_rwlock_unlock(&lock);
00476 if (0 == ierr) {
00477 LOGGER(ibis::gVerbose > 9)
00478 << "fileManager::releaseAccess for " << mesg;
00479 }
00480 else {
00481 LOGGER(ibis::gVerbose >= 0)
00482 << "Warning -- fileManager::releaseAccess for " << mesg
00483 << " failed with error code " << ierr << " -- " << strerror(ierr);
00484 }
00485 }
00486
00487 inline void ibis::fileManager::gainReadAccess(const char* mesg) const {
00488 int ierr = pthread_rwlock_rdlock(&lock);
00489 if (0 == ierr) {
00490 LOGGER(ibis::gVerbose > 9)
00491 << "fileManager::gainReadAccess for " << mesg;
00492 }
00493 else {
00494 LOGGER(ibis::gVerbose >= 0)
00495 << "Warning -- fileManager::gainReadAccess for " << mesg
00496 << " failed with error code " << ierr << " -- " << strerror(ierr);
00497 }
00498 }
00499
00500 inline void ibis::fileManager::gainWriteAccess(const char* mesg) const {
00501 int ierr = pthread_rwlock_wrlock(&lock);
00502 if (0 == ierr) {
00503 LOGGER(ibis::gVerbose > 9)
00504 << "fileManager::gainWriteAccess for " << mesg;
00505 }
00506 else {
00507 LOGGER(ibis::gVerbose >= 0)
00508 << "Warning -- fileManager::gainWriteAccess for " << mesg
00509 << " failed with error code " << ierr << " -- " << strerror(ierr);
00510 }
00511 }
00512
00513
00514 inline void ibis::fileManager::recordPages(off_t start, off_t stop) {
00515 if (start < stop) {
00516 start -= (start % pagesize);
00517 if (stop % pagesize)
00518 stop += pagesize - stop % pagesize;
00519 page_count += static_cast<double>((stop - start) / pagesize);
00520 }
00521 }
00522
00523 inline void
00524 ibis::fileManager::increaseUse(size_t inc, const char* evt) {
00525 if (inc > 0) {
00526 ibis::fileManager::totalBytes += inc;
00527 LOGGER(evt && ibis::gVerbose > 9)
00528 << evt << " added " << inc << " to increase totalBytes to "
00529 << ibis::fileManager::totalBytes();
00530 }
00531 }
00532
00533 inline void
00534 ibis::fileManager::decreaseUse(size_t dec, const char* evt) {
00535 if (dec > 0) {
00536 ibis::fileManager::totalBytes -= dec;
00537 LOGGER(evt && ibis::gVerbose > 9)
00538 << evt << " removed " << dec << " to decrease totalBytes to "
00539 << ibis::fileManager::totalBytes();
00540 }
00541 }
00542
00543 inline void
00544 ibis::fileManager::storage::swap(ibis::fileManager::storage& rhs) throw () {
00545 {char* tmp = name; name = rhs.name; rhs.name = tmp;}
00546 {char* tmp = m_begin; m_begin = rhs.m_begin; rhs.m_begin = tmp;}
00547 {char* tmp = m_end; m_end = rhs.m_end; rhs.m_end = tmp;}
00548 {unsigned itmp = nacc; nacc = rhs.nacc; rhs.nacc = itmp;}
00549 nref.swap(rhs.nref);
00550 }
00551 #endif // IBIS_FILEMANAGER_H