IBR-DTNSuite  0.10
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 
46  { }
47 
49  {
50  }
51 
52  std::ostream& BLOB::copy(std::ostream &output, std::istream &input, const std::streamsize size, const size_t buffer_size)
53  {
54  // read payload
55  std::vector<char> buffer(buffer_size);
56 
57  size_t remain = size;
58 
59  while (remain > 0)
60  {
61  // something bad happened, abort!
62  if (input.bad())
63  {
64  std::stringstream errmsg; errmsg << "input stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
65  throw ibrcommon::IOException(errmsg.str());
66  }
67 
68  // reached EOF too early
69  if (input.eof())
70  {
71  std::stringstream errmsg; errmsg << "input stream reached EOF [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
72  throw ibrcommon::IOException(errmsg.str());
73  }
74 
75  // check if the destination stream is ok
76  if (output.bad())
77  {
78  std::stringstream errmsg; errmsg << "output stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
79  throw ibrcommon::IOException(errmsg.str());
80  }
81 
82  // retry if the read failed
83  if (input.fail())
84  {
85  IBRCOMMON_LOGGER_TAG("BLOB::copy", warning) << "input stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
86  input.clear();
87  }
88 
89  // if the last write failed, then retry
90  if (output.fail())
91  {
92  IBRCOMMON_LOGGER_TAG("BLOB::copy", warning) << "output stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
93  output.clear();
94  }
95  else
96  {
97  // read the full buffer size of less?
98  if (remain > buffer_size)
99  {
100  input.read(&buffer[0], buffer_size);
101  }
102  else
103  {
104  input.read(&buffer[0], remain);
105  }
106 
107  // retry if the read failed
108  if (!input.eof() && input.fail()) continue;
109  }
110 
111  // write the bytes to the BLOB
112  output.write(&buffer[0], input.gcount());
113 
114  // shrink the remaining bytes by the red bytes
115  remain -= input.gcount();
116  }
117 
118  return output;
119  }
120 
122  {
124  }
125 
127  {
129  }
130 
131  void BLOB::changeProvider(BLOB::Provider *p, bool auto_delete)
132  {
133  ibrcommon::BLOB::provider.change(p, auto_delete);
134  }
135 
137  { }
138 
140  : _provider(provider), _auto_delete(auto_delete)
141  {
142  }
143 
145  {
146  if (_auto_delete)
147  {
148  delete _provider;
149  }
150  }
151 
152  void BLOB::ProviderRef::change(BLOB::Provider *p, bool auto_delete)
153  {
154  if (_auto_delete)
155  {
156  delete _provider;
157  }
158 
159  _provider = p;
160  _auto_delete = auto_delete;
161  }
162 
164  {
165  return _provider->create();
166  }
167 
169  {
170  }
171 
173  {
174  }
175 
177  {
178  return StringBLOB::create();
179  }
180 
182  : _tmppath(path)
183  {
184  }
185 
187  {
188  }
189 
191  {
192  return ibrcommon::BLOB::Reference(new TmpFileBLOB(_tmppath));
193  }
194 
196  : _blob(ref._blob)
197  {
198  }
199 
201  {
202  }
203 
205  {
206  return BLOB::iostream(*_blob);
207  }
208 
210  : _blob(blob)
211  {
212  }
213 
215  {
216  return *_blob;
217  }
218 
219  BLOB::Reference MemoryBLOBProvider::StringBLOB::create()
220  {
221  BLOB::Reference ref(new MemoryBLOBProvider::StringBLOB());
222  return ref;
223  }
224 
225  void MemoryBLOBProvider::StringBLOB::clear()
226  {
227  _stringstream.str("");
228  }
229 
230  MemoryBLOBProvider::StringBLOB::StringBLOB()
231  : BLOB(), _stringstream()
232  {
233 
234  }
235 
236  MemoryBLOBProvider::StringBLOB::~StringBLOB()
237  {
238  }
239 
240  void MemoryBLOBProvider::StringBLOB::open()
241  {
242  // set pointer to the beginning of the stream and remove any error flags
243  _stringstream.clear();
244  _stringstream.seekp(0);
245  _stringstream.seekg(0);
246  }
247 
248  void MemoryBLOBProvider::StringBLOB::close()
249  {
250  }
251 
252  std::streamsize MemoryBLOBProvider::StringBLOB::__get_size()
253  {
254  // store current position
255  std::streamoff pos = _stringstream.tellg();
256 
257  _stringstream.seekg(0, std::ios_base::end);
258  std::streamoff size = _stringstream.tellg();
259  _stringstream.seekg(pos);
260 
261  return static_cast<std::streamsize>(size);
262  }
263 
265  {
266  throw ibrcommon::IOException("clear is not possible on a read only file");
267  }
268 
270  : ibrcommon::BLOB(), _filestream(), _file(f)
271  {
272  if (!f.exists())
273  {
275  }
276  }
277 
279  {
280  }
281 
283  {
285 
286  // open the file
287  _filestream.open(_file.getPath().c_str(), ios::in|ios::binary);
288 
289  if (!_filestream.is_open())
290  {
292  }
293  }
294 
296  {
297  // close the file
298  _filestream.close();
299 
301  }
302 
303  std::streamsize FileBLOB::__get_size()
304  {
305  return _file.size();
306  }
307 
308  void FileBLOBProvider::TmpFileBLOB::clear()
309  {
310  // close the file
311  _filestream.close();
312 
313  // open temporary file
314  _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::trunc | ios::binary );
315 
316  if (!_filestream.is_open())
317  {
318  IBRCOMMON_LOGGER_TAG("TmpFileBLOB::clear", error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
319  throw ibrcommon::CanNotOpenFileException(_tmpfile);
320  }
321  }
322 
323  FileBLOBProvider::TmpFileBLOB::TmpFileBLOB(const File &tmppath)
324  : BLOB(), _filestream(), _fd(0), _tmpfile(tmppath, "blob")
325  {
326  }
327 
328  FileBLOBProvider::TmpFileBLOB::~TmpFileBLOB()
329  {
330  // delete the file if the last reference is destroyed
331  _tmpfile.remove();
332  }
333 
334  void FileBLOBProvider::TmpFileBLOB::open()
335  {
337 
338  // open temporary file
339  _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::binary );
340 
341  if (!_filestream.is_open())
342  {
343  IBRCOMMON_LOGGER_TAG("TmpFileBLOB::open", error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
344  throw ibrcommon::CanNotOpenFileException(_tmpfile);
345  }
346  }
347 
348  void FileBLOBProvider::TmpFileBLOB::close()
349  {
350  // flush the filestream
351  _filestream.flush();
352 
353  // close the file
354  _filestream.close();
355 
357  }
358 
359  std::streamsize FileBLOBProvider::TmpFileBLOB::__get_size()
360  {
361  return _tmpfile.size();
362  }
363 }