Avoiding hash collisions of a match with its reverse
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / match / Match.java
index 30c25af57f688539c7bf569aa4ecccf0f804af26..910695c1e9cbc0ebcfb121b621fb7187305aff37 100644 (file)
@@ -20,6 +20,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.TreeMap;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
@@ -354,7 +355,7 @@ public class Match implements Cloneable, Serializable {
                         .getSubnetMaskLength(thisMask);
                 int otherMaskLen = (otherMask == null) ? ((otherAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
                         .getSubnetMaskLength(otherMask);
-                if (otherMaskLen < thisMaskLen) {
+                if (thisMaskLen < otherMaskLen) {
                     intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(otherAddress, otherMaskLen),
                             otherMask));
                 } else {
@@ -441,7 +442,20 @@ public class Match implements Cloneable, Serializable {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((fields == null) ? 0 : fields.hashCode());
+        if (this.fields == null) {
+            result = prime * result;
+        } else {
+            // use a tree map as the order of hashMap is not guaranteed.
+            // 2 Match objects with fields in different order are still equal.
+            // Hence the hashCode should be the same too.
+            TreeMap<MatchType, MatchField> tm = new TreeMap<MatchType, MatchField>(this.fields);
+            for (MatchType field : tm.keySet()) {
+                MatchField f = tm.get(field);
+                int fieldHashCode = (field==null ? 0 : field.calculateConsistentHashCode()) ^
+                             (f==null ? 0 : f.hashCode());
+                result = prime * result + fieldHashCode;
+            }
+        }
         result = prime * result + matches;
         return result;
     }
@@ -473,6 +487,13 @@ public class Match implements Cloneable, Serializable {
 
     @Override
     public String toString() {
-        return "Match[" + fields.values() + "]";
+        StringBuilder builder = new StringBuilder();
+        builder.append("Match [fields=");
+        builder.append(fields);
+        builder.append(", matches=");
+        builder.append(matches);
+        builder.append("]");
+        return builder.toString();
     }
+
 }