Skip to content

Commit

Permalink
[release/5.x] Cherry pick: Don't throw error if the ledger directory …
Browse files Browse the repository at this point in the history
…exists but is empty on node start (#6859) (#6885)

Co-authored-by: Andrea Piccione <[email protected]>
  • Loading branch information
achamayou and andpiccione authored Mar 6, 2025
1 parent 7c2cb4b commit 6f83884
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 2 deletions.
6 changes: 4 additions & 2 deletions src/host/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,12 @@ int main(int argc, char** argv)
{
if (config.command.type == StartType::Start)
{
if (files::exists(config.ledger.directory))
if (
files::exists(config.ledger.directory) &&
!fs::is_empty(config.ledger.directory))
{
throw std::logic_error(fmt::format(
"On start, ledger directory should not exist ({})",
"On start, ledger directory should not exist or be empty ({})",
config.ledger.directory));
}
// Count members with public encryption key as only these members will be
Expand Down
6 changes: 6 additions & 0 deletions src/host/snapshots.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ namespace asynchost
continue;
}

if (fs::exists(f.path()) && fs::is_empty(f.path()))
{
LOG_INFO_FMT("Ignoring empty snapshot file {}", file_name);
continue;
}

auto snapshot_idx = get_snapshot_idx_from_file_name(file_name);
if (snapshot_idx > latest_committed_snapshot_idx)
{
Expand Down
77 changes: 77 additions & 0 deletions tests/e2e_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,40 @@ def test_large_snapshot(network, args):
)


def test_empty_snapshot(network, args):

LOG.info("Check that empty snapshot is ignored")

with tempfile.TemporaryDirectory() as snapshots_dir:
LOG.debug(f"Using {snapshots_dir} as snapshots directory")

snapshot_name = "snapshot_1000_1500.committed"

with open(
os.path.join(snapshots_dir, snapshot_name), "wb+"
) as temp_empty_snapshot:

LOG.debug(f"Created empty snapshot {temp_empty_snapshot.name}")

# Check the file is indeed empty
assert (
os.stat(temp_empty_snapshot.name).st_size == 0
), temp_empty_snapshot.name

# Create new node and join network
new_node = network.create_node("local://localhost")
network.join_node(new_node, args.package, args, snapshots_dir=snapshots_dir)
new_node.stop()

# Check that the empty snapshot is correctly skipped
if not new_node.check_log_for_error_message(
f"Ignoring empty snapshot file {snapshot_name}"
):
raise AssertionError(
f"Expected empty snapshot file {snapshot_name} to be skipped in node logs"
)


def split_all_ledger_files_in_dir(input_dir, output_dir):
# A ledger file can only be split at a seqno that contains a signature
# (so that all files end on a signature that verifies their integrity).
Expand Down Expand Up @@ -292,6 +326,7 @@ def run_file_operations(args):
test_forced_ledger_chunk(network, args)
test_forced_snapshot(network, args)
test_large_snapshot(network, args)
test_empty_snapshot(network, args)

primary, _ = network.find_primary()
# Scoped transactions are not handled by historical range queries
Expand Down Expand Up @@ -589,6 +624,47 @@ def run_service_subject_name_check(args):
assert cert.subject.rfc4514_string() == "CN=This test service", cert


def run_empty_ledger_dir_check(args):
with infra.network.network(
args.nodes,
args.binary_dir,
args.debug_nodes,
args.perf_nodes,
pdb=args.pdb,
) as network:
LOG.info("Check that empty ledger directory is handled correctly")
with tempfile.TemporaryDirectory() as tmp_dir:
LOG.debug(f"Using {tmp_dir} as ledger directory")

dir_name = os.path.basename(tmp_dir)

# Check tmp_dir is indeed empty
assert len(os.listdir(tmp_dir)) == 0, tmp_dir

# Start network, this should not fail
network.start_and_open(args, ledger_dir=tmp_dir)
primary, _ = network.find_primary()
network.stop_all_nodes()

# Now write a file in the directory
with open(os.path.join(tmp_dir, "ledger_1000_1500.committed"), "wb") as f:
f.write(b"bar")

# Start new network, this should fail
try:
network.start(args, ledger_dir=tmp_dir)
except Exception:
pass

# Check that the node has failed with the expected error message
if not primary.check_log_for_error_message(
f"On start, ledger directory should not exist or be empty ({dir_name})"
):
raise AssertionError(
f"Expected node error message with non-empty ledger directory {dir_name}"
)


def run(args):
run_max_uncommitted_tx_count(args)
run_file_operations(args)
Expand All @@ -599,3 +675,4 @@ def run(args):
run_preopen_readiness_check(args)
run_sighup_check(args)
run_service_subject_name_check(args)
run_empty_ledger_dir_check(args)
1 change: 1 addition & 0 deletions tests/infra/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ def _start_all_nodes(
workspace=args.workspace,
label=args.label,
common_dir=self.common_dir,
ledger_dir=ledger_dir,
members_info=self.consortium.get_members_info(),
**forwarded_args_with_overrides,
**kwargs,
Expand Down

0 comments on commit 6f83884

Please sign in to comment.