Go to the documentation of this file.00001 #include "Utilities/StorageFactory/interface/LocalCacheFile.h"
00002 #include "FWCore/Utilities/interface/EDMException.h"
00003 #include <utility>
00004 #include <iostream>
00005 #include <stdlib.h>
00006 #include <string.h>
00007 #include <unistd.h>
00008 #include <sys/mman.h>
00009 #include <errno.h>
00010
00011 static const IOOffset CHUNK_SIZE = 128*1024*1024;
00012
00013 static void
00014 nowrite(const char *why)
00015 {
00016 throw cms::Exception("LocalCacheFile")
00017 << "Cannot change file but operation '" << why << "' was called";
00018 }
00019
00020
00021 LocalCacheFile::LocalCacheFile(Storage *base, const std::string &tmpdir )
00022 : image_(base->size()),
00023 file_(0),
00024 storage_(base),
00025 closedFile_(false),
00026 cacheCount_(0),
00027 cacheTotal_((image_ + CHUNK_SIZE - 1) / CHUNK_SIZE)
00028 {
00029 present_.resize(cacheTotal_, 0);
00030
00031 std::string pattern(tmpdir);
00032 if (pattern.empty())
00033 if (char *p = getenv("TMPDIR"))
00034 pattern = p;
00035 if (pattern.empty())
00036 pattern = "/tmp";
00037 pattern += "/cmssw-shadow-XXXXXX";
00038
00039 std::vector<char> temp(pattern.c_str(), pattern.c_str()+pattern.size()+1);
00040 int fd = mkstemp(&temp[0]);
00041 if (fd == -1)
00042 throw cms::Exception("LocalCacheFile")
00043 << "Cannot create temporary file '" << pattern << "': "
00044 << strerror(errno) << " (error " << errno << ")";
00045
00046 unlink(&temp[0]);
00047 file_ = new File(fd);
00048 file_->resize(image_);
00049 }
00050
00051 LocalCacheFile::~LocalCacheFile(void)
00052 {
00053 delete file_;
00054 delete storage_;
00055 }
00056
00057 void
00058 LocalCacheFile::cache(IOOffset start, IOOffset end)
00059 {
00060 start = (start / CHUNK_SIZE) * CHUNK_SIZE;
00061 end = std::min(end, image_);
00062
00063 IOSize nread = 0;
00064 IOSize index = start / CHUNK_SIZE;
00065
00066 while (start < end)
00067 {
00068 IOSize len = std::min(image_ - start, CHUNK_SIZE);
00069 if (! present_[index])
00070 {
00071 void *window = mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, file_->fd(), start);
00072 if (window == MAP_FAILED)
00073 throw cms::Exception("LocalCacheFile")
00074 << "Unable to map a window of local cache file: "
00075 << strerror(errno) << " (error " << errno << ")";
00076
00077 try
00078 {
00079 nread = storage_->read(window, len, start);
00080 }
00081 catch (cms::Exception &e)
00082 {
00083 munmap(window, len);
00084 throw cms::Exception("LocalCacheFile")
00085 << "Unable to cache " << len << " byte file segment at " << start
00086 << ": " << e.what();
00087 }
00088
00089 munmap(window, len);
00090
00091 if (nread != len)
00092 throw cms::Exception("LocalCacheFile")
00093 << "Unable to cache " << len << " byte file segment at " << start
00094 << ": got only " << nread << " bytes back";
00095
00096 present_[index] = 1;
00097 ++cacheCount_;
00098 if (cacheCount_ == cacheTotal_)
00099 {
00100 storage_->close();
00101 closedFile_ = true;
00102 }
00103 }
00104
00105 start += len;
00106 ++index;
00107 }
00108 }
00109
00110 IOSize
00111 LocalCacheFile::read(void *into, IOSize n)
00112 {
00113 IOOffset here = file_->position();
00114 cache(here, here + n);
00115
00116 return file_->read(into, n);
00117 }
00118
00119 IOSize
00120 LocalCacheFile::read(void *into, IOSize n, IOOffset pos)
00121 {
00122 cache(pos, pos + n);
00123 return file_->read(into, n, pos);
00124 }
00125
00126 IOSize
00127 LocalCacheFile::readv(IOBuffer *into, IOSize n)
00128 {
00129 IOOffset start = file_->position();
00130 IOOffset end = start;
00131 for (IOSize i = 0; i < n; ++i)
00132 end += into[i].size();
00133 cache(start, end);
00134
00135 return file_->readv(into, n);
00136 }
00137
00138 IOSize
00139 LocalCacheFile::readv(IOPosBuffer *into, IOSize n)
00140 {
00141 for (IOSize i = 0; i < n; ++i)
00142 {
00143 IOOffset start = into[i].offset();
00144 IOOffset end = start + into[i].size();
00145 cache(start, end);
00146 }
00147
00148 return storage_->readv(into, n);
00149 }
00150
00151 IOSize
00152 LocalCacheFile::write(const void *from, IOSize n)
00153 { nowrite("write"); return 0; }
00154
00155 IOSize
00156 LocalCacheFile::write(const void *from, IOSize n, IOOffset pos)
00157 { nowrite("write"); return 0; }
00158
00159 IOSize
00160 LocalCacheFile::writev(const IOBuffer *from, IOSize n)
00161 { nowrite("writev"); return 0; }
00162
00163 IOSize
00164 LocalCacheFile::writev(const IOPosBuffer *from, IOSize n)
00165 { nowrite("writev"); return 0; }
00166
00167 IOOffset
00168 LocalCacheFile::position(IOOffset offset, Relative whence)
00169 { return file_->position(offset, whence); }
00170
00171 void
00172 LocalCacheFile::resize(IOOffset size)
00173 { nowrite("resize"); }
00174
00175 void
00176 LocalCacheFile::flush(void)
00177 { nowrite("flush"); }
00178
00179 void
00180 LocalCacheFile::close(void)
00181 {
00182 if (!closedFile_)
00183 {
00184 storage_->close();
00185 }
00186 file_->close();
00187 }
00188
00189 bool
00190 LocalCacheFile::prefetch(const IOPosBuffer *what, IOSize n)
00191 {
00192 for (IOSize i = 0; i < n; ++i)
00193 {
00194 IOOffset start = what[i].offset();
00195 IOOffset end = start + what[i].size();
00196 cache(start, end);
00197 }
00198
00199 return file_->prefetch(what, n);
00200 }