IBR-DTNSuite  0.12
BLOB.cpp
Go to the documentation of this file.
1 /*
2  * BLOB.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "ibrcommon/data/BLOB.h"
24 #include "ibrcommon/Exceptions.h"
25 #include "ibrcommon/Logger.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <cstring>
30 #include <cerrno>
31 #include <vector>
32 
33 #ifdef __DEVELOPMENT_ASSERTIONS__
34 #include <cassert>
35 #endif
36 
37 namespace ibrcommon
38 {
39  // maximum of concurrent opened files
41 
42  // default BLOB provider - memory based; auto deletion enabled
44 
45  BLOB::BLOB(const std::streamsize intitial_size)
46  : _const_size(intitial_size)
47  { }
48 
50  {
51  }
52 
53  std::streamsize BLOB::size() const
54  {
55  return _const_size;
56  }
57 
58  void BLOB::update()
59  {
60  _const_size = __get_size();
61  }
62 
63  std::ostream& BLOB::copy(std::ostream &output, std::istream &input, const std::streamsize size, const size_t buffer_size)
64  {
65  // read payload
66  std::vector<char> buffer(buffer_size);
67 
68  size_t remain = size;
69 
70  while (remain > 0)
71  {
72  // something bad happened, abort!
73  if (input.bad())
74  {
75  std::stringstream errmsg; errmsg << "input stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
76  throw ibrcommon::IOException(errmsg.str());
77  }
78 
79  // reached EOF too early
80  if (input.eof())
81  {
82  std::stringstream errmsg; errmsg << "input stream reached EOF [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
83  throw ibrcommon::IOException(errmsg.str());
84  }
85 
86  // check if the destination stream is ok
87  if (output.bad())
88  {
89  std::stringstream errmsg; errmsg << "output stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
90  throw ibrcommon::IOException(errmsg.str());
91  }
92 
93  // retry if the read failed
94  if (input.fail())
95  {
96  IBRCOMMON_LOGGER_TAG("BLOB::copy", warning) << "input stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
97  input.clear();
98  }
99 
100  // if the last write failed, then retry
101  if (output.fail())
102  {
103  IBRCOMMON_LOGGER_TAG("BLOB::copy", warning) << "output stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
104  output.clear();
105  }
106  else
107  {
108  // read the full buffer size of less?
109  if (remain > buffer_size)
110  {
111  input.read(&buffer[0], buffer_size);
112  }
113  else
114  {
115  input.read(&buffer[0], remain);
116  }
117 
118  // retry if the read failed
119  if (!input.eof() && input.fail()) continue;
120  }
121 
122  // write the bytes to the BLOB
123  output.write(&buffer[0], input.gcount());
124 
125  // shrink the remaining bytes by the red bytes
126  remain -= input.gcount();
127  }
128 
129  return output;
130  }
131 
133  {
135  }
136 
138  {
140  }
141 
142  void BLOB::changeProvider(BLOB::Provider *p, bool auto_delete)
143  {
144  ibrcommon::BLOB::provider.change(p, auto_delete);
145  }
146 
148  { }
149 
151  : _provider(provider), _auto_delete(auto_delete)
152  {
153  }
154 
156  {
157  if (_auto_delete)
158  {
159  delete _provider;
160  }
161  }
162 
163  void BLOB::ProviderRef::change(BLOB::Provider *p, bool auto_delete)
164  {
165  if (_auto_delete)
166  {
167  delete _provider;
168  }
169 
170  _provider = p;
171  _auto_delete = auto_delete;
172  }
173 
175  {
176  return _provider->create();
177  }
178 
180  {
181  }
182 
184  {
185  }
186 
188  {
189  return StringBLOB::create();
190  }
191 
193  : _tmppath(path)
194  {
195  }
196 
198  {
199  }
200 
202  {
203  return ibrcommon::BLOB::Reference(new TmpFileBLOB(_tmppath));
204  }
205 
207  : _blob(ref._blob)
208  {
209  }
210 
212  {
213  }
214 
215  std::streamsize BLOB::Reference::size() const
216  {
217  return _blob->size();
218  }
219 
221  {
222  return BLOB::iostream(*_blob);
223  }
224 
226  : _blob(blob)
227  {
228  }
229 
231  {
232  return *_blob;
233  }
234 
235  BLOB::Reference MemoryBLOBProvider::StringBLOB::create()
236  {
237  BLOB::Reference ref(new MemoryBLOBProvider::StringBLOB());
238  return ref;
239  }
240 
241  void MemoryBLOBProvider::StringBLOB::clear()
242  {
243  _stringstream.str("");
244  }
245 
246  MemoryBLOBProvider::StringBLOB::StringBLOB()
247  : BLOB(), _stringstream()
248  {
249 
250  }
251 
252  MemoryBLOBProvider::StringBLOB::~StringBLOB()
253  {
254  }
255 
256  void MemoryBLOBProvider::StringBLOB::open()
257  {
258  // set pointer to the beginning of the stream and remove any error flags
259  _stringstream.clear();
260  _stringstream.seekp(0);
261  _stringstream.seekg(0);
262  }
263 
264  void MemoryBLOBProvider::StringBLOB::close()
265  {
266  }
267 
268  std::streamsize MemoryBLOBProvider::StringBLOB::__get_size()
269  {
270  // store current position
271  std::streamoff pos = _stringstream.tellg();
272 
273  // clear all marker (EOF, fail, etc.)
274  _stringstream.clear();
275 
276  _stringstream.seekg(0, std::ios_base::end);
277  std::streamoff size = _stringstream.tellg();
278  _stringstream.seekg(pos);
279 
280  return static_cast<std::streamsize>(size);
281  }
282 
284  {
285  throw ibrcommon::IOException("clear is not possible on a read only file");
286  }
287 
289  : ibrcommon::BLOB(f.size()), _filestream(), _file(f)
290  {
291  if (!f.exists())
292  {
294  }
295  }
296 
298  {
299  }
300 
302  {
304 
305  // open the file
306  _filestream.open(_file.getPath().c_str(), ios::in|ios::binary);
307 
308  if (!_filestream.is_open())
309  {
311  }
312  }
313 
315  {
316  // close the file
317  _filestream.close();
318 
320  }
321 
322  std::streamsize FileBLOB::__get_size()
323  {
324  return _file.size();
325  }
326 
327  void FileBLOBProvider::TmpFileBLOB::clear()
328  {
329  // close the file
330  _filestream.close();
331 
332  // open temporary file
333  _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::trunc | ios::binary );
334 
335  if (!_filestream.is_open())
336  {
337  IBRCOMMON_LOGGER_TAG("TmpFileBLOB::clear", error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
338  throw ibrcommon::CanNotOpenFileException(_tmpfile);
339  }
340  }
341 
342  FileBLOBProvider::TmpFileBLOB::TmpFileBLOB(const File &tmppath)
343  : BLOB(), _filestream(), _fd(0), _tmpfile(tmppath, "blob")
344  {
345  }
346 
347  FileBLOBProvider::TmpFileBLOB::~TmpFileBLOB()
348  {
349  // delete the file if the last reference is destroyed
350  _tmpfile.remove();
351  }
352 
353  void FileBLOBProvider::TmpFileBLOB::open()
354  {
356 
357  // open temporary file
358  _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::binary );
359 
360  if (!_filestream.is_open())
361  {
362  IBRCOMMON_LOGGER_TAG("TmpFileBLOB::open", error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
363  throw ibrcommon::CanNotOpenFileException(_tmpfile);
364  }
365  }
366 
367  void FileBLOBProvider::TmpFileBLOB::close()
368  {
369  // flush the filestream
370  _filestream.flush();
371 
372  // close the file
373  _filestream.close();
374 
376  }
377 
378  std::streamsize FileBLOBProvider::TmpFileBLOB::__get_size()
379  {
380  return _tmpfile.size();
381  }
382 }