Improve fingerprint computation for pipeconf
Do not read extensions in memory and consider pipeline model.
Change-Id: I3e077fbcd9ed0a2dba78b4e1c87e95ecb7287be6
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java b/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
index cff8248..464bdd7 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
@@ -17,7 +17,8 @@
package org.onosproject.net.pi.model;
import com.google.common.collect.ImmutableMap;
-import org.apache.commons.io.IOUtils;
+import com.google.common.hash.Hashing;
+import com.google.common.hash.HashingInputStream;
import org.onosproject.net.driver.Behaviour;
import java.io.IOException;
@@ -188,21 +189,32 @@
checkNotNull(pipelineModel);
Map<ExtensionType, URL> extensions = extensionMapBuilder.build();
- return new DefaultPiPipeconf(id, pipelineModel, generateFingerprint(extensions),
- behaviourMapBuilder.build(), extensions);
+ Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours =
+ behaviourMapBuilder.build();
+ return new DefaultPiPipeconf(
+ id, pipelineModel, generateFingerprint(extensions.values()),
+ behaviours, extensions);
}
- private long generateFingerprint(Map<ExtensionType, URL> extensions) {
- Collection<Integer> hashArray = new ArrayList<>();
- for (Map.Entry<ExtensionType, URL> pair : extensions.entrySet()) {
+ private long generateFingerprint(Collection<URL> extensions) {
+ Collection<Integer> hashes = new ArrayList<>();
+ for (URL extUrl : extensions) {
try {
- hashArray.add(Arrays.hashCode(ByteBuffer.wrap(IOUtils.toByteArray(
- pair.getValue().openStream())).array()));
+ HashingInputStream hin = new HashingInputStream(
+ Hashing.crc32(), extUrl.openStream());
+ //noinspection StatementWithEmptyBody
+ while (hin.read() != -1) {
+ // Do nothing. Reading all input stream to update hash.
+ }
+ hashes.add(hin.hash().asInt());
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
- return Arrays.hashCode(hashArray.toArray());
+ // FIXME: how to include behaviours in the hash?
+ int low = Arrays.hashCode(hashes.toArray());
+ int high = pipelineModel.hashCode();
+ return ByteBuffer.allocate(8).putInt(high).putInt(low).getLong(0);
}
}
}
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfManager.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfManager.java
index 29deb4f..3070d66 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfManager.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfManager.java
@@ -20,6 +20,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Striped;
+import org.onlab.util.HexString;
import org.onlab.util.ItemNotFoundException;
import org.onlab.util.SharedExecutors;
import org.onosproject.net.DeviceId;
@@ -56,6 +57,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
+import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
import static org.onlab.util.Tools.groupedThreads;
import static org.slf4j.LoggerFactory.getLogger;
@@ -123,24 +125,28 @@
@Override
public void register(PiPipeconf pipeconf) throws IllegalStateException {
+ checkNotNull(pipeconf);
if (pipeconfs.containsKey(pipeconf.id())) {
throw new IllegalStateException(format("Pipeconf %s is already registered", pipeconf.id()));
}
pipeconfs.put(pipeconf.id(), pipeconf);
- log.info("New pipeconf registered: {}", pipeconf.id());
+ log.info("New pipeconf registered: {} (fingerprint={})",
+ pipeconf.id(), HexString.toHexString(pipeconf.fingerprint()));
executor.execute(() -> attemptMergeAll(pipeconf.id()));
}
@Override
public void remove(PiPipeconfId pipeconfId) throws IllegalStateException {
+ checkNotNull(pipeconfId);
// TODO add mechanism to remove from device.
if (!pipeconfs.containsKey(pipeconfId)) {
throw new IllegalStateException(format("Pipeconf %s is not registered", pipeconfId));
}
// TODO remove the binding from the distributed Store when the lifecycle of a pipeconf is defined.
// pipeconfMappingStore.removeBindings(pipeconfId);
- log.info("Removing pipeconf {}", pipeconfId);
- pipeconfs.remove(pipeconfId);
+ final PiPipeconf pipeconf = pipeconfs.remove(pipeconfId);
+ log.info("Unregistered pipeconf: {} (fingerprint={})",
+ pipeconfId, HexString.toHexString(pipeconf.fingerprint()));
}
@Override