Skip to content

Commit

Permalink
feat: Check platform status before syncing (#11429) (#12679)
Browse files Browse the repository at this point in the history
Signed-off-by: Austin Littley <[email protected]>
  • Loading branch information
litt3 authored Apr 9, 2024
1 parent abc8870 commit 19e0ff1
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ public SyncGossip(
>= eventConfig.eventIntakeQueueThrottleSize(),
Duration.ZERO,
syncMetrics,
time)))))
platformStatusManager)))))
.build());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import static com.swirlds.common.utility.CompareTo.isGreaterThanOrEqualTo;

import com.swirlds.base.time.Time;
import com.swirlds.common.context.PlatformContext;
import com.swirlds.common.platform.NodeId;
import com.swirlds.common.threading.pool.ParallelExecutionException;
Expand All @@ -32,6 +31,7 @@
import com.swirlds.platform.network.Connection;
import com.swirlds.platform.network.NetworkProtocolException;
import com.swirlds.platform.network.protocol.Protocol;
import com.swirlds.platform.system.status.PlatformStatusGetter;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.IOException;
import java.time.Duration;
Expand Down Expand Up @@ -91,24 +91,23 @@ public class SyncProtocol implements Protocol {
*/
private final Duration sleepAfterSync;

/**
* A source of time
*/
private final Time time;

private final PlatformContext platformContext;

private final PlatformStatusGetter platformStatusGetter;

/**
* Constructs a new sync protocol
*
* @param platformContext the platform context
* @param peerId the id of the peer being synced with in this protocol
* @param synchronizer the shadow graph synchronizer, responsible for actually doing the sync
* @param fallenBehindManager manager to determine whether this node has fallen behind
* @param permitProvider provides permits to sync
* @param sleepAfterSync the amount of time to sleep after a sync
* @param syncMetrics metrics tracking syncing
* @param time a source of time
* @param platformContext the platform context
* @param peerId the id of the peer being synced with in this protocol
* @param synchronizer the shadow graph synchronizer, responsible for actually doing the sync
* @param fallenBehindManager manager to determine whether this node has fallen behind
* @param permitProvider provides permits to sync
* @param gossipHalted returns true if gossip is halted, false otherwise
* @param intakeIsTooFull returns true if the intake queue is too full to continue syncing, false otherwise
* @param sleepAfterSync the amount of time to sleep after a sync
* @param syncMetrics metrics tracking syncing
* @param platformStatusGetter provides the current platform status
*/
public SyncProtocol(
@NonNull final PlatformContext platformContext,
Expand All @@ -120,7 +119,7 @@ public SyncProtocol(
@NonNull final BooleanSupplier intakeIsTooFull,
@NonNull final Duration sleepAfterSync,
@NonNull final SyncMetrics syncMetrics,
@NonNull final Time time) {
@NonNull final PlatformStatusGetter platformStatusGetter) {

this.platformContext = Objects.requireNonNull(platformContext);
this.peerId = Objects.requireNonNull(peerId);
Expand All @@ -131,14 +130,15 @@ public SyncProtocol(
this.intakeIsTooFull = Objects.requireNonNull(intakeIsTooFull);
this.sleepAfterSync = Objects.requireNonNull(sleepAfterSync);
this.syncMetrics = Objects.requireNonNull(syncMetrics);
this.time = Objects.requireNonNull(time);
this.platformStatusGetter = Objects.requireNonNull(platformStatusGetter);
}

/**
* @return true if the cooldown period after a sync has elapsed, else false
*/
private boolean syncCooldownComplete() {
final Duration elapsed = Duration.between(lastSyncTime, time.now());
final Duration elapsed =
Duration.between(lastSyncTime, platformContext.getTime().now());

return isGreaterThanOrEqualTo(elapsed, sleepAfterSync);
}
Expand All @@ -149,6 +149,10 @@ private boolean syncCooldownComplete() {
* @return true if the node should sync, false otherwise
*/
private boolean shouldSync() {
if (!SyncStatusChecker.doesStatusPermitSync(platformStatusGetter.getCurrentStatus())) {
syncMetrics.doNotSyncPlatformStatus();
return false;
}

if (!syncCooldownComplete()) {
syncMetrics.doNotSyncCooldown();
Expand Down Expand Up @@ -269,7 +273,7 @@ public void runProtocol(@NonNull final Connection connection)
} finally {
returnPermit();

lastSyncTime = time.now();
lastSyncTime = platformContext.getTime().now();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.swirlds.platform.gossip.sync.protocol;

import com.swirlds.platform.system.status.PlatformStatus;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Collection;
import java.util.Set;

/**
* A utility class for checking if a platform status permits syncing
*/
public class SyncStatusChecker {
/**
* The platform statuses that permit syncing. If the platform isn't in one of these statuses, no syncs will be
* initiated or accepted
*/
public static final Collection<PlatformStatus> STATUSES_THAT_PERMIT_SYNC = Set.of(
PlatformStatus.ACTIVE,
PlatformStatus.FREEZING,
PlatformStatus.FREEZE_COMPLETE,
PlatformStatus.OBSERVING,
PlatformStatus.CHECKING,
PlatformStatus.RECONNECT_COMPLETE);

/**
* Hidden constructor
*/
private SyncStatusChecker() {}

/**
* Determines if the given status permits syncing
*
* @param status the status to check
* @return true if the status permits syncing, false otherwise
*/
public static boolean doesStatusPermitSync(@NonNull final PlatformStatus status) {
return STATUSES_THAT_PERMIT_SYNC.contains(status);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ public class SyncMetrics {
.withDescription("the average time spent filtering events during a sync")
.withUnit("nanoseconds");

private static final CountPerSecond.Config DO_NOT_SYNC_PLATFORM_STATUS = new CountPerSecond.Config(
PLATFORM_CATEGORY, "doNotSyncPlatformStatus")
.withUnit("hz")
.withDescription("Number of times per second we do not sync because the platform status doesn't permit it");
private final CountPerSecond doNoSyncPlatformStatus;

private static final CountPerSecond.Config DO_NOT_SYNC_COOLDOWN_CONFIG = new CountPerSecond.Config(
PLATFORM_CATEGORY, "doNotSyncCooldown")
.withUnit("hz")
Expand Down Expand Up @@ -169,6 +175,7 @@ public SyncMetrics(final Metrics metrics) {
syncsPerSec = new CountPerSecond(metrics, SYNCS_PER_SECOND_CONFIG);
syncFilterTime = metrics.getOrCreate(SYNC_FILTER_TIME_CONFIG);

doNoSyncPlatformStatus = new CountPerSecond(metrics, DO_NOT_SYNC_PLATFORM_STATUS);
doNotSyncCooldown = new CountPerSecond(metrics, DO_NOT_SYNC_COOLDOWN_CONFIG);
doNotSyncHalted = new CountPerSecond(metrics, DO_NOT_SYNC_HALTED_CONFIG);
doNotSyncIntakeQueue = new CountPerSecond(metrics, DO_NOT_SYNC_INTAKE_QUEUE_CONFIG);
Expand Down Expand Up @@ -398,6 +405,13 @@ public void recordSyncFilterTime(final long nanoseconds) {
syncFilterTime.update(nanoseconds);
}

/**
* Signal that we chose not to sync because of the current platform status
*/
public void doNotSyncPlatformStatus() {
doNoSyncPlatformStatus.count();
}

/**
* Signal that we chose not to sync because we are in sync cooldown.
*/
Expand Down
Loading

0 comments on commit 19e0ff1

Please sign in to comment.