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