Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:31:52

0001 #include "Utilities/StorageFactory/interface/LocalCacheFile.h"
0002 #include "FWCore/Utilities/interface/EDMException.h"
0003 #include <utility>
0004 #include <iostream>
0005 #include <cstdlib>
0006 #include <cstring>
0007 #include <unistd.h>
0008 #include <sys/mman.h>
0009 #include <cerrno>
0010 #include <sstream>
0011 
0012 using namespace edm::storage;
0013 
0014 static constexpr IOOffset CHUNK_SIZE = 128 * 1024 * 1024;
0015 
0016 static void nowrite(const std::string &why) {
0017   cms::Exception ex("LocalCacheFile");
0018   ex << "Cannot change file but operation '" << why << "' was called";
0019   ex.addContext("LocalCacheFile::" + why + "()");
0020   throw ex;
0021 }
0022 
0023 LocalCacheFile::LocalCacheFile(std::unique_ptr<Storage> base, const std::string &tmpdir /* = "" */)
0024     : image_(base->size()),
0025       file_(),
0026       storage_(std::move(base)),
0027       closedFile_(false),
0028       cacheCount_(0),
0029       cacheTotal_((image_ + CHUNK_SIZE - 1) / CHUNK_SIZE) {
0030   present_.resize(cacheTotal_, 0);
0031 
0032   std::string pattern(tmpdir);
0033   if (pattern.empty())
0034     if (char *p = std::getenv("TMPDIR"))
0035       pattern = p;
0036   if (pattern.empty())
0037     pattern = "/tmp";
0038   pattern += "/cmssw-shadow-XXXXXX";
0039 
0040   std::vector<char> temp(pattern.c_str(), pattern.c_str() + pattern.size() + 1);
0041   int fd = mkstemp(&temp[0]);
0042   if (fd == -1) {
0043     edm::Exception ex(edm::errors::FileOpenError);
0044     ex << "Cannot create temporary file '" << pattern << "': " << strerror(errno) << " (error " << errno << ")";
0045     ex.addContext("LocalCacheFile::LocalCacheFile");
0046   }
0047 
0048   unlink(&temp[0]);
0049   file_ = std::make_unique<File>(fd);
0050   file_->resize(image_);
0051 }
0052 
0053 LocalCacheFile::~LocalCacheFile(void) {}
0054 
0055 void LocalCacheFile::cache(IOOffset start, IOOffset end) {
0056   start = (start / CHUNK_SIZE) * CHUNK_SIZE;
0057   end = std::min(end, image_);
0058 
0059   IOSize nread = 0;
0060   IOSize index = start / CHUNK_SIZE;
0061 
0062   while (start < end) {
0063     IOSize len = std::min(image_ - start, CHUNK_SIZE);
0064     if (!present_[index]) {
0065       void *window = mmap(nullptr, len, PROT_READ | PROT_WRITE, MAP_SHARED, file_->fd(), start);
0066       if (window == MAP_FAILED) {
0067         edm::Exception ex(edm::errors::FileReadError);
0068         ex << "Unable to map a window of local cache file: " << strerror(errno) << " (error " << errno << ")";
0069         ex.addContext("LocalCacheFile::cache()");
0070         throw ex;
0071       }
0072 
0073       try {
0074         nread = storage_->read(window, len, start);
0075       } catch (cms::Exception &e) {
0076         munmap(window, len);
0077         std::ostringstream ost;
0078         ost << "Unable to cache " << len << " byte file segment at " << start << ": ";
0079         edm::Exception ex(edm::errors::FileReadError, ost.str(), e);
0080         ex.addContext("LocalCacheFile::cache()");
0081         throw ex;
0082       }
0083 
0084       munmap(window, len);
0085 
0086       if (nread != len) {
0087         edm::Exception ex(edm::errors::FileReadError);
0088         ex << "Unable to cache " << len << " byte file segment at " << start << ": got only " << nread << " bytes back";
0089         ex.addContext("LocalCacheFile::cache()");
0090         throw ex;
0091       }
0092 
0093       present_[index] = 1;
0094       ++cacheCount_;
0095       if (cacheCount_ == cacheTotal_) {
0096         storage_->close();
0097         closedFile_ = true;
0098       }
0099     }
0100 
0101     start += len;
0102     ++index;
0103   }
0104 }
0105 
0106 IOSize LocalCacheFile::read(void *into, IOSize n) {
0107   IOOffset here = file_->position();
0108   cache(here, here + n);
0109 
0110   return file_->read(into, n);
0111 }
0112 
0113 IOSize LocalCacheFile::read(void *into, IOSize n, IOOffset pos) {
0114   cache(pos, pos + n);
0115   return file_->read(into, n, pos);
0116 }
0117 
0118 IOSize LocalCacheFile::readv(IOBuffer *into, IOSize n) {
0119   IOOffset start = file_->position();
0120   IOOffset end = start;
0121   for (IOSize i = 0; i < n; ++i)
0122     end += into[i].size();
0123   cache(start, end);
0124 
0125   return file_->readv(into, n);
0126 }
0127 
0128 IOSize LocalCacheFile::readv(IOPosBuffer *into, IOSize n) {
0129   for (IOSize i = 0; i < n; ++i) {
0130     IOOffset start = into[i].offset();
0131     IOOffset end = start + into[i].size();
0132     cache(start, end);
0133   }
0134 
0135   return storage_->readv(into, n);
0136 }
0137 
0138 IOSize LocalCacheFile::write(const void * /*from*/, IOSize) {
0139   nowrite("write");
0140   return 0;
0141 }
0142 
0143 IOSize LocalCacheFile::write(const void * /*from*/, IOSize, IOOffset /*pos*/) {
0144   nowrite("write");
0145   return 0;
0146 }
0147 
0148 IOSize LocalCacheFile::writev(const IOBuffer * /*from*/, IOSize) {
0149   nowrite("writev");
0150   return 0;
0151 }
0152 
0153 IOSize LocalCacheFile::writev(const IOPosBuffer * /*from*/, IOSize) {
0154   nowrite("writev");
0155   return 0;
0156 }
0157 
0158 IOOffset LocalCacheFile::position(IOOffset offset, Relative whence) { return file_->position(offset, whence); }
0159 
0160 void LocalCacheFile::resize(IOOffset /*size*/) { nowrite("resize"); }
0161 
0162 void LocalCacheFile::flush(void) { nowrite("flush"); }
0163 
0164 void LocalCacheFile::close(void) {
0165   if (!closedFile_) {
0166     storage_->close();
0167   }
0168   file_->close();
0169 }
0170 
0171 bool LocalCacheFile::prefetch(const IOPosBuffer *what, IOSize n) {
0172   for (IOSize i = 0; i < n; ++i) {
0173     IOOffset start = what[i].offset();
0174     IOOffset end = start + what[i].size();
0175     cache(start, end);
0176   }
0177 
0178   return file_->prefetch(what, n);
0179 }