BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
object_database.cpp
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  */
25 
26 #include <fc/io/raw.hpp>
27 #include <fc/container/flat.hpp>
28 #include <fc/thread/parallel.hpp>
29 
30 namespace graphene { namespace db {
31 
33 :_undo_db(*this)
34 {
35  _index.resize(_index_size);
36  _undo_db.enable();
37 }
38 
40 {
41 }
42 
43 const object* object_database::find_object( const object_id_type& id )const
44 {
45  return get_index(id.space(),id.type()).find( id );
46 }
47 const object& object_database::get_object( const object_id_type& id )const
48 {
49  return get_index(id.space(),id.type()).get( id );
50 }
51 
52 const index& object_database::get_index(uint8_t space_id, uint8_t type_id)const
53 {
54  FC_ASSERT( _index.size() > space_id,
55  "Database index ${space_id}.${type_id} does not exist, index size is ${index.size}",
56  ("space_id",space_id)("type_id",type_id)("index.size",_index.size()) );
57  FC_ASSERT( _index[space_id].size() > type_id,
58  "Database index ${space_id}.${type_id} does not exist, space size is ${index[space_id].size}",
59  ("space_id",space_id)("type_id",type_id)("index[space_id].size",_index[space_id].size()) );
60  const auto& tmp = _index[space_id][type_id]; // it is a unique_ptr
61  FC_ASSERT( tmp != nullptr,
62  "Database index ${space_id}.${type_id} has not been initialized",
63  ("space_id",space_id)("type_id",type_id) );
64  return *tmp;
65 }
66 index& object_database::get_mutable_index(uint8_t space_id, uint8_t type_id)
67 {
68  FC_ASSERT( _index.size() > space_id,
69  "Database index ${space_id}.${type_id} does not exist, index size is ${index.size}",
70  ("space_id",space_id)("type_id",type_id)("index.size",_index.size()) );
71  FC_ASSERT( _index[space_id].size() > type_id ,
72  "Database index ${space_id}.${type_id} does not exist, space size is ${index[space_id].size}",
73  ("space_id",space_id)("type_id",type_id)("index[space_id].size",_index[space_id].size()) );
74  const auto& idx = _index[space_id][type_id]; // it is a unique_ptr
75  FC_ASSERT( idx != nullptr,
76  "Database index ${space_id}.${type_id} has not been initialized",
77  ("space_id",space_id)("type_id",type_id) );
78  return *idx;
79 }
80 
82 {
83  const auto tmp_dir = _data_dir / "object_database.tmp";
84  const auto old_dir = _data_dir / "object_database.old";
85  const auto target_dir = _data_dir / "object_database";
86 
87  if( fc::exists( tmp_dir ) )
88  fc::remove_all( tmp_dir );
89  fc::create_directories( tmp_dir / "lock" );
90  std::vector<fc::future<void>> tasks;
91  constexpr size_t max_tasks = 200;
92  tasks.reserve(max_tasks);
93 
94  auto push_task = [this,&tasks,&tmp_dir]( size_t space, size_t type ) {
95  if( _index[space][type] )
96  tasks.push_back( fc::do_parallel( [this,space,type,&tmp_dir] () {
97  _index[space][type]->save( tmp_dir / fc::to_string(space) / fc::to_string(type) );
98  } ) );
99  };
100 
101  const auto spaces = _index.size();
102  for( size_t space = 0; space < spaces; ++space )
103  {
104  fc::create_directories( tmp_dir / fc::to_string(space) );
105  const auto types = _index[space].size();
106  for( size_t type = 0; type < types; ++type )
107  push_task( space, type );
108  }
109  for( auto& task : tasks )
110  task.wait();
111  fc::remove_all( tmp_dir / "lock" );
112  if( fc::exists( target_dir ) )
113  {
114  if( fc::exists( old_dir ) )
115  fc::remove_all( old_dir );
116  fc::rename( target_dir, old_dir );
117  }
118  fc::rename( tmp_dir, target_dir );
119  fc::remove_all( old_dir );
120 }
121 
122 void object_database::wipe(const fc::path& data_dir)
123 {
124  close();
125  ilog("Wiping object database...");
126  fc::remove_all(data_dir / "object_database");
127  ilog("Done wiping object database.");
128 }
129 
130 void object_database::open(const fc::path& data_dir)
131 { try {
132  _data_dir = data_dir;
133  if( fc::exists( _data_dir / "object_database" / "lock" ) )
134  {
135  wlog("Ignoring locked object_database");
136  return;
137  }
138  std::vector<fc::future<void>> tasks;
139  tasks.reserve(200);
140 
141  auto push_task = [this,&tasks]( size_t space, size_t type ) {
142  if( _index[space][type] )
143  tasks.push_back( fc::do_parallel( [this,space,type] () {
144  _index[space][type]->open( _data_dir / "object_database" / fc::to_string(space) / fc::to_string(type) );
145  } ) );
146  };
147 
148  ilog("Opening object database from ${d} ...", ("d", data_dir));
149  const auto spaces = _index.size();
150  for( size_t space = 0; space < spaces; ++space )
151  {
152  const auto types = _index[space].size();
153  for( size_t type = 0; type < types; ++type )
154  push_task( space, type );
155  }
156  for( auto& task : tasks )
157  task.wait();
158  ilog( "Done opening object database." );
159 
160 } FC_CAPTURE_AND_RETHROW( (data_dir) ) }
161 
162 
164 { try {
167 
168 void object_database::save_undo( const object& obj )
169 {
170  _undo_db.on_modify( obj );
171 }
172 
173 void object_database::save_undo_add( const object& obj )
174 {
175  _undo_db.on_create( obj );
176 }
177 
178 void object_database::save_undo_remove(const object& obj)
179 {
180  _undo_db.on_remove( obj );
181 }
182 
183 } } // namespace graphene::db
graphene::db::object_database::find_object
const object * find_object(const object_id_type &id) const
Definition: object_database.cpp:43
FC_CAPTURE_AND_RETHROW
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:479
fc::remove_all
void remove_all(const path &p)
Definition: filesystem.cpp:240
wlog
#define wlog(FORMAT,...)
Definition: logger.hpp:123
fc::to_string
std::string to_string(double)
Definition: string.cpp:73
graphene::db::object_database::flush
void flush()
Definition: object_database.cpp:81
parallel.hpp
graphene::db::object_database::open
void open(const fc::path &data_dir)
Definition: object_database.cpp:130
graphene::db::undo_database::enable
void enable()
Definition: undo_database.cpp:30
graphene::db::object_database::close
void close()
Definition: object_database.cpp:39
graphene::db::object_database::get_mutable_index
index & get_mutable_index()
Definition: object_database.hpp:179
fc::do_parallel
auto do_parallel(Functor &&f, const char *desc FC_TASK_NAME_DEFAULT_ARG) -> fc::future< decltype(f())>
Definition: parallel.hpp:98
graphene::db::object_database::_index_size
static constexpr uint8_t _index_size
Definition: object_database.hpp:45
fc::path
wraps boost::filesystem::path to provide platform independent path manipulation.
Definition: filesystem.hpp:28
ilog
#define ilog(FORMAT,...)
Definition: logger.hpp:117
graphene::db::index::get
const object & get(object_id_type id) const
Definition: index.hpp:110
graphene::db::object_database::get_object
const object & get_object(const object_id_type &id) const
Definition: object_database.cpp:47
graphene::db::undo_database::on_create
void on_create(const object &obj)
Definition: undo_database.cpp:60
flat.hpp
graphene::db::index::find
virtual const object * find(object_id_type id) const =0
graphene::db::undo_database::pop_commit
void pop_commit()
Definition: undo_database.cpp:264
graphene::db::undo_database::on_remove
void on_remove(const object &obj)
Definition: undo_database.cpp:86
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::object_id_type
Definition: object_id.hpp:30
graphene::db::object_database::object_database
object_database()
Definition: object_database.cpp:32
fc::create_directories
void create_directories(const path &p)
Definition: filesystem.cpp:210
graphene::db::object_database::get_index
const index & get_index() const
Definition: object_database.hpp:83
graphene::db::index
abstract base class for accessing objects indexed in various ways.
Definition: index.hpp:70
object_database.hpp
graphene::db::object_database::pop_undo
void pop_undo()
Definition: object_database.cpp:163
graphene::db::undo_database::on_modify
void on_modify(const object &obj)
Definition: undo_database.cpp:73
fc::rename
void rename(const path &from, const path &to)
Definition: filesystem.cpp:302
graphene
Definition: api.cpp:48
graphene::db::object_database::wipe
void wipe(const fc::path &data_dir)
Definition: object_database.cpp:122
fc::exists
bool exists(const path &p)
Definition: filesystem.cpp:209
graphene::db::object_database::_undo_db
undo_database _undo_db
Definition: object_database.hpp:170
raw.hpp