Brian O'Connor

Added error count for IntentData (ONOS-1060)

Change-Id: Ida6313603c15fb6c1c1793c298206587b370a13e
......@@ -44,6 +44,7 @@ public class IntentData { //FIXME need to make this "immutable"
private IntentState state;
private Timestamp version;
private NodeId origin;
private int errorCount;
private List<Intent> installables;
......@@ -75,6 +76,7 @@ public class IntentData { //FIXME need to make this "immutable"
version = intentData.version;
origin = intentData.origin;
installables = intentData.installables;
errorCount = intentData.errorCount;
}
// kryo constructor
......@@ -165,6 +167,32 @@ public class IntentData { //FIXME need to make this "immutable"
}
/**
* Increments the error count for this intent.
*/
public void incrementErrorCount() {
errorCount++;
}
/**
* Sets the error count for this intent.
*
* @param newCount new count
*/
public void setErrorCount(int newCount) {
errorCount = newCount;
}
/**
* Returns the number of times that this intent has encountered an error
* during installation or withdrawal.
*
* @return error count
*/
public int errorCount() {
return errorCount;
}
/**
* Sets the intent installables to the given list of intents.
*
* @param installables list of installables for this intent
......
......@@ -59,12 +59,17 @@ public class IntentCleanup implements Runnable, IntentListener {
private static final Logger log = getLogger(IntentManager.class);
private static final int DEFAULT_PERIOD = 5; //seconds
private static final int DEFAULT_THRESHOLD = 5; //tries
@Property(name = "period", intValue = DEFAULT_PERIOD,
label = "Frequency in ms between cleanup runs")
protected int period = DEFAULT_PERIOD;
private long periodMs;
@Property(name = "retryThreshold", intValue = DEFAULT_THRESHOLD,
label = "Number of times to retry CORRUPT intent without delay")
private int retryThreshold = DEFAULT_THRESHOLD;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentService service;
......@@ -106,6 +111,9 @@ public class IntentCleanup implements Runnable, IntentListener {
try {
String s = get(properties, "period");
newPeriod = isNullOrEmpty(s) ? period : Integer.parseInt(s.trim());
s = get(properties, "retryThreshold");
retryThreshold = isNullOrEmpty(s) ? period : Integer.parseInt(s.trim());
} catch (NumberFormatException e) {
log.warn(e.getMessage());
newPeriod = period;
......@@ -147,9 +155,9 @@ public class IntentCleanup implements Runnable, IntentListener {
}
private void resubmitCorrupt(IntentData intentData, boolean checkThreshold) {
//TODO we might want to give up when retry count exceeds a threshold
// FIXME drop this if we exceed retry threshold
if (checkThreshold && intentData.errorCount() >= retryThreshold) {
return; // threshold met or exceeded
}
switch (intentData.request()) {
case INSTALL_REQ:
......@@ -211,7 +219,7 @@ public class IntentCleanup implements Runnable, IntentListener {
@Override
public void event(IntentEvent event) {
// fast path for CORRUPT intents, retry on event notification
// this is the fast path for CORRUPT intents, retry on event notification.
//TODO we might consider using the timer to back off for subsequent retries
if (event.type() == IntentEvent.Type.CORRUPT) {
Key key = event.subject().key();
......
......@@ -448,6 +448,7 @@ public class IntentManager
log.warn("Failed installation: {} {} on {}",
installData.key(), installData.intent(), ops);
installData.setState(CORRUPT);
installData.incrementErrorCount();
store.write(installData);
}
// if toUninstall was cause of error, then CORRUPT (another job will clean this up)
......@@ -456,6 +457,7 @@ public class IntentManager
log.warn("Failed withdrawal: {} {} on {}",
uninstallData.key(), uninstallData.intent(), ops);
uninstallData.setState(CORRUPT);
uninstallData.incrementErrorCount();
store.write(uninstallData);
}
}
......
......@@ -21,6 +21,7 @@ import org.onosproject.net.intent.impl.IntentProcessor;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.transferErrorCount;
/**
* Represents a phase where intent installation has been requested.
......@@ -47,6 +48,8 @@ final class InstallRequest implements IntentProcessPhase {
@Override
public Optional<IntentProcessPhase> execute() {
transferErrorCount(data, stored);
return Optional.of(new Compiling(processor, data, stored));
}
}
......
......@@ -18,6 +18,7 @@ package org.onosproject.net.intent.impl.phase;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.impl.IntentProcessor;
import java.util.Objects;
import java.util.Optional;
/**
......@@ -57,4 +58,16 @@ public interface IntentProcessPhase {
}
}
static void transferErrorCount(IntentData data, Optional<IntentData> stored) {
if (stored.isPresent()) {
IntentData storedData = stored.get();
if (Objects.equals(data.intent(), storedData.intent()) &&
Objects.equals(data.request(), storedData.request())) {
data.setErrorCount(storedData.errorCount());
} else {
data.setErrorCount(0);
}
}
}
}
......
......@@ -21,6 +21,7 @@ import org.onosproject.net.intent.impl.IntentProcessor;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.transferErrorCount;
/**
* Represents a phase of requesting a withdraw of an intent.
......@@ -51,6 +52,8 @@ final class WithdrawRequest implements IntentProcessPhase {
// same version i.e. they are the same
// Note: this call is not just the symmetric version of submit
transferErrorCount(data, stored);
if (!stored.isPresent() || stored.get().installables().isEmpty()) {
switch (data.request()) {
case INSTALL_REQ:
......