mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-06-07 10:47:08 +00:00
Refactoring hpfs, hpfs sync and hpfs serve code. (#231)
* Refactoring hpfs code to a class so it can support multiple mounts. * Refactoring hpfs serve into a class to support mulitiple mount serving. * Refactoring hpfs sync into class to support multiple instances. * Code improvements in hpfs_sync. * Taking a sync target list for hpfs syncing target set.
This commit is contained in:
committed by
GitHub
parent
08680ee8d4
commit
d08d2630f6
@@ -6,13 +6,12 @@
|
||||
#include "../ledger.hpp"
|
||||
#include "../hplog.hpp"
|
||||
#include "../util/util.hpp"
|
||||
#include "../hpfs/hpfs.hpp"
|
||||
#include "../util/h32.hpp"
|
||||
#include "hpfs_sync.hpp"
|
||||
#include "../sc.hpp"
|
||||
#include "../unl.hpp"
|
||||
|
||||
namespace hpfs_sync
|
||||
namespace hpfs
|
||||
{
|
||||
// Idle loop sleep time (milliseconds).
|
||||
constexpr uint16_t IDLE_WAIT = 40;
|
||||
@@ -28,25 +27,26 @@ namespace hpfs_sync
|
||||
|
||||
constexpr int FILE_PERMS = 0644;
|
||||
|
||||
// No. of milliseconds to wait before resubmitting a request.
|
||||
uint16_t REQUEST_RESUBMIT_TIMEOUT;
|
||||
sync_context ctx;
|
||||
bool init_success = false;
|
||||
|
||||
int init()
|
||||
/**
|
||||
* This should be called to activate the hpfs sync.
|
||||
*/
|
||||
int hpfs_sync::init(std::string_view name, hpfs::hpfs_mount *fs_mount)
|
||||
{
|
||||
if (fs_mount == NULL)
|
||||
return -1;
|
||||
|
||||
this->name = name;
|
||||
this->fs_mount = fs_mount;
|
||||
REQUEST_RESUBMIT_TIMEOUT = hpfs::get_request_resubmit_timeout();
|
||||
ctx.target_state_hash = util::h32_empty;
|
||||
ctx.target_patch_hash = util::h32_empty;
|
||||
ctx.current_parent_target_hash = util::h32_empty;
|
||||
// Patch file sync has the highest priority.
|
||||
ctx.current_syncing_parent = hpfs::HPFS_PARENT_COMPONENTS::PATCH;
|
||||
ctx.hpfs_sync_thread = std::thread(hpfs_syncer_loop);
|
||||
ctx.hpfs_sync_thread = std::thread(&hpfs_sync::hpfs_syncer_loop, this);
|
||||
init_success = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void deinit()
|
||||
/**
|
||||
* Perform relavent cleaning.
|
||||
*/
|
||||
void hpfs_sync::deinit()
|
||||
{
|
||||
if (init_success)
|
||||
{
|
||||
@@ -57,41 +57,35 @@ namespace hpfs_sync
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new target states for the syncing process.
|
||||
* @param target_state_hash The target hpfs state which we should sync towards.
|
||||
* @param target_patch_hash The target hpfs patch state which we should sync towards.
|
||||
* Sets a list of sync targets. Sync finishes when all the targets are synced.
|
||||
* Syncing happens sequentially.
|
||||
* @param target_list List of sync targets to sync towards.
|
||||
*/
|
||||
void set_target(const util::h32 target_state_hash, const util::h32 target_patch_hash)
|
||||
void hpfs_sync::set_target(const std::queue<sync_target> &target_list)
|
||||
{
|
||||
std::unique_lock lock(ctx.target_state_mutex);
|
||||
|
||||
// Do not do anything if we are already syncing towards the specified target states.
|
||||
if (ctx.is_shutting_down || (ctx.is_syncing && ctx.target_state_hash == target_state_hash && ctx.target_patch_hash == target_patch_hash))
|
||||
if (target_list.empty())
|
||||
return;
|
||||
|
||||
ctx.target_state_hash = target_state_hash;
|
||||
ctx.target_patch_hash = target_patch_hash;
|
||||
if (hpfs::ctx.get_hash(hpfs::HPFS_PARENT_COMPONENTS::PATCH) != target_patch_hash)
|
||||
{
|
||||
ctx.current_syncing_parent = hpfs::HPFS_PARENT_COMPONENTS::PATCH;
|
||||
ctx.current_parent_target_hash = ctx.target_patch_hash;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.current_syncing_parent = hpfs::HPFS_PARENT_COMPONENTS::STATE;
|
||||
ctx.current_parent_target_hash = ctx.target_state_hash;
|
||||
}
|
||||
// Do not do anything if we are already syncing towards the specified target states.
|
||||
if (ctx.is_shutting_down || (ctx.is_syncing && ctx.original_target_list == target_list))
|
||||
return;
|
||||
|
||||
ctx.original_target_list = target_list;
|
||||
ctx.target_list = std::move(target_list);
|
||||
|
||||
std::unique_lock lock(ctx.current_target_mutex);
|
||||
ctx.current_target = ctx.target_list.front(); // Make the first element of the list the first target to sync.
|
||||
ctx.is_syncing = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the hpfs sync worker loop.
|
||||
*/
|
||||
void hpfs_syncer_loop()
|
||||
void hpfs_sync::hpfs_syncer_loop()
|
||||
{
|
||||
util::mask_signal();
|
||||
|
||||
LOG_INFO << "hpfs sync: Worker started.";
|
||||
LOG_INFO << "hpfs " << name << " sync: Worker started.";
|
||||
|
||||
while (!ctx.is_shutting_down)
|
||||
{
|
||||
@@ -102,115 +96,81 @@ namespace hpfs_sync
|
||||
if (!ctx.is_syncing)
|
||||
continue;
|
||||
|
||||
if (hpfs::acquire_rw_session() != -1)
|
||||
if (fs_mount->acquire_rw_session() != -1)
|
||||
{
|
||||
while (!ctx.is_shutting_down)
|
||||
{
|
||||
{
|
||||
std::shared_lock lock(ctx.target_state_mutex);
|
||||
if (ctx.current_syncing_parent == hpfs::HPFS_PARENT_COMPONENTS::PATCH)
|
||||
LOG_INFO << "hpfs sync: Starting sync for target patch hash: " << ctx.target_patch_hash;
|
||||
else
|
||||
LOG_INFO << "hpfs sync: Starting sync for target state hash: " << ctx.target_state_hash;
|
||||
std::shared_lock lock(ctx.current_target_mutex);
|
||||
LOG_INFO << "hpfs " << name << " sync: Starting sync for target " << ctx.current_target.name << " hash: " << ctx.current_target.hash;
|
||||
}
|
||||
util::h32 new_state = util::h32_empty;
|
||||
const int result = request_loop(ctx.current_parent_target_hash, new_state);
|
||||
const int result = request_loop(ctx.current_target.hash, new_state);
|
||||
|
||||
ctx.pending_requests.clear();
|
||||
ctx.candidate_hpfs_responses.clear();
|
||||
ctx.submitted_requests.clear();
|
||||
|
||||
if (result == -1 || ctx.is_shutting_down)
|
||||
if (result == -1 || result == 1 || ctx.is_shutting_down)
|
||||
break;
|
||||
|
||||
{
|
||||
std::shared_lock lock(ctx.target_state_mutex);
|
||||
std::shared_lock lock(ctx.current_target_mutex);
|
||||
|
||||
if (new_state == ctx.current_parent_target_hash)
|
||||
if (new_state == ctx.current_target.hash)
|
||||
{
|
||||
if (ctx.current_syncing_parent == hpfs::HPFS_PARENT_COMPONENTS::PATCH)
|
||||
{
|
||||
ctx.target_patch_hash = util::h32_empty;
|
||||
LOG_INFO << "hpfs sync: Target patch state achieved: " << new_state;
|
||||
LOG_INFO << "hpfs " << name << " sync: Target " << ctx.current_target.name << " hash achieved: " << new_state;
|
||||
on_current_sync_state_acheived();
|
||||
|
||||
// Appling new patch file changes to hpcore runtime.
|
||||
if (conf::apply_patch_config(hpfs::RW_SESSION_NAME) == -1)
|
||||
{
|
||||
LOG_ERROR << "Appling patch file changes after sync failed";
|
||||
}
|
||||
else
|
||||
{
|
||||
unl::update_unl_changes_from_patch();
|
||||
|
||||
// Update global hash tracker with the new patch file hash.
|
||||
util::h32 updated_patch_hash;
|
||||
hpfs::get_hash(updated_patch_hash, hpfs::RW_SESSION_NAME, hpfs::PATCH_FILE_PATH);
|
||||
hpfs::ctx.set_hash(hpfs::HPFS_PARENT_COMPONENTS::PATCH, updated_patch_hash);
|
||||
}
|
||||
|
||||
if (ctx.target_state_hash == hpfs::ctx.get_hash(hpfs::HPFS_PARENT_COMPONENTS::STATE))
|
||||
break;
|
||||
|
||||
ctx.current_parent_target_hash = ctx.target_state_hash;
|
||||
ctx.current_syncing_parent = hpfs::HPFS_PARENT_COMPONENTS::STATE;
|
||||
continue;
|
||||
}
|
||||
else if (ctx.current_syncing_parent == hpfs::HPFS_PARENT_COMPONENTS::STATE)
|
||||
{
|
||||
ctx.target_state_hash = util::h32_empty;
|
||||
LOG_INFO << "hpfs sync: Target state achieved: " << new_state;
|
||||
// Start syncing to next target.
|
||||
const int result = start_syncing_next_target();
|
||||
if (result == 0)
|
||||
break;
|
||||
}
|
||||
else if (result == 1)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO << "hpfs sync: Continuing sync for new target: " << ctx.current_parent_target_hash;
|
||||
LOG_INFO << "hpfs " << name << " sync: Continuing sync for new target: " << ctx.current_target.hash;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO << "hpfs sync: All parents synced.";
|
||||
hpfs::release_rw_session();
|
||||
LOG_INFO << "hpfs " << name << " sync: All parents synced.";
|
||||
fs_mount->release_rw_session();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "hpfs sync: Failed to start hpfs rw session";
|
||||
LOG_ERROR << "hpfs " << name << " sync: Failed to start hpfs rw session";
|
||||
}
|
||||
|
||||
std::unique_lock lock(ctx.target_state_mutex);
|
||||
ctx.current_parent_target_hash = util::h32_empty;
|
||||
// Clear target list and original target list since the sync is complete.
|
||||
ctx.target_list = {};
|
||||
ctx.original_target_list = {};
|
||||
ctx.is_syncing = false;
|
||||
}
|
||||
|
||||
LOG_INFO << "hpfs sync: Worker stopped.";
|
||||
LOG_INFO << "hpfs " << name << " sync: Worker stopped.";
|
||||
}
|
||||
|
||||
int request_loop(const util::h32 current_target, util::h32 &updated_state)
|
||||
/**
|
||||
* Reqest loop.
|
||||
* @return -1 on error. 0 when current sync state acheived or sync is stopped due to target change.
|
||||
* Returns 1 on successfully finishing all the sync targets.
|
||||
*/
|
||||
int hpfs_sync::request_loop(const util::h32 current_target, util::h32 &updated_state)
|
||||
{
|
||||
std::string target_parent_vpath;
|
||||
BACKLOG_ITEM_TYPE target_parent_backlog_item_type;
|
||||
if (ctx.current_syncing_parent == hpfs::HPFS_PARENT_COMPONENTS::STATE)
|
||||
{
|
||||
target_parent_vpath = hpfs::STATE_DIR_PATH;
|
||||
target_parent_backlog_item_type = BACKLOG_ITEM_TYPE::DIR;
|
||||
}
|
||||
else if (ctx.current_syncing_parent == hpfs::HPFS_PARENT_COMPONENTS::PATCH)
|
||||
{
|
||||
target_parent_vpath = hpfs::PATCH_FILE_PATH;
|
||||
target_parent_backlog_item_type = BACKLOG_ITEM_TYPE::FILE;
|
||||
}
|
||||
std::string lcl = ledger::ctx.get_lcl();
|
||||
|
||||
// Send the initial root hpfs request of the current target.
|
||||
submit_request(backlog_item{ctx.current_target.item_type, ctx.current_target.vpath, -1, current_target}, lcl);
|
||||
|
||||
// Indicates whether any responses were processed in the previous loop iteration.
|
||||
bool prev_responses_processed = false;
|
||||
|
||||
// No. of repetitive resubmissions so far. (This is reset whenever we receive a hpfs response)
|
||||
uint16_t resubmissions_count = 0;
|
||||
|
||||
// Send the initial root hpfs request.
|
||||
submit_request(backlog_item{target_parent_backlog_item_type, target_parent_vpath, -1, current_target}, lcl);
|
||||
|
||||
while (!should_stop_request_loop(current_target))
|
||||
{
|
||||
// Wait a small delay if there were no responses processed during previous iteration.
|
||||
@@ -220,13 +180,8 @@ namespace hpfs_sync
|
||||
// Get current lcl.
|
||||
std::string lcl = ledger::ctx.get_lcl();
|
||||
|
||||
{
|
||||
std::scoped_lock lock(p2p::ctx.collected_msgs.hpfs_responses_mutex);
|
||||
|
||||
// Move collected hpfs responses over to local candidate responses list.
|
||||
if (!p2p::ctx.collected_msgs.hpfs_responses.empty())
|
||||
ctx.candidate_hpfs_responses.splice(ctx.candidate_hpfs_responses.end(), p2p::ctx.collected_msgs.hpfs_responses);
|
||||
}
|
||||
// Move the received hpfs responses to the local response list.
|
||||
swap_collected_responses();
|
||||
|
||||
prev_responses_processed = !ctx.candidate_hpfs_responses.empty();
|
||||
|
||||
@@ -239,7 +194,7 @@ namespace hpfs_sync
|
||||
if (should_stop_request_loop(current_target))
|
||||
return 0;
|
||||
|
||||
LOG_DEBUG << "hpfs sync: Processing hpfs response from [" << response.first.substr(2, 10) << "]";
|
||||
LOG_DEBUG << "hpfs " << name << " sync: Processing hpfs response from [" << response.first.substr(2, 10) << "]";
|
||||
|
||||
const msg::fbuf::p2pmsg::Content *content = msg::fbuf::p2pmsg::GetContent(response.second.data());
|
||||
const msg::fbuf::p2pmsg::Hpfs_Response_Message *resp_msg = content->message_as_Hpfs_Response_Message();
|
||||
@@ -252,7 +207,7 @@ namespace hpfs_sync
|
||||
const auto pending_resp_itr = ctx.submitted_requests.find(key);
|
||||
if (pending_resp_itr == ctx.submitted_requests.end())
|
||||
{
|
||||
LOG_DEBUG << "hpfs sync: Skipping hpfs response due to hash mismatch.";
|
||||
LOG_DEBUG << "hpfs " << name << " sync: Skipping hpfs response due to hash mismatch.";
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -270,7 +225,7 @@ namespace hpfs_sync
|
||||
// Validate received fs data against the hash.
|
||||
if (!validate_fs_entry_hash(vpath, hash, peer_fs_entry_map))
|
||||
{
|
||||
LOG_INFO << "hpfs sync: Skipping hpfs response due to fs entry hash mismatch.";
|
||||
LOG_INFO << "hpfs " << name << " sync: Skipping hpfs response due to fs entry hash mismatch.";
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -287,7 +242,7 @@ namespace hpfs_sync
|
||||
// Validate received hashmap against the hash.
|
||||
if (!validate_file_hashmap_hash(vpath, hash, peer_hashes, peer_hash_count))
|
||||
{
|
||||
LOG_INFO << "hpfs sync: Skipping hpfs response due to file hashmap hash mismatch.";
|
||||
LOG_INFO << "hpfs " << name << " sync: Skipping hpfs response due to file hashmap hash mismatch.";
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -304,7 +259,7 @@ namespace hpfs_sync
|
||||
// Validate received block data against the hash.
|
||||
if (!validate_file_block_hash(hash, block_id, buf))
|
||||
{
|
||||
LOG_INFO << "hpfs sync: Skipping hpfs response due to file block hash mismatch.";
|
||||
LOG_INFO << "hpfs " << name << " sync: Skipping hpfs response due to file block hash mismatch.";
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -316,16 +271,16 @@ namespace hpfs_sync
|
||||
|
||||
// After handling each response, check whether we have reached target hpfs state.
|
||||
// get_hash returns 0 incase target parent is not existing in our side.
|
||||
if (hpfs::get_hash(updated_state, hpfs::RW_SESSION_NAME, target_parent_vpath) == -1)
|
||||
if (fs_mount->get_hash(updated_state, hpfs::RW_SESSION_NAME, ctx.current_target.vpath) == -1)
|
||||
{
|
||||
LOG_ERROR << "hpfs sync: exiting due to hash check error.";
|
||||
LOG_ERROR << "hpfs " << name << " sync: exiting due to hash check error.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Update the central hpfs state tracker.
|
||||
hpfs::ctx.set_hash(ctx.current_syncing_parent, updated_state);
|
||||
fs_mount->set_parent_hash(ctx.current_target.vpath, updated_state);
|
||||
|
||||
LOG_DEBUG << "hpfs sync: current:" << updated_state << " | target:" << current_target;
|
||||
LOG_DEBUG << "hpfs " << name << " sync: current:" << updated_state << " | target:" << current_target;
|
||||
if (updated_state == current_target)
|
||||
return 0;
|
||||
}
|
||||
@@ -347,13 +302,18 @@ namespace hpfs_sync
|
||||
{
|
||||
if (++resubmissions_count > ABANDON_THRESHOLD)
|
||||
{
|
||||
LOG_INFO << "hpfs sync: Resubmission threshold exceeded. Abandoning sync.";
|
||||
return -1;
|
||||
LOG_INFO << "hpfs " << name << " sync: Resubmission threshold exceeded. Abandoning sync.";
|
||||
|
||||
std::shared_lock lock(ctx.current_target_mutex);
|
||||
const int result = start_syncing_next_target();
|
||||
if (result == 0)
|
||||
return 1; // To stop syncing since we have sync all the targets.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset the counter and re-submit request.
|
||||
request.waiting_time = 0;
|
||||
LOG_DEBUG << "hpfs sync: Resubmitting request...";
|
||||
LOG_DEBUG << "hpfs " << name << " sync: Resubmitting request...";
|
||||
submit_request(request, lcl);
|
||||
}
|
||||
}
|
||||
@@ -373,7 +333,6 @@ namespace hpfs_sync
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -384,7 +343,7 @@ namespace hpfs_sync
|
||||
* @param fs_entry_map Received fs entry map.
|
||||
* @returns true if hash is valid, otherwise false.
|
||||
*/
|
||||
bool validate_fs_entry_hash(std::string_view vpath, std::string_view hash, const std::unordered_map<std::string, p2p::hpfs_fs_hash_entry> &fs_entry_map)
|
||||
bool hpfs_sync::validate_fs_entry_hash(std::string_view vpath, std::string_view hash, const std::unordered_map<std::string, p2p::hpfs_fs_hash_entry> &fs_entry_map)
|
||||
{
|
||||
util::h32 content_hash;
|
||||
|
||||
@@ -410,7 +369,7 @@ namespace hpfs_sync
|
||||
* @param hash_count Size of the hash list.
|
||||
* @returns true if hash is valid, otherwise false.
|
||||
*/
|
||||
bool validate_file_hashmap_hash(std::string_view vpath, std::string_view hash, const util::h32 *hashes, const size_t hash_count)
|
||||
bool hpfs_sync::validate_file_hashmap_hash(std::string_view vpath, std::string_view hash, const util::h32 *hashes, const size_t hash_count)
|
||||
{
|
||||
util::h32 content_hash = util::h32_empty;
|
||||
|
||||
@@ -435,7 +394,7 @@ namespace hpfs_sync
|
||||
* @param buf Block buffer.
|
||||
* @returns true if hash is valid, otherwise false.
|
||||
*/
|
||||
bool validate_file_block_hash(std::string_view hash, const uint32_t block_id, std::string_view buf)
|
||||
bool hpfs_sync::validate_file_block_hash(std::string_view hash, const uint32_t block_id, std::string_view buf)
|
||||
{
|
||||
// Calculate block offset of this block.
|
||||
const off_t block_offset = block_id * hpfs::BLOCK_SIZE;
|
||||
@@ -446,14 +405,14 @@ namespace hpfs_sync
|
||||
/**
|
||||
* Indicates whether to break out of hpfs request processing loop.
|
||||
*/
|
||||
bool should_stop_request_loop(const util::h32 current_target)
|
||||
bool hpfs_sync::should_stop_request_loop(const util::h32 ¤t_target)
|
||||
{
|
||||
if (ctx.is_shutting_down)
|
||||
return true;
|
||||
|
||||
// Stop request loop if the target has changed.
|
||||
std::shared_lock lock(ctx.target_state_mutex);
|
||||
return current_target != ctx.current_parent_target_hash;
|
||||
std::shared_lock lock(ctx.current_target_mutex);
|
||||
return current_target != ctx.current_target.hash;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,24 +423,25 @@ namespace hpfs_sync
|
||||
* @param expected_hash The expected hash of the requested data. The peer will ignore the request if their hash is different.
|
||||
* @param target_pubkey The peer pubkey the request was submitted to.
|
||||
*/
|
||||
void request_state_from_peer(const std::string &path, const bool is_file, const int32_t block_id,
|
||||
const util::h32 expected_hash, std::string_view lcl, std::string &target_pubkey)
|
||||
void hpfs_sync::request_state_from_peer(const std::string &path, const bool is_file, const int32_t block_id,
|
||||
const util::h32 expected_hash, std::string_view lcl, std::string &target_pubkey)
|
||||
{
|
||||
p2p::hpfs_request hr;
|
||||
hr.parent_path = path;
|
||||
hr.is_file = is_file;
|
||||
hr.block_id = block_id;
|
||||
hr.expected_hash = expected_hash;
|
||||
hr.mount_id = fs_mount->mount_id;
|
||||
|
||||
flatbuffers::FlatBufferBuilder fbuf(1024);
|
||||
msg::fbuf::p2pmsg::create_msg_from_state_request(fbuf, hr, lcl);
|
||||
msg::fbuf::p2pmsg::create_msg_from_hpfs_request(fbuf, hr, lcl);
|
||||
p2p::send_message_to_random_peer(fbuf, target_pubkey); //todo: send to a node that hold the majority hpfs state to improve reliability of retrieving hpfs state.
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits a pending hpfs request to the peer.
|
||||
*/
|
||||
void submit_request(const backlog_item &request, std::string_view lcl)
|
||||
void hpfs_sync::submit_request(const backlog_item &request, std::string_view lcl)
|
||||
{
|
||||
const std::string key = std::string(request.path)
|
||||
.append(reinterpret_cast<const char *>(&request.expected_hash), sizeof(util::h32));
|
||||
@@ -492,7 +452,7 @@ namespace hpfs_sync
|
||||
request_state_from_peer(request.path, is_file, request.block_id, request.expected_hash, lcl, target_pubkey);
|
||||
|
||||
if (!target_pubkey.empty())
|
||||
LOG_DEBUG << "hpfs sync: Requesting from [" << target_pubkey.substr(2, 10) << "]. type:" << request.type
|
||||
LOG_DEBUG << "hpfs " << name << " sync: Requesting from [" << target_pubkey.substr(2, 10) << "]. type:" << request.type
|
||||
<< " path:" << request.path << " block_id:" << request.block_id
|
||||
<< " hash:" << request.expected_hash;
|
||||
}
|
||||
@@ -503,19 +463,19 @@ namespace hpfs_sync
|
||||
* @param fs_entry_map Received fs entry map.
|
||||
* @returns 0 on success, otherwise -1.
|
||||
*/
|
||||
int handle_fs_entry_response(std::string_view vpath, std::unordered_map<std::string, p2p::hpfs_fs_hash_entry> &fs_entry_map)
|
||||
int hpfs_sync::handle_fs_entry_response(std::string_view vpath, std::unordered_map<std::string, p2p::hpfs_fs_hash_entry> &fs_entry_map)
|
||||
{
|
||||
// Get the parent path of the fs entries we have received.
|
||||
LOG_DEBUG << "hpfs sync: Processing fs entries response for " << vpath;
|
||||
LOG_DEBUG << "hpfs " << name << " sync: Processing fs entries response for " << vpath;
|
||||
|
||||
// Create physical directory on our side if not exist.
|
||||
std::string parent_physical_path = conf::ctx.hpfs_rw_dir + vpath.data();
|
||||
std::string parent_physical_path = fs_mount->rw_dir + vpath.data();
|
||||
if (util::create_dir_tree_recursive(parent_physical_path) == -1)
|
||||
return -1;
|
||||
|
||||
// Get the children hash entries and compare with what we got from peer.
|
||||
std::vector<hpfs::child_hash_node> existing_fs_entries;
|
||||
if (hpfs::get_dir_children_hashes(existing_fs_entries, hpfs::RW_SESSION_NAME, vpath) == -1)
|
||||
if (fs_mount->get_dir_children_hashes(existing_fs_entries, hpfs::RW_SESSION_NAME, vpath) == -1)
|
||||
return -1;
|
||||
|
||||
// Request more info on fs entries that exist on both sides but are different.
|
||||
@@ -544,13 +504,13 @@ namespace hpfs_sync
|
||||
else
|
||||
{
|
||||
// If there was an entry that does not exist on other side, delete it.
|
||||
std::string child_physical_path = conf::ctx.hpfs_rw_dir + child_vpath.data();
|
||||
std::string child_physical_path = fs_mount->rw_dir + child_vpath.data();
|
||||
|
||||
if ((ex_entry.is_file && unlink(child_physical_path.c_str()) == -1) ||
|
||||
!ex_entry.is_file && util::remove_directory_recursively(child_physical_path.c_str()) == -1)
|
||||
return -1;
|
||||
|
||||
LOG_DEBUG << "hpfs sync: Deleted " << (ex_entry.is_file ? "file" : "dir") << " path " << child_vpath;
|
||||
LOG_DEBUG << "hpfs " << name << " sync: Deleted " << (ex_entry.is_file ? "file" : "dir") << " path " << child_vpath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,14 +540,14 @@ namespace hpfs_sync
|
||||
* @param file_length Size of the file.
|
||||
* @returns 0 on success, otherwise -1.
|
||||
*/
|
||||
int handle_file_hashmap_response(std::string_view vpath, const util::h32 *hashes, const size_t hash_count, const uint64_t file_length)
|
||||
int hpfs_sync::handle_file_hashmap_response(std::string_view vpath, const util::h32 *hashes, const size_t hash_count, const uint64_t file_length)
|
||||
{
|
||||
// Get the file path of the block hashes we have received.
|
||||
LOG_DEBUG << "hpfs sync: Processing file block hashes response for " << vpath;
|
||||
LOG_DEBUG << "hpfs " << name << " sync: Processing file block hashes response for " << vpath;
|
||||
|
||||
// File block hashes on our side (file might not exist on our side).
|
||||
std::vector<util::h32> existing_hashes;
|
||||
if (hpfs::get_file_block_hashes(existing_hashes, hpfs::RW_SESSION_NAME, vpath) == -1 && errno != ENOENT)
|
||||
if (fs_mount->get_file_block_hashes(existing_hashes, hpfs::RW_SESSION_NAME, vpath) == -1 && errno != ENOENT)
|
||||
return -1;
|
||||
const size_t existing_hash_count = existing_hashes.size();
|
||||
|
||||
@@ -604,7 +564,7 @@ namespace hpfs_sync
|
||||
if (existing_hashes.size() >= hash_count)
|
||||
{
|
||||
// If peer file might be smaller, truncate our file to match with peer file.
|
||||
std::string file_physical_path = conf::ctx.hpfs_rw_dir + vpath.data();
|
||||
std::string file_physical_path = fs_mount->rw_dir + vpath.data();
|
||||
if (truncate(file_physical_path.c_str(), file_length) == -1)
|
||||
return -1;
|
||||
}
|
||||
@@ -619,13 +579,13 @@ namespace hpfs_sync
|
||||
* @param buf Block buffer.
|
||||
* @returns 0 on success, otherwise -1.
|
||||
*/
|
||||
int handle_file_block_response(std::string_view vpath, const uint32_t block_id, std::string_view buf)
|
||||
int hpfs_sync::handle_file_block_response(std::string_view vpath, const uint32_t block_id, std::string_view buf)
|
||||
{
|
||||
LOG_DEBUG << "hpfs sync: Writing block_id " << block_id
|
||||
LOG_DEBUG << "hpfs " << name << " sync: Writing block_id " << block_id
|
||||
<< " (len:" << buf.length()
|
||||
<< ") of " << vpath;
|
||||
|
||||
std::string file_physical_path = conf::ctx.hpfs_rw_dir + vpath.data();
|
||||
std::string file_physical_path = fs_mount->rw_dir + vpath.data();
|
||||
const int fd = open(file_physical_path.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, FILE_PERMS);
|
||||
if (fd == -1)
|
||||
{
|
||||
@@ -645,4 +605,61 @@ namespace hpfs_sync
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace hpfs_sync
|
||||
/**
|
||||
* This method can be used to invoke mount specific custom logic (after extending this super class) to be executed after
|
||||
* a sync target is acheived.
|
||||
*/
|
||||
void hpfs_sync::on_current_sync_state_acheived()
|
||||
{
|
||||
if (ctx.current_target.vpath == hpfs::PATCH_FILE_PATH)
|
||||
{
|
||||
// Appling new patch file changes to hpcore runtime.
|
||||
if (conf::apply_patch_config(hpfs::RW_SESSION_NAME) == -1)
|
||||
{
|
||||
LOG_ERROR << "Appling patch file changes after sync failed";
|
||||
}
|
||||
else
|
||||
{
|
||||
unl::update_unl_changes_from_patch();
|
||||
|
||||
// Update global hash tracker with the new patch file hash.
|
||||
util::h32 updated_patch_hash;
|
||||
fs_mount->get_hash(updated_patch_hash, hpfs::RW_SESSION_NAME, hpfs::PATCH_FILE_PATH);
|
||||
fs_mount->set_parent_hash(ctx.current_target.vpath, updated_patch_hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts syncing next target if available after current target finishes.
|
||||
* @return returns 0 when the full sync is complete and 1 when more sync targets are available.
|
||||
*/
|
||||
int hpfs_sync::start_syncing_next_target()
|
||||
{
|
||||
ctx.target_list.pop(); // Remove the synced parent from the target list.
|
||||
if (ctx.target_list.empty())
|
||||
{
|
||||
ctx.current_target = {};
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.current_target = ctx.target_list.front();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the collected responses from hpfs responses to a local response list.
|
||||
*/
|
||||
void hpfs_sync::swap_collected_responses()
|
||||
{
|
||||
// This logic will be added to a child class in next PBI.
|
||||
std::scoped_lock lock(p2p::ctx.collected_msgs.contract_hpfs_responses_mutex);
|
||||
|
||||
// Move collected hpfs responses over to local candidate responses list.
|
||||
if (!p2p::ctx.collected_msgs.contract_hpfs_responses.empty())
|
||||
ctx.candidate_hpfs_responses.splice(ctx.candidate_hpfs_responses.end(), p2p::ctx.collected_msgs.contract_hpfs_responses);
|
||||
}
|
||||
|
||||
} // namespace hpfs
|
||||
Reference in New Issue
Block a user