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