Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: replacing minGenNonAncient data flow with NonAncientEventWindow #10597

Merged
merged 16 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import com.swirlds.platform.consensus.ConsensusSnapshot;
import com.swirlds.platform.consensus.GraphGenerations;
import com.swirlds.platform.consensus.NonAncientEventWindow;
import com.swirlds.platform.event.GossipEvent;
import com.swirlds.platform.internal.ConsensusRound;
import com.swirlds.platform.internal.EventImpl;
Expand Down Expand Up @@ -82,7 +83,12 @@ private static Round buildMockRound(final List<List<Long>> eventContents, final
Mockito.when(mockSnapshot.round()).thenReturn(roundReceived);

return new ConsensusRound(
mock(AddressBook.class), mockEvents, mock(EventImpl.class), mock(GraphGenerations.class), mockSnapshot);
mock(AddressBook.class),
mockEvents,
mock(EventImpl.class),
mock(GraphGenerations.class),
mock(NonAncientEventWindow.class),
mockSnapshot);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.swirlds.platform.consensus.ConsensusUtils;
import com.swirlds.platform.consensus.CountingVote;
import com.swirlds.platform.consensus.InitJudges;
import com.swirlds.platform.consensus.NonAncientEventWindow;
import com.swirlds.platform.consensus.RoundElections;
import com.swirlds.platform.consensus.SequentialRingBuffer;
import com.swirlds.platform.consensus.ThreadSafeConsensusInfo;
Expand Down Expand Up @@ -655,6 +656,8 @@ private List<EventImpl> getStronglySeenInPreviousRound(final EventImpl event) {
consensusEvents,
recentEvents.get(recentEvents.size() - 1),
new Generations(this),
NonAncientEventWindow.createUsingRoundsNonAncient(
decidedRoundNumber, getMinGenerationNonAncient(), config.roundsNonAncient()),
new ConsensusSnapshot(
decidedRoundNumber,
ConsensusUtils.getHashes(judges),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import com.swirlds.platform.components.transaction.system.PreconsensusSystemTransactionManager;
import com.swirlds.platform.config.ThreadConfig;
import com.swirlds.platform.consensus.ConsensusConfig;
import com.swirlds.platform.consensus.NonAncientEventWindow;
import com.swirlds.platform.crypto.CryptoStatic;
import com.swirlds.platform.crypto.KeysAndCerts;
import com.swirlds.platform.crypto.PlatformSigner;
Expand Down Expand Up @@ -904,7 +905,13 @@ public class SwirldsPlatform implements Platform {
if (eventConfig.useLegacyIntake()) {
eventLinker.loadFromSignedState(initialState);
} else {
platformWiring.updateMinimumGenerationNonAncient(initialMinimumGenerationNonAncient);
platformWiring.updateNonAncientEventWindow(NonAncientEventWindow.createUsingRoundsNonAncient(
initialState.getRound(),
initialMinimumGenerationNonAncient,
platformContext
.getConfiguration()
.getConfigData(ConsensusConfig.class)
.roundsNonAncient()));
}

// We don't want to invoke these callbacks until after we are starting up.
Expand Down Expand Up @@ -1054,8 +1061,13 @@ private void loadStateIntoEventCreator(@NonNull final SignedState signedState) {
}

try {
eventCreator.setMinimumGenerationNonAncient(
signedState.getState().getPlatformState().getMinimumGenerationNonAncient());
eventCreator.setNonAncientEventWindow(NonAncientEventWindow.createUsingRoundsNonAncient(
signedState.getRound(),
signedState.getState().getPlatformState().getMinimumGenerationNonAncient(),
platformContext
.getConfiguration()
.getConfigData(ConsensusConfig.class)
.roundsNonAncient()));
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("interrupted while loading state into event creator", e);
Expand Down Expand Up @@ -1152,7 +1164,13 @@ private void loadReconnectState(final SignedState signedState) {
.inject(new AddressBookUpdate(
signedState.getState().getPlatformState().getPreviousAddressBook(),
signedState.getState().getPlatformState().getAddressBook()));
platformWiring.updateMinimumGenerationNonAncient(signedState.getMinRoundGeneration());
platformWiring.updateNonAncientEventWindow(NonAncientEventWindow.createUsingRoundsNonAncient(
signedState.getRound(),
signedState.getMinRoundGeneration(),
platformContext
.getConfiguration()
.getConfigData(ConsensusConfig.class)
.roundsNonAncient()));
}
} finally {
intakeQueue.resume();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.swirlds.common.platform.NodeId;
import com.swirlds.common.threading.manager.ThreadManager;
import com.swirlds.platform.Consensus;
import com.swirlds.platform.consensus.ConsensusConfig;
import com.swirlds.platform.consensus.NonAncientEventWindow;
import com.swirlds.platform.event.GossipEvent;
import com.swirlds.platform.event.linking.EventLinker;
import com.swirlds.platform.event.validation.StaticValidators;
Expand Down Expand Up @@ -79,6 +81,7 @@ public class EventIntake {

private final EventIntakeMetrics metrics;
private final Time time;
private final Long roundsNonAncient;

/**
* Measures the time spent in each phase of event intake
Expand Down Expand Up @@ -137,6 +140,10 @@ public EventIntake(
this.intakeEventCounter = Objects.requireNonNull(intakeEventCounter);

final EventConfig eventConfig = platformContext.getConfiguration().getConfigData(EventConfig.class);
this.roundsNonAncient = (long) platformContext
.getConfiguration()
.getConfigData(ConsensusConfig.class)
.roundsNonAncient();

final BlockingQueue<Runnable> prehandlePoolQueue = new LinkedBlockingQueue<>();
prehandlePool = new ThreadPoolExecutor(
Expand Down Expand Up @@ -214,7 +221,10 @@ public void addEvent(final EventImpl event) {
phaseTimer.activatePhase(EventIntakePhase.HANDLING_STALE_EVENTS);
handleStale(minGenNonAncientBeforeAdding);
if (latestEventTipsetTracker != null) {
latestEventTipsetTracker.setMinimumGenerationNonAncient(minimumGenerationNonAncient);
// FUTURE WORK: When this class is refactored, it should not be constructing the
// NonAncientEventWindow, but receiving it through the PlatformWiring instead.
latestEventTipsetTracker.setNonAncientEventWindow(NonAncientEventWindow.createUsingRoundsNonAncient(
consensus().getLastRoundDecided(), minimumGenerationNonAncient, roundsNonAncient));
}
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import com.swirlds.base.time.Time;
import com.swirlds.common.context.PlatformContext;
import com.swirlds.platform.Consensus;
import com.swirlds.platform.consensus.ConsensusConfig;
import com.swirlds.platform.consensus.NonAncientEventWindow;
import com.swirlds.platform.eventhandling.ConsensusRoundHandler;
import com.swirlds.platform.gossip.IntakeEventCounter;
import com.swirlds.platform.gossip.shadowgraph.LatestEventTipsetTracker;
Expand Down Expand Up @@ -61,6 +63,7 @@ public class LinkedEventIntake {

private final EventIntakeMetrics metrics;
private final Time time;
private final Long roundsNonAncient;

/**
* Tracks the number of events from each peer have been received, but aren't yet through the intake pipeline
Expand Down Expand Up @@ -104,6 +107,10 @@ public LinkedEventIntake(

this.paused = false;
metrics = new EventIntakeMetrics(platformContext, () -> -1);
this.roundsNonAncient = (long) platformContext
.getConfiguration()
.getConfigData(ConsensusConfig.class)
.roundsNonAncient();
}

/**
Expand Down Expand Up @@ -150,7 +157,12 @@ public List<ConsensusRound> addEvent(@NonNull final EventImpl event) {
// with no consensus events, so we check the diff in generations to look for stale events
handleStale(minimumGenerationNonAncientBeforeAdding);
if (latestEventTipsetTracker != null) {
latestEventTipsetTracker.setMinimumGenerationNonAncient(minimumGenerationNonAncient);
// FUTURE WORK: When this class is refactored, it should not be constructing the
// NonAncientEventWindow, but receiving it through the PlatformWiring instead.
latestEventTipsetTracker.setNonAncientEventWindow(NonAncientEventWindow.createUsingRoundsNonAncient(
consensusSupplier.get().getLastRoundDecided(),
minimumGenerationNonAncient,
roundsNonAncient));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright (C) 2023 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.consensus;

import com.swirlds.base.utility.ToStringBuilder;
import com.swirlds.platform.event.GossipEvent;
import com.swirlds.platform.system.events.EventConstants;
import com.swirlds.platform.system.events.EventDescriptor;
import edu.umd.cs.findbugs.annotations.NonNull;

/**
* Determines the non-ancient lower bound (inclusive) on events and communicates the window of rounds between the
* pendingConsensusRound and the minimumRoundNonAncient (inclusive).
*/
public class NonAncientEventWindow {

/**
* The initial NonAncientEventWindow. This constant is used to initialize NonAncientEventWindow variables before
* receiving an updated value.
*/
public static NonAncientEventWindow INITIAL_EVENT_WINDOW = new NonAncientEventWindow(
ConsensusConstants.ROUND_FIRST, ConsensusConstants.ROUND_FIRST, EventConstants.FIRST_GENERATION);

private final long latestConsensusRound;
private final long minRoundNonAncient;
private final long minGenNonAncient;

/**
* Create a new NonAncientEventWindow with the given bounds. The latestConsensusRound must be greater than or equal
* to the first round of consensus. If the minimum round non-ancient is set to a number lower than the first round
* of consensus, the first round of consensus is used instead. The minGenNonAncient value must be greater than or
* equal to the first generation for events.
*
* @param latestConsensusRound the latest round that has come to consensus
* @param minRoundNonAncient the minimum round that is non-ancient
* @param minGenNonAncient the minimum generation that is non-ancient
* @throws IllegalArgumentException if the latestConsensusRound is less than the first round of consensus or if the
* minGenNonAncient value is less than the first generation for events.
*/
public NonAncientEventWindow(
final long latestConsensusRound, final long minRoundNonAncient, final long minGenNonAncient) {
if (latestConsensusRound < ConsensusConstants.ROUND_FIRST) {
throw new IllegalArgumentException(
"The latest consensus round cannot be less than the first round of consensus.");
}
if (minGenNonAncient < EventConstants.FIRST_GENERATION) {
throw new IllegalArgumentException(
"the minimum generation non-ancient cannot be lower than the first generation for events.");
}
this.latestConsensusRound = latestConsensusRound;
this.minRoundNonAncient = Math.max(minRoundNonAncient, ConsensusConstants.ROUND_FIRST);
this.minGenNonAncient = minGenNonAncient;
}

/**
* @return the pending round coming to consensus, i.e. 1 + the latestConsensusRound
*/
public long pendingConsensusRound() {
return latestConsensusRound + 1;
}
edward-swirldslabs marked this conversation as resolved.
Show resolved Hide resolved

/**
* @return the lower bound of the non-ancient event window
*/
public long getLowerBound() {
// FUTURE WORK: return minRoundNonAncient once we switch from minGenNonAncient.
return minGenNonAncient;
}

/**
* Determines if the given event is ancient.
*
* @param event the event to check for being ancient.
* @return true if the event is ancient, false otherwise.
*/
public boolean isAncient(@NonNull final GossipEvent event) {
// FUTURE WORK: use generation until we throw the switch to using round
return event.getGeneration() < minGenNonAncient;
}

/**
* Determines if the given event is ancient.
*
* @param event the event to check for being ancient.
* @return true if the event is ancient, false otherwise.
*/
public boolean isAncient(@NonNull final EventDescriptor event) {
// FUTURE WORK: use generation until we throw the switch to using round
return event.getGeneration() < minGenNonAncient;
}

/**
* Determines if the given long value is ancient.
*
* @param testValue the value to check for being ancient.
* @return true if the value is ancient, false otherwise.
*/
public boolean isAncient(final long testValue) {
// FUTURE WORK: use generation until we throw the switch to using round
return testValue < minGenNonAncient;
}

/**
* Create a NonAncientEventWindow by calculating the minRoundNonAncient value from the latestConsensusRound and
* roundsNonAncient.
*
* @param latestConsensusRound the latest round that has come to consensus
* @param minGenNonAncient the minimum generation that is non-ancient
* @param roundsNonAncient the number of rounds that are non-ancient
* @return the new NonAncientEventWindow
*/
@NonNull
public static NonAncientEventWindow createUsingRoundsNonAncient(
edward-swirldslabs marked this conversation as resolved.
Show resolved Hide resolved
final long latestConsensusRound, final long minGenNonAncient, final long roundsNonAncient) {
return new NonAncientEventWindow(
latestConsensusRound, latestConsensusRound - roundsNonAncient + 1, minGenNonAncient);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("latestConsensusRound", latestConsensusRound)
.append("minRoundNonAncient", minRoundNonAncient)
.append("minGenNonAncient", minGenNonAncient)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.swirlds.common.threading.framework.config.QueueThreadMetricsConfiguration;
import com.swirlds.common.threading.futures.StandardFuture;
import com.swirlds.common.threading.manager.ThreadManager;
import com.swirlds.platform.consensus.NonAncientEventWindow;
import com.swirlds.platform.internal.EventImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Objects;
Expand Down Expand Up @@ -60,9 +61,9 @@ public class AsyncEventCreationManager implements Lifecycle {
private final BlockingQueueInserter<EventImpl> eventInserter;

/**
* The object used to enqueue updates to the minimum generation non-ancient onto the work queue.
* The object used to enqueue updates to the non-ancient event window onto the work queue.
*/
private final BlockingQueueInserter<Long> minimumGenerationNonAncientInserter;
private final BlockingQueueInserter<NonAncientEventWindow> nonAncientEventWindowInserter;

/**
* Used to signal a desired pause.
Expand Down Expand Up @@ -102,7 +103,7 @@ public AsyncEventCreationManager(
.setCapacity(eventCreationConfig.creationQueueSize())
.setMaxBufferSize(eventCreationConfig.creationQueueBufferSize())
.addHandler(EventImpl.class, this::handleEvent)
.addHandler(Long.class, this::handleMinimumGenerationNonAncient)
.addHandler(NonAncientEventWindow.class, this::handleNonAncientEventWindow)
.addHandler(PauseRequest.class, this::handlePauseStatusChange)
.setIdleCallback(eventCreator::maybeCreateEvent)
.setBatchHandledCallback(eventCreator::maybeCreateEvent)
Expand All @@ -113,7 +114,7 @@ public AsyncEventCreationManager(
.build();

eventInserter = workQueue.getInserter(EventImpl.class);
minimumGenerationNonAncientInserter = workQueue.getInserter(Long.class);
nonAncientEventWindowInserter = workQueue.getInserter(NonAncientEventWindow.class);
setPauseStatusInserter = workQueue.getInserter(PauseRequest.class);
}

Expand All @@ -128,12 +129,13 @@ public void registerEvent(@NonNull final EventImpl event) throws InterruptedExce
}

/**
* Update the minimum generation non-ancient
* Update the non-ancient event window
*
* @param minimumGenerationNonAncient the new minimum generation non-ancient
* @param nonAncientEventWindow the new minimum generation non-ancient
*/
public void setMinimumGenerationNonAncient(final long minimumGenerationNonAncient) throws InterruptedException {
minimumGenerationNonAncientInserter.put(minimumGenerationNonAncient);
public void setNonAncientEventWindow(@NonNull final NonAncientEventWindow nonAncientEventWindow)
throws InterruptedException {
nonAncientEventWindowInserter.put(nonAncientEventWindow);
}

/**
Expand All @@ -146,12 +148,12 @@ private void handleEvent(@NonNull final EventImpl event) {
}

/**
* Pass a new minimum generation non-ancient into the event creator.
* Pass a new non-ancient event window into the event creator.
*
* @param minimumGenerationNonAncient the new minimum generation non-ancient
* @param nonAncientEventWindow the new non-ancient event window
*/
private void handleMinimumGenerationNonAncient(final long minimumGenerationNonAncient) {
eventCreator.setMinimumGenerationNonAncient(minimumGenerationNonAncient);
private void handleNonAncientEventWindow(@NonNull final NonAncientEventWindow nonAncientEventWindow) {
eventCreator.setNonAncientEventWindow(nonAncientEventWindow);
}

/**
Expand Down