BitShares-Core  4.0.0
BitShares blockchain implementation and command-line interface software
index.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #pragma once
25 #include <graphene/db/object.hpp>
26 
28 #include <fc/io/raw.hpp>
29 #include <fc/io/json.hpp>
30 #include <fc/crypto/sha256.hpp>
31 
32 #include <fstream>
33 #include <stack>
34 
35 namespace graphene { namespace db {
36  class object_database;
37  using fc::path;
38 
44  {
45  public:
46  virtual ~index_observer(){}
48  virtual void on_add( const object& obj ){}
50  virtual void on_remove( const object& obj ){}
52  virtual void on_modify( const object& obj ){}
53  };
54 
71  class index
72  {
73  public:
74  virtual ~index(){}
75 
76  virtual uint8_t object_space_id()const = 0;
77  virtual uint8_t object_type_id()const = 0;
78 
79  virtual object_id_type get_next_id()const = 0;
80  virtual void use_next_id() = 0;
81  virtual void set_next_id( object_id_type id ) = 0;
82 
83  virtual const object& load( const std::vector<char>& data ) = 0;
88  virtual const object& insert( object&& obj ) = 0;
89 
94  virtual const object& create( const std::function<void(object&)>& constructor ) = 0;
95 
99  virtual void open( const fc::path& db ) = 0;
100  virtual void save( const fc::path& db ) = 0;
101 
102 
103 
105  virtual const object* find( object_id_type id )const = 0;
106 
111  const object& get( object_id_type id )const
112  {
113  auto maybe_found = find( id );
114  FC_ASSERT( maybe_found != nullptr, "Unable to find Object ${id}", ("id",id) );
115  return *maybe_found;
116  }
117 
118  virtual void modify( const object& obj, const std::function<void(object&)>& ) = 0;
119  virtual void remove( const object& obj ) = 0;
120 
127  template<typename Object, typename Lambda>
128  void modify( const Object& obj, const Lambda& l ) {
129  modify( static_cast<const object&>(obj), std::function<void(object&)>( [&]( object& o ){ l( static_cast<Object&>(o) ); } ) );
130  }
131 
132  virtual void inspect_all_objects(std::function<void(const object&)> inspector)const = 0;
133  virtual void add_observer( const shared_ptr<index_observer>& ) = 0;
134 
135  virtual void object_from_variant( const fc::variant& var, object& obj, uint32_t max_depth )const = 0;
136  virtual void object_default( object& obj )const = 0;
137  };
138 
140  {
141  public:
142  virtual ~secondary_index(){};
143  virtual void object_inserted( const object& obj ){};
144  virtual void object_removed( const object& obj ){};
145  virtual void about_to_modify( const object& before ){};
146  virtual void object_modified( const object& after ){};
147  };
148 
153  {
154  public:
156 
158  void save_undo( const object& obj );
159 
161  void on_add( const object& obj );
162 
164  void on_remove( const object& obj );
165 
167  void on_modify( const object& obj );
168 
169  template<typename T, typename... Args>
170  T* add_secondary_index(Args... args)
171  {
172  _sindex.emplace_back( new T(args...) );
173  return static_cast<T*>(_sindex.back().get());
174  }
175 
176  template<typename T>
177  const T& get_secondary_index()const
178  {
179  for( const auto& item : _sindex )
180  {
181  const T* result = dynamic_cast<const T*>(item.get());
182  if( result != nullptr ) return *result;
183  }
184  FC_THROW_EXCEPTION( fc::assert_exception, "invalid index type" );
185  }
186 
187  protected:
188  vector< shared_ptr<index_observer> > _observers;
189  vector< unique_ptr<secondary_index> > _sindex;
190 
191  private:
192  object_database& _db;
193  };
194 
204  template<typename Object, uint8_t chunkbits>
206  {
207  static_assert( chunkbits < 64, "Do you really want arrays with more than 2^63 elements???" );
208 
209  // private
210  static const size_t MAX_HOLE = 100;
211  static const size_t _mask = ((1 << chunkbits) - 1);
212  uint64_t next = 0;
213  vector< vector< const Object* > > content;
214  std::stack< object_id_type > ids_being_modified;
215 
216  public:
218  FC_ASSERT( (1ULL << chunkbits) > MAX_HOLE, "Small chunkbits is inefficient." );
219  }
220 
221  virtual ~direct_index(){}
222 
223  virtual void object_inserted( const object& obj )
224  {
225  uint64_t instance = obj.id.instance();
226  if( instance == next )
227  {
228  if( !(next & _mask) )
229  {
230  content.resize((next >> chunkbits) + 1);
231  content[next >> chunkbits].resize( 1 << chunkbits, nullptr );
232  }
233  next++;
234  }
235  else if( instance < next )
236  FC_ASSERT( !content[instance >> chunkbits][instance & _mask], "Overwriting insert at {id}!", ("id",obj.id) );
237  else // instance > next, allow small "holes"
238  {
239  FC_ASSERT( instance <= next + MAX_HOLE, "Out-of-order insert: {id} > {next}!", ("id",obj.id)("next",next) );
240  if( !(next & _mask) || (next & (~_mask)) != (instance & (~_mask)) )
241  {
242  content.resize((instance >> chunkbits) + 1);
243  content[instance >> chunkbits].resize( 1 << chunkbits, nullptr );
244  }
245  while( next <= instance )
246  {
247  content[next >> chunkbits][next & _mask] = nullptr;
248  next++;
249  }
250  }
251  FC_ASSERT( nullptr != dynamic_cast<const Object*>(&obj), "Wrong object type!" );
252  content[instance >> chunkbits][instance & _mask] = static_cast<const Object*>( &obj );
253  }
254 
255  virtual void object_removed( const object& obj )
256  {
257  FC_ASSERT( nullptr != dynamic_cast<const Object*>(&obj), "Wrong object type!" );
258  uint64_t instance = obj.id.instance();
259  FC_ASSERT( instance < next, "Removing out-of-range object: {id} > {next}!", ("id",obj.id)("next",next) );
260  FC_ASSERT( content[instance >> chunkbits][instance & _mask], "Removing non-existent object {id}!", ("id",obj.id) );
261  content[instance >> chunkbits][instance & _mask] = nullptr;
262  }
263 
264  virtual void about_to_modify( const object& before )
265  {
266  ids_being_modified.emplace( before.id );
267  }
268 
269  virtual void object_modified( const object& after )
270  {
271  FC_ASSERT( ids_being_modified.top() == after.id, "Modification of ID is not supported!");
272  ids_being_modified.pop();
273  }
274 
275  template< typename object_id >
276  const Object* find( const object_id& id )const
277  {
278  static_assert( object_id::space_id == Object::space_id, "Space ID mismatch!" );
279  static_assert( object_id::type_id == Object::type_id, "Type_ID mismatch!" );
280  if( id.instance >= next ) return nullptr;
281  return content[id.instance.value >> chunkbits][id.instance.value & _mask];
282  };
283 
284  template< typename object_id >
285  const Object& get( const object_id& id )const
286  {
287  const Object* ptr = find( id );
288  FC_ASSERT( ptr != nullptr, "Object not found!" );
289  return *ptr;
290  };
291 
292  const Object* find( const object_id_type& id )const
293  {
294  FC_ASSERT( id.space() == Object::space_id, "Space ID mismatch!" );
295  FC_ASSERT( id.type() == Object::type_id, "Type_ID mismatch!" );
296  if( id.instance() >= next ) return nullptr;
297  return content[id.instance() >> chunkbits][id.instance() & ((1 << chunkbits) - 1)];
298  };
299  };
300 
308  template<typename DerivedIndex, uint8_t DirectBits = 0>
309  class primary_index : public DerivedIndex, public base_primary_index
310  {
311  public:
312  typedef typename DerivedIndex::object_type object_type;
313 
315  :base_primary_index(db),_next_id(object_type::space_id,object_type::type_id,0)
316  {
317  if( DirectBits > 0 )
318  _direct_by_id = add_secondary_index< direct_index< object_type, DirectBits > >();
319  }
320 
321  virtual uint8_t object_space_id()const override
322  { return object_type::space_id; }
323 
324  virtual uint8_t object_type_id()const override
325  { return object_type::type_id; }
326 
327  virtual object_id_type get_next_id()const override { return _next_id; }
328  virtual void use_next_id()override { ++_next_id.number; }
329  virtual void set_next_id( object_id_type id )override { _next_id = id; }
330 
332  virtual const object* find( object_id_type id )const override
333  {
334  if( DirectBits > 0 )
335  return _direct_by_id->find( id );
336  return DerivedIndex::find( id );
337  }
338 
340  {
341  std::string desc = "1.0";//get_type_description<object_type>();
342  return fc::sha256::hash(desc);
343  }
344 
345  virtual void open( const path& db )override
346  {
347  if( !fc::exists( db ) ) return;
348  fc::file_mapping fm( db.generic_string().c_str(), fc::read_only );
350  fc::datastream<const char*> ds( (const char*)mr.get_address(), mr.get_size() );
351  fc::sha256 open_ver;
352 
353  fc::raw::unpack(ds, _next_id);
354  fc::raw::unpack(ds, open_ver);
355  FC_ASSERT( open_ver == get_object_version(), "Incompatible Version, the serialization of objects in this index has changed" );
356  vector<char> tmp;
357  while( ds.remaining() > 0 )
358  {
359  fc::raw::unpack( ds, tmp );
360  load( tmp );
361  }
362  }
363 
364  virtual void save( const path& db ) override
365  {
366  std::ofstream out( db.generic_string(),
367  std::ofstream::binary | std::ofstream::out | std::ofstream::trunc );
368  FC_ASSERT( out );
369  auto ver = get_object_version();
370  fc::raw::pack( out, _next_id );
371  fc::raw::pack( out, ver );
372  this->inspect_all_objects( [&]( const object& o ) {
373  auto vec = fc::raw::pack( static_cast<const object_type&>(o) );
374  auto packed_vec = fc::raw::pack( vec );
375  out.write( packed_vec.data(), packed_vec.size() );
376  });
377  }
378 
379  virtual const object& load( const std::vector<char>& data )override
380  {
381  const auto& result = DerivedIndex::insert( fc::raw::unpack<object_type>( data ) );
382  for( const auto& item : _sindex )
383  item->object_inserted( result );
384  return result;
385  }
386 
387 
388  virtual const object& create(const std::function<void(object&)>& constructor )override
389  {
390  const auto& result = DerivedIndex::create( constructor );
391  for( const auto& item : _sindex )
392  item->object_inserted( result );
393  on_add( result );
394  return result;
395  }
396 
397  virtual const object& insert( object&& obj ) override
398  {
399  const auto& result = DerivedIndex::insert( std::move( obj ) );
400  for( const auto& item : _sindex )
401  item->object_inserted( result );
402  on_add( result );
403  return result;
404  }
405 
406  virtual void remove( const object& obj ) override
407  {
408  for( const auto& item : _sindex )
409  item->object_removed( obj );
410  on_remove(obj);
412  }
413 
414  virtual void modify( const object& obj, const std::function<void(object&)>& m )override
415  {
416  save_undo( obj );
417  for( const auto& item : _sindex )
418  item->about_to_modify( obj );
419  DerivedIndex::modify( obj, m );
420  for( const auto& item : _sindex )
421  item->object_modified( obj );
422  on_modify( obj );
423  }
424 
425  virtual void add_observer( const shared_ptr<index_observer>& o ) override
426  {
427  _observers.emplace_back( o );
428  }
429 
430  virtual void object_from_variant( const fc::variant& var, object& obj, uint32_t max_depth )const override
431  {
432  object_id_type id = obj.id;
433  object_type* result = dynamic_cast<object_type*>( &obj );
434  FC_ASSERT( result != nullptr );
435  fc::from_variant( var, *result, max_depth );
436  obj.id = id;
437  }
438 
439  virtual void object_default( object& obj )const override
440  {
441  object_id_type id = obj.id;
442  object_type* result = dynamic_cast<object_type*>( &obj );
443  FC_ASSERT( result != nullptr );
444  (*result) = object_type();
445  obj.id = id;
446  }
447 
448  private:
449  object_id_type _next_id;
450  const direct_index< object_type, DirectBits >* _direct_by_id = nullptr;
451  };
452 
453 } } // graphene::db
bool exists(const path &p)
Definition: filesystem.cpp:209
virtual ~index()
Definition: index.hpp:74
Wraps a derived index to intercept calls to create, modify, and remove so that callbacks may be fired...
Definition: index.hpp:309
void pack(Stream &s, const flat_set< T, A... > &value, uint32_t _max_depth)
Definition: flat.hpp:11
virtual object_id_type get_next_id() const override
Definition: index.hpp:327
Definition: api.cpp:56
base_primary_index(object_database &db)
Definition: index.hpp:155
virtual void on_add(const object &obj)
Definition: index.hpp:48
virtual void object_inserted(const object &obj)
Definition: index.hpp:143
virtual const object & load(const std::vector< char > &data) override
Definition: index.hpp:379
primary_index(object_database &db)
Definition: index.hpp:314
virtual void about_to_modify(const object &before)
Definition: index.hpp:145
virtual void object_removed(const object &obj)
Definition: index.hpp:144
virtual const object & create(const std::function< void(object &)> &constructor) override
Definition: index.hpp:388
virtual void use_next_id() override
Definition: index.hpp:328
virtual void on_modify(const object &obj)
Definition: index.hpp:52
void unpack(Stream &s, flat_set< T, A... > &value, uint32_t _max_depth)
Definition: flat.hpp:23
T * add_secondary_index(Args...args)
Definition: index.hpp:170
A secondary index that tracks objects in vectors indexed by object id. It is meant for fully (or almo...
Definition: index.hpp:205
DerivedIndex::object_type object_type
Definition: index.hpp:312
std::string generic_string() const
Definition: filesystem.cpp:95
static sha256 hash(const char *d, uint32_t dlen)
Definition: sha256.cpp:41
virtual void object_inserted(const object &obj)
Definition: index.hpp:223
virtual void object_default(object &obj) const override
Definition: index.hpp:439
uint64_t instance() const
Definition: object_id.hpp:50
virtual const object * find(object_id_type id) const override
Definition: index.hpp:332
virtual uint8_t object_space_id() const override
Definition: index.hpp:321
virtual void about_to_modify(const object &before)
Definition: index.hpp:264
object_id_type id
Definition: object.hpp:73
fc::sha256 get_object_version() const
Definition: index.hpp:339
static const uint8_t type_id
Definition: object_id.hpp:111
vector< unique_ptr< secondary_index > > _sindex
Definition: index.hpp:189
maintains a set of indexed objects that can be modified with multi-level rollback support ...
virtual void set_next_id(object_id_type id) override
Definition: index.hpp:329
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
virtual void on_remove(const object &obj)
Definition: index.hpp:50
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object&#39;s.
Definition: variant.hpp:198
uint64_t file_size(const path &p)
Definition: filesystem.cpp:219
virtual const object & insert(object &&obj) override
Definition: index.hpp:397
const T & get_secondary_index() const
Definition: index.hpp:177
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:378
used to get callbacks when objects change
Definition: index.hpp:43
virtual void object_removed(const object &obj)
Definition: index.hpp:255
virtual void add_observer(const shared_ptr< index_observer > &o) override
Definition: index.hpp:425
virtual void object_modified(const object &after)
Definition: index.hpp:269
void from_variant(const variant &var, flat_set< T, A... > &vo, uint32_t _max_depth)
Definition: flat.hpp:116
virtual void open(const path &db) override
Definition: index.hpp:345
const Object * find(const object_id &id) const
Definition: index.hpp:276
bool remove(const path &p)
Definition: filesystem.cpp:327
virtual void object_modified(const object &after)
Definition: index.hpp:146
abstract base class for accessing objects indexed in various ways.
Definition: index.hpp:71
const Object * find(const object_id_type &id) const
Definition: index.hpp:292
virtual void modify(const object &obj, const std::function< void(object &)> &m) override
Definition: index.hpp:414
virtual void object_from_variant(const fc::variant &var, object &obj, uint32_t max_depth) const override
Definition: index.hpp:430
static const uint8_t space_id
Definition: object_id.hpp:110
wraps boost::filesystem::path to provide platform independent path manipulation.
Definition: filesystem.hpp:28
void modify(const Object &obj, const Lambda &l)
Definition: index.hpp:128
vector< shared_ptr< index_observer > > _observers
Definition: index.hpp:188
virtual void save(const path &db) override
Definition: index.hpp:364
virtual uint8_t object_type_id() const override
Definition: index.hpp:324