IBR-DTN  1.0.0
MemoryBundleSet.cpp
Go to the documentation of this file.
1 /*
2  * MemoryBundleSet.cpp
3  *
4  * Copyright (C) 2013 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  * Created on: 18.12.2012
21  * renamed from BundleSet.cpp 04.04.2013
22  */
23 
25 
26 namespace dtn
27 {
28  namespace data
29  {
30  ibrcommon::File MemoryBundleSet::__store_path__;
31  bool MemoryBundleSet::__store_path_set__ = false;
32 
34  : _name(), _bf_size(bf_size), _bf(bf_size * 8), _listener(listener), _consistent(true)
35  {
36  }
37 
38  MemoryBundleSet::MemoryBundleSet(const std::string &name, BundleSet::Listener *listener, Length bf_size)
39  : _name(name), _bf_size(bf_size), _bf(bf_size * 8), _listener(listener), _consistent(true)
40  {
41  try {
42  restore();
43  } catch (const dtn::InvalidDataException &ex) {
44  // restore failed to invalid data
45  } catch (const std::exception &ex) {
46  // restore failed
47  }
48  }
49 
51  {
52  store();
53  }
54 
55  refcnt_ptr<BundleSetImpl> MemoryBundleSet::copy() const
56  {
57  MemoryBundleSet *set = new MemoryBundleSet(_listener, _bf_size);
58 
59  // copy Bloom-filter
60  set->_bf_size = _bf_size;
61  set->_bf = _bf;
62  set->_consistent = _consistent;
63 
64  // copy bundles
65  set->_bundles.insert(_bundles.begin(), _bundles.end());
66 
67  // create a new expiration set
68  for (bundle_set::const_iterator it = set->_bundles.begin(); it != set->_bundles.end(); ++it)
69  {
71  set->_expire.insert(exb);
72  }
73 
74  return refcnt_ptr<BundleSetImpl>(set);
75  }
76 
77  void MemoryBundleSet::assign(const refcnt_ptr<BundleSetImpl> &other)
78  {
79  // clear all bundles first
80  clear();
81 
82  try {
83  // cast the given set to a MemoryBundleSet
84  const MemoryBundleSet &set = dynamic_cast<const MemoryBundleSet&>(*other);
85 
86  // copy Bloom-filter
87  _bf_size = set._bf_size;
88  _bf = set._bf;
89  _consistent = set._consistent;
90 
91  // clear bundles and expiration set
92  _bundles.clear();
93  _expire.clear();
94 
95  // copy bundles
96  _bundles.insert(set._bundles.begin(), set._bundles.end());
97 
98  // create a new expiration set
99  for (bundle_set::const_iterator it = _bundles.begin(); it != _bundles.end(); ++it)
100  {
102  _expire.insert(exb);
103  }
104  } catch (const std::bad_cast&) {
105  // incompatible bundle-set implementation - abort here
106  }
107  }
108 
109  void MemoryBundleSet::add(const dtn::data::MetaBundle &bundle) throw ()
110  {
111  // insert bundle id to the private list
112  pair<bundle_set::iterator,bool> ret = _bundles.insert(bundle);
113 
114  BundleSetImpl::ExpiringBundle exb(*ret.first);
115  _expire.insert(exb);
116 
117  // add bundle to the bloomfilter
118  bundle.addTo(_bf);
119  }
120 
121  void MemoryBundleSet::clear() throw ()
122  {
123  _consistent = true;
124  _bundles.clear();
125  _expire.clear();
126  _bf.clear();
127  }
128 
129  bool MemoryBundleSet::has(const dtn::data::BundleID &bundle) const throw ()
130  {
131  // check bloom-filter first
132  if (bundle.isIn(_bf)) {
133  // Return true if the bloom-filter is not consistent with
134  // the bundles set. This happen if the MemoryBundleSet gets deserialized.
135  if (!_consistent) return true;
136 
137  bundle_set::iterator iter = _bundles.find(dtn::data::MetaBundle::create(bundle));
138  return (iter != _bundles.end());
139  }
140 
141  return false;
142  }
143 
144  Size MemoryBundleSet::size() const throw ()
145  {
146  return _bundles.size();
147  }
148 
149  void MemoryBundleSet::expire(const Timestamp timestamp) throw ()
150  {
151  bool commit = false;
152 
153  // we can not expire bundles if we have no idea of time
154  if (timestamp == 0) return;
155 
156  expire_set::iterator iter = _expire.begin();
157 
158  while (iter != _expire.end())
159  {
160  const BundleSetImpl::ExpiringBundle &b = (*iter);
161 
162  if ( b.bundle.expiretime >= timestamp ) break;
163 
164  // raise expired event
165  if (_listener != NULL)
166  _listener->eventBundleExpired( b.bundle );
167 
168  // remove this item in public list
169  _bundles.erase( b.bundle );
170 
171  // remove this item in private list
172  _expire.erase( iter++ );
173 
174  // set commit to true (triggers bloom-filter rebuild)
175  commit = true;
176  }
177 
178  if (commit)
179  {
180  // rebuild the bloom-filter
181  _bf.clear();
182  for (bundle_set::const_iterator iter = _bundles.begin(); iter != _bundles.end(); ++iter)
183  {
184  (*iter).addTo(_bf);
185  }
186  }
187  }
188 
189  const ibrcommon::BloomFilter& MemoryBundleSet::getBloomFilter() const throw ()
190  {
191  return _bf;
192  }
193 
194  MemoryBundleSet::bundle_set MemoryBundleSet::getNotIn(const ibrcommon::BloomFilter &filter) const throw ()
195  {
196  bundle_set ret;
197 
198 // // if the lists are equal return an empty list
199 // if (filter == _bf) return ret;
200 
201  // iterate through all items to find the differences
202  for (bundle_set::const_iterator iter = _bundles.begin(); iter != _bundles.end(); ++iter)
203  {
204  if (!(*iter).isIn(filter))
205  {
206  ret.insert( (*iter) );
207  }
208  }
209 
210  return ret;
211  }
212 
214  {
215  return dtn::data::Number(_bf.size()).getLength() + _bf.size();
216  }
217 
218  std::ostream& MemoryBundleSet::serialize(std::ostream &stream) const
219  {
220  dtn::data::Number size(_bf.size());
221  stream << size;
222 
223  const char *data = reinterpret_cast<const char*>(_bf.table());
224  stream.write(data, _bf.size());
225 
226  return stream;
227  }
228 
229  std::istream& MemoryBundleSet::deserialize(std::istream &stream)
230  {
231  dtn::data::Number count;
232  stream >> count;
233 
234  std::vector<char> buffer(count.get<size_t>());
235 
236  stream.read(&buffer[0], buffer.size());
237 
239  _bf.load((unsigned char*)&buffer[0], buffer.size());
240 
241  // set the set to in-consistent mode
242  _consistent = false;
243 
244  return stream;
245  }
246 
247  void MemoryBundleSet::setPath(const ibrcommon::File &path)
248  {
249  // copy the file object
250  ibrcommon::File p = path;
251 
252  // create path
253  ibrcommon::File::createDirectory(p);
254 
255  if (p.exists() && p.isDirectory()) {
256  __store_path__ = p;
257  __store_path_set__ = true;
258  }
259  }
260 
261  void MemoryBundleSet::sync() throw ()
262  {
263  // store the bundle set to disk
264  store();
265  }
266 
267  void MemoryBundleSet::store()
268  {
269  // abort if the store path is not set
270  if (!MemoryBundleSet::__store_path_set__) return;
271 
272  // abort if the name is not set
273  if (_name.length() == 0) return;
274 
275  // create directory, if it does not existt
276  if (!__store_path__.exists())
277  ibrcommon::File::createDirectory(__store_path__);
278 
279  // delete file for bundles, if it exists
280  std::stringstream ss; ss << __store_path__.getPath() << "/" << _name;
281  ibrcommon::File path_bundles(ss.str().c_str());
282  if(path_bundles.exists())
283  path_bundles.remove();
284 
285  // open file
286  ofstream output_file;
287  output_file.open(path_bundles.getPath().c_str());
288 
289  // write number of bundles
290  output_file << _bundles.size();
291 
292  bundle_set::iterator iter = _bundles.begin();
293  while( iter != _bundles.end())
294  {
295  output_file << (*iter++);
296  }
297 
298  output_file.close();
299  }
300 
301  void MemoryBundleSet::restore()
302  {
303  // abort if the store path is not set
304  if (!MemoryBundleSet::__store_path_set__) return;
305 
306  std::stringstream ss; ss << __store_path__.getPath() << "/" << _name;
307  ibrcommon::File path_bundles(ss.str().c_str());
308 
309  // abort if storage files does not exist
310  if (!path_bundles.exists()) return;
311 
312  ifstream input_file;
313  input_file.open(ss.str().c_str());
314 
315  // read number of bundles
316  size_t num_bundles;
317  input_file >> num_bundles;
318  size_t i = 0;
319  while (( i < num_bundles) && input_file.good())
320  {
321  MetaBundle b;
322  input_file >> b;
323  add(b);
324  i++;
325  }
326 
327  input_file.close();
328  }
329  } /* namespace data */
330 } /* namespace dtn */
virtual bool has(const dtn::data::BundleID &bundle) const
virtual std::ostream & serialize(std::ostream &stream) const
size_t Length
Definition: Number.h:33
virtual std::istream & deserialize(std::istream &stream)
virtual refcnt_ptr< BundleSetImpl > copy() const
MemoryBundleSet(BundleSet::Listener *listener=NULL, Length bf_size=1024)
virtual void assign(const refcnt_ptr< BundleSetImpl > &)
std::set< dtn::data::MetaBundle > getNotIn(const ibrcommon::BloomFilter &filter) const
virtual void add(const dtn::data::MetaBundle &bundle)
virtual void expire(const Timestamp timestamp)
virtual Size size() const
size_t Size
Definition: Number.h:34
static MetaBundle create(const dtn::data::BundleID &id)
Definition: MetaBundle.cpp:34
const ibrcommon::BloomFilter & getBloomFilter() const
dtn::data::SDNV< Size > Number
Definition: Number.h:38
const dtn::data::MetaBundle & bundle
Definition: BundleSetImpl.h:94
static void setPath(const ibrcommon::File &path)