CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/Utilities/XrdAdaptor/src/XrdFile.cc

Go to the documentation of this file.
00001 #include "Utilities/XrdAdaptor/src/XrdFile.h"
00002 #include "FWCore/Utilities/interface/Exception.h"
00003 #include "FWCore/Utilities/interface/EDMException.h"
00004 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00005 #include <vector>
00006 
00007 XrdFile::XrdFile (void)
00008   : m_client (0),
00009     m_offset (0),
00010     m_close (false)
00011 {}
00012 
00013 XrdFile::XrdFile (const char *name,
00014                   int flags /* = IOFlags::OpenRead */,
00015                   int perms /* = 066 */)
00016   : m_client (0),
00017     m_offset (0),
00018     m_close (false)
00019 { open (name, flags, perms); }
00020 
00021 XrdFile::XrdFile (const std::string &name,
00022                   int flags /* = IOFlags::OpenRead */,
00023                   int perms /* = 066 */)
00024   : m_client (0),
00025     m_offset (0),
00026     m_close (false)
00027 { open (name.c_str (), flags, perms); }
00028 
00029 XrdFile::~XrdFile (void)
00030 {
00031   if (m_close)
00032     edm::LogError("XrdFileError")
00033       << "Destructor called on XROOTD file '" << m_name
00034       << "' but the file is still open";
00035 }
00036 
00038 void
00039 XrdFile::create (const char *name,
00040                  bool exclusive /* = false */,
00041                  int perms /* = 066 */)
00042 {
00043   open (name,
00044         (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate
00045          | (exclusive ? IOFlags::OpenExclusive : 0)),
00046         perms);
00047 }
00048 
00049 void
00050 XrdFile::create (const std::string &name,
00051                  bool exclusive /* = false */,
00052                  int perms /* = 066 */)
00053 {
00054   open (name.c_str (),
00055         (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate
00056          | (exclusive ? IOFlags::OpenExclusive : 0)),
00057         perms);
00058 }
00059 
00060 void
00061 XrdFile::open (const std::string &name,
00062                int flags /* = IOFlags::OpenRead */,
00063                int perms /* = 066 */)
00064 { open (name.c_str (), flags, perms); }
00065 
00066 void
00067 XrdFile::open (const char *name,
00068                int flags /* = IOFlags::OpenRead */,
00069                int perms /* = 066 */)
00070 {
00071   m_name = name;
00072 
00073   // Actual open
00074   if ((name == 0) || (*name == 0)) {
00075     edm::Exception ex(edm::errors::FileOpenError);
00076     ex << "Cannot open a file without a name";
00077     ex.addContext("Calling XrdFile::open()");
00078     throw ex;
00079   }
00080   if ((flags & (IOFlags::OpenRead | IOFlags::OpenWrite)) == 0) {
00081     edm::Exception ex(edm::errors::FileOpenError);
00082     ex << "Must open file '" << name << "' at least for read or write";
00083     ex.addContext("Calling XrdFile::open()");
00084     throw ex;
00085   }
00086   // If I am already open, close old file first
00087   if (m_client && m_close)
00088     close();
00089   else
00090     abort();
00091 
00092   // Translate our flags to system flags
00093   int openflags = 0;
00094 
00095   if (flags & IOFlags::OpenWrite)
00096     openflags |= kXR_open_updt;
00097   else if (flags & IOFlags::OpenRead)
00098     openflags |= kXR_open_read;
00099 
00100   if (flags & IOFlags::OpenAppend) {
00101     edm::Exception ex(edm::errors::FileOpenError);
00102     ex << "Opening file '" << name << "' in append mode not supported";
00103     ex.addContext("Calling XrdFile::open()");
00104     throw ex;
00105   }
00106 
00107   if (flags & IOFlags::OpenCreate)
00108   {
00109     if (! (flags & IOFlags::OpenExclusive))
00110       openflags |= kXR_delete;
00111     openflags |= kXR_new;
00112     openflags |= kXR_mkpath;
00113   }
00114 
00115   if ((flags & IOFlags::OpenTruncate) && (flags & IOFlags::OpenWrite))
00116     openflags |= kXR_delete;
00117 
00118   m_client = new XrdClient(name);
00119   if (! m_client->Open(perms, openflags)
00120       || m_client->LastServerResp()->status != kXR_ok) {
00121     edm::Exception ex(edm::errors::FileOpenError);
00122     ex << "XrdClient::Open(name='" << name
00123        << "', flags=0x" << std::hex << openflags
00124        << ", permissions=0" << std::oct << perms << std::dec
00125        << ") => error '" << m_client->LastServerError()->errmsg
00126        << "' (errno=" << m_client->LastServerError()->errnum << ")";
00127     ex.addContext("Calling XrdFile::open()");
00128     throw ex;
00129   }
00130   if (! m_client->Stat(&m_stat)) {
00131     edm::Exception ex(edm::errors::FileOpenError);
00132     ex << "XrdClient::Stat(name='" << name
00133       << ") => error '" << m_client->LastServerError()->errmsg
00134       << "' (errno=" << m_client->LastServerError()->errnum << ")";
00135     ex.addContext("Calling XrdFile::open()");
00136     throw ex;
00137   }
00138   m_offset = 0;
00139   m_close = true;
00140   edm::LogInfo("XrdFileInfo") << "Opened " << m_name;
00141 }
00142 
00143 void
00144 XrdFile::close (void)
00145 {
00146   if (! m_client)
00147   {
00148     edm::LogError("XrdFileError")
00149       << "XrdFile::close(name='" << m_name
00150       << "') called but the file is not open";
00151     m_close = false;
00152     return;
00153   }
00154 
00155   if (! m_client->Close())
00156     edm::LogWarning("XrdFileWarning")
00157       << "XrdFile::close(name='" << m_name
00158       << "') failed with error '" << m_client->LastServerError()->errmsg
00159       << "' (errno=" << m_client->LastServerError()->errnum << ")";
00160   delete m_client;
00161   m_client = 0;
00162 
00163   m_close = false;
00164   m_offset = 0;
00165   memset(&m_stat, 0, sizeof (m_stat));
00166   edm::LogInfo("XrdFileInfo") << "Closed " << m_name;
00167 }
00168 
00169 void
00170 XrdFile::abort (void)
00171 {
00172   delete m_client;
00173   m_client = 0;
00174   m_close = false;
00175   m_offset = 0;
00176   memset(&m_stat, 0, sizeof (m_stat));
00177 }
00178 
00180 IOSize
00181 XrdFile::read (void *into, IOSize n)
00182 {
00183   if (n > 0x7fffffff) {
00184     edm::Exception ex(edm::errors::FileReadError);
00185     ex << "XrdFile::read(name='" << m_name << "', n=" << n
00186        << ") too many bytes, limit is 0x7fffffff";
00187     ex.addContext("Calling XrdFile::read()");
00188     throw ex;
00189   }
00190   int s = m_client->Read(into, m_offset, n);
00191   if (s < 0) {
00192     edm::Exception ex(edm::errors::FileReadError);
00193     ex << "XrdClient::Read(name='" << m_name
00194        << "', offset=" << m_offset << ", n=" << n
00195        << ") failed with error '" << m_client->LastServerError()->errmsg
00196        << "' (errno=" << m_client->LastServerError()->errnum << ")";
00197     ex.addContext("Calling XrdFile::read()");
00198     throw ex;
00199   }
00200   m_offset += s;
00201   return s;
00202 }
00203 
00204 IOSize
00205 XrdFile::read (void *into, IOSize n, IOOffset pos)
00206 {
00207   if (n > 0x7fffffff) {
00208     edm::Exception ex(edm::errors::FileReadError);
00209     ex << "XrdFile::read(name='" << m_name << "', n=" << n
00210        << ") exceeds read size limit 0x7fffffff";
00211     ex.addContext("Calling XrdFile::read()");
00212     throw ex;
00213   }
00214   int s = m_client->Read(into, pos, n);
00215   if (s < 0) {
00216     edm::Exception ex(edm::errors::FileReadError);
00217     ex << "XrdClient::Read(name='" << m_name
00218        << "', offset=" << m_offset << ", n=" << n
00219        << ") failed with error '" << m_client->LastServerError()->errmsg
00220        << "' (errno=" << m_client->LastServerError()->errnum << ")";
00221     ex.addContext("Calling XrdFile::read()");
00222     throw ex;
00223   }
00224   return s;
00225 }
00226 
00227 IOSize
00228 XrdFile::readv (IOBuffer *into, IOSize n)
00229 {
00230   // Note that the XROOTD and our interfaces do not match.
00231   // XROOTD expects readv() into a single monolithic buffer
00232   // from multiple file locations, whereas we expect scatter
00233   // gather buffers read from a single file location.
00234   //
00235   // We work around this mismatch for now by issuing a cache
00236   // read on the background, and then individual reads.
00237   IOOffset pos = m_offset;
00238   std::vector<long long> offsets (n);
00239   std::vector<int> lengths (n);
00240   for (IOSize i = 0; i < n; ++i)
00241   {
00242     IOSize len = into[i].size();
00243     if (len > 0x7fffffff) {
00244       edm::Exception ex(edm::errors::FileReadError);
00245       ex << "XrdFile::readv(name='" << m_name << "')[" << i
00246          << "].size=" << len << " exceeds read size limit 0x7fffffff";
00247       ex.addContext("Calling XrdFile::readv()");
00248       throw ex;
00249     }
00250     offsets[i] = pos;
00251     lengths[i] = len;
00252     pos += len;
00253   }
00254 
00255   // Prefetch into the cache (if any).
00256   if (m_client->ReadV(0, &offsets[0], &lengths[0], n) < 0) {
00257     edm::Exception ex(edm::errors::FileReadError);
00258     ex << "XrdClient::ReadV(name='" << m_name
00259        << "') failed with error '" << m_client->LastServerError()->errmsg
00260        << "' (errno=" << m_client->LastServerError()->errnum << ")";
00261     ex.addContext("Calling XrdFile::readv()");
00262     throw ex;
00263   }
00264 
00265   // Issue actual reads.
00266   IOSize total = 0;
00267   for (IOSize i = 0; i < n; ++i)
00268   {
00269     int s = m_client->Read(into[i].data(), offsets[i], lengths[i]);
00270     if (s < 0)
00271     {
00272       if (i > 0)
00273         break;
00274       edm::Exception ex(edm::errors::FileReadError);
00275       ex << "XrdClient::Read(name='" << m_name
00276          << "', offset=" << offsets[i] << ", n=" << lengths[i]
00277          << ") failed with error '" << m_client->LastServerError()->errmsg
00278          << "' (errno=" << m_client->LastServerError()->errnum << ")";
00279       ex.addContext("Calling XrdFile::readv()");
00280       throw ex;
00281     }
00282     total += s;
00283     m_offset += s;
00284   }
00285 
00286   return total;
00287 }
00288 
00289 IOSize
00290 XrdFile::readv (IOPosBuffer *into, IOSize n)
00291 {
00292   // See comments in readv() above.
00293   std::vector<long long> offsets (n);
00294   std::vector<int> lengths (n);
00295   for (IOSize i = 0; i < n; ++i)
00296   {
00297     IOSize len = into[i].size();
00298     if (len > 0x7fffffff) {
00299       edm::Exception ex(edm::errors::FileReadError);
00300       ex << "XrdFile::readv(name='" << m_name << "')[" << i
00301          << "].size=" << len << " exceeds read size limit 0x7fffffff";
00302       ex.addContext("Calling XrdFile::readv()");
00303       throw ex;
00304     }
00305     offsets[i] = into[i].offset();
00306     lengths[i] = len;
00307   }
00308 
00309   // Prefetch into the cache (if any).
00310   if (m_client->ReadV(0, &offsets[0], &lengths[0], n) < 0) {
00311     edm::Exception ex(edm::errors::FileReadError);
00312     ex << "XrdClient::ReadV(name='" << m_name
00313        << "') failed with error '" << m_client->LastServerError()->errmsg
00314        << "' (errno=" << m_client->LastServerError()->errnum << ")";
00315     ex.addContext("Calling XrdFile::readv()");
00316     throw ex;
00317   }
00318   // Issue actual reads.
00319   IOSize total = 0;
00320   for (IOSize i = 0; i < n; ++i)
00321   {
00322     int s = m_client->Read(into[i].data(), offsets[i], lengths[i]);
00323     if (s < 0)
00324     {
00325       if (i > 0)
00326         break;
00327       edm::Exception ex(edm::errors::FileReadError);
00328       ex << "XrdClient::Read(name='" << m_name
00329          << "', offset=" << offsets[i] << ", n=" << lengths[i]
00330          << ") failed with error '" << m_client->LastServerError()->errmsg
00331          << "' (errno=" << m_client->LastServerError()->errnum << ")";
00332       ex.addContext("Calling XrdFile::readv()");
00333       throw ex;
00334     }
00335     total += s;
00336   }
00337 
00338   return total;
00339 }
00340 
00341 IOSize
00342 XrdFile::write (const void *from, IOSize n)
00343 {
00344   if (n > 0x7fffffff) {
00345     cms::Exception ex("FileWriteError");
00346     ex << "XrdFile::write(name='" << m_name << "', n=" << n
00347        << ") too many bytes, limit is 0x7fffffff";
00348     ex.addContext("Calling XrdFile::write()");
00349     throw ex;
00350   }
00351   ssize_t s = m_client->Write(from, m_offset, n);
00352   if (s < 0) {
00353     cms::Exception ex("FileWriteError");
00354     ex << "XrdFile::write(name='" << m_name << "', n=" << n
00355        << ") failed with error '" << m_client->LastServerError()->errmsg
00356        << "' (errno=" << m_client->LastServerError()->errnum << ")";
00357     ex.addContext("Calling XrdFile::write()");
00358     throw ex;
00359   }
00360   m_offset += s;
00361   if (m_offset > m_stat.size)
00362     m_stat.size = m_offset;
00363 
00364   return s;
00365 }
00366 
00367 IOSize
00368 XrdFile::write (const void *from, IOSize n, IOOffset pos)
00369 {
00370   if (n > 0x7fffffff) {
00371     cms::Exception ex("FileWriteError");
00372     ex << "XrdFile::write(name='" << m_name << "', n=" << n
00373        << ") too many bytes, limit is 0x7fffffff";
00374     ex.addContext("Calling XrdFile::write()");
00375     throw ex;
00376   }
00377   ssize_t s = m_client->Write(from, pos, n);
00378   if (s < 0) {
00379     cms::Exception ex("FileWriteError");
00380     ex << "XrdFile::write(name='" << m_name << "', n=" << n
00381        << ") failed with error '" << m_client->LastServerError()->errmsg
00382        << "' (errno=" << m_client->LastServerError()->errnum << ")";
00383     ex.addContext("Calling XrdFile::write()");
00384     throw ex;
00385   }
00386   if (pos + s > m_stat.size)
00387     m_stat.size = pos + s;
00388 
00389   return s;
00390 }
00391 
00392 bool
00393 XrdFile::prefetch (const IOPosBuffer *what, IOSize n)
00394 {
00395   XReqErrorType r = kOK;
00396   for (IOSize i = 0; i < n && r == kOK; ++i)
00397     r = m_client->Read_Async(what[i].offset(), what[i].size());
00398   return r == kOK;
00399 }
00400 
00404 IOOffset
00405 XrdFile::position (IOOffset offset, Relative whence /* = SET */)
00406 {
00407   if (! m_client) {
00408     cms::Exception ex("FilePositionError");
00409     ex << "XrdFile::position() called on a closed file";
00410     ex.addContext("Calling XrdFile::position()");
00411     throw ex;
00412   }
00413   switch (whence)
00414   {
00415   case SET:
00416     m_offset = offset;
00417     break;
00418 
00419   case CURRENT:
00420     m_offset += offset;
00421     break;
00422 
00423   case END:
00424     m_offset = m_stat.size + offset;
00425     break;
00426 
00427   default:
00428     cms::Exception ex("FilePositionError");
00429     ex << "XrdFile::position() called with incorrect 'whence' parameter";
00430     ex.addContext("Calling XrdFile::position()");
00431     throw ex;
00432   }
00433 
00434   if (m_offset < 0)
00435     m_offset = 0;
00436   if (m_offset > m_stat.size)
00437     m_stat.size = m_offset;
00438 
00439   return m_offset;
00440 }
00441 
00442 void
00443 XrdFile::resize (IOOffset /* size */)
00444 {
00445   cms::Exception ex("FileResizeError");
00446   ex << "XrdFile::resize(name='" << m_name << "') not implemented";
00447   ex.addContext("Calling XrdFile::resize()");
00448   throw ex;
00449 }