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 * , IOSize) {
0139 nowrite("write");
0140 return 0;
0141 }
0142
0143 IOSize LocalCacheFile::write(const void * , IOSize, IOOffset ) {
0144 nowrite("write");
0145 return 0;
0146 }
0147
0148 IOSize LocalCacheFile::writev(const IOBuffer * , IOSize) {
0149 nowrite("writev");
0150 return 0;
0151 }
0152
0153 IOSize LocalCacheFile::writev(const IOPosBuffer * , 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 ) { 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 }