IBR-DTNSuite 0.6

ibrcommon/ibrcommon/data/BLOB.cpp

Go to the documentation of this file.
00001 /*
00002  * BLOB.cpp
00003  *
00004  *  Created on: 15.12.2009
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/data/BLOB.h"
00009 #include "ibrcommon/thread/MutexLock.h"
00010 #include "ibrcommon/Exceptions.h"
00011 #include "ibrcommon/Logger.h"
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <string.h>
00015 #include <cstring>
00016 #include <cerrno>
00017 
00018 #ifdef __DEVELOPMENT_ASSERTIONS__
00019 #include <cassert>
00020 #endif
00021 
00022 namespace ibrcommon
00023 {
00024         ibrcommon::Semaphore BLOB::_filelimit(10);
00025 
00026         File BLOB::tmppath;
00027 
00028         BLOB::BLOB()
00029          : ibrcommon::Mutex(ibrcommon::Mutex::MUTEX_NORMAL), _locked(false), _refcount(0), _reflock(ibrcommon::Mutex::MUTEX_NORMAL)
00030         { }
00031 
00032         BLOB::~BLOB()
00033         {
00034         }
00035 
00036         std::ostream& BLOB::copy(std::ostream &output, std::istream &input, const size_t size, const size_t buffer_size)
00037         {
00038                 // read payload
00039                 char buffer[buffer_size];
00040                 size_t remain = size;
00041 
00042                 while (remain > 0)
00043                 {
00044                         // something bad happened, abort!
00045                         if (input.bad())
00046                         {
00047                                 std::stringstream errmsg; errmsg << "input stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
00048                                 throw ibrcommon::IOException(errmsg.str());
00049                         }
00050 
00051                         // reached EOF too early
00052                         if (input.eof())
00053                         {
00054                                 std::stringstream errmsg; errmsg << "input stream reached EOF [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
00055                                 throw ibrcommon::IOException(errmsg.str());
00056                         }
00057 
00058                         // check if the destination stream is ok
00059                         if (output.bad())
00060                         {
00061                                 std::stringstream errmsg; errmsg << "output stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
00062                                 throw ibrcommon::IOException(errmsg.str());
00063                         }
00064 
00065                         // retry if the read failed
00066                         if (input.fail())
00067                         {
00068                                 IBRCOMMON_LOGGER(warning) << "input stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
00069                                 input.clear();
00070                         }
00071 
00072                         // if the last write failed, then retry
00073                         if (output.fail())
00074                         {
00075                                 IBRCOMMON_LOGGER(warning) << "output stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
00076                                 output.clear();
00077                         }
00078                         else
00079                         {
00080                                 // read the full buffer size of less?
00081                                 if (remain > buffer_size)
00082                                 {
00083                                         input.read(buffer, buffer_size);
00084                                 }
00085                                 else
00086                                 {
00087                                         input.read(buffer, remain);
00088                                 }
00089 
00090                                 // retry if the read failed
00091                                 if (input.fail()) continue;
00092                         }
00093 
00094                         // write the bytes to the BLOB
00095                         output.write(buffer, input.gcount());
00096 
00097                         // shrink the remaining bytes by the red bytes
00098                         remain -= input.gcount();
00099                 }
00100 
00101                 return output;
00102         }
00103 
00104         BLOB::Reference::Reference(const Reference &ref)
00105          : ibrcommon::Mutex(MUTEX_NORMAL), _blob(ref._blob)
00106         {
00107                 MutexLock l(_blob->_reflock);
00108                 _blob->_refcount++;
00109         }
00110 
00111         BLOB::Reference::~Reference()
00112         {
00113                 // check if this is the last reference
00114                 {
00115                         MutexLock l(_blob->_reflock);
00116                         if ((_blob->_refcount--) > 1) return;
00117                 }
00118 
00119                 delete _blob;
00120         }
00121 
00122         BLOB::iostream BLOB::Reference::iostream()
00123         {
00124                 return BLOB::iostream(_blob);
00125         }
00126 
00127         std::iostream& BLOB::Reference::operator*()
00128         {
00129 #ifdef __DEVELOPMENT_ASSERTIONS__
00130                 assert(_blob->_locked);
00131 #endif
00132                 return _blob->__get_stream();
00133         }
00134 
00135         BLOB::Reference::Reference(BLOB *blob)
00136          : _blob(blob)
00137         {
00138                 MutexLock l(_blob->_reflock);
00139                 _blob->_refcount++;
00140         }
00141 
00142         void BLOB::Reference::enter() throw (ibrcommon::MutexException)
00143         {
00144                 // lock the stream
00145                 _blob->enter();
00146                 _blob->_locked = true;
00147 
00148                 // open the stream
00149                 _blob->open();
00150         }
00151 
00152         void BLOB::Reference::leave() throw (ibrcommon::MutexException)
00153         {
00154                 _blob->_locked = false;
00155 
00156                 // close the stream
00157                 _blob->close();
00158 
00159                 // unlock the stream
00160                 _blob->leave();
00161         }
00162 
00163         void BLOB::Reference::trylock() throw (ibrcommon::MutexException)
00164         {
00165                 // lock the stream
00166                 _blob->trylock();
00167                 _blob->_locked = true;
00168 
00169                 // open the stream
00170                 _blob->open();
00171         }
00172 
00173         size_t BLOB::Reference::getSize() const
00174         {
00175 #ifdef __DEVELOPMENT_ASSERTIONS__
00176                 assert(_blob->_locked);
00177 #endif
00178                 return _blob->__get_size();
00179         }
00180 
00181         void BLOB::Reference::clear()
00182         {
00183 #ifdef __DEVELOPMENT_ASSERTIONS__
00184                 assert(_blob->_locked);
00185 #endif
00186                 _blob->clear();
00187         }
00188 
00189         BLOB::Reference StringBLOB::create()
00190         {
00191                 BLOB::Reference ref(new StringBLOB());
00192                 return ref;
00193         }
00194 
00195         void StringBLOB::clear()
00196         {
00197                 _stringstream.str("");
00198         }
00199 
00200         StringBLOB::StringBLOB()
00201          : BLOB(), _stringstream()
00202         {
00203 
00204         }
00205 
00206         StringBLOB::~StringBLOB()
00207         {
00208         }
00209 
00210         void StringBLOB::open()
00211         {
00212                 // set pointer to the beginning of the stream and remove any error flags
00213                 _stringstream.clear();
00214                 _stringstream.seekp(0);
00215                 _stringstream.seekg(0);
00216         }
00217 
00218         void StringBLOB::close()
00219         {
00220         }
00221 
00222         size_t StringBLOB::__get_size()
00223         {
00224                 // store current position
00225                 size_t pos = _stringstream.tellg();
00226 
00227                 _stringstream.seekg(0, std::ios_base::end);
00228                 size_t size = _stringstream.tellg();
00229                 _stringstream.seekg(pos);
00230 
00231                 return size;
00232         }
00233 
00234         BLOB::Reference FileBLOB::create(const File &f)
00235         {
00236                 return BLOB::Reference(new FileBLOB(f));
00237         }
00238 
00239         void FileBLOB::clear()
00240         {
00241                 throw ibrcommon::IOException("clear is not possible on a read only file");
00242         }
00243 
00244         FileBLOB::FileBLOB(const File &f)
00245          : BLOB(), _filestream(), _file(f)
00246         {
00247                 if (!f.exists())
00248                 {
00249                         throw ibrcommon::FileNotExistsException(f);
00250                 }
00251         }
00252 
00253         FileBLOB::~FileBLOB()
00254         {
00255         }
00256 
00257         void FileBLOB::open()
00258         {
00259                 BLOB::_filelimit.wait();
00260 
00261                 // open the file
00262                 _filestream.open(_file.getPath().c_str(), ios::in|ios::binary);
00263 
00264                 if (!_filestream.is_open())
00265                 {
00266                         throw ibrcommon::CanNotOpenFileException(_file);
00267                 }
00268         }
00269 
00270         void FileBLOB::close()
00271         {
00272                 // close the file
00273                 _filestream.close();
00274 
00275                 BLOB::_filelimit.post();
00276         }
00277 
00278         size_t FileBLOB::__get_size()
00279         {
00280                 return _file.size();
00281         }
00282 
00283         BLOB::Reference TmpFileBLOB::create()
00284         {
00285                 try {
00286                         return BLOB::Reference(new TmpFileBLOB());
00287                 } catch (const ibrcommon::IOException&) {
00288                         return StringBLOB::create();
00289                 }
00290         }
00291 
00292         void TmpFileBLOB::clear()
00293         {
00294                 // close the file
00295                 _filestream.close();
00296 
00297                 // open temporary file
00298                 _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::trunc | ios::binary );
00299 
00300                 if (!_filestream.is_open())
00301                 {
00302                         IBRCOMMON_LOGGER(error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
00303                         throw ibrcommon::CanNotOpenFileException(_tmpfile);
00304                 }
00305         }
00306 
00307         TmpFileBLOB::TmpFileBLOB()
00308          : BLOB(), _filestream()
00309         {
00310                 // check if path is a directory
00311                 if (!BLOB::tmppath.isDirectory())
00312                 {
00313                         throw ibrcommon::IOException("BLOB::tmppath not initialized or path is not a directory.");
00314                 }
00315 
00316                 createtmpfile();
00317         }
00318 
00319         void TmpFileBLOB::createtmpfile()
00320         {
00321                 _tmpfile = ibrcommon::TemporaryFile(BLOB::tmppath, "blob");
00322                 _tmpfile.update();
00323         }
00324 
00325         TmpFileBLOB::~TmpFileBLOB()
00326         {
00327                 // delete the file if the last reference is destroyed
00328                 _tmpfile.remove();
00329         }
00330 
00331         void TmpFileBLOB::open()
00332         {
00333                 BLOB::_filelimit.wait();
00334 
00335                 // open temporary file
00336                 _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::binary );
00337 
00338                 if (!_filestream.is_open())
00339                 {
00340                         IBRCOMMON_LOGGER(error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
00341                         throw ibrcommon::CanNotOpenFileException(_tmpfile);
00342                 }
00343         }
00344 
00345         void TmpFileBLOB::close()
00346         {
00347                 // flush the filestream
00348                 _filestream.flush();
00349 
00350                 // close the file
00351                 _filestream.close();
00352 
00353                 BLOB::_filelimit.post();
00354         }
00355 
00356         size_t TmpFileBLOB::__get_size()
00357         {
00358                 return _tmpfile.size();
00359         }
00360 }