Repository: memgraph/memgraph
Pull request #2770: Bugfix: Avoid throwing in slk when a buffer isn't read fully
Author: login: as51340
Labels: name: bug
description: bug
name: Docs - changelog only
description: Docs - changelog only
name: CI -build=coverage -test=core
description: Run coverage build and core tests on push
Created: 2025-03-06T09:59:00Z | Merged: 2025-03-18T13:30:11Z

slk::Reader would throw before if data from the buffer wouldn't be completely ready. This caused network connections between main and replica to be constantly dying when unnecessary. Now when replica doesn't read all data from the buffer, the exception thrown in the slk part of the code is handled properly, avoiding the connection drop. Additionally, the PR tries to reduce the massive amount of logs produced in HA code when trace log level is used. The PR also improves jepsen's run script so that it doesn't fail when jepsen.log cannot be read. With this fix, we should be able to see at least part of the logs which can also be helpful for debugging. Jepsen tests are also checking whether `There is still leftover data in the SLK stream` exception will be thrown during the execution.


Diff:
diff --git a/src/coordination/data_instance_management_server_handlers.cpp b/src/coordination/data_instance_management_server_handlers.cpp
index da1c1864a8e..d7099832f07 100644
--- a/src/coordination/data_instance_management_server_handlers.cpp
+++ b/src/coordination/data_instance_management_server_handlers.cpp
@@ -88,9 +88,9 @@ void DataInstanceManagementServerHandlers::StateCheckHandler(const replication::
   });
 
   coordination::StateCheckRes const rpc_res{is_replica, uuid, writing_enabled};
-  rpc::SendFinalResponse(rpc_res, res_builder);
-  spdlog::info("State check returned: is_replica = {}, uuid = {}, writing_enabled = {}", is_replica,
-               uuid.has_value() ? std::string{*uuid} : "", writing_enabled);
+  rpc::SendFinalResponse(rpc_res, res_builder,
+                         fmt::format("is_replica = {}, uuid = {}, writing_enabled = {}", is_replica,
+                                     uuid.has_value() ? std::string{*uuid} : "", writing_enabled));
 }
 
 void DataInstanceManagementServerHandlers::GetDatabaseHistoriesHandler(
@@ -98,7 +98,6 @@ void DataInstanceManagementServerHandlers::GetDatabaseHistoriesHandler(
     slk::Builder *res_builder) {
   coordination::GetDatabaseHistoriesRes const rpc_res{replication_handler.GetDatabasesHistories()};
   rpc::SendFinalResponse(rpc_res, res_builder);
-  spdlog::info("Database's history returned successfully.");
 }
 
 void DataInstanceManagementServerHandlers::SwapMainUUIDHandler(replication::ReplicationHandler &replication_handler,
diff --git a/src/dbms/inmemory/replication_handlers.cpp b/src/dbms/inmemory/replication_handlers.cpp
index 55687661c91..7ea9aa7d590 100644
--- a/src/dbms/inmemory/replication_handlers.cpp
+++ b/src/dbms/inmemory/replication_handlers.cpp
@@ -30,7 +30,6 @@
 #include <range/v3/view/filter.hpp>
 #include <range/v3/view/transform.hpp>
 
-using memgraph::replication_coordination_glue::ReplicationRole;
 using memgraph::storage::Delta;
 using memgraph::storage::EdgeAccessor;
 using memgraph::storage::EdgeRef;
@@ -296,8 +295,8 @@ void InMemoryReplicationHandlers::AppendDeltasHandler(dbms::DbmsHandler *dbms_ha
     return;
   }
 
+  // Read at the beginning so that SLK stream gets cleared even when the request is invalid
   storage::replication::Decoder decoder(req_reader);
-
   auto maybe_epoch_id = decoder.ReadString();
   if (!maybe_epoch_id) {
     spdlog::error("Invalid replication message, couldn't read epoch id.");
@@ -309,8 +308,8 @@ void InMemoryReplicationHandlers::AppendDeltasHandler(dbms::DbmsHandler *dbms_ha
   auto *storage = static_cast<storage::InMemoryStorage *>(db_acc->get()->storage());
   auto &repl_storage_state = storage->repl_storage_state_;
   if (*maybe_epoch_id != repl_storage_state.epoch_.id()) {
-    spdlog::trace("Set epoch id to {} in AppendDeltasHandler for db {}.", *maybe_epoch_id, storage->name());
     auto prev_epoch = repl_storage_state.epoch_.SetEpoch(*maybe_epoch_id);
+    spdlog::trace("Set epoch to {} for db {}", *maybe_epoch_id, storage->name());
     repl_storage_state.AddEpochToHistoryForce(prev_epoch);
   }
 
@@ -439,6 +438,7 @@ void InMemoryReplicationHandlers::SnapshotHandler(DbmsHandler *dbms_handler,
       // If this step is present it should always be the first step of
       // the recovery so we use the UUID we read from snapshot
       storage->uuid().set(snapshot_info.uuid);
+      spdlog::trace("Set epoch to {} for db {}", snapshot_info.epoch_id, storage->name());
       storage->repl_storage_state_.epoch_.SetEpoch(std::move(snapshot_info.epoch_id));
       storage->vertex_id_ = recovery_info.next_vertex_id;
       storage->edge_id_ = recovery_info.next_edge_id;
@@ -677,7 +677,7 @@ std::pair<bool, uint32_t> InMemoryReplicationHandlers::LoadWal(storage::InMemory
     }
     // We trust only WAL files which contain changes we are interested in (newer changes)
     if (auto &replica_epoch = storage->repl_storage_state_.epoch_; wal_info.epoch_id != replica_epoch.id()) {
-      spdlog::trace("Set epoch id to {} while loading wal file {}.", wal_info.epoch_id, *maybe_wal_path);
+      spdlog::trace("Set epoch to {} for db {}", wal_info.epoch_id, storage->name());
       auto prev_epoch = replica_epoch.SetEpoch(wal_info.epoch_id);
       storage->repl_storage_state_.AddEpochToHistoryForce(prev_epoch);
     }
@@ -784,7 +784,11 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
   uint64_t applied_deltas = 0;     // Non-skipped deltas
   uint32_t current_batch_counter = start_batch_counter;
   auto max_delta_timestamp = storage->repl_storage_state_.last_durable_timestamp_.load();
+
   auto current_durable_commit_timestamp = max_delta_timestamp;
+  spdlog::trace("Current durable commit timestamp: {}", current_durable_commit_timestamp);
+
+  uint64_t prev_printed_timestamp = 0;
 
   for (bool transaction_complete = false; !transaction_complete; ++current_delta_idx, ++current_batch_counter) {
     if (current_batch_counter == kDeltasBatchProgressSize) {
@@ -794,13 +798,17 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
     }
 
     const auto [delta_timestamp, delta] = ReadDelta(decoder, version);
+    if (delta_timestamp != prev_printed_timestamp) {
+      spdlog::trace("Timestamp: {}", delta_timestamp);
+      prev_printed_timestamp = delta_timestamp;
+    }
+
     max_delta_timestamp = std::max(max_delta_timestamp, delta_timestamp);
 
     transaction_complete = IsWalDeltaDataTransactionEnd(delta, version);
 
     if (delta_timestamp <= current_durable_commit_timestamp) {
-      spdlog::trace("Skipping delta with timestamp: {}, current durable commit timestamp: {}", delta_timestamp,
-                    current_durable_commit_timestamp);
+      spdlog::trace("Skipping delta with timestamp: {}", delta_timestamp);
       continue;
     }
 
@@ -809,7 +817,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
     auto delta_apply = utils::Overloaded{
         [&](WalVertexCreate const &data) {
           auto const gid = data.gid.AsUint();
-          spdlog::trace("       Create vertex {}", gid);
+          spdlog::trace("  Delta {}. Create vertex {}", current_delta_idx, gid);
           auto *transaction = get_replication_accessor(delta_timestamp);
           if (!transaction->CreateVertexEx(data.gid).has_value()) {
             throw utils::BasicException("Vertex with gid {} already exists at replica.", gid);
@@ -817,7 +825,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
         },
         [&](WalVertexDelete const &data) {
           auto const gid = data.gid.AsUint();
-          spdlog::trace("       Delete vertex {}", gid);
+          spdlog::trace("  Delta {}. Delete vertex {}", current_delta_idx, gid);
           auto *transaction = get_replication_accessor(delta_timestamp);
           auto vertex = transaction->FindVertex(data.gid, View::NEW);
           if (!vertex) {
@@ -830,7 +838,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
         },
         [&](WalVertexAddLabel const &data) {
           auto const gid = data.gid.AsUint();
-          spdlog::trace("       Vertex {} add label {}", gid, data.label);
+          spdlog::trace("   Delta {}. Vertex {} add label {}", current_delta_idx, gid, data.label);
           auto *transaction = get_replication_accessor(delta_timestamp);
           auto vertex = transaction->FindVertex(data.gid, View::NEW);
           if (!vertex) {
@@ -844,7 +852,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
         },
         [&](WalVertexRemoveLabel const &data) {
           auto const gid = data.gid.AsUint();
-          spdlog::trace("       Vertex {} remove label {}", gid, data.label);
+          spdlog::trace("   Delta {}. Vertex {} remove label {}", current_delta_idx, gid, data.label);
           auto *transaction = get_replication_accessor(delta_timestamp);
           auto vertex = transaction->FindVertex(data.gid, View::NEW);
           if (!vertex) throw utils::BasicException("Failed to find vertex {} when removing label.", gid);
@@ -856,7 +864,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
         },
         [&](WalVertexSetProperty const &data) {
           auto const gid = data.gid.AsUint();
-          spdlog::trace("       Vertex {} set property", gid);
+          spdlog::trace("   Delta {}. Vertex {} set property", current_delta_idx, gid);
           // NOLINTNEXTLINE
           auto *transaction = get_replication_accessor(delta_timestamp);
           // NOLINTNEXTLINE
@@ -874,8 +882,8 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           auto const edge_gid = data.gid.AsUint();
           auto const from_vertex_gid = data.from_vertex.AsUint();
           auto const to_vertex_gid = data.to_vertex.AsUint();
-          spdlog::trace("       Create edge {} of type {} from vertex {} to vertex {}", edge_gid, data.edge_type,
-                        from_vertex_gid, to_vertex_gid);
+          spdlog::trace("   Delta {}. Create edge {} of type {} from vertex {} to vertex {}", current_delta_idx,
+                        edge_gid, data.edge_type, from_vertex_gid, to_vertex_gid);
           auto *transaction = get_replication_accessor(delta_timestamp);
           auto from_vertex = transaction->FindVertex(data.from_vertex, View::NEW);
           if (!from_vertex) {
@@ -896,8 +904,8 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           auto const edge_gid = data.gid.AsUint();
           auto const from_vertex_gid = data.from_vertex.AsUint();
           auto const to_vertex_gid = data.to_vertex.AsUint();
-          spdlog::trace("       Delete edge {} of type {} from vertex {} to vertex {}", edge_gid, data.edge_type,
-                        from_vertex_gid, to_vertex_gid);
+          spdlog::trace("   Delta {}. Delete edge {} of type {} from vertex {} to vertex {}", current_delta_idx,
+                        edge_gid, data.edge_type, from_vertex_gid, to_vertex_gid);
           auto *transaction = get_replication_accessor(delta_timestamp);
           auto from_vertex = transaction->FindVertex(data.from_vertex, View::NEW);
           if (!from_vertex) {
@@ -919,7 +927,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
         },
         [&](WalEdgeSetProperty const &data) {
           auto const edge_gid = data.gid.AsUint();
-          spdlog::trace(" Edge {} set property", edge_gid);
+          spdlog::trace("   Delta {}. Edge {} set property", current_delta_idx, edge_gid);
           if (!storage->config_.salient.items.properties_on_edges)
             throw utils::BasicException(
                 "Can't set properties on edges because properties on edges "
@@ -1009,7 +1017,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalTransactionEnd const &) {
-          spdlog::trace("       Transaction end");
+          spdlog::trace("   Delta {}. Transaction end", current_delta_idx);
           if (!commit_timestamp_and_accessor || commit_timestamp_and_accessor->first != delta_timestamp)
             throw utils::BasicException("Invalid commit data!");
           auto ret = commit_timestamp_and_accessor->second.Commit(
@@ -1018,20 +1026,20 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           commit_timestamp_and_accessor = std::nullopt;
         },
         [&](WalLabelIndexCreate const &data) {
-          spdlog::trace("       Create label index on :{}", data.label);
+          spdlog::trace("   Delta {}. Create label index on :{}", current_delta_idx, data.label);
           // Need to send the timestamp
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           if (transaction->CreateIndex(storage->NameToLabel(data.label)).HasError())
             throw utils::BasicException("Failed to create label index on :{}.", data.label);
         },
         [&](WalLabelIndexDrop const &data) {
-          spdlog::trace("       Drop label index on :{}", data.label);
+          spdlog::trace("   Delta {}. Drop label index on :{}", current_delta_idx, data.label);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           if (transaction->DropIndex(storage->NameToLabel(data.label)).HasError())
             throw utils::BasicException("Failed to drop label index on :{}.", data.label);
         },
         [&](WalLabelIndexStatsSet const &data) {
-          spdlog::trace("       Set label index statistics on :{}", data.label);
+          spdlog::trace("   Delta {}. Set label index statistics on :{}", current_delta_idx, data.label);
           // Need to send the timestamp
           auto *transaction = get_replication_accessor(delta_timestamp);
           const auto label = storage->NameToLabel(data.label);
@@ -1042,7 +1050,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           transaction->SetIndexStats(label, stats);
         },
         [&](WalLabelIndexStatsClear const &data) {
-          spdlog::trace("       Clear label index statistics on :{}", data.label);
+          spdlog::trace("   Delta {}. Clear label index statistics on :{}", current_delta_idx, data.label);
           // Need to send the timestamp
           auto *transaction = get_replication_accessor(delta_timestamp);
           if (!transaction->DeleteLabelIndexStats(storage->NameToLabel(data.label))) {
@@ -1050,7 +1058,8 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalLabelPropertyIndexCreate const &data) {
-          spdlog::trace("       Create label+property index on :{} ({})", data.label, data.property);
+          spdlog::trace("   Delta {}. Create label+property index on :{} ({})", current_delta_idx, data.label,
+                        data.property);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           if (transaction->CreateIndex(storage->NameToLabel(data.label), storage->NameToProperty(data.property))
                   .HasError())
@@ -1058,7 +1067,8 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
                                         data.property);
         },
         [&](WalLabelPropertyIndexDrop const &data) {
-          spdlog::trace("       Drop label+property index on :{} ({})", data.label, data.property);
+          spdlog::trace("   Delta {}. Drop label+property index on :{} ({})", current_delta_idx, data.label,
+                        data.property);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           if (transaction->DropIndex(storage->NameToLabel(data.label), storage->NameToProperty(data.property))
                   .HasError()) {
@@ -1066,7 +1076,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalLabelPropertyIndexStatsSet const &data) {
-          spdlog::trace("       Set label-property index statistics on :{}", data.label);
+          spdlog::trace("   Delta {}. Set label-property index statistics on :{}", current_delta_idx, data.label);
           // Need to send the timestamp
           auto *transaction = get_replication_accessor(delta_timestamp);
           const auto label = storage->NameToLabel(data.label);
@@ -1078,27 +1088,27 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           transaction->SetIndexStats(label, property, stats);
         },
         [&](WalLabelPropertyIndexStatsClear const &data) {
-          spdlog::trace("       Clear label-property index statistics on :{}", data.label);
+          spdlog::trace("   Delta {}. Clear label-property index statistics on :{}", current_delta_idx, data.label);
           // Need to send the timestamp
           auto *transaction = get_replication_accessor(delta_timestamp);
           transaction->DeleteLabelPropertyIndexStats(storage->NameToLabel(data.label));
         },
         [&](WalEdgeTypeIndexCreate const &data) {
-          spdlog::trace("       Create edge index on :{}", data.edge_type);
+          spdlog::trace("   Delta {}. Create edge index on :{}", current_delta_idx, data.edge_type);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           if (transaction->CreateIndex(storage->NameToEdgeType(data.edge_type)).HasError()) {
             throw utils::BasicException("Failed to create edge index on :{}.", data.edge_type);
           }
         },
         [&](WalEdgeTypeIndexDrop const &data) {
-          spdlog::trace("       Drop edge index on :{}", data.edge_type);
+          spdlog::trace("   Delta {}. Drop edge index on :{}", current_delta_idx, data.edge_type);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           if (transaction->DropIndex(storage->NameToEdgeType(data.edge_type)).HasError()) {
             throw utils::BasicException("Failed to drop edge index on :{}.", data.edge_type);
           }
         },
         [&](WalEdgeTypePropertyIndexCreate const &data) {
-          spdlog::trace("       Create edge index on :{}({})", data.edge_type, data.property);
+          spdlog::trace("   Delta {}. Create edge index on :{}({})", current_delta_idx, data.edge_type, data.property);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           if (transaction->CreateIndex(storage->NameToEdgeType(data.edge_type), storage->NameToProperty(data.property))
                   .HasError()) {
@@ -1107,7 +1117,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalEdgeTypePropertyIndexDrop const &data) {
-          spdlog::trace("       Drop edge index on :{}({})", data.edge_type, data.property);
+          spdlog::trace("   Delta {}. Drop edge index on :{}({})", current_delta_idx, data.edge_type, data.property);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           if (transaction->DropIndex(storage->NameToEdgeType(data.edge_type), storage->NameToProperty(data.property))
                   .HasError()) {
@@ -1122,7 +1132,8 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           /* NOTE: Text search doesn’t have replication in scope yet (Phases 1 and 2)*/
         },
         [&](WalExistenceConstraintCreate const &data) {
-          spdlog::trace("       Create existence constraint on :{} ({})", data.label, data.property);
+          spdlog::trace("   Delta {}. Create existence constraint on :{} ({})", current_delta_idx, data.label,
+                        data.property);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           auto ret = transaction->CreateExistenceConstraint(storage->NameToLabel(data.label),
                                                             storage->NameToProperty(data.property));
@@ -1132,7 +1143,8 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalExistenceConstraintDrop const &data) {
-          spdlog::trace("       Drop existence constraint on :{} ({})", data.label, data.property);
+          spdlog::trace("   Delta {}. Drop existence constraint on :{} ({})", current_delta_idx, data.label,
+                        data.property);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           if (transaction
                   ->DropExistenceConstraint(storage->NameToLabel(data.label), storage->NameToProperty(data.property))
@@ -1143,7 +1155,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
         [&](WalUniqueConstraintCreate const &data) {
           std::stringstream ss;
           utils::PrintIterable(ss, data.properties);
-          spdlog::trace("       Create unique constraint on :{} ({})", data.label, ss.str());
+          spdlog::trace("   Delta {}. Create unique constraint on :{} ({})", current_delta_idx, data.label, ss.str());
           std::set<PropertyId> properties;
           for (const auto &prop : data.properties) {
             properties.emplace(storage->NameToProperty(prop));
@@ -1157,7 +1169,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
         [&](WalUniqueConstraintDrop const &data) {
           std::stringstream ss;
           utils::PrintIterable(ss, data.properties);
-          spdlog::trace("       Drop unique constraint on :{} ({})", data.label, ss.str());
+          spdlog::trace("   Delta {}. Drop unique constraint on :{} ({})", current_delta_idx, data.label, ss.str());
           std::set<PropertyId> properties;
           for (const auto &prop : data.properties) {
             properties.emplace(storage->NameToProperty(prop));
@@ -1169,7 +1181,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalTypeConstraintCreate const &data) {
-          spdlog::trace("       Create IS TYPED {} constraint on :{} ({})",
+          spdlog::trace("   Delta {}. Create IS TYPED {} constraint on :{} ({})", current_delta_idx,
                         storage::TypeConstraintKindToString(data.kind), data.label, data.property);
 
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
@@ -1181,8 +1193,8 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalTypeConstraintDrop const &data) {
-          spdlog::trace("       Drop IS TYPED {} constraint on :{} ({})", TypeConstraintKindToString(data.kind),
-                        data.label, data.property);
+          spdlog::trace("   Delta {}. Drop IS TYPED {} constraint on :{} ({})", current_delta_idx,
+                        TypeConstraintKindToString(data.kind), data.label, data.property);
 
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           auto ret = transaction->DropTypeConstraint(storage->NameToLabel(data.label),
@@ -1195,7 +1207,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
         [&](WalEnumCreate const &data) {
           std::stringstream ss;
           utils::PrintIterable(ss, data.evalues);
-          spdlog::trace("       Create enum {} with values {}", data.etype, ss.str());
+          spdlog::trace("   Delta {}. Create enum {} with values {}", current_delta_idx, data.etype, ss.str());
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           auto res = transaction->CreateEnum(data.etype, data.evalues);
           if (res.HasError()) {
@@ -1203,7 +1215,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalEnumAlterAdd const &data) {
-          spdlog::trace("       Alter enum {} add value {}", data.etype, data.evalue);
+          spdlog::trace("   Delta {}. Alter enum {} add value {}", current_delta_idx, data.etype, data.evalue);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           auto res = transaction->EnumAlterAdd(data.etype, data.evalue);
           if (res.HasError()) {
@@ -1211,7 +1223,8 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalEnumAlterUpdate const &data) {
-          spdlog::trace("       Alter enum {} update {} to {}", data.etype, data.evalue_old, data.evalue_new);
+          spdlog::trace("   Delta {}. Alter enum {} update {} to {}", current_delta_idx, data.etype, data.evalue_old,
+                        data.evalue_new);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           auto res = transaction->EnumAlterUpdate(data.etype, data.evalue_old, data.evalue_new);
           if (res.HasError()) {
@@ -1220,7 +1233,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalPointIndexCreate const &data) {
-          spdlog::trace("       Create point index on :{}({})", data.label, data.property);
+          spdlog::trace("   Delta {}. Create point index on :{}({})", current_delta_idx, data.label, data.property);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           auto labelId = storage->NameToLabel(data.label);
           auto propId = storage->NameToProperty(data.property);
@@ -1230,7 +1243,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalPointIndexDrop const &data) {
-          spdlog::trace("       Drop point index on :{}({})", data.label, data.property);
+          spdlog::trace("   Delta {}. Drop point index on :{}({})", current_delta_idx, data.label, data.property);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           auto labelId = storage->NameToLabel(data.label);
           auto propId = storage->NameToProperty(data.property);
@@ -1240,7 +1253,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalVectorIndexCreate const &data) {
-          spdlog::trace("       Create vector index on :{}({})", data.label, data.property);
+          spdlog::trace("   Delta {}. Create vector index on :{}({})", current_delta_idx, data.label, data.property);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           auto labelId = storage->NameToLabel(data.label);
           auto propId = storage->NameToProperty(data.property);
@@ -1260,7 +1273,7 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
           }
         },
         [&](WalVectorIndexDrop const &data) {
-          spdlog::trace("       Drop vector index {} ", data.index_name);
+          spdlog::trace("   Delta {}. Drop vector index {} ", current_delta_idx, data.index_name);
           auto *transaction = get_replication_accessor(delta_timestamp, kUniqueAccess);
           auto res = transaction->DropVectorIndex(data.index_name);
           if (res.HasError()) {
@@ -1269,7 +1282,6 @@ std::pair<uint64_t, uint32_t> InMemoryReplicationHandlers::ReadAndApplyDeltasSin
         },
     };
 
-    spdlog::trace("  Delta {}", current_delta_idx);
     std::visit(delta_apply, delta.data_);
     applied_deltas++;
   }
diff --git a/src/io/network/endpoint.cpp b/src/io/network/endpoint.cpp
index b017d9c5ba7..bb29222e1d1 100644
--- a/src/io/network/endpoint.cpp
+++ b/src/io/network/endpoint.cpp
@@ -14,7 +14,6 @@
 #include <cstdint>
 #include <limits>
 #include <optional>
-#include <ostream>
 #include <string>
 #include <string_view>
 #include <tuple>
@@ -51,7 +50,6 @@ auto Endpoint::GetResolvedSocketAddress() const -> std::string {
 
   auto resolved_address = std::get<0>(*result);
   auto resolved_port = std::get<1>(*result);
-  spdlog::trace("{}:{} successfully resolved to {}:{}.", address_, port_, resolved_address, resolved_port);
 
   return fmt::format("{}{}{}", resolved_address, delimiter, resolved_port);
 }
@@ -63,7 +61,6 @@ auto Endpoint::GetResolvedIPAddress() const -> std::string {
   }
 
   auto resolved_address = std::get<0>(*result);
-  spdlog::trace("{}:{} successfully resolved to {}:{}.", address_, port_, resolved_address, port_);
 
   return resolved_address;
 }
diff --git a/src/replication/include/replication/epoch.hpp b/src/replication/include/replication/epoch.hpp
index 2bde13d7082..5d749714b1d 100644
--- a/src/replication/include/replication/epoch.hpp
+++ b/src/replication/include/replication/epoch.hpp
@@ -1,4 +1,4 @@
-// Copyright 2024 Memgraph Ltd.
+// Copyright 2025 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -15,6 +15,8 @@
 
 #include "utils/uuid.hpp"
 
+#include <spdlog/spdlog.h>
+
 namespace memgraph::replication {
 
 struct ReplicationEpoch {
diff --git a/src/replication/status.cpp b/src/replication/status.cpp
index 35d165c3833..90abfee7189 100644
--- a/src/replication/status.cpp
+++ b/src/replication/status.cpp
@@ -1,4 +1,4 @@
-// Copyright 2024 Memgraph Ltd.
+// Copyright 2025 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -64,7 +64,10 @@ void from_json(const nlohmann::json &j, ReplicationRoleEntry &p) {
     case replication_coordination_glue::ReplicationRole::MAIN: {
       auto json_epoch = j.value(kEpoch, std::string{});
       auto epoch = ReplicationEpoch{};
-      if (!json_epoch.empty()) epoch.SetEpoch(json_epoch);
+      if (!json_epoch.empty()) {
+        epoch.SetEpoch(json_epoch);
+        spdlog::trace("Restored epoch to {}", json_epoch);
+      }
       auto main_role = MainRole{.epoch = std::move(epoch)};
 
       if (j.contains(kMainUUID)) {
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index 816369aff93..869554ae5cc 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -80,13 +80,13 @@ void Session::Execute() {
   spdlog::trace("[RpcServer] received {}", it->second.req_type.name);
   try {
     it->second.callback(&req_reader, &res_builder);
+    // Finalize the SLK stream. It may fail because not all data has been read, that's fine.
+    req_reader.Finalize();
   } catch (const slk::SlkReaderException &e) {
     spdlog::error("Error occurred in the callback: {}", e.what());
     throw rpc::SlkRpcFailedException();
+  } catch (const slk::SlkReaderLeftoverDataException &) {
   }
-
-  // Finalize the SLK streams.
-  req_reader.Finalize();
 }
 
 }  // namespace memgraph::rpc
diff --git a/src/slk/streams.cpp b/src/slk/streams.cpp
index 2db0f2c883b..6007ac8eeca 100644
--- a/src/slk/streams.cpp
+++ b/src/slk/streams.cpp
@@ -83,7 +83,7 @@ void Reader::Finalize() { GetSegment(true); }
 void Reader::GetSegment(bool should_be_final) {
   if (have_ != 0) {
     if (should_be_final) {
-      throw SlkReaderException("There is still leftover data in the SLK stream!");
+      throw SlkReaderLeftoverDataException("There is still leftover data in the SLK stream!");
     }
     return;
   }
diff --git a/src/slk/streams.hpp b/src/slk/streams.hpp
index e2fff3c9bac..83c37340188 100644
--- a/src/slk/streams.hpp
+++ b/src/slk/streams.hpp
@@ -82,6 +82,12 @@ class SlkReaderException : public utils::BasicException {
   SPECIALIZE_GET_EXCEPTION_NAME(SlkReaderException)
 };
 
+class SlkReaderLeftoverDataException : public utils::BasicException {
+ public:
+  using utils::BasicException::BasicException;
+  SPECIALIZE_GET_EXCEPTION_NAME(SlkReaderLeftoverDataException)
+};
+
 /// Reader used to read data from a SLK segment stream.
 class Reader {
  public:
diff --git a/src/storage/v2/durability/durability.cpp b/src/storage/v2/durability/durability.cpp
index 4c6f5342396..a5af3b056e9 100644
--- a/src/storage/v2/durability/durability.cpp
+++ b/src/storage/v2/durability/durability.cpp
@@ -413,7 +413,8 @@ std::optional<RecoveryInfo> Recovery::RecoverData(
     utils::SkipList<Edge> *edges, utils::SkipList<EdgeMetadata> *edges_metadata, std::atomic<uint64_t> *edge_count,
     NameIdMapper *name_id_mapper, Indices *indices, Constraints *constraints, Config const &config,
     uint64_t *wal_seq_num, EnumStore *enum_store, SharedSchemaTracking *schema_info,
-    std::function<std::optional<std::tuple<EdgeRef, EdgeTypeId, Vertex *, Vertex *>>(Gid)> find_edge) {
+    std::function<std::optional<std::tuple<EdgeRef, EdgeTypeId, Vertex *, Vertex *>>(Gid)> find_edge,
+    std::string const &db_name) {
   utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
   spdlog::info("Recovering persisted data using snapshot ({}) and WAL directory ({}).", snapshot_directory_,
                wal_directory_);
@@ -465,10 +466,11 @@ std::optional<RecoveryInfo> Recovery::RecoverData(
     recovery_info = recovered_snapshot->recovery_info;
     indices_constraints = std::move(recovered_snapshot->indices_constraints);
     snapshot_timestamp = recovered_snapshot->snapshot_info.durable_timestamp;
+    spdlog::trace("Recovered epoch {} for db {}", recovered_snapshot->snapshot_info.epoch_id, db_name);
     repl_storage_state.epoch_.SetEpoch(std::move(recovered_snapshot->snapshot_info.epoch_id));
     recovery_info.last_durable_timestamp = snapshot_timestamp;
   } else {
-    // UUID couldn't be recovered from the snapshot; recoverying it from WALs
+    // UUID couldn't be recovered from the snapshot; recovering it from WALs
     spdlog::info("No snapshot file was found, collecting information from WAL directory {}.", wal_directory_);
     std::error_code error_code;
     if (!utils::DirExists(wal_directory_)) return std::nullopt;
@@ -581,6 +583,7 @@ std::optional<RecoveryInfo> Recovery::RecoverData(
           // no history or new epoch, add it
           epoch_history->emplace_back(wal_file.epoch_id, last_loaded_timestamp_value);
           repl_storage_state.epoch_.SetEpoch(wal_file.epoch_id);
+          spdlog::trace("Set epoch to {} for db {}", wal_file.epoch_id, db_name);
         } else if (epoch_history->back().second < last_loaded_timestamp_value) {
           // existing epoch, update with newer timestamp
           epoch_history->back().second = last_loaded_timestamp_value;
diff --git a/src/storage/v2/durability/durability.hpp b/src/storage/v2/durability/durability.hpp
index 6cdb7af242a..e1aa0adf75e 100644
--- a/src/storage/v2/durability/durability.hpp
+++ b/src/storage/v2/durability/durability.hpp
@@ -146,7 +146,8 @@ struct Recovery {
       utils::SkipList<Edge> *edges, utils::SkipList<EdgeMetadata> *edges_metadata, std::atomic<uint64_t> *edge_count,
       NameIdMapper *name_id_mapper, Indices *indices, Constraints *constraints, Config const &config,
       uint64_t *wal_seq_num, EnumStore *enum_store, SharedSchemaTracking *schema_info,
-      std::function<std::optional<std::tuple<EdgeRef, EdgeTypeId, Vertex *, Vertex *>>(Gid)> find_edge);
+      std::function<std::optional<std::tuple<EdgeRef, EdgeTypeId, Vertex *, Vertex *>>(Gid)> find_edge,
+      std::string const &db_name);
 
   const std::filesystem::path snapshot_directory_;
   const std::filesystem::path wal_directory_;
diff --git a/src/storage/v2/inmemory/storage.cpp b/src/storage/v2/inmemory/storage.cpp
index de3b1856bde..b7e700d4d99 100644
--- a/src/storage/v2/inmemory/storage.cpp
+++ b/src/storage/v2/inmemory/storage.cpp
@@ -179,11 +179,11 @@ InMemoryStorage::InMemoryStorage(Config config, std::optional<free_mem_fn> free_
   }
 
   if (config_.durability.recover_on_startup) {
-    auto info =
-        recovery_.RecoverData(uuid(), repl_storage_state_, &vertices_, &edges_, &edges_metadata_, &edge_count_,
-                              name_id_mapper_.get(), &indices_, &constraints_, config_, &wal_seq_num_, &enum_store_,
-                              config_.salient.items.enable_schema_info ? &schema_info_.Get() : nullptr,
-                              [this](Gid edge_gid) { return FindEdge(edge_gid); });
+    auto info = recovery_.RecoverData(
+        uuid(), repl_storage_state_, &vertices_, &edges_, &edges_metadata_, &edge_count_, name_id_mapper_.get(),
+        &indices_, &constraints_, config_, &wal_seq_num_, &enum_store_,
+        config_.salient.items.enable_schema_info ? &schema_info_.Get() : nullptr,
+        [this](Gid edge_gid) { return FindEdge(edge_gid); }, name());
     if (info) {
       vertex_id_ = info->next_vertex_id;
       edge_id_ = info->next_edge_id;
@@ -2620,6 +2620,7 @@ utils::BasicResult<InMemoryStorage::RecoverSnapshotError> InMemoryStorage::Recov
         &edge_count_, config_, &enum_store_, config_.salient.items.enable_schema_info ? &schema_info_.Get() : nullptr);
     spdlog::debug("Snapshot recovered successfully");
     uuid().set(recovered_snapshot.snapshot_info.uuid);
+    spdlog::trace("Set epoch to {} for db {}", recovered_snapshot.snapshot_info.epoch_id, name());
     repl_storage_state_.epoch_.SetEpoch(std::move(recovered_snapshot.snapshot_info.epoch_id));
     const auto &recovery_info = recovered_snapshot.recovery_info;
     vertex_id_ = recovery_info.next_vertex_id;
diff --git a/src/storage/v2/replication/replication_client.cpp b/src/storage/v2/replication/replication_client.cpp
index 0a4a90b7986..77394f56fa2 100644
--- a/src/storage/v2/replication/replication_client.cpp
+++ b/src/storage/v2/replication/replication_client.cpp
@@ -168,8 +168,8 @@ void ReplicationStorageClient::UpdateReplicaState(Storage *main_storage, Databas
   auto engine_lock = std::unique_lock{main_storage->engine_lock_};
   spdlog::trace("Current timestamp on replica {} for db {} is {}.", client_.name_, main_db_name,
                 heartbeat_res.current_commit_timestamp);
-  spdlog::trace("Current timestamp on main for db {} is {}. Current durable timestamp on main for db {} is {}",
-                main_db_name, main_storage->timestamp_, main_db_name, replStorageState.last_durable_timestamp_.load());
+  spdlog::trace("Current durable timestamp on main for db {} is {}", main_db_name,
+                replStorageState.last_durable_timestamp_.load());
 
   replica_state_.WithLock([&](auto &state) {
     // Recovered state didn't change in the meantime
diff --git a/src/utils/uuid.hpp b/src/utils/uuid.hpp
index 9c2df055fb8..68458d0b7c6 100644
--- a/src/utils/uuid.hpp
+++ b/src/utils/uuid.hpp
@@ -16,6 +16,7 @@
 #include "fmt/format.h"
 
 #include <array>
+// NOLINTNEXTLINE
 #include <nlohmann/json.hpp>
 #include <string>
 
diff --git a/tests/jepsen/run.sh b/tests/jepsen/run.sh
index 77f8d05decb..ae17121b986 100755
--- a/tests/jepsen/run.sh
+++ b/tests/jepsen/run.sh
@@ -191,9 +191,18 @@ PROCESS_RESULTS() {
     all_workloads=$(docker exec jepsen-control bash -c 'ls /jepsen/memgraph/store/' | grep test-)
     all_workload_run_folders=""
     for workload in $all_workloads; do
-        INFO "jepsen.log for $workload/latest"
-        docker exec jepsen-control bash -c "tail -n 50 /jepsen/memgraph/store/$workload/latest/jepsen.log"
-        all_workload_run_folders="$all_workload_run_folders /jepsen/memgraph/store/$workload/latest"
+      workload_dir="/jepsen/memgraph/store/$workload/latest"
+      # Construct the full path of jepsen.log
+      log_file_path="$workload_dir/jepsen.log"
+      # Check if the directory exists before proceeding
+      if docker exec jepsen-control bash -c "[ -d '$workload_dir' ]"; then
+        INFO "Checking jepsen.log for $workload/latest"
+        # Execute the existence check and tail command in the same subshell to avoid context errors
+        docker exec jepsen-control bash -c "if [ -f '$log_file_path' ]; then tail -n 50 '$log_file_path'; else echo 'jepsen.log does not exist for $workload'; fi"
+        all_workload_run_folders="$all_workload_run_folders $workload_dir"
+      else
+        INFO "$workload_dir does not exist."
+      fi
     done
     INFO "Packing results..."
     docker exec jepsen-control bash -c "tar --ignore-failed-read -czvf /jepsen/memgraph/Jepsen.tar.gz -h $all_workload_run_folders"
diff --git a/tests/jepsen/src/memgraph/core.clj b/tests/jepsen/src/memgraph/core.clj
index c72eb08b78b..cb11d4aa342 100644
--- a/tests/jepsen/src/memgraph/core.clj
+++ b/tests/jepsen/src/memgraph/core.clj
@@ -93,7 +93,7 @@
             :checker         (checker/compose
                               {:stats      (checker/stats)
                                :exceptions (unhandled-exceptions)
-                               :log-checker (checker/log-file-pattern #"[Aa]ssert*|Segmentation fault|core dumped|critical|NullPointerException|json.exception.parse_error|Message response was of unexpected type|Received malformed message from cluster" "memgraph.log")
+                               :log-checker (checker/log-file-pattern #"[Aa]ssert*|Segmentation fault|core dumped|critical|NullPointerException|json.exception.parse_error|Message response was of unexpected type|Received malformed message from cluster|There is still leftover data in the SLK stream" "memgraph.log")
                                :workload   (:checker workload)})
             :nodes           (keys (:nodes-config opts))
             :nemesis         (:nemesis nemesis-config)
diff --git a/tests/unit/slk_streams.cpp b/tests/unit/slk_streams.cpp
index 8a673af1c9f..c6e8e22b623 100644
--- a/tests/unit/slk_streams.cpp
+++ b/tests/unit/slk_streams.cpp
@@ -1,4 +1,4 @@
-// Copyright 2023 Memgraph Ltd.
+// Copyright 2025 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -191,7 +191,7 @@ TEST(Reader, SingleSegment) {
     memgraph::slk::Reader reader(buffer.data(), buffer.size());
     uint8_t block[memgraph::slk::kSegmentMaxDataSize];
     reader.Load(block, input.size() / 2);
-    ASSERT_THROW(reader.Finalize(), memgraph::slk::SlkReaderException);
+    ASSERT_THROW(reader.Finalize(), memgraph::slk::SlkReaderLeftoverDataException);
   }
 
   // read data with several loads
@@ -271,7 +271,7 @@ TEST(Reader, MultipleSegments) {
     memgraph::slk::Reader reader(buffer.data(), buffer.size());
     uint8_t block[memgraph::slk::kSegmentMaxDataSize * 2];
     reader.Load(block, input.size() / 2);
-    ASSERT_THROW(reader.Finalize(), memgraph::slk::SlkReaderException);
+    ASSERT_THROW(reader.Finalize(), memgraph::slk::SlkReaderLeftoverDataException);
   }
 
   // read data with several loads
diff --git a/tests/unit/storage_v2_durability_inmemory.cpp b/tests/unit/storage_v2_durability_inmemory.cpp
index 75fbdb8f587..2679dfce598 100644
--- a/tests/unit/storage_v2_durability_inmemory.cpp
+++ b/tests/unit/storage_v2_durability_inmemory.cpp
@@ -3461,9 +3461,10 @@ TEST_P(DurabilityTest, ConstraintsRecoveryFunctionSetting) {
       config.durability.storage_directory / memgraph::storage::durability::kWalDirectory};
 
   // Recover snapshot.
-  const auto info = recovery.RecoverData(uuid, repl_storage_state, &vertices, &edges, &edges_metadata, &edge_count,
-                                         name_id_mapper.get(), &indices, &constraints, config, &wal_seq_num,
-                                         &enum_store, nullptr /* schema_info */, [](auto in) { return std::nullopt; });
+  const auto info = recovery.RecoverData(
+      uuid, repl_storage_state, &vertices, &edges, &edges_metadata, &edge_count, name_id_mapper.get(), &indices,
+      &constraints, config, &wal_seq_num, &enum_store, nullptr /* schema_info */, [](auto in) { return std::nullopt; },
+      "memgraph");
 
   MG_ASSERT(info.has_value(), "Info doesn't have value present");
   const auto par_exec_info = memgraph::storage::durability::GetParallelExecInfo(*info, config);


Reviews:
user: login: andrejtonev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T13:01:47Z
user: login: as51340
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T13:24:52Z
user: login: andrejtonev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T08:12:23Z
user: login: andrejtonev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T08:15:25Z
user: login: as51340
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T09:12:56Z
user: login: as51340
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T13:12:28Z
user: login: andrejtonev
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T12:07:22Z

Review comments:
diff_hunk: @@ -282,6 +281,10 @@ void InMemoryReplicationHandlers::AppendDeltasHandler(dbms::DbmsHandler *dbms_ha
   storage::replication::AppendDeltasReq req;
   slk::Load(&req, req_reader);
 
+  // Read at the beginning so that SLK stream gets cleared even when the request is invalid
+  storage::replication::Decoder decoder(req_reader);
+  auto maybe_epoch_id = decoder.ReadString();
+
path: src/dbms/inmemory/replication_handlers.cpp
user: login: andrejtonev
body: I guess we need to read the whole message before throwing in every handler, right?
created_at: 2025-03-10T13:01:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -282,6 +281,10 @@ void InMemoryReplicationHandlers::AppendDeltasHandler(dbms::DbmsHandler *dbms_ha
   storage::replication::AppendDeltasReq req;
   slk::Load(&req, req_reader);
 
+  // Read at the beginning so that SLK stream gets cleared even when the request is invalid
+  storage::replication::Decoder decoder(req_reader);
+  auto maybe_epoch_id = decoder.ReadString();
+
path: src/dbms/inmemory/replication_handlers.cpp
user: login: as51340
body: yes
created_at: 2025-03-10T13:24:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -282,6 +281,10 @@ void InMemoryReplicationHandlers::AppendDeltasHandler(dbms::DbmsHandler *dbms_ha
   storage::replication::AppendDeltasReq req;
   slk::Load(&req, req_reader);
 
+  // Read at the beginning so that SLK stream gets cleared even when the request is invalid
+  storage::replication::Decoder decoder(req_reader);
+  auto maybe_epoch_id = decoder.ReadString();
+
path: src/dbms/inmemory/replication_handlers.cpp
user: login: andrejtonev
body: Is this still needed if the try catch has been added?
created_at: 2025-03-13T08:12:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -85,8 +85,11 @@ void Session::Execute() {
     throw rpc::SlkRpcFailedException();
   }
 
-  // Finalize the SLK streams.
-  req_reader.Finalize();
+  // Finalize the SLK stream. It may fail because not all data has been read, that's fine.
+  try {
+    req_reader.Finalize();
+  } catch (const slk::SlkReaderLeftoverDataException &) {
+  }
path: src/rpc/protocol.cpp
user: login: andrejtonev
body: The Finalize can be put inside the previous try block.
created_at: 2025-03-13T08:15:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -282,6 +281,10 @@ void InMemoryReplicationHandlers::AppendDeltasHandler(dbms::DbmsHandler *dbms_ha
   storage::replication::AppendDeltasReq req;
   slk::Load(&req, req_reader);
 
+  // Read at the beginning so that SLK stream gets cleared even when the request is invalid
+  storage::replication::Decoder decoder(req_reader);
+  auto maybe_epoch_id = decoder.ReadString();
+
path: src/dbms/inmemory/replication_handlers.cpp
user: login: as51340
body: no, will revert
created_at: 2025-03-13T09:12:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -85,8 +85,11 @@ void Session::Execute() {
     throw rpc::SlkRpcFailedException();
   }
 
-  // Finalize the SLK streams.
-  req_reader.Finalize();
+  // Finalize the SLK stream. It may fail because not all data has been read, that's fine.
+  try {
+    req_reader.Finalize();
+  } catch (const slk::SlkReaderLeftoverDataException &) {
+  }
path: src/rpc/protocol.cpp
user: login: as51340
body: yep

created_at: 2025-03-13T13:12:28Z
author_association: CONTRIBUTOR

PR comments:
user: login: as51340
created_at: 2025-03-06T09:59:08Z
body: ### Tracking
- [x] **[Link to Epic/Issue](https://github.com/memgraph/memgraph/issues/2771)**


### Standard development
- [ ] Update unit/E2E tests
- [ ] Compare the [benchmarking results](https://bench-graph.memgraph.com/) between the master branch this branch


### CI Testing Labels
- [x] Select the appropriate CI test labels _(CI -build=**build-name** -test=**test-suite**)_


### Documentation checklist
- [x] Add the documentation label
- [x] Add the bug / feature label
- [x] Add the milestone for which this feature is intended
    - If not known, set for a later milestone
- [x] Write a release note, including added/changed clauses
    - **Bugfix: Serialization reader would throw before if data from the buffer wouldn't be ready fully. This caused network connections between main and replica to be constantly dying when unnecessary. Now when replica doesn't read all data from the buffer, the exception thrown in the slk part of the code is handled properly, avoiding the connection drop. Additionally, the PR tries to reduce the massive amount of logs produced in HA code when trace log level is used, [#2770](https://github.com/memgraph/memgraph/pull/2770)**
- [ ] **[ Documentation PR link memgraph/documentation#XXXX ]**
    - [ ] Is back linked to this development PR
- [ ] **[ Tag someone from docs team ]**

author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-03-14T06:50:09Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=memgraph_memgraph&pullRequest=2770) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=memgraph_memgraph&pullRequest=2770&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=memgraph_memgraph&pullRequest=2770&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=memgraph_memgraph&pullRequest=2770&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=memgraph_memgraph&pullRequest=2770&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [4.3% Duplication on New Code](https://sonarcloud.io/component_measures?id=memgraph_memgraph&pullRequest=2770&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=memgraph_memgraph&pullRequest=2770)


author_association: NONE