BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet 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 
43  {
44  public:
45  virtual ~index_observer() = default;
47  virtual void on_add( const object& obj ){}
49  virtual void on_remove( const object& obj ){}
51  virtual void on_modify( const object& obj ){}
52  };
53 
70  class index
71  {
72  public:
73  virtual ~index() = default;
74 
75  virtual uint8_t object_space_id()const = 0;
76  virtual uint8_t object_type_id()const = 0;
77 
78  virtual object_id_type get_next_id()const = 0;
79  virtual void use_next_id() = 0;
80  virtual void set_next_id( object_id_type id ) = 0;
81 
82  virtual const object& load( const std::vector<char>& data ) = 0;
87  virtual const object& insert( object&& obj ) = 0;
88 
93  virtual const object& create( const std::function<void(object&)>& constructor ) = 0;
94 
98  virtual void open( const fc::path& db ) = 0;
99  virtual void save( const fc::path& db ) = 0;
100 
101 
102 
104  virtual const object* find( object_id_type id )const = 0;
105 
110  const object& get( object_id_type id )const
111  {
112  auto maybe_found = find( id );
113  FC_ASSERT( maybe_found != nullptr, "Unable to find Object ${id}", ("id",id) );
114  return *maybe_found;
115  }
116 
117  virtual void modify( const object& obj, const std::function<void(object&)>& ) = 0;
118  virtual void remove( const object& obj ) = 0;
119 
126  template<typename Object, typename Lambda>
127  void modify( const Object& obj, const Lambda& l ) {
128  modify( static_cast<const object&>(obj),
129  std::function<void(object&)>( [&l]( 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 std::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() = default;
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:
155  explicit base_primary_index( object_database& db ):_db(db){}
156 
157  virtual ~base_primary_index() = default;
158 
160  void save_undo( const object& obj );
161 
163  void on_add( const object& obj );
164 
166  void on_remove( const object& obj );
167 
169  void on_modify( const object& obj );
170 
171  template<typename T, typename... Args>
172  T* add_secondary_index(Args... args)
173  {
174  _sindex.emplace_back( std::make_unique<T>(args...) );
175  return static_cast<T*>(_sindex.back().get());
176  }
177 
178  template<typename T>
179  const T& get_secondary_index()const
180  {
181  for( const auto& item : _sindex )
182  {
183  const T* result = dynamic_cast<const T*>(item.get());
184  if( result != nullptr ) return *result;
185  }
186  FC_THROW_EXCEPTION( fc::assert_exception, "invalid index type" );
187  }
188 
189  protected:
190  std::vector< std::shared_ptr<index_observer> > _observers;
191  std::vector< std::unique_ptr<secondary_index> > _sindex;
192 
193  private:
194  object_database& _db;
195  };
196 
206  template<typename Object, uint8_t chunkbits>
208  {
209  static_assert( chunkbits < 64, "Do you really want arrays with more than 2^63 elements???" );
210 
211  // private
212  static const size_t MAX_HOLE = 100;
213  static const size_t _mask = ((1ULL << chunkbits) - 1);
214  uint64_t next = 0;
215  std::vector< std::vector< const Object* > > content;
216  std::stack< object_id_type > ids_being_modified;
217 
218  public:
220  FC_ASSERT( (1ULL << chunkbits) > MAX_HOLE, "Small chunkbits is inefficient." );
221  }
222 
223  void object_inserted( const object& obj ) override
224  {
225  uint64_t instance = obj.id.instance();
226  if( instance == next )
227  {
228  if( 0 == (next & _mask) )
229  {
230  content.resize((next >> chunkbits) + 1);
231  content[next >> chunkbits].resize( 1ULL << chunkbits, nullptr );
232  }
233  next++;
234  }
235  else if( instance < next )
236  FC_ASSERT( !content[instance >> chunkbits][instance & _mask],
237  "Overwriting insert at {id}!", ("id",obj.id) );
238  else // instance > next, allow small "holes"
239  {
240  FC_ASSERT( instance <= next + MAX_HOLE,
241  "Out-of-order insert: {id} > {next}!", ("id",obj.id)("next",next) );
242  if( 0 == (next & _mask) || (next & (~_mask)) != (instance & (~_mask)) )
243  {
244  content.resize((instance >> chunkbits) + 1);
245  content[instance >> chunkbits].resize( 1ULL << chunkbits, nullptr );
246  }
247  while( next <= instance )
248  {
249  content[next >> chunkbits][next & _mask] = nullptr;
250  next++;
251  }
252  }
253  FC_ASSERT( nullptr != dynamic_cast<const Object*>(&obj), "Wrong object type!" );
254  content[instance >> chunkbits][instance & _mask] = static_cast<const Object*>( &obj );
255  }
256 
257  void object_removed( const object& obj ) override
258  {
259  FC_ASSERT( nullptr != dynamic_cast<const Object*>(&obj), "Wrong object type!" );
260  uint64_t instance = obj.id.instance();
261  FC_ASSERT( instance < next, "Removing out-of-range object: {id} > {next}!", ("id",obj.id)("next",next) );
262  FC_ASSERT( content[instance >> chunkbits][instance & _mask],
263  "Removing non-existent object {id}!", ("id",obj.id) );
264  content[instance >> chunkbits][instance & _mask] = nullptr;
265  }
266 
267  void about_to_modify( const object& before ) override
268  {
269  ids_being_modified.emplace( before.id );
270  }
271 
272  void object_modified( const object& after ) override
273  {
274  FC_ASSERT( ids_being_modified.top() == after.id, "Modification of ID is not supported!");
275  ids_being_modified.pop();
276  }
277 
278  template< typename object_id >
279  const Object* find( const object_id& id )const
280  {
281  static_assert( object_id::space_id == Object::space_id, "Space ID mismatch!" );
282  static_assert( object_id::type_id == Object::type_id, "Type_ID mismatch!" );
283  if( id.instance >= next ) return nullptr;
284  return content[id.instance.value >> chunkbits][id.instance.value & _mask];
285  };
286 
287  template< typename object_id >
288  const Object& get( const object_id& id )const
289  {
290  const Object* ptr = find( id );
291  FC_ASSERT( ptr != nullptr, "Object not found!" );
292  return *ptr;
293  };
294 
295  const Object* find( const object_id_type& id )const
296  {
297  FC_ASSERT( id.space() == Object::space_id, "Space ID mismatch!" );
298  FC_ASSERT( id.type() == Object::type_id, "Type_ID mismatch!" );
299  if( id.instance() >= next ) return nullptr;
300  return content[id.instance() >> chunkbits][id.instance() & ((1ULL << chunkbits) - 1)];
301  };
302  };
303 
311  template<typename DerivedIndex, uint8_t DirectBits = 0>
312  class primary_index : public DerivedIndex, public base_primary_index
313  {
314  public:
315  using object_type = typename DerivedIndex::object_type;
316 
318  :base_primary_index(db),_next_id(object_type::space_id,object_type::type_id,0)
319  {
320  if( DirectBits > 0 )
321  _direct_by_id = add_secondary_index< direct_index< object_type, DirectBits > >();
322  }
323 
324  uint8_t object_space_id()const override
325  { return object_type::space_id; }
326 
327  uint8_t object_type_id()const override
328  { return object_type::type_id; }
329 
330  object_id_type get_next_id()const override { return _next_id; }
331  void use_next_id()override { ++_next_id.number; }
332  void set_next_id( object_id_type id )override { _next_id = id; }
333 
335  const object* find( object_id_type id )const override
336  {
337  if( DirectBits > 0 )
338  return _direct_by_id->find( id );
339  return DerivedIndex::find( id );
340  }
341 
343  {
344  std::string desc = "1.0";
345  return fc::sha256::hash(desc);
346  }
347 
348  void open( const fc::path& db )override
349  {
350  if( !fc::exists( db ) ) return;
351  fc::file_mapping fm( db.generic_string().c_str(), fc::read_only );
353  fc::datastream<const char*> ds( (const char*)mr.get_address(), mr.get_size() );
354  fc::sha256 open_ver;
355 
356  fc::raw::unpack(ds, _next_id);
357  fc::raw::unpack(ds, open_ver);
358  FC_ASSERT( open_ver == get_object_version(),
359  "Incompatible Version, the serialization of objects in this index has changed" );
360  std::vector<char> tmp;
361  while( ds.remaining() > 0 )
362  {
363  fc::raw::unpack( ds, tmp );
364  load( tmp );
365  }
366  }
367 
368  void save( const fc::path& db ) override
369  {
370  std::ofstream out( db.generic_string(),
371  std::ofstream::binary | std::ofstream::out | std::ofstream::trunc );
372  FC_ASSERT( out );
373  auto ver = get_object_version();
374  fc::raw::pack( out, _next_id );
375  fc::raw::pack( out, ver );
376  this->inspect_all_objects( [&out]( const object& o ) {
377  auto vec = fc::raw::pack( static_cast<const object_type&>(o) );
378  auto packed_vec = fc::raw::pack( vec );
379  out.write( packed_vec.data(), packed_vec.size() );
380  });
381  }
382 
383  const object& load( const std::vector<char>& data )override
384  {
385  const auto& result = DerivedIndex::insert( fc::raw::unpack<object_type>( data ) );
386  for( const auto& item : _sindex )
387  item->object_inserted( result );
388  return result;
389  }
390 
391 
392  const object& create(const std::function<void(object&)>& constructor )override
393  {
394  const auto& result = DerivedIndex::create( constructor );
395  for( const auto& item : _sindex )
396  item->object_inserted( result );
397  on_add( result );
398  return result;
399  }
400 
401  const object& insert( object&& obj ) override
402  {
403  const auto& result = DerivedIndex::insert( std::move( obj ) );
404  for( const auto& item : _sindex )
405  item->object_inserted( result );
406  on_add( result );
407  return result;
408  }
409 
410  void remove( const object& obj ) override
411  {
412  for( const auto& item : _sindex )
413  item->object_removed( obj );
414  on_remove(obj);
416  }
417 
418  void modify( const object& obj, const std::function<void(object&)>& m )override
419  {
420  save_undo( obj );
421  for( const auto& item : _sindex )
422  item->about_to_modify( obj );
423  DerivedIndex::modify( obj, m );
424  for( const auto& item : _sindex )
425  item->object_modified( obj );
426  on_modify( obj );
427  }
428 
429  void add_observer( const std::shared_ptr<index_observer>& o ) override
430  {
431  _observers.emplace_back( o );
432  }
433 
434  void object_from_variant( const fc::variant& var, object& obj, uint32_t max_depth )const override
435  {
436  object_id_type id = obj.id;
437  object_type* result = dynamic_cast<object_type*>( &obj );
438  FC_ASSERT( result != nullptr );
439  fc::from_variant( var, *result, max_depth );
440  obj.id = id;
441  }
442 
443  void object_default( object& obj )const override
444  {
445  object_id_type id = obj.id;
446  object_type* result = dynamic_cast<object_type*>( &obj );
447  FC_ASSERT( result != nullptr );
448  (*result) = object_type();
449  obj.id = id;
450  }
451 
452  private:
453  object_id_type _next_id;
454  const direct_index< object_type, DirectBits >* _direct_by_id = nullptr;
455  };
456 
457 } } // graphene::db
graphene::db::primary_index::create
const object & create(const std::function< void(object &)> &constructor) override
Definition: index.hpp:392
graphene::db::object::id
object_id_type id
Definition: object.hpp:69
graphene::db::primary_index::object_type
typename DerivedIndex::object_type object_type
Definition: index.hpp:315
graphene::db::object_id::type_id
static constexpr uint8_t type_id
Definition: object_id.hpp:110
graphene::db::index::object_default
virtual void object_default(object &obj) const =0
graphene::db::index::object_space_id
virtual uint8_t object_space_id() const =0
fc::datastream::remaining
size_t remaining() const
Definition: datastream.hpp:69
graphene::db::primary_index::save
void save(const fc::path &db) override
Definition: index.hpp:368
graphene::db::primary_index::primary_index
primary_index(object_database &db)
Definition: index.hpp:317
graphene::db::index::inspect_all_objects
virtual void inspect_all_objects(std::function< void(const object &)> inspector) const =0
graphene::db::primary_index::object_type_id
uint8_t object_type_id() const override
Definition: index.hpp:327
graphene::db::base_primary_index::add_secondary_index
T * add_secondary_index(Args... args)
Definition: index.hpp:172
graphene::db::primary_index
Wraps a derived index to intercept calls to create, modify, and remove so that callbacks may be fired...
Definition: index.hpp:312
graphene::db::direct_index::object_inserted
void object_inserted(const object &obj) override
Definition: index.hpp:223
fc::raw::unpack
void unpack(Stream &s, flat_set< T, A... > &value, uint32_t _max_depth)
Definition: flat.hpp:23
graphene::db::base_primary_index::on_modify
void on_modify(const object &obj)
Definition: index.cpp:41
graphene::db::base_primary_index::get_secondary_index
const T & get_secondary_index() const
Definition: index.hpp:179
graphene::db::index_observer::on_modify
virtual void on_modify(const object &obj)
Definition: index.hpp:51
graphene::db::index::add_observer
virtual void add_observer(const std::shared_ptr< index_observer > &)=0
graphene::db::index::create
virtual const object & create(const std::function< void(object &)> &constructor)=0
graphene::db::primary_index::add_observer
void add_observer(const std::shared_ptr< index_observer > &o) override
Definition: index.hpp:429
graphene::db::base_primary_index::on_remove
void on_remove(const object &obj)
Definition: index.cpp:38
file_mapping.hpp
graphene::db::index::open
virtual void open(const fc::path &db)=0
fc::datastream
Definition: datastream.hpp:20
graphene::db::primary_index::find
const object * find(object_id_type id) const override
Definition: index.hpp:335
graphene::db::index::save
virtual void save(const fc::path &db)=0
fc::sha256
Definition: sha256.hpp:10
graphene::db::direct_index
A secondary index that tracks objects in vectors indexed by object id. It is meant for fully (or almo...
Definition: index.hpp:207
graphene::db::direct_index::direct_index
direct_index()
Definition: index.hpp:219
graphene::db::base_primary_index::_observers
std::vector< std::shared_ptr< index_observer > > _observers
Definition: index.hpp:190
graphene::db::primary_index::use_next_id
void use_next_id() override
Definition: index.hpp:331
fc::from_variant
void from_variant(const variant &var, flat_set< T, A... > &vo, uint32_t _max_depth)
Definition: flat.hpp:116
graphene::db::secondary_index::object_modified
virtual void object_modified(const object &after)
Definition: index.hpp:146
graphene::db::generic_index::object_type
ObjectType object_type
Definition: generic_index.hpp:47
graphene::db::base_primary_index::~base_primary_index
virtual ~base_primary_index()=default
graphene::db::object_id::space_id
static constexpr uint8_t space_id
Definition: object_id.hpp:109
graphene::db::index::object_from_variant
virtual void object_from_variant(const fc::variant &var, object &obj, uint32_t max_depth) const =0
graphene::db::primary_index::object_from_variant
void object_from_variant(const fc::variant &var, object &obj, uint32_t max_depth) const override
Definition: index.hpp:434
graphene::db::base_primary_index::on_add
void on_add(const object &obj)
Definition: index.cpp:32
graphene::db::base_primary_index
Definition: index.hpp:152
graphene::db::primary_index::load
const object & load(const std::vector< char > &data) override
Definition: index.hpp:383
graphene::db::primary_index::remove
void remove(const object &obj) override
Definition: index.hpp:410
graphene::db::index_observer
used to get callbacks when objects change
Definition: index.hpp:42
fc::read_only
@ read_only
Definition: file_mapping.hpp:14
graphene::db::direct_index::about_to_modify
void about_to_modify(const object &before) override
Definition: index.hpp:267
graphene::db::object_id_type::instance
uint64_t instance() const
Definition: object_id.hpp:49
graphene::db::direct_index::object_modified
void object_modified(const object &after) override
Definition: index.hpp:272
fc::remove
bool remove(const path &p)
Definition: filesystem.cpp:327
fc::path
wraps boost::filesystem::path to provide platform independent path manipulation.
Definition: filesystem.hpp:28
graphene::db::index::get
const object & get(object_id_type id) const
Definition: index.hpp:110
graphene::db::primary_index::set_next_id
void set_next_id(object_id_type id) override
Definition: index.hpp:332
graphene::db::primary_index::modify
void modify(const object &obj, const std::function< void(object &)> &m) override
Definition: index.hpp:418
graphene::db::base_primary_index::base_primary_index
base_primary_index(object_database &db)
Definition: index.hpp:155
graphene::db::index_observer::on_add
virtual void on_add(const object &obj)
Definition: index.hpp:47
graphene::db::index::insert
virtual const object & insert(object &&obj)=0
graphene::db::primary_index::object_default
void object_default(object &obj) const override
Definition: index.hpp:443
graphene::db::index::find
virtual const object * find(object_id_type id) const =0
graphene::db::secondary_index::object_inserted
virtual void object_inserted(const object &obj)
Definition: index.hpp:143
graphene::db::base_primary_index::save_undo
void save_undo(const object &obj)
Definition: index.cpp:29
fc::path::generic_string
std::string generic_string() const
Definition: filesystem.cpp:95
graphene::db::primary_index::object_space_id
uint8_t object_space_id() const override
Definition: index.hpp:324
graphene::db::primary_index::insert
const object & insert(object &&obj) override
Definition: index.hpp:401
fc::mapped_region
Definition: file_mapping.hpp:32
graphene::db::index_observer::on_remove
virtual void on_remove(const object &obj)
Definition: index.hpp:49
graphene::db::object_database
maintains a set of indexed objects that can be modified with multi-level rollback support
Definition: object_database.hpp:39
json.hpp
FC_ASSERT
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
graphene::db::direct_index::find
const Object * find(const object_id_type &id) const
Definition: index.hpp:295
graphene::db::index::get_next_id
virtual object_id_type get_next_id() const =0
fc::variant
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition: variant.hpp:198
graphene::db::primary_index::get_object_version
fc::sha256 get_object_version() const
Definition: index.hpp:342
graphene::db::direct_index::get
const Object & get(const object_id &id) const
Definition: index.hpp:288
graphene::db::object_id_type
Definition: object_id.hpp:30
graphene::db::object_id
Definition: object_id.hpp:103
graphene::db::object_id_type::number
uint64_t number
Definition: object_id.hpp:83
graphene::db::index::use_next_id
virtual void use_next_id()=0
fc::file_size
uint64_t file_size(const path &p)
Definition: filesystem.cpp:219
graphene::db::index::load
virtual const object & load(const std::vector< char > &data)=0
fc::mapped_region::get_size
size_t get_size() const
Definition: file_mapping.cpp:37
graphene::db::index_observer::~index_observer
virtual ~index_observer()=default
graphene::db::secondary_index::about_to_modify
virtual void about_to_modify(const object &before)
Definition: index.hpp:145
graphene::db::index::~index
virtual ~index()=default
graphene::db::index::remove
virtual void remove(const object &obj)=0
graphene::db::direct_index::find
const Object * find(const object_id &id) const
Definition: index.hpp:279
graphene::db::index::object_type_id
virtual uint8_t object_type_id() const =0
graphene::db::primary_index::open
void open(const fc::path &db) override
Definition: index.hpp:348
graphene::db::base_primary_index::_sindex
std::vector< std::unique_ptr< secondary_index > > _sindex
Definition: index.hpp:191
graphene::db::secondary_index::object_removed
virtual void object_removed(const object &obj)
Definition: index.hpp:144
graphene::db::index::set_next_id
virtual void set_next_id(object_id_type id)=0
FC_THROW_EXCEPTION
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:379
graphene::db::secondary_index
Definition: index.hpp:139
graphene::db::index::modify
virtual void modify(const object &obj, const std::function< void(object &)> &)=0
graphene::db::secondary_index::~secondary_index
virtual ~secondary_index()=default
fc::file_mapping
Definition: file_mapping.hpp:19
object.hpp
graphene::db::index
abstract base class for accessing objects indexed in various ways.
Definition: index.hpp:70
fc::mapped_region::get_address
void * get_address() const
Definition: file_mapping.cpp:27
graphene::db::primary_index::get_next_id
object_id_type get_next_id() const override
Definition: index.hpp:330
graphene::db::index::modify
void modify(const Object &obj, const Lambda &l)
Definition: index.hpp:127
fc::sha256::hash
static sha256 hash(const char *d, uint32_t dlen)
Definition: sha256.cpp:41
graphene
Definition: api.cpp:48
fc::exists
bool exists(const path &p)
Definition: filesystem.cpp:209
graphene::db::direct_index::object_removed
void object_removed(const object &obj) override
Definition: index.hpp:257
fc::raw::pack
void pack(Stream &s, const flat_set< T, A... > &value, uint32_t _max_depth)
Definition: flat.hpp:11
sha256.hpp
raw.hpp