io.vlingo.xoom.cluster.model.attribute.Confirmables Maven / Gradle / Ivy
// Copyright © 2012-2022 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.
package io.vlingo.xoom.cluster.model.attribute;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import io.vlingo.xoom.cluster.model.Properties;
import io.vlingo.xoom.cluster.model.attribute.message.ApplicationMessage;
import io.vlingo.xoom.wire.node.Node;
final class Confirmables {
private final Supplier> allOtherNodesSupplier;
private final List expectedConfirmables;
private final Node node;
Confirmables(final Node node, final Supplier> allOtherNodesSupplier) {
this.node = node;
this.allOtherNodesSupplier = allOtherNodesSupplier;
this.expectedConfirmables = new ArrayList<>();
}
Collection allRedistributable() {
final List ready = new ArrayList<>();
for (final Confirmable confirmable : expectedConfirmables) {
if (confirmable.isRedistributableAsOf()) {
ready.add(confirmable);
}
}
return ready;
}
Collection allTrackingIds() {
final List all = new ArrayList<>();
for (final Confirmable confirmable : expectedConfirmables) {
all.add(confirmable.message.trackingId);
}
return all;
}
void confirm(final String trackingId, final Node node) {
final Confirmable confirmable = confirmableOf(trackingId);
confirmable.confirm(node);
if (!confirmable.hasUnconfirmedNodes()) {
expectedConfirmables.remove(confirmable);
}
}
Confirmable confirmableOf(final String trackingId) {
for (final Confirmable confirmable : expectedConfirmables) {
if (confirmable.trackingId.equals(trackingId)) {
return confirmable;
}
}
return Confirmable.NoConfirmable;
}
Confirmable unconfirmed(final ApplicationMessage message) {
return unconfirmedFor(message, allOtherNodesSupplier.get());
}
Confirmable unconfirmedFor(final ApplicationMessage message, final Collection nodes) {
if (nodes.contains(node)) {
new Exception().printStackTrace();
}
final Confirmable confirmable = new Confirmable(message, nodes);
expectedConfirmables.add(confirmable);
return confirmable;
}
static final class Confirmable {
static final int TotalRetries = Properties.instance().clusterAttributesRedistributionRetries();
static final Confirmable NoConfirmable = new Confirmable();
private final long createdOn;
private final ApplicationMessage message;
private final String trackingId;
private Map unconfirmedNodes;
Confirmable(final ApplicationMessage message, final Collection allOtherNodes) {
this.message = message;
this.unconfirmedNodes = allUnconfirmedFor(allOtherNodes);
this.createdOn = System.currentTimeMillis();
this.trackingId = message.trackingId;
}
private Confirmable() {
this.message = null;
this.unconfirmedNodes = new HashMap<>(0);
this.createdOn = 0L;
this.trackingId = "";
}
private Map allUnconfirmedFor(final Collection allOtherNodes) {
final Map allUnconfirmed = new HashMap<>(allOtherNodes.size());
for (final Node node : allOtherNodes) {
allUnconfirmed.put(node, 0);
}
return allUnconfirmed;
}
void confirm(final Node node) {
unconfirmedNodes.remove(node);
}
boolean hasUnconfirmedNodes() {
return !unconfirmedNodes.isEmpty();
}
ApplicationMessage message() {
return message;
}
boolean isRedistributableAsOf() {
final long targetTime = createdOn + Properties.instance().clusterAttributesRedistributionInterval();
if (targetTime < System.currentTimeMillis()) {
final Map allUnconfirmed = new HashMap<>(unconfirmedNodes.size());
for (final Node node : unconfirmedNodes.keySet()) {
final int tries = unconfirmedNodes.get(node) + 1;
if (tries <= TotalRetries) {
allUnconfirmed.put(node, tries);
}
}
unconfirmedNodes = allUnconfirmed;
return true;
}
return false;
}
Collection unconfirmedNodes() {
return unconfirmedNodes.keySet();
}
@Override
public boolean equals(final Object other) {
if (other == null || other.getClass() != Confirmable.class) {
return false;
}
return this.trackingId.equals(((Confirmable)other).trackingId);
}
@Override
public String toString() {
return "Confirmable[trackingId=" + trackingId + " nodes=" + unconfirmedNodes + "]";
}
}
}