Detect circular app dependency
Change-Id: Ib3e2d802dfe3675ef5c8ef8818c1127ed145adf1
diff --git a/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java b/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java
index f1c5007..9809d11 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java
@@ -17,6 +17,7 @@
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
@@ -57,6 +58,8 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
@@ -98,6 +101,8 @@
private static final int APP_LOAD_DELAY_MS = 500;
+ private static List<String> pendingApps = Lists.newArrayList();
+
public enum InternalState {
INSTALLED, ACTIVATED, DEACTIVATED
}
@@ -197,6 +202,8 @@
}
private Application loadFromDisk(String appName) {
+ pendingApps.add(appName);
+
for (int i = 0; i < MAX_LOAD_RETRIES; i++) {
try {
// Directly return if app already exists
@@ -204,19 +211,33 @@
if (appId != null) {
Application application = getApplication(appId);
if (application != null) {
+ pendingApps.remove(appName);
return application;
}
}
ApplicationDescription appDesc = getApplicationDescription(appName);
+
+ Optional<String> loop = appDesc.requiredApps().stream()
+ .filter(app -> pendingApps.contains(app)).findAny();
+ if (loop.isPresent()) {
+ log.error("Circular app dependency detected: {} -> {}", pendingApps, loop.get());
+ pendingApps.remove(appName);
+ return null;
+ }
+
boolean success = appDesc.requiredApps().stream()
.noneMatch(requiredApp -> loadFromDisk(requiredApp) == null);
+ pendingApps.remove(appName);
+
return success ? create(appDesc, false) : null;
+
} catch (Exception e) {
log.warn("Unable to load application {} from disk; retrying", appName);
randomDelay(RETRY_DELAY_MS); //FIXME: This is a deliberate hack; fix in Falcon
}
}
+ pendingApps.remove(appName);
return null;
}