Persisting hpfs log responses to the hpfs (#291)

Fixing the in memory raw shard hash update.
Passing the seq_no of index update to verify that the index records are consistent.
Restart rw session after completing last primary shard sync.
Fixed issue in fs read write by multiple threads.
Hpfs log sync modifications.
This commit is contained in:
Chalith Desaman
2021-04-16 20:06:20 +05:30
committed by GitHub
parent 2283d2bf89
commit 05e8077e5b
14 changed files with 157 additions and 114 deletions

View File

@@ -25,6 +25,9 @@ namespace sc::hpfs_log_sync
sync_context sync_ctx;
bool init_success = false;
// Represent sequence number and the root hash of the genesis ledger.
p2p::sequence_hash genesis_seq_hash;
/**
* Initialize log record syncer.
*/
@@ -34,6 +37,8 @@ namespace sc::hpfs_log_sync
sync_ctx.log_record_sync_thread = std::thread(hpfs_log_syncer_loop);
genesis_seq_hash = {ledger::genesis.seq_no, hpfs::get_root_hash(ledger::genesis.config_hash, ledger::genesis.state_hash)};
init_success = true;
return 0;
}
@@ -47,18 +52,21 @@ namespace sc::hpfs_log_sync
}
}
void set_sync_target(const p2p::sequence_hash target)
void set_sync_target(const uint64_t target)
{
{
std::scoped_lock lock(sync_ctx.target_log_record_mutex);
if (sync_ctx.is_shutting_down || (sync_ctx.is_syncing && sync_ctx.target_log_record == target))
std::scoped_lock lock(sync_ctx.target_log_seq_no_mutex);
if (sync_ctx.is_shutting_down || (sync_ctx.is_syncing && sync_ctx.target_log_seq_no == target))
return;
sync_ctx.target_log_record = target;
sync_ctx.target_log_seq_no = target;
// Finding the minimum seq_no to request hpfs logs.
if (get_verified_min_record() == -1)
return;
}
if (get_verified_min_record() == -1)
return;
LOG_INFO << "Hpfs log sync: Starting sync for target: " << sync_ctx.target_log_seq_no << " min: " << sync_ctx.min_log_record.seq_no;
sync_ctx.target_requested_on = 0;
sync_ctx.request_submissions = 0;
@@ -81,25 +89,44 @@ namespace sc::hpfs_log_sync
// Perform log sync activities.
{
std::scoped_lock<std::mutex> lock(sync_ctx.target_log_record_mutex);
if (!sync_ctx.target_log_record.empty())
std::scoped_lock<std::mutex> lock(sync_ctx.target_log_seq_no_mutex);
if (sync_ctx.target_log_seq_no > 0)
send_hpfs_log_sync_request(); // Send log record requests if needed (or abandon if sync timeout).
// Process any history responses from other nodes.
if (!sync_ctx.target_log_record.empty() && check_hpfs_log_sync_responses() == 1)
// Process any hpfs log responses from other nodes.
if (sync_ctx.target_log_seq_no > 0 && check_hpfs_log_sync_responses() == 1)
processed = true;
// Here we check for the updated log records to check whether target has archived.
if (sync_ctx.is_syncing && get_verified_min_record() == 1)
// Here we check for the updated log records to check whether target has archived only if any responses have been processed.
if (sync_ctx.is_syncing && processed && get_verified_min_record() == 1)
{
LOG_INFO << "Hpfs log sync: sync target archived " << sync_ctx.target_log_record;
sync_ctx.target_log_record = {};
sync_ctx.min_log_record = {};
sync_ctx.is_syncing = false;
LOG_INFO << "Hpfs log sync: sync target archived: " << sync_ctx.target_log_seq_no;
sync_ctx.clear_target();
// After archiving the target, update latest state and patch hash in the in memory map.
util::h32 state_hash, patch_hash;
const std::string session_name = "ro_hpfs_log_sync";
if (sc::contract_fs.start_ro_session(session_name, true) != -1)
{
if (sc::contract_fs.get_hash(state_hash, session_name, sc::STATE_DIR_PATH) != -1)
sc::contract_fs.set_parent_hash(sc::STATE_DIR_PATH, state_hash);
else
LOG_ERROR << "Hpfs log sync: error getting the updated state hash";
if (sc::contract_fs.get_hash(patch_hash, session_name, sc::PATCH_FILE_PATH) != -1)
sc::contract_fs.set_parent_hash(sc::STATE_DIR_PATH, state_hash);
else
LOG_ERROR << "Hpfs log sync: error getting the updated patch hash";
sc::contract_fs.stop_ro_session(session_name);
}
else
LOG_ERROR << "Hpfs log sync: error starting the hpfs ro session";
}
}
// Serve any history requests from other nodes.
// Serve any hpfs log requests from other nodes.
if (check_hpfs_log_sync_requests() == 1)
processed = true;
@@ -112,7 +139,7 @@ namespace sc::hpfs_log_sync
}
/**
* Submits/resubmits log record requests as needed. Abandons sync if threshold reached.
* Submits/resubmits hpfs log requests as needed. Abandons sync if threshold reached.
*/
void send_hpfs_log_sync_request()
{
@@ -124,13 +151,13 @@ namespace sc::hpfs_log_sync
if (sync_ctx.request_submissions < ABANDON_THRESHOLD)
{
flatbuffers::FlatBufferBuilder fbuf;
p2pmsg::create_msg_from_hpfs_log_request(fbuf, {sync_ctx.target_log_record, sync_ctx.min_log_record});
p2pmsg::create_msg_from_hpfs_log_request(fbuf, {sync_ctx.target_log_seq_no, sync_ctx.min_log_record});
std::string target_pubkey;
p2p::send_message_to_random_peer(fbuf, target_pubkey, true);
if (!target_pubkey.empty())
LOG_DEBUG << "Hpfs log sync: Requesting from [" << target_pubkey.substr(2, 10) << "]."
<< " min:" << sync_ctx.min_log_record
<< " target:" << sync_ctx.target_log_record;
<< " min:" << sync_ctx.min_log_record.seq_no
<< " target:" << sync_ctx.target_log_seq_no;
sync_ctx.target_requested_on = time_now;
sync_ctx.request_submissions++;
@@ -144,30 +171,29 @@ namespace sc::hpfs_log_sync
}
/**
* Processes any log record responses we have received from other peers.
* Processes any hpfs log responses we have received from other peers.
* @return 0 if no respones were processed. 1 if at least one response was processed.
*/
int check_hpfs_log_sync_responses()
{
// Move over the collected responses to the local list.
std::list<std::pair<std::string, p2p::hpfs_log_response>> log_record_responses;
std::list<std::pair<std::string, p2p::hpfs_log_response>> hpfs_log_responses;
{
std::scoped_lock lock(p2p::ctx.collected_msgs.log_record_response_mutex);
std::scoped_lock lock(p2p::ctx.collected_msgs.hpfs_log_response_mutex);
// Move collected hpfs responses over to local candidate responses list.
if (!p2p::ctx.collected_msgs.log_record_responses.empty())
log_record_responses.splice(log_record_responses.end(), p2p::ctx.collected_msgs.log_record_responses);
if (!p2p::ctx.collected_msgs.hpfs_log_responses.empty())
hpfs_log_responses.splice(hpfs_log_responses.end(), p2p::ctx.collected_msgs.hpfs_log_responses);
}
for (const auto &[sess_id, log_response] : log_record_responses)
for (const auto &[sess_id, log_response] : hpfs_log_responses)
handle_hpfs_log_sync_response(log_response);
return log_record_responses.empty() ? 0 : 1;
return hpfs_log_responses.empty() ? 0 : 1;
}
/**
* Serves any log record requests we have received from other peers.
* Serves any hpfs log requests we have received from other peers.
* @return 0 if no requests were served. 1 if at least one request was served.
*/
int check_hpfs_log_sync_requests()
@@ -176,11 +202,11 @@ namespace sc::hpfs_log_sync
std::list<std::pair<std::string, p2p::hpfs_log_request>> log_record_requests;
{
std::scoped_lock lock(p2p::ctx.collected_msgs.log_record_request_mutex);
std::scoped_lock lock(p2p::ctx.collected_msgs.hpfs_log_request_mutex);
// Move collected hpfs responses over to local candidate responses list.
if (!p2p::ctx.collected_msgs.log_record_requests.empty())
log_record_requests.splice(log_record_requests.end(), p2p::ctx.collected_msgs.log_record_requests);
if (!p2p::ctx.collected_msgs.hpfs_log_requests.empty())
log_record_requests.splice(log_record_requests.end(), p2p::ctx.collected_msgs.hpfs_log_requests);
}
for (const auto &[session_id, lr] : log_record_requests)
@@ -191,7 +217,7 @@ namespace sc::hpfs_log_sync
continue;
p2p::hpfs_log_response resp;
if (sc::contract_fs.read_hpfs_logs(lr.min_record_id.seq_no, lr.target_record_id.seq_no, resp.log_record_bytes) == -1)
if (sc::contract_fs.read_hpfs_logs(lr.min_record_id.seq_no, lr.target_seq_no, resp.log_record_bytes) == -1)
continue;
resp.min_record_id = lr.min_record_id;
flatbuffers::FlatBufferBuilder fbuf(1024);
@@ -220,8 +246,7 @@ namespace sc::hpfs_log_sync
bool check_required_log_record_availability(const p2p::hpfs_log_request &log_request)
{
// If requested min is the genesis we serve without checking.
const p2p::sequence_hash genesis{ledger::genesis.seq_no, hpfs::get_root_hash(ledger::genesis.config_hash, ledger::genesis.state_hash)};
if (log_request.min_record_id == genesis)
if (log_request.min_record_id == genesis_seq_hash)
return true;
util::h32 root_hash;
@@ -230,7 +255,7 @@ namespace sc::hpfs_log_sync
if (root_hash != log_request.min_record_id.hash)
{
LOG_DEBUG << "Requested root hash does not match with ours: seq no " << log_request.min_record_id.seq_no;
LOG_DEBUG << "Requested root hash does not match with ours: " << log_request.min_record_id;
return false;
}
@@ -244,15 +269,8 @@ namespace sc::hpfs_log_sync
*/
int handle_hpfs_log_sync_response(const p2p::hpfs_log_response &log_response)
{
p2p::sequence_hash requested_min_seq_id;
{
std::scoped_lock<std::mutex> lock(sync_ctx.min_log_record_mutex);
requested_min_seq_id = sync_ctx.min_log_record;
}
// Append only if the response contains min_seq_no staring from requested min seq_no.
const p2p::sequence_hash genesis{ledger::genesis.seq_no, hpfs::get_root_hash(ledger::genesis.config_hash, ledger::genesis.state_hash)};
if (log_response.min_record_id != requested_min_seq_id)
if (log_response.min_record_id != sync_ctx.min_log_record)
{
LOG_DEBUG << "Invalid joining point in the received hpfs log response";
return -1;
@@ -260,7 +278,7 @@ namespace sc::hpfs_log_sync
if (sc::contract_fs.append_hpfs_log_records(log_response.log_record_bytes) == -1)
{
LOG_ERROR << errno << ": Error persisting hpfs log responses";
LOG_ERROR << "Error persisting hpfs log responses";
return -1;
}
return 0;
@@ -284,8 +302,7 @@ namespace sc::hpfs_log_sync
if (last_from_index.seq_no == ledger::genesis.seq_no || last_from_ledger.seq_no == ledger::genesis.seq_no)
{
// Request full ledger.
std::scoped_lock<std::mutex> lock(sync_ctx.min_log_record_mutex);
sync_ctx.min_log_record = {ledger::genesis.seq_no, hpfs::get_root_hash(ledger::genesis.config_hash, ledger::genesis.state_hash)};
sync_ctx.min_log_record = genesis_seq_hash;
return 0;
}
@@ -295,11 +312,10 @@ namespace sc::hpfs_log_sync
return -1;
}
// In sync. No need to sync.
if (last_from_index == last_from_ledger)
{
// In sync. No need to sync.
return 1;
}
if (last_from_index.seq_no == last_from_ledger.seq_no)
{
@@ -320,10 +336,7 @@ namespace sc::hpfs_log_sync
}
if (root_hash_from_ledger == last_from_index.hash)
{
std::scoped_lock<std::mutex> lock(sync_ctx.min_log_record_mutex);
sync_ctx.min_log_record = last_from_index;
}
else
{
// Fork.
@@ -358,12 +371,11 @@ namespace sc::hpfs_log_sync
if (starting_point == 0)
{
// Request full ledger.
std::scoped_lock<std::mutex> lock(sync_ctx.min_log_record_mutex);
sync_ctx.min_log_record = {ledger::genesis.seq_no, hpfs::get_root_hash(ledger::genesis.config_hash, ledger::genesis.state_hash)};
sync_ctx.min_log_record = genesis_seq_hash;
return 0;
}
const char *session_name = "get_min_verified_ledger_record";
const char *session_name = "ro_get_min_verified_ledger_record";
if (ledger::ledger_fs.start_ro_session(session_name, false) == -1)
return -1;
@@ -426,28 +438,25 @@ namespace sc::hpfs_log_sync
if (ledger_root_hash != index_root_hash)
{
// Remove the full log and index file data and start from scratch.
if (sc::contract_fs.truncate_log_file(1) == -1)
if (sc::contract_fs.truncate_log_file(genesis_seq_hash.seq_no) == -1)
{
LOG_ERROR << "Error truncating hpfs log file and index file from : " << (current_seq_no - 1);
LOG_ERROR << "Error truncating hpfs log file and index file from : 0";
return -1;
}
// Request full ledger
std::scoped_lock<std::mutex> lock(sync_ctx.min_log_record_mutex);
sync_ctx.min_log_record = {ledger::genesis.seq_no, hpfs::get_root_hash(ledger::genesis.config_hash, ledger::genesis.state_hash)};
sync_ctx.min_log_record = genesis_seq_hash;
}
else
{
// To account current_seq_no-- at the loop end.
current_seq_no++;
// We have to truncate keeping the joining record. +1 is added to account that.
if (sc::contract_fs.truncate_log_file(current_seq_no + 1) == -1)
if (sc::contract_fs.truncate_log_file(current_seq_no) == -1)
{
LOG_ERROR << "Error truncating hpfs log file and index file from : " << (current_seq_no + 1);
LOG_ERROR << "Error truncating hpfs log file and index file from : " << current_seq_no;
return -1;
}
// we have found the joining point
std::scoped_lock<std::mutex> lock(sync_ctx.min_log_record_mutex);
// We have found the joining point.
sync_ctx.min_log_record = {current_seq_no, ledger_root_hash};
}
return 0;