CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/Utilities/StorageFactory/src/LocalCacheFile.cc

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 #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 */*from*/, IOSize)
00154 { nowrite("write"); return 0; }
00155 
00156 IOSize
00157 LocalCacheFile::write(const void */*from*/, IOSize, IOOffset /*pos*/)
00158 { nowrite("write"); return 0; }
00159 
00160 IOSize
00161 LocalCacheFile::writev(const IOBuffer */*from*/, IOSize)
00162 { nowrite("writev"); return 0; }
00163 
00164 IOSize
00165 LocalCacheFile::writev(const IOPosBuffer */*from*/, 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 /*size*/)
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 }