Sitelet https://github.com/EOSIO/eos/pull/9340
Skip to content
This repository was archived by the owner on Aug 2, 2022. It is now read-only.

Kvapi rocksdb nodeos integration first working version check in - #9340

Merged
brianjohnson5972 merged 8 commits into
rocksdb_nodeos_integrationfrom
kvapi_rocksdb_nodeos_integration
Aug 4, 2020
Merged

brianjohnson5972 merged 8 commits into
rocksdb_nodeos_integrationfrom
kvapi_rocksdb_nodeos_integration

Conversation

@linhuang-blockone

@linhuang-blockone linhuang-blockone commented Jul 24, 2020 •

Copy link
Copy Markdown
Contributor

Change Description

This PR checks in the first KV API RocksDB working version, serving as a baseline example for the team. All new test cases have passed. Comments from Bucky at the review meeting have not yet been incorporated. They are marked by "#warning: TODO" so compiler will generate a warning and we will not forget. Please pay attention to them as they represent new direction. I will incorporate them in my next PR.

Change Type

Select ONE

  • Documentation
  • Stability bug fix
  • [ X] Other
  • Other - special case

Consensus Changes

  • Consensus Changes

API Changes

  • API Changes

Documentation Additions

  • Documentation Additions

std::vector<char> prefix = rocksdb_contract_kv_prefix;
b1::chain_kv::append_key(prefix, kvdisk_id.to_uint64_t());
it->Seek(b1::chain_kv::to_slice(rocksdb_contract_kv_prefix));
while(it->Valid()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if the rocksdb::Iterator supported the appropriate iterator concept to allow for range base for loops. This might be something that we could wrap within chain_kv.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should wait on these. @revl needs to make several changes for this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@revl is working on this

if ( header.version < kv_object::minimum_snapshot_version )
return;
if (conf.use_rocksdb_for_disk) {
rocksdb::WriteBatch batch;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My opinion is that the controller should have no direct dependency on rocksdb types. Can this functionality be pushed down into the chain_kv api?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, and @revl will handle this after this PR is committed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@revl is working on this

snapshot->write_section<value_t>([this]( auto& section ){
// This ordering depends on the fact the eosio.kvdisk is before eosio.kvram and only eosio.kvdisk can be stored in rocksdb.
if (db.get<kv_db_config_object>().using_rocksdb_for_disk) {
std::unique_ptr<rocksdb::Iterator> it{kv_database.rdb->NewIterator(rocksdb::ReadOptions())};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this functionality be pushed down into chain_kv?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@linhuang-blockone apply my comment about leaving refactoring for @revl for all these comments about pushing this down into chain_kv. @revl and @TimothyBanks can work this out later.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@revl is working on this

chainbase::database& controller::mutable_db()const { return my->db; }

const fork_database& controller::fork_db()const { return my->fork_db; }
b1::chain_kv::database& controller::kv_database() { return my->kv_database; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any need for a const overload of this method?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whether or not there is, I think @revl should look at that. Lin doesn't need to do it here since what he has implemented obviously isn't needing it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(from Lin) Cannot add const here, as db and undo_stack parameters in create_kv_rocksdb_context are non-const.


const fork_database& controller::fork_db()const { return my->fork_db; }
b1::chain_kv::database& controller::kv_database() { return my->kv_database; }
b1::chain_kv::undo_stack& controller::kv_undo_stack() { return my->kv_undo_stack; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any need for a const overload of this method?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_kv_rocksdb_context() needs kv_database and kv_undo_stack as argutments but kv_database() and kv_undo_stack() aren't accessible because they are private.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not following why @kimjh2005 thinks this, since the code does that and it compiles

auto kv = kv_it.get_kv();

// kv is always non-null due to the check of is_valid()
*found_key_size = kv->key.size();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who is responsible for the null check on found_key_size and found_value_size?

kv_resource_manager resource_manager;
const kv_database_config& limits;
uint32_t num_iterators = 0;
std::shared_ptr<const std::vector<char>> temp_data_buffer;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who is this shared with?

}; // kv_iterator_rocksdb

struct kv_context_rocksdb : kv_context {
b1::chain_kv::database& database;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just wanting to make sure that there are guarantees that make sure the database (and undo stack below) stay in scope with the kv_context.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kv_context_rocksdb is created and destroyed by apply_context, which is created and destroyed by controller. Controller creates the database on startup and destroys it on shutdown.

}
FC_LOG_AND_RETHROW()
}
CATCH_AND_EXIT_DB_FAILURE()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure we want to terminate the program?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this isn't a refactoring from the existing code, then we definitely cannot

}
FC_LOG_AND_RETHROW()
}
CATCH_AND_EXIT_DB_FAILURE()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last time, do these warrant program termination?

#include <eosio/chain/types.hpp>

namespace eosio { namespace chain {
class kv_db_config_object : public chainbase::object<kv_db_config_object_type, kv_db_config_object> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since KV and DB storage will always be the same (either both in RocksDB or both in chainbase), this object should be named something like backing_storage_config_object and should be defined in an *_objects file that isn't specific to KV. (In general we should avoid using "db" in anything refering to RocksDB vs chainbase, since we use kv and db to distinguish the intrinsics)

OBJECT_CTOR(kv_db_config_object)

id_type id;
bool using_rocksdb_for_disk = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to drop the "_for_disk" extension here, on the similarly named functions, and elsewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to make this an enum that is called "backing_storage" with the default value being chain_base, and could be set to rocks_db. This way if we add other backing stores in the future, we could just add them here, instead of having a new parameter and having to validate that parameter's value doesn't conflict with this parameter's value.

if (db.get<kv_db_config_object>().using_rocksdb_for_disk)
return;
auto& idx = db.get_index<kv_index, by_kv_key>();
auto it = idx.lower_bound(boost::make_tuple(kvdisk_id, name{}, std::string_view{}));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should all be kvram_id and eosio.kvram

composite_key_compare<std::less<name>, std::less<name>, unsigned_blob_less>>>>;

inline void use_rocksdb_for_disk(chainbase::database& db) {
if (db.get<kv_db_config_object>().using_rocksdb_for_disk)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

store off db.get<kv_db_config_object>() in a variable and use the variable here and below

kv_iterators.resize(1);
kv_destroyed_iterators.clear();
if (!context_free) {
#warning TODO: Remove kv_ram. Rename kv_disk

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix this comment and switch code below to be for kv_ram instead of kv_disk

}

// skip the kv_db_config as it only determines where the kv-database is stored
if (std::is_same_v<value_t, kv_db_config_object>) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this. If you don't add it to the using definition (above) for controller_index_set, then it won't be present in the walk_indices.

if constexpr (std::is_same_v<value_t, kv_object>) {
if ( header.version < kv_object::minimum_snapshot_version )
return;
if (conf.use_rocksdb_for_disk) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue that I mentioned in writing snapshot section above, if you have a kv_object then we are using chainbase as the backing store and use_rocksdb won't be set. The check should be used after reading the data, before determining if you should write to the rocksdb (key value) backing store or the chainbase backing store. That code should be through an abstraction, that takes the snapshot data and then there will be a chainbase implementation or a rocksdb (key value) implementation (not sure if this would go in kv_context_*** or not, it probably can)

// Currently kv_undo_stack returns a wrong revision after restart,
// failing tests/terminate-scenarios-test.py.
// As chain_kv is being rewritten, comment out this check for now
// and retest after chain_kv rewriting is finished.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has Timothy been made aware of this problem in kv_undo_stack?

Comment thread unittests/kv_tests.cpp
class kv_tester : public tester {
public:
kv_tester() {
eosio::chain::use_rocksdb_for_disk(const_cast<chainbase::database&>(control->db()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix indentation, and why don't you use your helper method you added?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this line means that kv_tester only tests kv with rockdb and not chainbase. To test both you can use BOOST_AUTO_TEST_CASE_TEMPLATE below and make kv_tester templated on backend_store (chainbase, rocksdb - see other comment about use_rocksdb_for_disk not being a bool) . See snapshot_tests.cpp for examples of how to use.

Comment thread unittests/kv_tests.cpp
// BOOST_TEST(iterlimit({{N(eosio.kvram), 0xFFFFFFFF, false}, {N(eosio.kvdisk), 1, false}}) == "Too many iterators");
}

// Make sure that a failed transaction correctly rolls back changes to the database,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now I see what you are doing. Use my suggestion above, revert these methods and the BOOST_AUTO_TEST_CASE_TEMPLATE will take care of testing both chainbase and rocksdb.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or you cans use BOOST_DATA_TEST_CASE_F, but no reason that I can see to repeat all these tests 3 times, unless I am missing something.

@linhuang-blockone
linhuang-blockone force-pushed the kvapi_rocksdb_nodeos_integration branch from 31c34f7 to 513e0e1 Compare August 1, 2020 19:44
Comment thread libraries/chain/include/eosio/chain/exceptions.hpp

@brianjohnson5972 brianjohnson5972 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking this PR in as-is and @linhuang-blockone will be breaking up the cleanup into their own individual PRs.

@brianjohnson5972
brianjohnson5972 merged commit 4111468 into rocksdb_nodeos_integration Aug 4, 2020
@larryk85
larryk85 deleted the kvapi_rocksdb_nodeos_integration branch August 31, 2020 19:49
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants