IBR-DTNSuite  0.12
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 
56  {
57  MemoryBundleSet *set = new MemoryBundleSet(_listener, _bf_size);
58 
59  for (bundle_set::const_iterator iter = _bundles.begin(); iter != _bundles.end(); iter++)
60  {
61  set->add(*iter);
62  }
63 
64  return refcnt_ptr<BundleSetImpl>(set);
65  }
66 
68  {
69  // clear all bundles first
70  clear();
71 
72  // cast the given set to a MemoryBundleSet
73  const MemoryBundleSet *set = dynamic_cast<const MemoryBundleSet*>(other.getPointer());
74 
75  // incompatible bundle-set implementation - abort here
76  if (set == NULL) return;
77 
78  // add all bundles
79  for (bundle_set::const_iterator iter = set->_bundles.begin(); iter != set->_bundles.end(); iter++)
80  {
81  add(*iter);
82  }
83  }
84 
85  void MemoryBundleSet::add(const dtn::data::MetaBundle &bundle) throw ()
86  {
87  // insert bundle id to the private list
88  pair<bundle_set::iterator,bool> ret = _bundles.insert(bundle);
89 
90  BundleSetImpl::ExpiringBundle exb(*ret.first);
91  _expire.insert(exb);
92 
93  // add bundle to the bloomfilter
94  bundle.addTo(_bf);
95  }
96 
97  void MemoryBundleSet::clear() throw ()
98  {
99  _consistent = true;
100  _bundles.clear();
101  _expire.clear();
102  _bf.clear();
103  }
104 
105  bool MemoryBundleSet::has(const dtn::data::BundleID &bundle) const throw ()
106  {
107  // check bloom-filter first
108  if (bundle.isIn(_bf)) {
109  // Return true if the bloom-filter is not consistent with
110  // the bundles set. This happen if the MemoryBundleSet gets deserialized.
111  if (!_consistent) return true;
112 
113  bundle_set::iterator iter = _bundles.find(dtn::data::MetaBundle::create(bundle));
114  return (iter != _bundles.end());
115  }
116 
117  return false;
118  }
119 
120  Size MemoryBundleSet::size() const throw ()
121  {
122  return _bundles.size();
123  }
124 
125  void MemoryBundleSet::expire(const Timestamp timestamp) throw ()
126  {
127  bool commit = false;
128 
129  // we can not expire bundles if we have no idea of time
130  if (timestamp == 0) return;
131 
132  expire_set::iterator iter = _expire.begin();
133 
134  while (iter != _expire.end())
135  {
136  const BundleSetImpl::ExpiringBundle &b = (*iter);
137 
138  if ( b.bundle.expiretime >= timestamp ) break;
139 
140  // raise expired event
141  if (_listener != NULL)
142  _listener->eventBundleExpired( b.bundle );
143 
144  // remove this item in public list
145  _bundles.erase( b.bundle );
146 
147  // remove this item in private list
148  _expire.erase( iter++ );
149 
150  // set commit to true (triggers bloom-filter rebuild)
151  commit = true;
152  }
153 
154  if (commit)
155  {
156  // rebuild the bloom-filter
157  _bf.clear();
158  for (bundle_set::const_iterator iter = _bundles.begin(); iter != _bundles.end(); ++iter)
159  {
160  (*iter).addTo(_bf);
161  }
162  }
163  }
164 
166  {
167  return _bf;
168  }
169 
170  MemoryBundleSet::bundle_set MemoryBundleSet::getNotIn(const ibrcommon::BloomFilter &filter) const throw ()
171  {
172  bundle_set ret;
173 
174 // // if the lists are equal return an empty list
175 // if (filter == _bf) return ret;
176 
177  // iterate through all items to find the differences
178  for (bundle_set::const_iterator iter = _bundles.begin(); iter != _bundles.end(); ++iter)
179  {
180  if (!(*iter).isIn(filter))
181  {
182  ret.insert( (*iter) );
183  }
184  }
185 
186  return ret;
187  }
188 
190  {
191  return dtn::data::Number(_bf.size()).getLength() + _bf.size();
192  }
193 
194  std::ostream& MemoryBundleSet::serialize(std::ostream &stream) const
195  {
196  dtn::data::Number size(_bf.size());
197  stream << size;
198 
199  const char *data = reinterpret_cast<const char*>(_bf.table());
200  stream.write(data, _bf.size());
201 
202  return stream;
203  }
204 
205  std::istream& MemoryBundleSet::deserialize(std::istream &stream)
206  {
207  dtn::data::Number count;
208  stream >> count;
209 
210  std::vector<char> buffer(count.get<size_t>());
211 
212  stream.read(&buffer[0], buffer.size());
213 
215  _bf.load((unsigned char*)&buffer[0], buffer.size());
216 
217  // set the set to in-consistent mode
218  _consistent = false;
219 
220  return stream;
221  }
222 
224  {
225  // copy the file object
226  ibrcommon::File p = path;
227 
228  // create path
230 
231  if (p.exists() && p.isDirectory()) {
232  __store_path__ = p;
233  __store_path_set__ = true;
234  }
235  }
236 
237  void MemoryBundleSet::sync() throw ()
238  {
239  // store the bundle set to disk
240  store();
241  }
242 
243  void MemoryBundleSet::store()
244  {
245  // abort if the store path is not set
246  if (!MemoryBundleSet::__store_path_set__) return;
247 
248  // abort it the name is not set
249  if (_name.length() == 0) return;
250 
251  // create directory, if it does not existt
252  if (!__store_path__.exists())
253  ibrcommon::File::createDirectory(__store_path__);
254 
255  //delete file for bundles, if it exists
256  std::stringstream ss; ss << __store_path__.getPath() << "/" << _name;
257  ibrcommon::File path_bundles(ss.str().c_str());
258  if(path_bundles.exists())
259  path_bundles.remove();
260 
261  //open file
262  ofstream output_file;
263  output_file.open(path_bundles.getPath().c_str());
264 
265  //write number of bundles
266  output_file << _bundles.size();
267 
268  bundle_set::iterator iter = _bundles.begin();
269  while( iter != _bundles.end())
270  {
271  output_file << (*iter++);
272  }
273 
274  output_file.close();
275  }
276 
277  void MemoryBundleSet::restore()
278  {
279  // abort if the store path is not set
280  if (!MemoryBundleSet::__store_path_set__) return;
281 
282  std::stringstream ss; ss << __store_path__.getPath() << "/" << _name;
283  ibrcommon::File path_bundles(ss.str().c_str());
284 
285  //abort if storage files does not exist
286  if(!path_bundles.exists())
287  return;
288 
289  ifstream input_file;
290  input_file.open(ss.str().c_str());
291 
292  //read number of bundles
293  size_t num_bundles;
294  input_file >> num_bundles;
295  size_t i = 0;
296  while (( i < num_bundles) && input_file.good())
297  {
298  MetaBundle b;
299  input_file >> b;
300  _bundles.insert(b);
301  i++;
302  }
303 
304  input_file.close();
305  }
306  } /* namespace data */
307 } /* namespace dtn */