From b8982d4b49d385b94ecfb00ac5838d3b98f46636 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sat, 4 Feb 2023 03:11:49 +0100 Subject: Performance improvements by replacing hash depth calculation with shifting, improving code quality. + formatting --- .../refinery/store/map/internal/ImmutableNode.java | 65 ++++----- .../refinery/store/map/internal/MutableNode.java | 156 ++++++++++----------- .../tools/refinery/store/map/internal/Node.java | 87 ++++++++---- .../store/map/internal/VersionedMapImpl.java | 32 ++++- 4 files changed, 193 insertions(+), 147 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java index 9397dede..e437aceb 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java @@ -42,8 +42,7 @@ public class ImmutableNode extends Node { * available. * @return an immutable version of the input node. */ - static ImmutableNode constructImmutable(MutableNode node, - Map, ImmutableNode> cache) { + static ImmutableNode constructImmutable(MutableNode node, Map, ImmutableNode> cache) { // 1. try to return from cache if (cache != null) { ImmutableNode cachedResult = cache.get(node); @@ -75,8 +74,7 @@ public class ImmutableNode extends Node { resultContent[datas * 2 + 1] = node.content[i * 2 + 1]; datas++; } else { - @SuppressWarnings("unchecked") - var subnode = (Node) node.content[i * 2 + 1]; + @SuppressWarnings("unchecked") var subnode = (Node) node.content[i * 2 + 1]; if (subnode != null) { ImmutableNode immutableSubnode = subnode.toImmutable(cache); resultNodeMap |= bitposition; @@ -107,11 +105,9 @@ public class ImmutableNode extends Node { // If the key is stored as a data if ((dataMap & bitposition) != 0) { int keyIndex = 2 * index(dataMap, bitposition); - @SuppressWarnings("unchecked") - K keyCandidate = (K) content[keyIndex]; + @SuppressWarnings("unchecked") K keyCandidate = (K) content[keyIndex]; if (keyCandidate.equals(key)) { - @SuppressWarnings("unchecked") - V value = (V) content[keyIndex + 1]; + @SuppressWarnings("unchecked") V value = (V) content[keyIndex + 1]; return value; } else { return defaultValue; @@ -120,9 +116,8 @@ public class ImmutableNode extends Node { // the key is stored as a node else if ((nodeMap & bitposition) != 0) { int keyIndex = content.length - 1 - index(nodeMap, bitposition); - @SuppressWarnings("unchecked") - var subNode = (ImmutableNode) content[keyIndex]; - int newDepth = depth + 1; + @SuppressWarnings("unchecked") var subNode = (ImmutableNode) content[keyIndex]; + int newDepth = incrementDepth(depth); int newHash = newHash(hashProvider, key, hash, newDepth); return subNode.getValue(key, hashProvider, defaultValue, newHash, newDepth); } @@ -133,14 +128,12 @@ public class ImmutableNode extends Node { } @Override - public Node putValue(K key, V value, OldValueBox oldValue, ContinousHashProvider hashProvider, - V defaultValue, int hash, int depth) { + public Node putValue(K key, V value, OldValueBox oldValue, ContinousHashProvider hashProvider, V defaultValue, int hash, int depth) { int selectedHashFragment = hashFragment(hash, shiftDepth(depth)); int bitposition = 1 << selectedHashFragment; if ((dataMap & bitposition) != 0) { int keyIndex = 2 * index(dataMap, bitposition); - @SuppressWarnings("unchecked") - K keyCandidate = (K) content[keyIndex]; + @SuppressWarnings("unchecked") K keyCandidate = (K) content[keyIndex]; if (keyCandidate.equals(key)) { if (value == defaultValue) { // delete @@ -151,7 +144,7 @@ public class ImmutableNode extends Node { oldValue.setOldValue(value); return this; } else { - // update existing nodeId + // update existing value MutableNode mutable = this.toMutable(); return mutable.updateValue(value, oldValue, selectedHashFragment); } @@ -161,16 +154,15 @@ public class ImmutableNode extends Node { oldValue.setOldValue(defaultValue); return this; } else { - // add new key + nodeId + // add new key + value MutableNode mutable = this.toMutable(); return mutable.putValue(key, value, oldValue, hashProvider, defaultValue, hash, depth); } } } else if ((nodeMap & bitposition) != 0) { int keyIndex = content.length - 1 - index(nodeMap, bitposition); - @SuppressWarnings("unchecked") - var subNode = (ImmutableNode) content[keyIndex]; - int newDepth = depth + 1; + @SuppressWarnings("unchecked") var subNode = (ImmutableNode) content[keyIndex]; + int newDepth = incrementDepth(depth); int newHash = newHash(hashProvider, key, hash, newDepth); var newsubNode = subNode.putValue(key, value, oldValue, hashProvider, defaultValue, newHash, newDepth); @@ -179,10 +171,11 @@ public class ImmutableNode extends Node { return this; } else { MutableNode mutable = toMutable(); - return mutable.updateWithSubNode(selectedHashFragment, newsubNode, value.equals(defaultValue)); + return mutable.updateWithSubNode(selectedHashFragment, newsubNode, + (value == null && defaultValue == null) || (value != null && value.equals(defaultValue))); } } else { - // add new key + nodeId + // add new key + value MutableNode mutable = this.toMutable(); return mutable.putValue(key, value, oldValue, hashProvider, defaultValue, hash, depth); } @@ -192,8 +185,7 @@ public class ImmutableNode extends Node { public long getSize() { int result = Integer.bitCount(this.dataMap); for (int subnodeIndex = 0; subnodeIndex < Integer.bitCount(this.nodeMap); subnodeIndex++) { - @SuppressWarnings("unchecked") - var subnode = (ImmutableNode) this.content[this.content.length - 1 - subnodeIndex]; + @SuppressWarnings("unchecked") var subnode = (ImmutableNode) this.content[this.content.length - 1 - subnodeIndex]; result += subnode.getSize(); } return result; @@ -289,10 +281,9 @@ public class ImmutableNode extends Node { int nodeMask = 1; for (int i = 0; i < FACTOR; i++) { if ((nodeMask & nodeMap) != 0) { - @SuppressWarnings("unchecked") - Node subNode = (Node) content[content.length - 1 - index(nodeMap, nodeMask)]; + @SuppressWarnings("unchecked") Node subNode = (Node) content[content.length - 1 - index(nodeMap, nodeMask)]; builder.append("\n"); - subNode.prettyPrint(builder, depth + 1, i); + subNode.prettyPrint(builder, incrementDepth(depth), i); } nodeMask <<= 1; } @@ -310,12 +301,11 @@ public class ImmutableNode extends Node { // check subnodes for (int i = 0; i < Integer.bitCount(nodeMap); i++) { - @SuppressWarnings("unchecked") - var subnode = (Node) this.content[this.content.length - 1 - i]; + @SuppressWarnings("unchecked") var subnode = (Node) this.content[this.content.length - 1 - i]; if (!(subnode instanceof ImmutableNode)) { throw new IllegalStateException("Immutable node contains mutable subnodes!"); } else { - subnode.checkIntegrity(hashProvider, defaultValue, depth + 1); + subnode.checkIntegrity(hashProvider, defaultValue, incrementDepth(depth)); } } } @@ -327,13 +317,10 @@ public class ImmutableNode extends Node { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; + if (this == obj) return true; + if (obj == null) return false; if (obj instanceof ImmutableNode other) { - return precalculatedHash == other.precalculatedHash && dataMap == other.dataMap && nodeMap == other.nodeMap - && Arrays.deepEquals(content, other.content); + return precalculatedHash == other.precalculatedHash && dataMap == other.dataMap && nodeMap == other.nodeMap && Arrays.deepEquals(content, other.content); } else if (obj instanceof MutableNode mutableObj) { return ImmutableNode.compareImmutableMutable(this, mutableObj); } else { @@ -351,12 +338,10 @@ public class ImmutableNode extends Node { if (key != null) { // Check whether a new Key-Value pair can fit into the immutable container if (datas * 2 + nodes + 2 <= immutableLength) { - if (!immutable.content[datas * 2].equals(key) - || !immutable.content[datas * 2 + 1].equals(mutable.content[i * 2 + 1])) { + if (!immutable.content[datas * 2].equals(key) || !immutable.content[datas * 2 + 1].equals(mutable.content[i * 2 + 1])) { return false; } - } else - return false; + } else return false; datas++; } else { var mutableSubnode = (Node) mutable.content[i * 2 + 1]; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java index 7c3cf7e8..9d15a0d7 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java @@ -7,15 +7,15 @@ import tools.refinery.store.map.ContinousHashProvider; public class MutableNode extends Node { int cachedHash; + protected boolean cachedHashValid; protected Object[] content; protected MutableNode() { this.content = new Object[2 * FACTOR]; - updateHash(); + invalidateHash(); } - public static MutableNode initialize(K key, V value, ContinousHashProvider hashProvider, - V defaultValue) { + public static MutableNode initialize(K key, V value, ContinousHashProvider hashProvider, V defaultValue) { if (value == defaultValue) { return null; } else { @@ -24,7 +24,7 @@ public class MutableNode extends Node { MutableNode res = new MutableNode<>(); res.content[2 * fragment] = key; res.content[2 * fragment + 1] = value; - res.updateHash(); + res.invalidateHash(); return res; } } @@ -32,7 +32,7 @@ public class MutableNode extends Node { /** * Constructs a {@link MutableNode} as a copy of an {@link ImmutableNode} * - * @param node + * @param node to be transformed */ protected MutableNode(ImmutableNode node) { this.content = new Object[2 * FACTOR]; @@ -49,27 +49,24 @@ public class MutableNode extends Node { nodeUsed++; } } - this.cachedHash = node.hashCode(); + this.cachedHashValid = false; } @Override public V getValue(K key, ContinousHashProvider hashProvider, V defaultValue, int hash, int depth) { int selectedHashFragment = hashFragment(hash, shiftDepth(depth)); - @SuppressWarnings("unchecked") - K keyCandidate = (K) this.content[2 * selectedHashFragment]; + @SuppressWarnings("unchecked") K keyCandidate = (K) this.content[2 * selectedHashFragment]; if (keyCandidate != null) { if (keyCandidate.equals(key)) { - @SuppressWarnings("unchecked") - V value = (V) this.content[2 * selectedHashFragment + 1]; + @SuppressWarnings("unchecked") V value = (V) this.content[2 * selectedHashFragment + 1]; return value; } else { return defaultValue; } } else { - @SuppressWarnings("unchecked") - var nodeCandidate = (Node) content[2 * selectedHashFragment + 1]; + @SuppressWarnings("unchecked") var nodeCandidate = (Node) content[2 * selectedHashFragment + 1]; if (nodeCandidate != null) { - int newDepth = depth + 1; + int newDepth = incrementDepth(depth); int newHash = newHash(hashProvider, key, hash, newDepth); return nodeCandidate.getValue(key, hashProvider, defaultValue, newHash, newDepth); } else { @@ -79,11 +76,9 @@ public class MutableNode extends Node { } @Override - public Node putValue(K key, V value, OldValueBox oldValueBox, ContinousHashProvider hashProvider, - V defaultValue, int hash, int depth) { + public Node putValue(K key, V value, OldValueBox oldValueBox, ContinousHashProvider hashProvider, V defaultValue, int hash, int depth) { int selectedHashFragment = hashFragment(hash, shiftDepth(depth)); - @SuppressWarnings("unchecked") - K keyCandidate = (K) content[2 * selectedHashFragment]; + @SuppressWarnings("unchecked") K keyCandidate = (K) content[2 * selectedHashFragment]; if (keyCandidate != null) { // If has key if (keyCandidate.equals(key)) { @@ -107,18 +102,17 @@ public class MutableNode extends Node { } } } else { - // If it does not have key, check for nodeId - @SuppressWarnings("unchecked") - var nodeCandidate = (Node) content[2 * selectedHashFragment + 1]; + // If it does not have key, check for value + @SuppressWarnings("unchecked") var nodeCandidate = (Node) content[2 * selectedHashFragment + 1]; if (nodeCandidate != null) { - // If it has nodeId, it is a subnode -> upate that - var newNode = nodeCandidate.putValue(key, value, oldValueBox, hashProvider, defaultValue, - newHash(hashProvider, key, hash, depth + 1), depth + 1); - return updateWithSubNode(selectedHashFragment, newNode, value.equals(defaultValue)); + // If it has value, it is a subnode -> upate that + int newDepth = incrementDepth(depth); + var newNode = nodeCandidate.putValue(key, value, oldValueBox, hashProvider, defaultValue, newHash(hashProvider, key, hash, newDepth), newDepth); + return updateWithSubNode(selectedHashFragment, newNode, (value == null && defaultValue == null) || (value != null && value.equals(defaultValue))); } else { - // If it does not have nodeId, put it in the empty place + // If it does not have value, put it in the empty place if (value == defaultValue) { - // dont need to add new key-nodeId pair + // dont need to add new key-value pair oldValueBox.setOldValue(defaultValue); return this; } else { @@ -133,30 +127,31 @@ public class MutableNode extends Node { content[2 * selectedHashFragment] = key; oldValueBox.setOldValue(defaultValue); content[2 * selectedHashFragment + 1] = value; - updateHash(); + invalidateHash(); return this; } /** - * Updates an entry in a selected hash-fragment to a non-default nodeId. + * Updates an entry in a selected hash-fragment to a non-default value. * - * @param value - * @param selectedHashFragment - * @return + * @param value new value + * @param selectedHashFragment position of the value + * @return updated node */ @SuppressWarnings("unchecked") Node updateValue(V value, OldValueBox oldValue, int selectedHashFragment) { oldValue.setOldValue((V) content[2 * selectedHashFragment + 1]); content[2 * selectedHashFragment + 1] = value; - updateHash(); + invalidateHash(); return this; } /** + * Updates an entry in a selected hash-fragment with a subtree. * - * @param selectedHashFragment - * @param newNode - * @return + * @param selectedHashFragment position of the value + * @param newNode the subtree + * @return updated node */ Node updateWithSubNode(int selectedHashFragment, Node newNode, boolean deletionHappened) { if (deletionHappened) { @@ -164,7 +159,7 @@ public class MutableNode extends Node { // Check whether this node become empty content[2 * selectedHashFragment + 1] = null; // i.e. the new node if (hasContent()) { - updateHash(); + invalidateHash(); return this; } else { return null; @@ -178,7 +173,7 @@ public class MutableNode extends Node { // orphan subnode data is replaced with data content[2 * selectedHashFragment] = immutableNewNode.content[orphaned * 2]; content[2 * selectedHashFragment + 1] = immutableNewNode.content[orphaned * 2 + 1]; - updateHash(); + invalidateHash(); return this; } } @@ -186,15 +181,13 @@ public class MutableNode extends Node { } // normal behaviour content[2 * selectedHashFragment + 1] = newNode; - updateHash(); + invalidateHash(); return this; - } private boolean hasContent() { for (Object element : this.content) { - if (element != null) - return true; + if (element != null) return true; } return false; } @@ -221,23 +214,20 @@ public class MutableNode extends Node { } @SuppressWarnings("unchecked") - private Node moveDownAndSplit(ContinousHashProvider hashProvider, K newKey, V newValue, - K previousKey, int hashOfNewKey, int depth, int selectedHashFragmentOfCurrentDepth) { + private Node moveDownAndSplit(ContinousHashProvider hashProvider, K newKey, V newValue, K previousKey, int hashOfNewKey, int depth, int selectedHashFragmentOfCurrentDepth) { V previousValue = (V) content[2 * selectedHashFragmentOfCurrentDepth + 1]; - MutableNode newSubNode = newNodeWithTwoEntries(hashProvider, previousKey, previousValue, - hashProvider.getHash(previousKey, hashDepth(depth)), newKey, newValue, hashOfNewKey, depth + 1); + MutableNode newSubNode = newNodeWithTwoEntries(hashProvider, previousKey, previousValue, hashProvider.getHash(previousKey, hashDepth(depth)), newKey, newValue, hashOfNewKey, incrementDepth(depth)); content[2 * selectedHashFragmentOfCurrentDepth] = null; content[2 * selectedHashFragmentOfCurrentDepth + 1] = newSubNode; - updateHash(); + invalidateHash(); return this; } // Pass everything as parameters for performance. @SuppressWarnings("squid:S107") - private MutableNode newNodeWithTwoEntries(ContinousHashProvider hashProvider, K key1, V value1, - int oldHash1, K key2, V value2, int oldHash2, int newdepth) { + private MutableNode newNodeWithTwoEntries(ContinousHashProvider hashProvider, K key1, V value1, int oldHash1, K key2, V value2, int oldHash2, int newdepth) { int newHash1 = newHash(hashProvider, key1, oldHash1, newdepth); int newHash2 = newHash(hashProvider, key2, oldHash2, newdepth); int newFragment1 = hashFragment(newHash1, shiftDepth(newdepth)); @@ -251,11 +241,10 @@ public class MutableNode extends Node { subNode.content[newFragment2 * 2] = key2; subNode.content[newFragment2 * 2 + 1] = value2; } else { - MutableNode subSubNode = newNodeWithTwoEntries(hashProvider, key1, value1, newHash1, key2, value2, - newHash2, newdepth + 1); + MutableNode subSubNode = newNodeWithTwoEntries(hashProvider, key1, value1, newHash1, key2, value2, newHash2, incrementDepth(newdepth)); subNode.content[newFragment1 * 2 + 1] = subSubNode; } - subNode.updateHash(); + subNode.invalidateHash(); return subNode; } @@ -265,7 +254,7 @@ public class MutableNode extends Node { oldValue.setOldValue((V) content[2 * selectedHashFragment + 1]); content[2 * selectedHashFragment + 1] = null; if (hasContent()) { - updateHash(); + invalidateHash(); return this; } else { return null; @@ -374,10 +363,9 @@ public class MutableNode extends Node { // print subnodes for (int i = 0; i < FACTOR; i++) { if (content[2 * i] == null && content[2 * i + 1] != null) { - @SuppressWarnings("unchecked") - Node subNode = (Node) content[2 * i + 1]; + @SuppressWarnings("unchecked") Node subNode = (Node) content[2 * i + 1]; builder.append("\n"); - subNode.prettyPrint(builder, depth + 1, i); + subNode.prettyPrint(builder, incrementDepth(depth), i); } } } @@ -394,57 +382,69 @@ public class MutableNode extends Node { // check the place of data for (int i = 0; i < FACTOR; i++) { if (this.content[2 * i] != null) { - @SuppressWarnings("unchecked") - K key = (K) this.content[2 * i]; - @SuppressWarnings("unchecked") - V value = (V) this.content[2 * i + 1]; + @SuppressWarnings("unchecked") K key = (K) this.content[2 * i]; + @SuppressWarnings("unchecked") V value = (V) this.content[2 * i + 1]; if (value == defaultValue) { - throw new IllegalStateException("Node contains default nodeId!"); + throw new IllegalStateException("Node contains default value!"); } int hashCode = hashProvider.getHash(key, hashDepth(depth)); int shiftDepth = shiftDepth(depth); int selectedHashFragment = hashFragment(hashCode, shiftDepth); if (i != selectedHashFragment) { - throw new IllegalStateException("Key " + key + " with hash code " + hashCode - + " is in bad place! Fragment=" + selectedHashFragment + ", Place=" + i); + throw new IllegalStateException("Key " + key + " with hash code " + hashCode + " is in bad place! Fragment=" + selectedHashFragment + ", Place=" + i); } } } // check subnodes for (int i = 0; i < FACTOR; i++) { if (this.content[2 * i + 1] != null && this.content[2 * i] == null) { - @SuppressWarnings("unchecked") - var subNode = (Node) this.content[2 * i + 1]; - subNode.checkIntegrity(hashProvider, defaultValue, depth + 1); + @SuppressWarnings("unchecked") var subNode = (Node) this.content[2 * i + 1]; + subNode.checkIntegrity(hashProvider, defaultValue, incrementDepth(depth)); } } // check the hash - int oldHash = this.cachedHash; - updateHash(); - int newHash = this.cachedHash; - if (oldHash != newHash) { - throw new IllegalStateException("Hash code was not up to date! (old=" + oldHash + ",new=" + newHash + ")"); + if (cachedHashValid) { + int oldHash = this.cachedHash; + invalidateHash(); + int newHash = hashCode(); + if (oldHash != newHash) { + throw new IllegalStateException("Hash code was not up to date! (old=" + oldHash + ",new=" + newHash + ")"); + } } } - protected void updateHash() { - this.cachedHash = Arrays.hashCode(content); + protected void invalidateHash() { + this.cachedHashValid = false; } @Override public int hashCode() { - return this.cachedHash; + if (this.cachedHashValid) { + return this.cachedHash; + } else { + this.cachedHash = Arrays.hashCode(content); + this.cachedHashValid = true; + return this.cachedHash; + } } @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; + if (this == obj) return true; + if (obj == null) return false; if (obj instanceof MutableNode mutableObj) { - return Arrays.deepEquals(this.content, mutableObj.content); + if (obj.hashCode() != this.hashCode()) { + return false; + } else { + for (int i = 0; i < FACTOR * 2; i++) { + Object thisContent = this.content[i]; + if (thisContent != null && !thisContent.equals(mutableObj.content[i])) { + return false; + } + } + return true; + } } else if (obj instanceof ImmutableNode immutableObj) { return ImmutableNode.compareImmutableMutable(immutableObj, this); } else { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java index 2260cd5b..c49be280 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java @@ -4,82 +4,121 @@ import java.util.Map; import tools.refinery.store.map.ContinousHashProvider; -public abstract class Node{ +public abstract class Node { public static final int BRANCHING_FACTOR_BITS = 5; - public static final int FACTOR = 1<> FACTOR_SELECTION_BITS; } /** * Calculates the which segment of a single hash should be used. + * * @param depth The depth of the node in the tree. * @return The segment of a hash code. */ protected static int shiftDepth(int depth) { - return depth%NUMBER_OF_FACTORS; + return depth & FACTOR_SELECTION_MASK; } + /** * Selects a segments from a complete hash for a given depth. - * @param hash A complete hash. + * + * @param hash A complete hash. * @param shiftDepth The index of the segment. * @return The segment as an integer. */ protected static int hashFragment(int hash, int shiftDepth) { - if(shiftDepth<0 || Node.NUMBER_OF_FACTORS= ContinousHashProvider.MAX_PRACTICAL_DEPTH) { + throw new IllegalArgumentException( + "Key " + key + " have the clashing hashcode over the practical depth limitation (" + + ContinousHashProvider.MAX_PRACTICAL_DEPTH + ")!"); + } + return hashProvider.getHash(key, hashDepth); + } else { + return hash; } - return depth%NUMBER_OF_FACTORS == 0? - hashProvider.getHash(key, hashDepth) : - hash; } + public abstract V getValue(K key, ContinousHashProvider hashProvider, V defaultValue, int hash, + int depth); + + public abstract Node putValue(K key, V value, OldValueBox old, + ContinousHashProvider hashProvider, V defaultValue, int hash, int depth); - public abstract V getValue(K key, ContinousHashProvider hashProvider, V defaultValue, int hash, int depth); - public abstract Node putValue(K key, V value, OldValueBox old, ContinousHashProvider hashProvider, V defaultValue, int hash, int depth); public abstract long getSize(); abstract MutableNode toMutable(); - public abstract ImmutableNode toImmutable( - Map,ImmutableNode> cache); + + public abstract ImmutableNode toImmutable(Map, ImmutableNode> cache); + protected abstract MutableNode isMutable(); + /** * Moves a {@link MapCursor} to its next position. + * * @param cursor the cursor - * @return Whether there was a next nodeId to move on. + * @return Whether there was a next value to move on. */ - abstract boolean moveToNext(MapCursor cursor); + abstract boolean moveToNext(MapCursor cursor); ///////// FOR printing public abstract void prettyPrint(StringBuilder builder, int depth, int code); + @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); prettyPrint(stringBuilder, 0, -1); return stringBuilder.toString(); } - public void checkIntegrity(ContinousHashProvider hashProvider, V defaultValue, int depth) {} + public void checkIntegrity(ContinousHashProvider hashProvider, V defaultValue, int depth) { + } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java index 301bcb95..57256472 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java @@ -18,7 +18,6 @@ public class VersionedMapImpl implements VersionedMap { protected final VersionedMapStoreImpl store; protected final ContinousHashProvider hashProvider; - protected final V defaultValue; protected Node root; @@ -109,6 +108,7 @@ public class VersionedMapImpl implements VersionedMap { @Override public DiffCursor getDiffCursor(long toVersion) { + Cursor fromCursor = this.getAll(); VersionedMap toMap = this.store.createMap(toVersion); Cursor toCursor = toMap.getAll(); @@ -131,13 +131,35 @@ public class VersionedMapImpl implements VersionedMap { root = this.store.revert(state); } - public void prettyPrint() { - StringBuilder s = new StringBuilder(); + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((root == null) ? 0 : root.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + VersionedMapImpl other = (VersionedMapImpl) obj; + if (root == null) { + return other.root == null; + } else return root.equals(other.root); + } + + public String prettyPrint() { if (this.root != null) { + StringBuilder s = new StringBuilder(); this.root.prettyPrint(s, 0, -1); - System.out.println(s.toString()); + return s.toString(); } else { - System.out.println("empty tree"); + return "empty tree"; } } -- cgit v1.2.3-70-g09d2 From 15dcbeff0e28f0d6d3da8702b24f60ac52686609 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sun, 5 Feb 2023 00:13:13 +0100 Subject: Code quality improvements in nodes printer appending + empty node stack checking --- .../main/java/tools/refinery/store/map/internal/ImmutableNode.java | 7 ++++--- .../main/java/tools/refinery/store/map/internal/MutableNode.java | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java index e437aceb..914bab08 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java @@ -225,6 +225,9 @@ public class ImmutableNode extends Node { // 2. look inside the subnodes int nodes = Integer.bitCount(this.nodeMap); + if(cursor.nodeIndexStack.peek()==null) { + throw new IllegalStateException("Cursor moved to the next state when the state is empty."); + } int newNodeIndex = cursor.nodeIndexStack.peek() + 1; if (newNodeIndex < nodes) { // 2.1 found next subnode, move down to the subnode @@ -252,9 +255,7 @@ public class ImmutableNode extends Node { @Override public void prettyPrint(StringBuilder builder, int depth, int code) { - for (int i = 0; i < depth; i++) { - builder.append("\t"); - } + builder.append("\t".repeat(Math.max(0, depth))); if (code >= 0) { builder.append(code); builder.append(":"); diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java index 9d15a0d7..cdc66a10 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java @@ -306,6 +306,9 @@ public class MutableNode extends Node { } // 2. look inside the subnodes + if(cursor.nodeIndexStack.peek()==null) { + throw new IllegalStateException("Cursor moved to the next state when the state is empty."); + } for (int index = cursor.nodeIndexStack.peek() + 1; index < FACTOR; index++) { if (this.content[index * 2] == null && this.content[index * 2 + 1] != null) { // 2.1 found next subnode, move down to the subnode @@ -335,9 +338,7 @@ public class MutableNode extends Node { @Override public void prettyPrint(StringBuilder builder, int depth, int code) { - for (int i = 0; i < depth; i++) { - builder.append("\t"); - } + builder.append("\t".repeat(Math.max(0, depth))); if (code >= 0) { builder.append(code); builder.append(":"); -- cgit v1.2.3-70-g09d2 From f90f42e8834964b4e3f5a3504d896e64995b9a01 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sun, 5 Feb 2023 00:37:55 +0100 Subject: Code quality improvements in cursors --- .../java/tools/refinery/store/map/internal/HashClash.java | 4 ++-- .../java/tools/refinery/store/map/internal/MapCursor.java | 12 +++++++----- .../tools/refinery/store/map/internal/MapDiffCursor.java | 13 ++++++------- 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java index 5402ed4a..0806c486 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java @@ -5,12 +5,12 @@ enum HashClash { * Not stuck. */ NONE, - + /** * Clashed, next we should return the key of cursor 1. */ STUCK_CURSOR_1, - + /** * Clashed, next we should return the key of cursor 2. */ diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java index 91a71e3d..f874137b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java @@ -96,7 +96,7 @@ public class MapCursor implements Cursor { return Set.of(this.map); } - public static boolean sameSubnode(MapCursor cursor1, MapCursor cursor2) { + public static boolean sameSubNode(MapCursor cursor1, MapCursor cursor2) { Node nodeOfCursor1 = cursor1.nodeStack.peek(); Node nodeOfCursor2 = cursor2.nodeStack.peek(); if (nodeOfCursor1 != null && nodeOfCursor2 != null) { @@ -107,10 +107,12 @@ public class MapCursor implements Cursor { } /** - * @param - * @param - * @param cursor1 - * @param cursor2 + * Compares the state of two cursors started on two @{@link VersionedMap of the }same + * {@link tools.refinery.store.map.VersionedMapStore}. + * @param Key type + * @param Value type + * @param cursor1 first cursor + * @param cursor2 second cursor * @return Positive number if cursor 1 is behind, negative number if cursor 2 is behind, and 0 if they are at the * same position. */ diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java index 9cd78113..beaff13b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java @@ -131,22 +131,21 @@ public class MapDiffCursor implements DiffCursor, Cursor { protected void resolveHashClashWithSecondEntry() { switch (this.hashClash) { - case STUCK_CURSOR_1: + case STUCK_CURSOR_1 -> { this.hashClash = HashClash.NONE; this.cursorRelation = 0; this.key = cursor1.key; this.fromValue = cursor1.value; this.toValue = defaultValue; - break; - case STUCK_CURSOR_2: + } + case STUCK_CURSOR_2 -> { this.hashClash = HashClash.NONE; this.cursorRelation = 0; this.key = cursor2.key; this.fromValue = defaultValue; this.toValue = cursor2.value; - break; - default: - throw new IllegalArgumentException("Inconsistent compare result for diffcursor"); + } + default -> throw new IllegalArgumentException("Inconsistent compare result for diffcursor"); } } @@ -189,7 +188,7 @@ public class MapDiffCursor implements DiffCursor, Cursor { boolean lastResult = true; do { changed = false; - if (MapCursor.sameSubnode(cursor1, cursor2)) { + if (MapCursor.sameSubNode(cursor1, cursor2)) { lastResult = skipNode(); changed = true; } -- cgit v1.2.3-70-g09d2 From 354ff11cfa8bc2baf879a61ede8a3afebdeeabda Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sun, 5 Feb 2023 01:32:16 +0100 Subject: DiffCursor value comparison support for null values. in case null != default --- .../tools/refinery/store/map/internal/MapDiffCursor.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java index beaff13b..6c076ce5 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java @@ -5,6 +5,7 @@ import tools.refinery.store.map.ContinousHashProvider; import tools.refinery.store.map.Cursor; import tools.refinery.store.map.DiffCursor; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -121,7 +122,7 @@ public class MapDiffCursor implements DiffCursor, Cursor { this.fromValue = defaultValue; this.toValue = cursor2.value; } else { - throw new IllegalArgumentException("Inconsistent compare result for diffcursor"); + throw new IllegalArgumentException("Inconsistent compare result for diffCursor"); } } @@ -145,16 +146,17 @@ public class MapDiffCursor implements DiffCursor, Cursor { this.fromValue = defaultValue; this.toValue = cursor2.value; } - default -> throw new IllegalArgumentException("Inconsistent compare result for diffcursor"); + default -> throw new IllegalArgumentException("Inconsistent compare result for diffCursor"); } } + /** + * Checks if two states has the same values, i.e., there is no difference. + * @return whether two states has the same values + */ protected boolean sameValues() { - if (this.fromValue == null) { - return this.toValue == null; - } else { - return this.fromValue.equals(this.toValue); - } + if(cursor1.isTerminated() || cursor2.isTerminated()) return false; + else return Objects.equals(this.fromValue, this.toValue); } protected boolean moveOne() { -- cgit v1.2.3-70-g09d2 From c5fe88455146ca948b28f85b39b1554d99529b20 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sun, 5 Feb 2023 01:33:46 +0100 Subject: Cursor comparison bugfix with empty cursors (and null values). --- .../main/java/tools/refinery/store/map/internal/MapCursor.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java index f874137b..50fcfcd3 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java @@ -117,7 +117,12 @@ public class MapCursor implements Cursor { * same position. */ public static int compare(MapCursor cursor1, MapCursor cursor2) { - // two cursors are equally deep + // Checking the state of the cursors + if(!cursor1.isTerminated() && cursor2.isTerminated()) return -1; + else if(cursor1.isTerminated() && !cursor2.isTerminated()) return 1; + else if(cursor1.isTerminated() && cursor2.isTerminated()) return 0; + + // If the state does not determine the order, then compare @nodeIndexStack. Iterator stack1 = cursor1.nodeIndexStack.descendingIterator(); Iterator stack2 = cursor2.nodeIndexStack.descendingIterator(); if (stack1.hasNext()) { @@ -137,6 +142,8 @@ public class MapCursor implements Cursor { // stack 2 has more element, thus stack 2 is deeper return 1; } + + // two cursors are equally deep decide by data index return Integer.compare(cursor1.dataIndex, cursor2.dataIndex); } } -- cgit v1.2.3-70-g09d2 From 80a08f099b220fe7aca45cb6ef30da02be0087ca Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sun, 5 Feb 2023 02:32:27 +0100 Subject: fixup! Performance improvements by replacing hash depth calculation with shifting, improving code quality. + formatting --- .../store/map/internal/VersionedMapImpl.java | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java index 57256472..674ffc47 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java @@ -131,28 +131,6 @@ public class VersionedMapImpl implements VersionedMap { root = this.store.revert(state); } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((root == null) ? 0 : root.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - VersionedMapImpl other = (VersionedMapImpl) obj; - if (root == null) { - return other.root == null; - } else return root.equals(other.root); - } - public String prettyPrint() { if (this.root != null) { StringBuilder s = new StringBuilder(); -- cgit v1.2.3-70-g09d2 From 8403277d0a967f234c46f09cf54185ce3ed01c8b Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sun, 5 Feb 2023 20:05:04 +0100 Subject: Extending map tests with null as default value. --- .../map/benchmarks/ImmutablePutExecutionPlan.java | 2 +- .../store/map/tests/fuzz/CommitFuzzTest.java | 28 ++++++++------ .../map/tests/fuzz/ContentEqualsFuzzTest.java | 27 +++++++------- .../store/map/tests/fuzz/DiffCursorFuzzTest.java | 29 +++++++++------ .../store/map/tests/fuzz/MultiThreadFuzzTest.java | 43 ++++++++++++---------- .../store/map/tests/fuzz/MutableFuzzTest.java | 27 ++++++++------ .../fuzz/MutableImmutableCompareFuzzTest.java | 26 +++++++------ .../store/map/tests/fuzz/RestoreFuzzTest.java | 25 +++++++------ .../store/map/tests/fuzz/SharedStoreFuzzTest.java | 32 ++++++++-------- .../store/map/tests/utils/MapTestEnvironment.java | 9 ++++- 10 files changed, 139 insertions(+), 109 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java index 756d504e..5484f115 100644 --- a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java +++ b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java @@ -35,7 +35,7 @@ public class ImmutablePutExecutionPlan { @Setup(Level.Trial) public void setUpTrial() { random = new Random(); - values = MapTestEnvironment.prepareValues(nValues); + values = MapTestEnvironment.prepareValues(nValues, true); } public VersionedMapImpl createSut() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java index 1f9d022f..c872b9da 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java @@ -19,9 +19,10 @@ import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; class CommitFuzzTest { - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, - boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue); + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, + boolean nullDefault, int commitFrequency, + boolean evilHash) { + String[] values = MapTestEnvironment.prepareValues(maxValue,nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); @@ -64,30 +65,33 @@ class CommitFuzzTest { } } - @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + + "seed={6} evil-hash={7}") @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, + boolean evilHash) { runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + nullDefault, commitFrequency, evilHash); } static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, + new Object[] { 2, 3 }, new Object[]{false,true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, new Object[] { false, true }); } - @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + + "seed={6} evil-hash={7}") @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + nullDefault, commitFrequency, evilHash); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index 93ecfec3..a5a68b94 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java @@ -20,9 +20,10 @@ import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; class ContentEqualsFuzzTest { - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, + boolean nullDefault, int commitFrequency, boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue); + String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); Random r = new Random(seed); @@ -80,33 +81,33 @@ class ContentEqualsFuzzTest { MapTestEnvironment.compareTwoMaps(scenario, sut1, sut2); } - @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + - "evil-hash={6}") + @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit frequency={5}" + + "seed={6} evil-hash={7}") @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + nullDefault, commitFrequency, evilHash); } static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, - new Object[]{2, 3}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, + new Object[]{2, 3}, new Object[]{false,true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, new Object[]{false, true}); } - @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + - "evil-hash={6}") + @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit frequency={5}" + + "seed={6} evil-hash={7}") @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + defaultNull, commitFrequency, evilHash); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java index e6334224..670b5445 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java @@ -20,17 +20,18 @@ import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; class DiffCursorFuzzTest { - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, + boolean nullDefault, int commitFrequency, boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue); + String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); - iterativeRandomPutsAndCommitsThenDiffcursor(scenario, store, steps, maxKey, values, seed, commitFrequency); + iterativeRandomPutsAndCommitsThenDiffCursor(scenario, store, steps, maxKey, values, seed, commitFrequency); } - private void iterativeRandomPutsAndCommitsThenDiffcursor(String scenario, VersionedMapStore store, - int steps, int maxKey, String[] values, int seed, int commitFrequency) { + private void iterativeRandomPutsAndCommitsThenDiffCursor(String scenario, VersionedMapStore store, + int steps, int maxKey, String[] values, int seed, int commitFrequency) { // 1. build a map with versions Random r = new Random(seed); VersionedMapImpl versioned = (VersionedMapImpl) store.createMap(); @@ -86,29 +87,33 @@ class DiffCursorFuzzTest { } - @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + + "commit frequency={5} seed={6} evil-hash={7}") @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, + void parametrizedFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, - noKeys, noValues, commitFrequency, evilHash); + noKeys, noValues, nullDefault, commitFrequency, evilHash); } static Stream parametrizedFuzz() { return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, + new Object[] { 2, 3 }, new Object[]{false,true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, new Object[] { false, true }); } - @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + + "commit frequency={5} seed={6} evil-hash={7}") @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, + void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + nullDefault, commitFrequency, evilHash); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java index 1ab431a8..d8e1a30f 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java @@ -22,31 +22,32 @@ import tools.refinery.store.map.tests.utils.MapTestEnvironment; class MultiThreadFuzzTest { public static final int noThreads = 32; - - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, - boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue); + + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, + boolean nullDefault, int commitFrequency, + boolean evilHash) { + String[] values = MapTestEnvironment.prepareValues(maxValue,nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); - + // initialize runnables MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads]; for(int i = 0; i errors = new LinkedList<>(); for(int i = 0; i parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[] { 10, 100 }, new Object[] { 1, 2, 3 }, + new Object[] { 2, 3 }, new Object[]{false, true}, new Object[] { 10, 100 }, new Object[] { 1, 2, 3 }, new Object[] { false, true }); } - @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + + "frequency={5} seed={6} evil-hash={7}") @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, + boolean evilHash) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + nullDefault, commitFrequency, evilHash); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java index d40c49c4..008258bd 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java @@ -19,8 +19,9 @@ import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; class MutableFuzzTest { - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue); + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, + boolean nullDefault, boolean evilHash) { + String[] values = MapTestEnvironment.prepareValues(maxValue,nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); @@ -60,30 +61,34 @@ class MutableFuzzTest { } } - @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}") + @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} seed={5} " + + "evil-hash={6}") @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) { + void parametrizedFuzz(int test, int steps, int noKeys, int noValues, boolean defaultNull, int seed, + boolean evilHash) { runFuzzTest( "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), - seed, steps, noKeys, noValues, evilHash); + seed, steps, noKeys, noValues, defaultNull, evilHash); } static Stream parametrizedFuzz() { return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, - new Object[] { 3, 32, 32 * 32, 32 * 32 * 32 * 32 }, new Object[] { 2, 3 }, new Object[] { 1, 2, 3 }, - new Object[] { false, true }); + new Object[] { 3, 32, 32 * 32, 32 * 32 * 32 * 32 }, new Object[] { 2, 3 }, new Object[] { false, true }, + new Object[] { 1, 2, 3 }, new Object[] { false, true }); } - - @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}") + + @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} seed={5} " + + "evil-hash={6}") @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) { + void parametrizedSlowFuzz(int test, int steps, int noKeys, int noValues, boolean nullDefault, int seed, + boolean evilHash) { runFuzzTest( "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), - seed, steps, noKeys, noValues, evilHash); + seed, steps, noKeys, noValues, nullDefault, evilHash); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java index 410705a2..6e15b8ca 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java @@ -19,9 +19,9 @@ import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; class MutableImmutableCompareFuzzTest { - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, - boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue); + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, + boolean nullDefault, int commitFrequency, boolean evilHash) { + String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); @@ -57,30 +57,32 @@ class MutableImmutableCompareFuzzTest { } } - @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + + "commit frequency={5} seed={6} evil-hash={7}") @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, - noKeys, noValues, commitFrequency, evilHash); + noKeys, noValues, nullDefault, commitFrequency, evilHash); } static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, + new Object[] { 2, 3 }, new Object[]{false,true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, new Object[] { false, true }); } - @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + + "commit frequency={5} seed={6} evil-hash={7}") @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, - noKeys, noValues, commitFrequency, evilHash); + noKeys, noValues, nullDefault, commitFrequency, evilHash); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java index 2e29a03f..35a54712 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java @@ -21,9 +21,10 @@ import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; class RestoreFuzzTest { - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, + boolean nullDefault, int commitFrequency, boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue); + String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); @@ -77,30 +78,32 @@ class RestoreFuzzTest { } - @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5}" + + " seed={6} evil-hash={7}") @MethodSource @Timeout(value = 10) @Tag("smoke") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + nullDefault, commitFrequency, evilHash); } static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, + new Object[] { 2, 3 }, new Object[]{false, true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, new Object[] { false, true }); } - @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5}" + + " seed={6} evil-hash={7}") @MethodSource @Tag("smoke") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + nullDefault, commitFrequency, evilHash); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java index 914a0f63..ac033edb 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java @@ -21,9 +21,9 @@ import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; class SharedStoreFuzzTest { - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, - boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue); + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, + boolean nullDefault, int commitFrequency, boolean evilHash) { + String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); List> stores = VersionedMapStoreImpl.createSharedVersionedMapStores(5, chp, values[0]); @@ -39,7 +39,7 @@ class SharedStoreFuzzTest { for(VersionedMapStore store : stores) { versioneds.add((VersionedMapImpl) store.createMap()); } - + List> index2Version = new LinkedList<>(); for(int i = 0; i()); @@ -56,7 +56,7 @@ class SharedStoreFuzzTest { index2Version.get(storeIndex).put(i, version); } MapTestEnvironment.printStatus(scenario, stepIndex, steps, "building"); - } + } } // 2. create a non-versioned and List> reference = new LinkedList<>(); @@ -76,35 +76,37 @@ class SharedStoreFuzzTest { MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference.get(storeIndex), versioneds.get(storeIndex)); } } - MapTestEnvironment.printStatus(scenario, index, steps, "comparison"); + MapTestEnvironment.printStatus(scenario, index, steps, "comparison"); } } - @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit " + + "frequency={4} seed={5} evil-hash={6}") @MethodSource @Timeout(value = 10) @Tag("smoke") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + nullDefault, commitFrequency, evilHash); } static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, + new Object[] { 2, 3 }, new Object[]{false, true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, new Object[] { false, true }); } - @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") + @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit " + + "frequency={4} seed={5} evil-hash={6}") @MethodSource @Tag("smoke") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + int seed, boolean evilHash) { runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - commitFrequency, evilHash); + nullDefault, commitFrequency, evilHash); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java index 2d03ebaf..10ea2796 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java @@ -9,9 +9,14 @@ import java.util.Map.Entry; import static org.junit.jupiter.api.Assertions.*; public class MapTestEnvironment { - public static String[] prepareValues(int maxValue) { + public static String[] prepareValues(int maxValue, boolean nullDefault) { String[] values = new String[maxValue]; - values[0] = "DEFAULT"; + if(nullDefault) { + values[0] = null; + } else { + values[0] = "DEFAULT"; + } + for (int i = 1; i < values.length; i++) { values[i] = "VAL" + i; } -- cgit v1.2.3-70-g09d2 From 01d06bb9d04894029d2be304f6d4dccb757ea9dc Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sun, 5 Feb 2023 20:27:45 +0100 Subject: Formatting fuzz tests + improving code qualitz --- .../store/map/tests/fuzz/CommitFuzzTest.java | 25 +++++----------- .../map/tests/fuzz/ContentEqualsFuzzTest.java | 6 ++-- .../store/map/tests/fuzz/DiffCursorFuzzTest.java | 17 ++++++----- .../store/map/tests/fuzz/MultiThreadFuzzTest.java | 32 ++++++++++---------- .../map/tests/fuzz/MultiThreadTestRunnable.java | 34 +++++++++++----------- .../store/map/tests/fuzz/MutableFuzzTest.java | 26 +++++------------ .../fuzz/MutableImmutableCompareFuzzTest.java | 12 ++++---- .../store/map/tests/fuzz/RestoreFuzzTest.java | 12 ++++---- .../store/map/tests/fuzz/SharedStoreFuzzTest.java | 18 ++++++------ .../store/map/tests/fuzz/utils/FuzzTestUtils.java | 10 +++---- .../map/tests/fuzz/utils/FuzzTestUtilsTest.java | 19 +++++++----- .../store/map/tests/utils/MapTestEnvironment.java | 25 +++++++--------- 12 files changed, 107 insertions(+), 129 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java index c872b9da..cd32337e 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java @@ -22,12 +22,12 @@ class CommitFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue,nullDefault); + String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); + VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); VersionedMapImpl sut = (VersionedMapImpl) store.createMap(); - MapTestEnvironment e = new MapTestEnvironment(sut); + MapTestEnvironment e = new MapTestEnvironment<>(sut); Random r = new Random(seed); @@ -35,24 +35,13 @@ class CommitFuzzTest { } private void iterativeRandomPutsAndCommits(String scenario, int steps, int maxKey, String[] values, - MapTestEnvironment e, Random r, int commitFrequency) { - int stopAt = -1; + MapTestEnvironment e, Random r, int commitFrequency) { for (int i = 0; i < steps; i++) { int index = i + 1; int nextKey = r.nextInt(maxKey); String nextValue = values[r.nextInt(values.length)]; - if (index == stopAt) { - System.out.println("issue!"); - System.out.println("State before:"); - e.printComparison(); - e.sut.prettyPrint(); - System.out.println("Next: put(" + nextKey + "," + nextValue + ")"); - } try { e.put(nextKey, nextValue); - if (index == stopAt) { - e.sut.prettyPrint(); - } e.checkEquivalence(scenario + ":" + index); } catch (Exception exception) { exception.printStackTrace(); @@ -78,9 +67,9 @@ class CommitFuzzTest { } static Stream parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[]{false,true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, - new Object[] { false, true }); + return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, + new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, + new Object[]{false, true}); } @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index a5a68b94..996bfa03 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java @@ -34,7 +34,7 @@ class ContentEqualsFuzzTest { private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider chp, int steps, int maxKey, String[] values, Random r, int commitFrequency) { - VersionedMapStore store1 = new VersionedMapStoreImpl(chp, values[0]); + VersionedMapStore store1 = new VersionedMapStoreImpl<>(chp, values[0]); VersionedMap sut1 = store1.createMap(); // Fill one map @@ -64,7 +64,7 @@ class ContentEqualsFuzzTest { // Randomize the order of the content Collections.shuffle(content, r); - VersionedMapStore store2 = new VersionedMapStoreImpl(chp, values[0]); + VersionedMapStore store2 = new VersionedMapStoreImpl<>(chp, values[0]); VersionedMap sut2 = store2.createMap(); int index2 = 1; for (SimpleEntry entry : content) { @@ -95,7 +95,7 @@ class ContentEqualsFuzzTest { static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, - new Object[]{2, 3}, new Object[]{false,true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, + new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, new Object[]{false, true}); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java index 670b5445..4f7f48b5 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java @@ -22,11 +22,11 @@ import tools.refinery.store.map.tests.utils.MapTestEnvironment; class DiffCursorFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, - boolean evilHash) { + boolean evilHash) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); + VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); iterativeRandomPutsAndCommitsThenDiffCursor(scenario, store, steps, maxKey, values, seed, commitFrequency); } @@ -62,7 +62,7 @@ class DiffCursorFuzzTest { for (int i = 0; i < steps; i++) { int index = i + 1; if (index % diffTravelFrequency == 0) { - // difftravel + // diff-travel long travelToVersion = r2.nextInt(largestCommit + 1); DiffCursor diffCursor = moving.getDiffCursor(travelToVersion); moving.putAll(diffCursor); @@ -94,16 +94,17 @@ class DiffCursorFuzzTest { @Tag("fuzz") void parametrizedFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, - boolean evilHash) { + boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); } static Stream parametrizedFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[]{false,true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, - new Object[] { false, true }); + return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, + new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, + new Object[]{false, true}); } + @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + "commit frequency={5} seed={6} evil-hash={7}") @MethodSource @@ -111,7 +112,7 @@ class DiffCursorFuzzTest { @Tag("slow") void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, - boolean evilHash) { + boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java index d8e1a30f..5412d958 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java @@ -26,64 +26,64 @@ class MultiThreadFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue,nullDefault); + String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); + VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); // initialize runnables MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads]; - for(int i = 0; i errors = new LinkedList<>(); - for(int i = 0; i parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[]{false, true}, new Object[] { 10, 100 }, new Object[] { 1, 2, 3 }, - new Object[] { false, true }); + return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, + new Object[]{2, 3}, new Object[]{false, true}, new Object[]{10, 100}, new Object[]{1, 2, 3}, + new Object[]{false, true}); } - @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + + @ParameterizedTest(name = "MultiThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + "frequency={5} seed={6} evil-hash={7}") @MethodSource @Tag("fuzz") diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java index f77f9ee5..4415e4e5 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java @@ -13,17 +13,17 @@ import tools.refinery.store.map.internal.VersionedMapImpl; import tools.refinery.store.map.tests.utils.MapTestEnvironment; public class MultiThreadTestRunnable implements Runnable { - String scenario; - VersionedMapStore store; - int steps; - int maxKey; - String[] values; - int seed; - int commitFrequency; - List errors = new LinkedList<>(); - + final String scenario; + final VersionedMapStore store; + final int steps; + final int maxKey; + final String[] values; + final int seed; + final int commitFrequency; + final List errors = new LinkedList<>(); + public MultiThreadTestRunnable(String scenario, VersionedMapStore store, int steps, - int maxKey, String[] values, int seed, int commitFrequency) { + int maxKey, String[] values, int seed, int commitFrequency) { super(); this.scenario = scenario; this.store = store; @@ -38,11 +38,11 @@ public class MultiThreadTestRunnable implements Runnable { AssertionError error = new AssertionError(message); errors.add(error); } - + public List getErrors() { return errors; } - + @Override public void run() { // 1. build a map with versions @@ -66,10 +66,10 @@ public class MultiThreadTestRunnable implements Runnable { } MapTestEnvironment.printStatus(scenario, index, steps, "building"); } - // 2. create a non-versioned + // 2. create a non-versioned VersionedMapImpl reference = (VersionedMapImpl) store.createMap(); r = new Random(seed); - Random r2 = new Random(seed+1); + Random r2 = new Random(seed + 1); for (int i = 0; i < steps; i++) { int index = i + 1; @@ -84,12 +84,12 @@ public class MultiThreadTestRunnable implements Runnable { // go back to an existing state and compare to the reference if (index % (commitFrequency) == 0) { versioned.restore(index2Version.get(i)); - MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned,errors); - + MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned, errors); + // go back to a random state (probably created by another thread) List states = new ArrayList<>(store.getStates()); Collections.shuffle(states, r2); - for(Long state : states.subList(0, Math.min(states.size(), 100))) { + for (Long state : states.subList(0, Math.min(states.size(), 100))) { versioned.restore(state); } versioned.restore(index2Version.get(i)); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java index 008258bd..2448268a 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java @@ -21,12 +21,12 @@ import tools.refinery.store.map.tests.utils.MapTestEnvironment; class MutableFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, boolean evilHash) { - String[] values = MapTestEnvironment.prepareValues(maxValue,nullDefault); + String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); + VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); VersionedMapImpl sut = (VersionedMapImpl) store.createMap(); - MapTestEnvironment e = new MapTestEnvironment(sut); + MapTestEnvironment e = new MapTestEnvironment<>(sut); Random r = new Random(seed); @@ -34,24 +34,14 @@ class MutableFuzzTest { } private void iterativeRandomPuts(String scenario, int steps, int maxKey, String[] values, - MapTestEnvironment e, Random r) { - int stopAt = -1; + MapTestEnvironment e, Random r) { for (int i = 0; i < steps; i++) { int index = i + 1; int nextKey = r.nextInt(maxKey); String nextValue = values[r.nextInt(values.length)]; - if (index == stopAt) { - System.out.println("issue!"); - System.out.println("State before:"); - e.printComparison(); - e.sut.prettyPrint(); - System.out.println("Next: put(" + nextKey + "," + nextValue + ")"); - } + try { e.put(nextKey, nextValue); - if (index == stopAt) { - e.sut.prettyPrint(); - } e.checkEquivalence(scenario + ":" + index); } catch (Exception exception) { exception.printStackTrace(); @@ -74,9 +64,9 @@ class MutableFuzzTest { } static Stream parametrizedFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, - new Object[] { 3, 32, 32 * 32, 32 * 32 * 32 * 32 }, new Object[] { 2, 3 }, new Object[] { false, true }, - new Object[] { 1, 2, 3 }, new Object[] { false, true }); + return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, + new Object[]{3, 32, 32 * 32, 32 * 32 * 32 * 32}, new Object[]{2, 3}, new Object[]{false, true}, + new Object[]{1, 2, 3}, new Object[]{false, true}); } @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} seed={5} " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java index 6e15b8ca..07ca4f69 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java @@ -24,7 +24,7 @@ class MutableImmutableCompareFuzzTest { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); + VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); VersionedMapImpl immutable = (VersionedMapImpl) store.createMap(); VersionedMapImpl mutable = (VersionedMapImpl) store.createMap(); @@ -35,8 +35,8 @@ class MutableImmutableCompareFuzzTest { } private void iterativeRandomPutsAndCommitsAndCompare(String scenario, VersionedMapImpl immutable, - VersionedMapImpl mutable, int steps, int maxKey, String[] values, Random r, - int commitFrequency) { + VersionedMapImpl mutable, int steps, int maxKey, String[] values, Random r, + int commitFrequency) { for (int i = 0; i < steps; i++) { int index = i + 1; int nextKey = r.nextInt(maxKey); @@ -69,9 +69,9 @@ class MutableImmutableCompareFuzzTest { } static Stream parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[]{false,true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, - new Object[] { false, true }); + return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, + new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, + new Object[]{false, true}); } @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java index 35a54712..e0366381 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java @@ -23,17 +23,17 @@ import tools.refinery.store.map.tests.utils.MapTestEnvironment; class RestoreFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, - boolean evilHash) { + boolean evilHash) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl(chp, values[0]); + VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); iterativeRandomPutsAndCommitsThenRestore(scenario, store, steps, maxKey, values, seed, commitFrequency); } private void iterativeRandomPutsAndCommitsThenRestore(String scenario, VersionedMapStore store, - int steps, int maxKey, String[] values, int seed, int commitFrequency) { + int steps, int maxKey, String[] values, int seed, int commitFrequency) { // 1. build a map with versions Random r = new Random(seed); VersionedMapImpl versioned = (VersionedMapImpl) store.createMap(); @@ -90,9 +90,9 @@ class RestoreFuzzTest { } static Stream parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[]{false, true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, - new Object[] { false, true }); + return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, + new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, + new Object[]{false, true}); } @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5}" + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java index ac033edb..a576b1c8 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java @@ -32,22 +32,22 @@ class SharedStoreFuzzTest { } private void iterativeRandomPutsAndCommitsThenRestore(String scenario, List> stores, - int steps, int maxKey, String[] values, int seed, int commitFrequency) { + int steps, int maxKey, String[] values, int seed, int commitFrequency) { // 1. maps with versions Random r = new Random(seed); List> versioneds = new LinkedList<>(); - for(VersionedMapStore store : stores) { + for (VersionedMapStore store : stores) { versioneds.add((VersionedMapImpl) store.createMap()); } List> index2Version = new LinkedList<>(); - for(int i = 0; i()); } for (int i = 0; i < steps; i++) { int stepIndex = i + 1; - for (int storeIndex = 0; storeIndex> reference = new LinkedList<>(); - for(VersionedMapStore store : stores) { + for (VersionedMapStore store : stores) { reference.add((VersionedMapImpl) store.createMap()); } r = new Random(seed); for (int i = 0; i < steps; i++) { int index = i + 1; - for (int storeIndex = 0; storeIndex parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, - new Object[] { 2, 3 }, new Object[]{false, true}, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, - new Object[] { false, true }); + return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, + new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, + new Object[]{false, true}); } @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java index e75d7f5a..92208e48 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java @@ -51,14 +51,12 @@ public final class FuzzTestUtils { public static Stream permutationWithSize(Object[]... valueOption) { int size = 1; - for (int i = 0; i < valueOption.length; i++) { - size *= valueOption[i].length; + for (Object[] objects : valueOption) { + size *= objects.length; } Object[][] newValueOption = new Object[valueOption.length + 1][]; - newValueOption[0] = new Object[] { size }; - for (int i = 1; i < newValueOption.length; i++) { - newValueOption[i] = valueOption[i - 1]; - } + newValueOption[0] = new Object[]{size}; + System.arraycopy(valueOption, 0, newValueOption, 1, newValueOption.length - 1); return permutation(newValueOption); } } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java index 72f2a46c..8c641205 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java @@ -1,31 +1,36 @@ package tools.refinery.store.map.tests.fuzz.utils; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.provider.Arguments; class FuzzTestUtilsTest { @Test void permutationInternalTest() { - List> res = FuzzTestUtils.permutationInternal(0, new Object[] { 1, 2, 3 }, - new Object[] { 'a', 'b', 'c' }, new Object[] { "alpha", "beta", "gamma", "delta" }); + List> res = FuzzTestUtils.permutationInternal(0, new Object[]{1, 2, 3}, + new Object[]{'a', 'b', 'c'}, new Object[]{"alpha", "beta", "gamma", "delta"}); assertEquals(3 * 3 * 4, res.size()); } @Test void permutationTest1() { - var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' }, - new Object[] { "alpha", "beta", "gamma", "delta" }); + var res = FuzzTestUtils.permutation(new Object[]{1, 2, 3}, new Object[]{'a', 'b', 'c'}, + new Object[]{"alpha", "beta", "gamma", "delta"}); assertEquals(3 * 3 * 4, res.count()); } @Test void permutationTest2() { - var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' }, - new Object[] { "alpha", "beta", "gamma", "delta" }); - var arguments = res.findFirst().get().get(); + var res = FuzzTestUtils.permutation(new Object[]{1, 2, 3}, new Object[]{'a', 'b', 'c'}, + new Object[]{"alpha", "beta", "gamma", "delta"}); + Optional first = res.findFirst(); + assertTrue(first.isPresent()); + var arguments = first.get().get(); assertEquals(1, arguments[0]); assertEquals('a', arguments[1]); assertEquals("alpha", arguments[2]); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java index 10ea2796..30f38201 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java @@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.*; public class MapTestEnvironment { public static String[] prepareValues(int maxValue, boolean nullDefault) { String[] values = new String[maxValue]; - if(nullDefault) { + if (nullDefault) { values[0] = null; } else { values[0] = "DEFAULT"; @@ -26,23 +26,18 @@ public class MapTestEnvironment { public static ContinousHashProvider prepareHashProvider(final boolean evil) { // Use maxPrime = 2147483629 - ContinousHashProvider chp = new ContinousHashProvider() { - - @Override - public int getHash(Integer key, int index) { - if (evil && index < 15 && index < key / 3) { - return 7; - } - int result = 1; - final int prime = 31; + return (key, index) -> { + if (evil && index < 15 && index < key / 3) { + return 7; + } + int result = 1; + final int prime = 31; - result = prime * result + key; - result = prime * result + index; + result = prime * result + key; + result = prime * result + index; - return result; - } + return result; }; - return chp; } public static void printStatus(String scenario, int actual, int max, String stepName) { -- cgit v1.2.3-70-g09d2 From 3b7bb0e09a292df61892613fda8ff1b17a999369 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sun, 5 Feb 2023 20:34:15 +0100 Subject: Fixing warning caused by an "unused parameter" which is used by an annotation --- .../test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java | 4 ++-- .../tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java | 4 ++-- .../java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java | 4 ++-- .../java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java | 4 ++-- .../java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java | 4 ++-- .../store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java | 4 ++-- .../java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java | 4 ++-- .../java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java index cd32337e..9e3f636b 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java @@ -59,7 +59,7 @@ class CommitFuzzTest { @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, @@ -77,7 +77,7 @@ class CommitFuzzTest { @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index 996bfa03..71cb3d11 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java @@ -86,7 +86,7 @@ class ContentEqualsFuzzTest { @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); @@ -104,7 +104,7 @@ class ContentEqualsFuzzTest { @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency, + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, evilHash); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java index 4f7f48b5..8a5576aa 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java @@ -92,7 +92,7 @@ class DiffCursorFuzzTest { @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, @@ -110,7 +110,7 @@ class DiffCursorFuzzTest { @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java index 5412d958..5d5f3ce3 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java @@ -71,7 +71,7 @@ class MultiThreadFuzzTest { @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency, + void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("MultiThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency + "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, evilHash); @@ -88,7 +88,7 @@ class MultiThreadFuzzTest { @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java index 2448268a..2d65ba0c 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java @@ -56,7 +56,7 @@ class MutableFuzzTest { @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFuzz(int test, int steps, int noKeys, int noValues, boolean defaultNull, int seed, + void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int seed, boolean evilHash) { runFuzzTest( "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), @@ -74,7 +74,7 @@ class MutableFuzzTest { @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int test, int steps, int noKeys, int noValues, boolean nullDefault, int seed, + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int seed, boolean evilHash) { runFuzzTest( "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java index 07ca4f69..da8a43c2 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java @@ -62,7 +62,7 @@ class MutableImmutableCompareFuzzTest { @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); @@ -79,7 +79,7 @@ class MutableImmutableCompareFuzzTest { @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java index e0366381..bd03d1e9 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java @@ -83,7 +83,7 @@ class RestoreFuzzTest { @MethodSource @Timeout(value = 10) @Tag("smoke") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); @@ -100,7 +100,7 @@ class RestoreFuzzTest { @MethodSource @Tag("smoke") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java index a576b1c8..0fc9cd38 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java @@ -86,7 +86,7 @@ class SharedStoreFuzzTest { @MethodSource @Timeout(value = 10) @Tag("smoke") - void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); @@ -103,7 +103,7 @@ class SharedStoreFuzzTest { @MethodSource @Tag("smoke") @Tag("slow") - void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean evilHash) { runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); -- cgit v1.2.3-70-g09d2 From a36a8eb9ad499eb0f50204e462e9bc1c45544294 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Sun, 5 Feb 2023 21:35:28 +0100 Subject: Delta store commit --- .../store/map/VersionedMapStoreDeltaImpl.java | 90 ++++++++++++ .../store/map/internal/DeltaDiffCursor.java | 127 +++++++++++++++++ .../store/map/internal/IteratorAsCursor.java | 62 ++++++++ .../refinery/store/map/internal/MapDelta.java | 15 ++ .../store/map/internal/MapTransaction.java | 34 +++++ .../map/internal/UncommittedDeltaArrayStore.java | 31 ++++ .../map/internal/UncommittedDeltaMapStore.java | 47 +++++++ .../store/map/internal/UncommittedDeltaStore.java | 10 ++ .../store/map/internal/VersionedMapDeltaImpl.java | 156 +++++++++++++++++++++ 9 files changed, 572 insertions(+) create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDelta.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/MapTransaction.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaArrayStore.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java new file mode 100644 index 00000000..2bd758e2 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java @@ -0,0 +1,90 @@ +package tools.refinery.store.map; + +import java.util.*; + +import tools.refinery.store.map.internal.DeltaDiffCursor; +import tools.refinery.store.map.internal.MapDelta; +import tools.refinery.store.map.internal.MapTransaction; +import tools.refinery.store.map.internal.VersionedMapDeltaImpl; + +public class VersionedMapStoreDeltaImpl implements VersionedMapStore{ + // Static data + protected final V defaultValue; + + // Dynamic data + protected final Map> states = new HashMap<>(); + protected long nextID = 0; + + public VersionedMapStoreDeltaImpl(V defaultValue) { + super(); + this.defaultValue = defaultValue; + } + + @Override + public VersionedMap createMap() { + return new VersionedMapDeltaImpl<>(this, defaultValue); + } + + @Override + public VersionedMap createMap(long state) { + VersionedMapDeltaImpl result = new VersionedMapDeltaImpl<>(this, defaultValue); + result.restore(state); + return result; + } + + public synchronized MapTransaction appendTransaction(MapDelta[] deltas, MapTransaction previous, long[] versionContainer) { + long version = nextID++; + versionContainer[0] = version; + if(deltas == null) { + states.put(version, previous); + return previous; + } else { + MapTransaction transaction = new MapTransaction<>(deltas, version, previous); + states.put(version, transaction); + return transaction; + } + } + + private synchronized MapTransaction getState(long state) { + return states.get(state); + } + + public void getPath(long to, List[]> forwardTransactions) { + MapTransaction toTransaction = getState(to); + while(toTransaction != null) { + forwardTransactions.add(toTransaction.deltas()); + toTransaction = toTransaction.parent(); + } + } + + public void getPath(long from, long to, + List[]> backwardTransactions, + List[]> forwardTransactions) + { + MapTransaction fromTransaction = getState(from); + MapTransaction toTransaction = getState(to); + while(fromTransaction != toTransaction) { + if(fromTransaction == null || fromTransaction.version() < toTransaction.version()) { + forwardTransactions.add(toTransaction.deltas()); + toTransaction = toTransaction.parent(); + } else { + backwardTransactions.add(fromTransaction.deltas()); + fromTransaction = fromTransaction.parent(); + } + } + } + + + @Override + public synchronized Set getStates() { + return states.keySet(); + } + + @Override + public DiffCursor getDiffCursor(long fromState, long toState) { + List[]> backwardTransactions = new ArrayList<>(); + List[]> forwardTransactions = new ArrayList<>(); + getPath(fromState, toState, backwardTransactions, forwardTransactions); + return new DeltaDiffCursor<>(backwardTransactions, forwardTransactions); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java new file mode 100644 index 00000000..75180bf9 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java @@ -0,0 +1,127 @@ +package tools.refinery.store.map.internal; + +import tools.refinery.store.map.AnyVersionedMap; +import tools.refinery.store.map.DiffCursor; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class DeltaDiffCursor implements DiffCursor { + final List[]> backwardTransactions; + final List[]> forwardTransactions; + + /** + * Denotes the direction of traversal. False means backwards, true means + * forward. + */ + boolean direction; + int listIndex; + int arrayIndex; + + public DeltaDiffCursor(List[]> backwardTransactions, List[]> forwardTransactions) { + this.backwardTransactions = backwardTransactions; + this.forwardTransactions = forwardTransactions; + + if (!backwardTransactions.isEmpty()) { + direction = false; + listIndex = 0; + arrayIndex = backwardTransactions.get(listIndex).length - 1; + } else if (!forwardTransactions.isEmpty()) { + direction = true; + listIndex = forwardTransactions.size() - 1; + arrayIndex = 0; + } else { + direction = true; + listIndex = -1; + } + } + + protected MapDelta getCurrentDelta() { + final List[]> list; + if (!direction) { + list = this.backwardTransactions; + } else { + list = this.forwardTransactions; + } + return list.get(listIndex)[arrayIndex]; + } + + @Override + public K getKey() { + return getCurrentDelta().getKey(); + } + + @Override + public V getValue() { + return getToValue(); + } + + @Override + public boolean isTerminated() { + return this.direction && listIndex == -1; + } + + @Override + public boolean move() { + if (isTerminated()) { + return false; + } else { + if (this.direction) { + if (arrayIndex+1 < forwardTransactions.get(listIndex).length) { + arrayIndex++; + return true; + } else { + if (listIndex-1 >= 0) { + listIndex--; + return true; + } else { + listIndex = -1; + return false; + } + } + } else { + if (arrayIndex > 0) { + arrayIndex--; + return true; + } else { + if (listIndex+1 < backwardTransactions.size()) { + listIndex++; + this.arrayIndex = backwardTransactions.get(listIndex).length - 1; + return true; + } else { + this.direction = true; + if (!this.forwardTransactions.isEmpty()) { + listIndex = forwardTransactions.size() - 1; + arrayIndex = 0; + return true; + } else { + listIndex = -1; + return false; + } + } + } + } + } + } + + @Override + public boolean isDirty() { + return false; + } + + @Override + public Set getDependingMaps() { + return Collections.emptySet(); + } + + @Override + public V getFromValue() { + return getCurrentDelta().getOldValue(); + } + + @Override + public V getToValue() { + return getCurrentDelta().getNewValue(); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java new file mode 100644 index 00000000..4a8e9709 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java @@ -0,0 +1,62 @@ +package tools.refinery.store.map.internal; + +import java.util.*; +import java.util.Map.Entry; + +import tools.refinery.store.map.AnyVersionedMap; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.map.VersionedMap; + +public class IteratorAsCursor implements Cursor { + final Iterator> iterator; + final VersionedMap source; + + private boolean terminated; + private K key; + private V value; + + public IteratorAsCursor(VersionedMap source, Map current) { + this.iterator = current.entrySet().iterator(); + this.source = source; + move(); + } + + @Override + public K getKey() { + return key; + } + + @Override + public V getValue() { + return value; + } + + @Override + public boolean isTerminated() { + return terminated; + } + + @Override + public boolean move() { + terminated = iterator.hasNext(); + if (terminated) { + this.key = null; + this.value = null; + } else { + Entry next = iterator.next(); + this.key = next.getKey(); + this.value = next.getValue(); + } + return !terminated; + } + + @Override + public boolean isDirty() { + return false; + } + + @Override + public Set getDependingMaps() { + return Set.of(this.source); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDelta.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDelta.java new file mode 100644 index 00000000..86e9fe62 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDelta.java @@ -0,0 +1,15 @@ +package tools.refinery.store.map.internal; + +public record MapDelta(K key, V oldValue, V newValue) { + public K getKey() { + return key; + } + + public V getOldValue() { + return oldValue; + } + + public V getNewValue() { + return newValue; + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapTransaction.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapTransaction.java new file mode 100644 index 00000000..5996048e --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapTransaction.java @@ -0,0 +1,34 @@ +package tools.refinery.store.map.internal; + +import java.util.Arrays; +import java.util.Objects; + +public record MapTransaction(MapDelta[] deltas, long version, MapTransaction parent) { + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(deltas); + result = prime * result + Objects.hash(parent, version); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + @SuppressWarnings("unchecked") + MapTransaction other = (MapTransaction) obj; + return Arrays.equals(deltas, other.deltas) && Objects.equals(parent, other.parent) && version == other.version; + } + + @Override + public String toString() { + return "MapTransaction " + version + " " + Arrays.toString(deltas); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaArrayStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaArrayStore.java new file mode 100644 index 00000000..3b3f94ae --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaArrayStore.java @@ -0,0 +1,31 @@ +package tools.refinery.store.map.internal; + +import java.util.ArrayList; +import java.util.List; + +public class UncommittedDeltaArrayStore implements UncommittedDeltaStore { + final List> uncommittedOldValues = new ArrayList<>(); + + @Override + public void processChange(K key, V oldValue, V newValue) { + uncommittedOldValues.add(new MapDelta<>(key, oldValue, newValue)); + } + + @Override + public MapDelta[] extractDeltas() { + if (uncommittedOldValues.isEmpty()) { + return null; + } else { + @SuppressWarnings("unchecked") + MapDelta[] result = uncommittedOldValues.toArray(new MapDelta[0]); + return result; + } + } + + @Override + public MapDelta[] extractAndDeleteDeltas() { + MapDelta[] res = extractDeltas(); + this.uncommittedOldValues.clear(); + return res; + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java new file mode 100644 index 00000000..73df5080 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java @@ -0,0 +1,47 @@ +package tools.refinery.store.map.internal; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import tools.refinery.store.map.VersionedMap; + +public class UncommittedDeltaMapStore implements UncommittedDeltaStore { + final VersionedMap source; + final Map uncommittedOldValues = new HashMap<>(); + + public UncommittedDeltaMapStore(VersionedMap source) { + this.source = source; + } + + @Override + public void processChange(K key, V oldValue, V newValue) { + this.uncommittedOldValues.putIfAbsent(key, oldValue); + } + + @Override + public MapDelta[] extractDeltas() { + if (uncommittedOldValues.isEmpty()) { + return null; + } else { + @SuppressWarnings("unchecked") + MapDelta[] deltas = new MapDelta[uncommittedOldValues.size()]; + int i = 0; + for (Entry entry : uncommittedOldValues.entrySet()) { + final K key = entry.getKey(); + final V oldValue = entry.getValue(); + final V newValue = source.get(key); + deltas[i] = new MapDelta<>(key, oldValue, newValue); + } + + return deltas; + } + } + + @Override + public MapDelta[] extractAndDeleteDeltas() { + MapDelta[] res = extractDeltas(); + this.uncommittedOldValues.clear(); + return res; + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java new file mode 100644 index 00000000..37e5817c --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java @@ -0,0 +1,10 @@ +package tools.refinery.store.map.internal; + +public interface UncommittedDeltaStore { + void processChange(K key, V oldValue, V newValue); + + MapDelta[] extractDeltas(); + + MapDelta[] extractAndDeleteDeltas(); + +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java new file mode 100644 index 00000000..deedf134 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java @@ -0,0 +1,156 @@ +package tools.refinery.store.map.internal; + +import java.util.*; + +import tools.refinery.store.map.*; + +public class VersionedMapDeltaImpl implements VersionedMap { + protected final VersionedMapStoreDeltaImpl store; + + final Map current; + + final UncommittedDeltaStore uncommittedStore; + MapTransaction previous; + + protected final V defaultValue; + + public VersionedMapDeltaImpl(VersionedMapStoreDeltaImpl store, V defaultValue) { + this.store = store; + this.defaultValue = defaultValue; + + current = new HashMap<>(); + uncommittedStore = new UncommittedDeltaArrayStore<>(); + } + + @Override + public long commit() { + MapDelta[] deltas = uncommittedStore.extractAndDeleteDeltas(); + long[] versionContainer = new long[1]; + this.previous = this.store.appendTransaction(deltas, previous, versionContainer); + return versionContainer[0]; + } + + @Override + public void restore(long state) { + // 1. restore uncommitted states + MapDelta[] uncommitted = this.uncommittedStore.extractAndDeleteDeltas(); + if (uncommitted != null) { + backward(uncommitted); + } + + // 2. get common ancestor + List[]> forward = new ArrayList<>(); + if (this.previous == null) { + this.store.getPath(state, forward); + this.forward(forward); + } else { + List[]> backward = new ArrayList<>(); + this.store.getPath(this.previous.version(), state, backward, forward); + this.backward(backward); + this.forward(forward); + } + } + + protected void forward(List[]> changes) { + for (int i = changes.size() - 1; i >= 0; i--) { + forward(changes.get(i)); + } + } + + protected void backward(List[]> changes) { + for (int i = 0; i < changes.size(); i++) { + backward(changes.get(i)); + } + } + + protected void forward(MapDelta[] changes) { + for (int i = 0; i < changes.length; i++) { + final MapDelta change = changes[i]; + current.put(change.getKey(), change.getNewValue()); + } + } + + protected void backward(MapDelta[] changes) { + for (int i = changes.length - 1; i >= 0; i--) { + final MapDelta change = changes[i]; + current.put(change.getKey(), change.getOldValue()); + } + } + + @Override + public V get(K key) { + return current.getOrDefault(key, defaultValue); + } + + @Override + public Cursor getAll() { + return new IteratorAsCursor<>(this, current); + } + + @Override + public V put(K key, V value) { + if (value == defaultValue) { + V res = current.remove(key); + if (res == null) { + // no changes + return defaultValue; + } else { + uncommittedStore.processChange(key, res, value); + return res; + } + } else { + V oldValue = current.put(key, value); + uncommittedStore.processChange(key, oldValue, value); + return oldValue; + } + } + + @Override + public void putAll(Cursor cursor) { + throw new UnsupportedOperationException(); + + } + + @Override + public long getSize() { + return current.size(); + } + + @Override + public DiffCursor getDiffCursor(long state) { + MapDelta[] backward = this.uncommittedStore.extractDeltas(); + List[]> backwardTransactions = new ArrayList<>(); + List[]> forwardTransactions = new ArrayList<>(); + + if (backward != null) { + backwardTransactions.add(backward); + } + + if (this.previous != null) { + store.getPath(this.previous.version(), state, backwardTransactions, forwardTransactions); + } else { + store.getPath(state, forwardTransactions); + } + + return new DeltaDiffCursor<>(backwardTransactions, forwardTransactions); + } + + @Override + public int contentHashCode(ContentHashCode mode) { + return this.current.hashCode(); + } + + @Override + public boolean contentEquals(AnyVersionedMap other) { + if (other instanceof VersionedMapDeltaImpl versioned) { + if (versioned == this) { + return true; + } else { + return Objects.equals(this.defaultValue, versioned.defaultValue) && + Objects.equals(this.current, versioned.current); + } + } else { + throw new UnsupportedOperationException("Comparing different map implementations is ineffective."); + } + } +} -- cgit v1.2.3-70-g09d2 From 07dfaba3102075d7669927b2b189dffe95044e94 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Fri, 10 Feb 2023 01:41:04 +0100 Subject: VersionedMapStoreBuilder for delta and state based stores --- .../store/map/VersionedMapStoreBuilder.java | 81 ++++++++++++++++++++++ .../store/map/VersionedMapStoreDeltaImpl.java | 41 ++++++----- .../store/map/internal/VersionedMapDeltaImpl.java | 11 +-- 3 files changed, 108 insertions(+), 25 deletions(-) create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java new file mode 100644 index 00000000..7e413a86 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java @@ -0,0 +1,81 @@ +package tools.refinery.store.map; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class VersionedMapStoreBuilder { + public enum StoreStrategy { + STATE, DELTA + } + + public enum DeltaStorageStrategy { + LIST, SET + } + + public enum StateStorageStrategy { + NO_NODE_CACHE, SHARED_NODE_CACHE, SHARED_NODE_CACHE_IN_GROUP + } + + protected Optional defaultValue = Optional.empty(); + protected StoreStrategy strategy = StoreStrategy.DELTA; + protected Boolean stateBasedImmutableWhenCommitting = false; + protected StateStorageStrategy stateBasedNodeSharingStrategy = StateStorageStrategy.SHARED_NODE_CACHE_IN_GROUP; + protected Optional> hashProvider = Optional.empty(); + protected DeltaStorageStrategy deltaStorageStrategy = DeltaStorageStrategy.LIST; + + public void setDefaultValue(V defaultValue) { + this.defaultValue = Optional.of(defaultValue); + } + + public void setStrategy(StoreStrategy strategy) { + this.strategy = strategy; + } + + public void setHashProvider(ContinousHashProvider hashProvider) { + this.hashProvider = Optional.of(hashProvider); + } + + public void setStateBasedImmutableWhenCommitting(boolean toImmutableWhenCommitting) { + this.stateBasedImmutableWhenCommitting = toImmutableWhenCommitting; + } + + public void setStateBasedNodeSharingStrategy(StateStorageStrategy strategy) { + this.stateBasedNodeSharingStrategy = strategy; + } + + public VersionedMapStore buildOne() { + return switch (strategy) { + case DELTA -> new VersionedMapStoreDeltaImpl<>( + this.deltaStorageStrategy == DeltaStorageStrategy.SET, + this.defaultValue.orElseThrow()); + case STATE -> new VersionedMapStoreImpl<>( + this.hashProvider.orElseThrow(), + this.defaultValue.orElseThrow(), + new VersionedMapStoreConfiguration( + this.stateBasedImmutableWhenCommitting, + this.stateBasedNodeSharingStrategy != StateStorageStrategy.NO_NODE_CACHE, + this.stateBasedNodeSharingStrategy == StateStorageStrategy.SHARED_NODE_CACHE_IN_GROUP)); + }; + } + + public List> buildGroup(int amount) { + if (this.strategy == StoreStrategy.STATE && + this.stateBasedNodeSharingStrategy == StateStorageStrategy.SHARED_NODE_CACHE_IN_GROUP) { + return VersionedMapStoreImpl.createSharedVersionedMapStores( + amount, + this.hashProvider.orElseThrow(), + this.defaultValue.orElseThrow(), + new VersionedMapStoreConfiguration( + this.stateBasedImmutableWhenCommitting, + true, + true)); + } else { + List> result = new ArrayList<>(amount); + for (int i = 0; i < amount; i++) { + result.add(buildOne()); + } + return result; + } + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java index 2bd758e2..98dec2bb 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java @@ -2,32 +2,32 @@ package tools.refinery.store.map; import java.util.*; -import tools.refinery.store.map.internal.DeltaDiffCursor; -import tools.refinery.store.map.internal.MapDelta; -import tools.refinery.store.map.internal.MapTransaction; -import tools.refinery.store.map.internal.VersionedMapDeltaImpl; +import tools.refinery.store.map.internal.*; + +public class VersionedMapStoreDeltaImpl implements VersionedMapStore { + // Configuration + protected final boolean summarizeChanges; -public class VersionedMapStoreDeltaImpl implements VersionedMapStore{ // Static data protected final V defaultValue; // Dynamic data - protected final Map> states = new HashMap<>(); + protected final Map> states = new HashMap<>(); protected long nextID = 0; - public VersionedMapStoreDeltaImpl(V defaultValue) { - super(); + public VersionedMapStoreDeltaImpl(boolean summarizeChanges, V defaultValue) { + this.summarizeChanges = summarizeChanges; this.defaultValue = defaultValue; } @Override public VersionedMap createMap() { - return new VersionedMapDeltaImpl<>(this, defaultValue); + return new VersionedMapDeltaImpl<>(this, this.summarizeChanges, this.defaultValue); } @Override public VersionedMap createMap(long state) { - VersionedMapDeltaImpl result = new VersionedMapDeltaImpl<>(this, defaultValue); + VersionedMapDeltaImpl result = new VersionedMapDeltaImpl<>(this, this.summarizeChanges, this.defaultValue); result.restore(state); return result; } @@ -35,7 +35,7 @@ public class VersionedMapStoreDeltaImpl implements VersionedMapStore public synchronized MapTransaction appendTransaction(MapDelta[] deltas, MapTransaction previous, long[] versionContainer) { long version = nextID++; versionContainer[0] = version; - if(deltas == null) { + if (deltas == null) { states.put(version, previous); return previous; } else { @@ -45,26 +45,25 @@ public class VersionedMapStoreDeltaImpl implements VersionedMapStore } } - private synchronized MapTransaction getState(long state) { + private synchronized MapTransaction getState(long state) { return states.get(state); } public void getPath(long to, List[]> forwardTransactions) { - MapTransaction toTransaction = getState(to); - while(toTransaction != null) { + MapTransaction toTransaction = getState(to); + while (toTransaction != null) { forwardTransactions.add(toTransaction.deltas()); toTransaction = toTransaction.parent(); } } public void getPath(long from, long to, - List[]> backwardTransactions, - List[]> forwardTransactions) - { - MapTransaction fromTransaction = getState(from); - MapTransaction toTransaction = getState(to); - while(fromTransaction != toTransaction) { - if(fromTransaction == null || fromTransaction.version() < toTransaction.version()) { + List[]> backwardTransactions, + List[]> forwardTransactions) { + MapTransaction fromTransaction = getState(from); + MapTransaction toTransaction = getState(to); + while (fromTransaction != toTransaction) { + if (fromTransaction == null || fromTransaction.version() < toTransaction.version()) { forwardTransactions.add(toTransaction.deltas()); toTransaction = toTransaction.parent(); } else { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java index deedf134..6f2996e1 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java @@ -14,12 +14,16 @@ public class VersionedMapDeltaImpl implements VersionedMap { protected final V defaultValue; - public VersionedMapDeltaImpl(VersionedMapStoreDeltaImpl store, V defaultValue) { + public VersionedMapDeltaImpl(VersionedMapStoreDeltaImpl store, boolean summarizeChanges, V defaultValue) { this.store = store; this.defaultValue = defaultValue; current = new HashMap<>(); - uncommittedStore = new UncommittedDeltaArrayStore<>(); + if(summarizeChanges) { + this.uncommittedStore = new UncommittedDeltaMapStore<>(this); + } else { + this.uncommittedStore = new UncommittedDeltaArrayStore<>(); + } } @Override @@ -146,8 +150,7 @@ public class VersionedMapDeltaImpl implements VersionedMap { if (versioned == this) { return true; } else { - return Objects.equals(this.defaultValue, versioned.defaultValue) && - Objects.equals(this.current, versioned.current); + return Objects.equals(this.defaultValue, versioned.defaultValue) && Objects.equals(this.current, versioned.current); } } else { throw new UnsupportedOperationException("Comparing different map implementations is ineffective."); -- cgit v1.2.3-70-g09d2 From 55c8acd527bf0b5608e15587be9a9bfad3dc3c6b Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Fri, 10 Feb 2023 11:49:47 +0100 Subject: Moved test parametrization to FuzzTestCollections.java --- .../tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java | 8 +++++--- .../refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java | 7 +++---- .../refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java | 12 +++++------- .../refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java | 7 ++++--- .../tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java | 6 +++--- .../map/tests/fuzz/MutableImmutableCompareFuzzTest.java | 6 +++--- .../tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java | 6 +++--- .../refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java | 7 ++++--- .../store/map/tests/fuzz/utils/FuzzTestCollections.java | 11 +++++++++++ 9 files changed, 41 insertions(+), 29 deletions(-) create mode 100644 subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java (limited to 'subprojects/store') diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java index 9e3f636b..b61152f5 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java @@ -18,7 +18,10 @@ import tools.refinery.store.map.internal.VersionedMapImpl; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; + class CommitFuzzTest { + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, boolean evilHash) { @@ -67,9 +70,8 @@ class CommitFuzzTest { } static Stream parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, - new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, - new Object[]{false, true}); + return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, + commitFrequencyOptions, randomSeedOptions, evilHashOptions); } @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index 71cb3d11..c17b0a95 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java @@ -18,6 +18,7 @@ import java.util.Random; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; class ContentEqualsFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, @@ -93,10 +94,8 @@ class ContentEqualsFuzzTest { } static Stream parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, - 32 * 32}, - new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, - new Object[]{false, true}); + return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, + commitFrequencyOptions, randomSeedOptions, evilHashOptions); } @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit frequency={5}" + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java index 8a5576aa..90aa8e01 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java @@ -1,6 +1,7 @@ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.fail; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; import java.util.Random; import java.util.stream.Stream; @@ -93,16 +94,14 @@ class DiffCursorFuzzTest { @Timeout(value = 10) @Tag("fuzz") void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, - boolean evilHash) { + int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); } static Stream parametrizedFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, - new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, - new Object[]{false, true}); + return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, + commitFrequencyOptions, randomSeedOptions, evilHashOptions); } @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + @@ -111,8 +110,7 @@ class DiffCursorFuzzTest { @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, - boolean evilHash) { + int seed, boolean evilHash) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, evilHash); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java index 5d5f3ce3..9325a938 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java @@ -2,6 +2,7 @@ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; import java.util.Collections; import java.util.LinkedList; @@ -78,9 +79,9 @@ class MultiThreadFuzzTest { } static Stream parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, - new Object[]{2, 3}, new Object[]{false, true}, new Object[]{10, 100}, new Object[]{1, 2, 3}, - new Object[]{false, true}); + return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, + new Object[]{10, 100}, randomSeedOptions, + evilHashOptions); } @ParameterizedTest(name = "MultiThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java index 2d65ba0c..ab37ef83 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java @@ -1,6 +1,7 @@ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.fail; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; import java.util.Random; import java.util.stream.Stream; @@ -64,9 +65,8 @@ class MutableFuzzTest { } static Stream parametrizedFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, - new Object[]{3, 32, 32 * 32, 32 * 32 * 32 * 32}, new Object[]{2, 3}, new Object[]{false, true}, - new Object[]{1, 2, 3}, new Object[]{false, true}); + return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, + randomSeedOptions, evilHashOptions); } @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} seed={5} " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java index da8a43c2..b58b06f9 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java @@ -1,6 +1,7 @@ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.fail; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; import java.util.Random; import java.util.stream.Stream; @@ -69,9 +70,8 @@ class MutableImmutableCompareFuzzTest { } static Stream parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, - new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, - new Object[]{false, true}); + return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, + commitFrequencyOptions, randomSeedOptions, evilHashOptions); } @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java index bd03d1e9..77b26c41 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java @@ -1,6 +1,7 @@ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.fail; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; import java.util.HashMap; import java.util.Map; @@ -90,9 +91,8 @@ class RestoreFuzzTest { } static Stream parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, - new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, - new Object[]{false, true}); + return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, + commitFrequencyOptions, randomSeedOptions, evilHashOptions); } @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5}" + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java index 0fc9cd38..4462c55b 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java @@ -20,6 +20,8 @@ import tools.refinery.store.map.internal.VersionedMapImpl; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; + class SharedStoreFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, boolean evilHash) { @@ -93,9 +95,8 @@ class SharedStoreFuzzTest { } static Stream parametrizedFastFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, 32 * 32}, - new Object[]{2, 3}, new Object[]{false, true}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, - new Object[]{false, true}); + return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, + commitFrequencyOptions, randomSeedOptions, evilHashOptions); } @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java new file mode 100644 index 00000000..add4ca5d --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java @@ -0,0 +1,11 @@ +package tools.refinery.store.map.tests.fuzz.utils; + +public final class FuzzTestCollections { + public static final Object[] stepCounts = {FuzzTestUtils.FAST_STEP_COUNT}; + public static final Object[] keyCounts = {3, 32, 32 * 32}; + public static final Object[] valueCounts = {2, 3}; + public static final Object[] nullDefaultOptions = {false, true}; + public static final Object[] commitFrequencyOptions = {1, 10, 100}; + public static final Object[] randomSeedOptions = {1, 2, 3}; + public static final Object[] evilHashOptions = {false, true}; +} -- cgit v1.2.3-70-g09d2 From 1543e42dd5b63af6f4228ec545d4f2666ff73274 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Mon, 13 Feb 2023 01:15:44 +0100 Subject: VersionedMapStoreBuilder returns builder state. --- .../store/map/VersionedMapStoreBuilder.java | 85 +++++++++++++++++----- 1 file changed, 67 insertions(+), 18 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java index 7e413a86..1a9aa0b3 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java @@ -2,7 +2,6 @@ package tools.refinery.store.map; import java.util.ArrayList; import java.util.List; -import java.util.Optional; public class VersionedMapStoreBuilder { public enum StoreStrategy { @@ -17,41 +16,76 @@ public class VersionedMapStoreBuilder { NO_NODE_CACHE, SHARED_NODE_CACHE, SHARED_NODE_CACHE_IN_GROUP } - protected Optional defaultValue = Optional.empty(); + public static VersionedMapStoreBuilder builder() { + return new VersionedMapStoreBuilder<>(); + } + protected VersionedMapStoreBuilder() { + } + protected VersionedMapStoreBuilder(VersionedMapStoreBuilder other) { + this.defaultValue = other.defaultValue; + this.defaultSet = other.defaultSet; + this.strategy = other.strategy; + this.stateBasedImmutableWhenCommitting = other.stateBasedImmutableWhenCommitting; + this.stateBasedNodeSharingStrategy = other.stateBasedNodeSharingStrategy; + this.hashProvider = other.hashProvider; + this.deltaStorageStrategy = other.deltaStorageStrategy; + } + protected boolean defaultSet = false; + protected V defaultValue = null; protected StoreStrategy strategy = StoreStrategy.DELTA; protected Boolean stateBasedImmutableWhenCommitting = false; protected StateStorageStrategy stateBasedNodeSharingStrategy = StateStorageStrategy.SHARED_NODE_CACHE_IN_GROUP; - protected Optional> hashProvider = Optional.empty(); + protected ContinousHashProvider hashProvider = null; protected DeltaStorageStrategy deltaStorageStrategy = DeltaStorageStrategy.LIST; - public void setDefaultValue(V defaultValue) { - this.defaultValue = Optional.of(defaultValue); + public VersionedMapStoreBuilder setDefaultValue(V defaultValue) { + var result = new VersionedMapStoreBuilder<>(this); + result.defaultValue = defaultValue; + result.defaultSet = true; + return result; + } + + public VersionedMapStoreBuilder setStrategy(StoreStrategy strategy) { + var result = new VersionedMapStoreBuilder<>(this); + result.strategy = strategy; + return result; } - public void setStrategy(StoreStrategy strategy) { - this.strategy = strategy; + public VersionedMapStoreBuilder setHashProvider(ContinousHashProvider hashProvider) { + var result = new VersionedMapStoreBuilder<>(this); + result.hashProvider = hashProvider; + return result; } - public void setHashProvider(ContinousHashProvider hashProvider) { - this.hashProvider = Optional.of(hashProvider); + public VersionedMapStoreBuilder setStateBasedImmutableWhenCommitting(boolean toImmutableWhenCommitting) { + var result = new VersionedMapStoreBuilder<>(this); + result.stateBasedImmutableWhenCommitting = toImmutableWhenCommitting; + return result; } - public void setStateBasedImmutableWhenCommitting(boolean toImmutableWhenCommitting) { - this.stateBasedImmutableWhenCommitting = toImmutableWhenCommitting; + public VersionedMapStoreBuilder setStateBasedNodeSharingStrategy(StateStorageStrategy strategy) { + var result = new VersionedMapStoreBuilder<>(this); + result.stateBasedNodeSharingStrategy = strategy; + return result; } - public void setStateBasedNodeSharingStrategy(StateStorageStrategy strategy) { - this.stateBasedNodeSharingStrategy = strategy; + public VersionedMapStoreBuilder setDeltaStorageStrategy(DeltaStorageStrategy deltaStorageStrategy) { + var result = new VersionedMapStoreBuilder<>(this); + result.deltaStorageStrategy = deltaStorageStrategy; + return result; } public VersionedMapStore buildOne() { + if(!defaultSet) { + throw new IllegalStateException("Default value is missing!"); + } return switch (strategy) { case DELTA -> new VersionedMapStoreDeltaImpl<>( this.deltaStorageStrategy == DeltaStorageStrategy.SET, - this.defaultValue.orElseThrow()); + this.defaultValue); case STATE -> new VersionedMapStoreImpl<>( - this.hashProvider.orElseThrow(), - this.defaultValue.orElseThrow(), + this.hashProvider, + this.defaultValue, new VersionedMapStoreConfiguration( this.stateBasedImmutableWhenCommitting, this.stateBasedNodeSharingStrategy != StateStorageStrategy.NO_NODE_CACHE, @@ -60,12 +94,15 @@ public class VersionedMapStoreBuilder { } public List> buildGroup(int amount) { + if(!defaultSet) { + throw new IllegalStateException("Default value is missing!"); + } if (this.strategy == StoreStrategy.STATE && this.stateBasedNodeSharingStrategy == StateStorageStrategy.SHARED_NODE_CACHE_IN_GROUP) { return VersionedMapStoreImpl.createSharedVersionedMapStores( amount, - this.hashProvider.orElseThrow(), - this.defaultValue.orElseThrow(), + this.hashProvider, + this.defaultValue, new VersionedMapStoreConfiguration( this.stateBasedImmutableWhenCommitting, true, @@ -78,4 +115,16 @@ public class VersionedMapStoreBuilder { return result; } } + + @Override + public String toString() { + return "VersionedMapStoreBuilder{" + + "defaultValue=" + defaultValue + + ", strategy=" + strategy + + ", stateBasedImmutableWhenCommitting=" + stateBasedImmutableWhenCommitting + + ", stateBasedNodeSharingStrategy=" + stateBasedNodeSharingStrategy + + ", hashProvider=" + hashProvider + + ", deltaStorageStrategy=" + deltaStorageStrategy + + '}'; + } } -- cgit v1.2.3-70-g09d2 From 4f447bb7efd453eb6aa17fb29b8a0d7d65c03fcd Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Mon, 13 Feb 2023 01:29:28 +0100 Subject: Multiple small updates and fixes to support all upcoming tests. - AnyVersionedMap.checkIntegrity added to the superclass - Default value of the map is gettable. - Errors fixed: - Delta store failed to update reference to the previous transaction in some cases. Fixed in VersionedMapStoreDeltaImpl.java import java.util.HashMap; - Null values caused issues in UncommittedDeltaMapStore.java as putIfAbsent does not work with null. - Small fixes in DeltaDiffCursor.java and IteratorAsCursor.java --- .../tools/refinery/store/map/AnyVersionedMap.java | 5 ++ .../tools/refinery/store/map/VersionedMap.java | 2 + .../store/map/VersionedMapStoreDeltaImpl.java | 8 +- .../store/map/internal/DeltaDiffCursor.java | 2 + .../store/map/internal/IteratorAsCursor.java | 3 +- .../map/internal/UncommittedDeltaMapStore.java | 11 +-- .../store/map/internal/UncommittedDeltaStore.java | 14 ++++ .../store/map/internal/VersionedMapDeltaImpl.java | 85 ++++++++++++++++++---- .../store/map/internal/VersionedMapImpl.java | 2 + 9 files changed, 107 insertions(+), 25 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java index f82a8bb1..ead79878 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java @@ -37,4 +37,9 @@ public sealed interface AnyVersionedMap extends Versioned permits VersionedMap { @SuppressWarnings("squid:S1133") @Deprecated(since = "0.0.0") boolean equals(Object obj); + + /** + * Checks the integrity of the map, and throws an exception if an inconsistency is detected. + */ + void checkIntegrity(); } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java index 31985e94..08ce1dbd 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java @@ -1,6 +1,8 @@ package tools.refinery.store.map; public non-sealed interface VersionedMap extends AnyVersionedMap { + V getDefaultValue(); + V get(K key); Cursor getAll(); diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java index 98dec2bb..e556a8bb 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java @@ -49,21 +49,22 @@ public class VersionedMapStoreDeltaImpl implements VersionedMapStore return states.get(state); } - public void getPath(long to, List[]> forwardTransactions) { + public MapTransaction getPath(long to, List[]> forwardTransactions) { MapTransaction toTransaction = getState(to); while (toTransaction != null) { forwardTransactions.add(toTransaction.deltas()); toTransaction = toTransaction.parent(); } + return toTransaction; } - public void getPath(long from, long to, + public MapTransaction getPath(long from, long to, List[]> backwardTransactions, List[]> forwardTransactions) { MapTransaction fromTransaction = getState(from); MapTransaction toTransaction = getState(to); while (fromTransaction != toTransaction) { - if (fromTransaction == null || fromTransaction.version() < toTransaction.version()) { + if (fromTransaction == null || (toTransaction != null && fromTransaction.version() < toTransaction.version())) { forwardTransactions.add(toTransaction.deltas()); toTransaction = toTransaction.parent(); } else { @@ -71,6 +72,7 @@ public class VersionedMapStoreDeltaImpl implements VersionedMapStore fromTransaction = fromTransaction.parent(); } } + return toTransaction; } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java index 75180bf9..49ea1f67 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java @@ -62,6 +62,7 @@ public class DeltaDiffCursor implements DiffCursor { return this.direction && listIndex == -1; } + @Override public boolean move() { if (isTerminated()) { @@ -74,6 +75,7 @@ public class DeltaDiffCursor implements DiffCursor { } else { if (listIndex-1 >= 0) { listIndex--; + arrayIndex = 0; return true; } else { listIndex = -1; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java index 4a8e9709..c1a0aec4 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java @@ -18,7 +18,6 @@ public class IteratorAsCursor implements Cursor { public IteratorAsCursor(VersionedMap source, Map current) { this.iterator = current.entrySet().iterator(); this.source = source; - move(); } @Override @@ -38,7 +37,7 @@ public class IteratorAsCursor implements Cursor { @Override public boolean move() { - terminated = iterator.hasNext(); + terminated = !iterator.hasNext(); if (terminated) { this.key = null; this.value = null; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java index 73df5080..31423b1c 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java @@ -1,7 +1,6 @@ package tools.refinery.store.map.internal; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; import tools.refinery.store.map.VersionedMap; @@ -16,7 +15,9 @@ public class UncommittedDeltaMapStore implements UncommittedDeltaStore implements UncommittedDeltaStore[] deltas = new MapDelta[uncommittedOldValues.size()]; + MapDelta[] deltas = new MapDelta[uncommittedOldValues.size()]; int i = 0; for (Entry entry : uncommittedOldValues.entrySet()) { final K key = entry.getKey(); final V oldValue = entry.getValue(); final V newValue = source.get(key); - deltas[i] = new MapDelta<>(key, oldValue, newValue); + deltas[i++] = new MapDelta<>(key, oldValue, newValue); } return deltas; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java index 37e5817c..7b017c8e 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java @@ -7,4 +7,18 @@ public interface UncommittedDeltaStore { MapDelta[] extractAndDeleteDeltas(); + default void checkIntegrity() { + MapDelta[] extractedDeltas = extractDeltas(); + if(extractedDeltas != null) { + for(var uncommittedOldValue : extractedDeltas) { + if(uncommittedOldValue == null) { + throw new IllegalArgumentException("Null entry in deltas!"); + } + if(uncommittedOldValue.getKey() == null) { + throw new IllegalStateException("Null key in deltas!"); + } + } + } + } + } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java index 6f2996e1..d09e54ba 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java @@ -19,13 +19,18 @@ public class VersionedMapDeltaImpl implements VersionedMap { this.defaultValue = defaultValue; current = new HashMap<>(); - if(summarizeChanges) { + if (summarizeChanges) { this.uncommittedStore = new UncommittedDeltaMapStore<>(this); } else { this.uncommittedStore = new UncommittedDeltaArrayStore<>(); } } + @Override + public V getDefaultValue() { + return defaultValue; + } + @Override public long commit() { MapDelta[] deltas = uncommittedStore.extractAndDeleteDeltas(); @@ -43,16 +48,18 @@ public class VersionedMapDeltaImpl implements VersionedMap { } // 2. get common ancestor + final MapTransaction parent; List[]> forward = new ArrayList<>(); if (this.previous == null) { - this.store.getPath(state, forward); + parent = this.store.getPath(state, forward); this.forward(forward); } else { List[]> backward = new ArrayList<>(); - this.store.getPath(this.previous.version(), state, backward, forward); + parent = this.store.getPath(this.previous.version(), state, backward, forward); this.backward(backward); this.forward(forward); } + this.previous = parent; } protected void forward(List[]> changes) { @@ -70,14 +77,28 @@ public class VersionedMapDeltaImpl implements VersionedMap { protected void forward(MapDelta[] changes) { for (int i = 0; i < changes.length; i++) { final MapDelta change = changes[i]; - current.put(change.getKey(), change.getNewValue()); + K key = change.getKey(); + V newValue = change.getNewValue(); + + if(newValue == defaultValue) { + current.remove(key); + } else { + current.put(key,newValue); + } } } protected void backward(MapDelta[] changes) { for (int i = changes.length - 1; i >= 0; i--) { final MapDelta change = changes[i]; - current.put(change.getKey(), change.getOldValue()); + K key = change.getKey(); + V oldValue = change.oldValue(); + + if(oldValue == defaultValue) { + current.remove(key); + } else { + current.put(key,oldValue); + } } } @@ -93,26 +114,46 @@ public class VersionedMapDeltaImpl implements VersionedMap { @Override public V put(K key, V value) { - if (value == defaultValue) { - V res = current.remove(key); + final V oldValue; + if (Objects.equals(value, defaultValue)) { + final V res = current.remove(key); if (res == null) { - // no changes - return defaultValue; + // no changes: default > default + oldValue = defaultValue; } else { - uncommittedStore.processChange(key, res, value); - return res; + oldValue = res; } } else { - V oldValue = current.put(key, value); + final var mapValue = current.put(key, value); + if (mapValue == null) { + oldValue = defaultValue; + } else { + oldValue = mapValue; + } + } + if(!Objects.equals(oldValue,value)) { uncommittedStore.processChange(key, oldValue, value); - return oldValue; } + return oldValue; } @Override public void putAll(Cursor cursor) { - throw new UnsupportedOperationException(); - + if (cursor.getDependingMaps().contains(this)) { + List keys = new ArrayList<>(); + List values = new ArrayList<>(); + while (cursor.move()) { + keys.add(cursor.getKey()); + values.add(cursor.getValue()); + } + for (int i = 0; i < keys.size(); i++) { + this.put(keys.get(i), values.get(i)); + } + } else { + while (cursor.move()) { + this.put(cursor.getKey(), cursor.getValue()); + } + } } @Override @@ -156,4 +197,18 @@ public class VersionedMapDeltaImpl implements VersionedMap { throw new UnsupportedOperationException("Comparing different map implementations is ineffective."); } } + + @Override + public void checkIntegrity() { + this.uncommittedStore.checkIntegrity(); + + for (var entry : this.current.entrySet()) { + var value = entry.getValue(); + if (value == this.defaultValue) { + throw new IllegalStateException("Default value stored in map!"); + } else if (value == null) { + throw new IllegalStateException("null value stored in map!"); + } + } + } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java index 674ffc47..fb359431 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java @@ -43,6 +43,7 @@ public class VersionedMapImpl implements VersionedMap { this.root = data; } + @Override public V getDefaultValue() { return defaultValue; } @@ -141,6 +142,7 @@ public class VersionedMapImpl implements VersionedMap { } } + @Override public void checkIntegrity() { if (this.root != null) { this.root.checkIntegrity(hashProvider, defaultValue, 0); -- cgit v1.2.3-70-g09d2 From 71809f2867baad1acb373cee0fa1f86394c14370 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Mon, 13 Feb 2023 22:23:05 +0100 Subject: Potential synchronization issue fixed in VersionedMapStoreDeltaImpl.getStates --- .../main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java index e556a8bb..f41a2d75 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java @@ -78,7 +78,7 @@ public class VersionedMapStoreDeltaImpl implements VersionedMapStore @Override public synchronized Set getStates() { - return states.keySet(); + return new HashSet<>(states.keySet()); } @Override -- cgit v1.2.3-70-g09d2 From b5026e94f87bb619ea66d84e7799e089cfb8fa07 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Tue, 14 Feb 2023 00:32:26 +0100 Subject: Nasty error fixed in VersionedMapStoreDeltaImpl.java when setting the new parent state --- .../tools/refinery/store/map/VersionedMapStoreDeltaImpl.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java index f41a2d75..31cdbf95 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java @@ -50,19 +50,22 @@ public class VersionedMapStoreDeltaImpl implements VersionedMapStore } public MapTransaction getPath(long to, List[]> forwardTransactions) { - MapTransaction toTransaction = getState(to); + final MapTransaction target = getState(to); + MapTransaction toTransaction = target; while (toTransaction != null) { forwardTransactions.add(toTransaction.deltas()); toTransaction = toTransaction.parent(); } - return toTransaction; + return target; } public MapTransaction getPath(long from, long to, List[]> backwardTransactions, List[]> forwardTransactions) { MapTransaction fromTransaction = getState(from); - MapTransaction toTransaction = getState(to); + final MapTransaction target = getState(to); + MapTransaction toTransaction = target; + while (fromTransaction != toTransaction) { if (fromTransaction == null || (toTransaction != null && fromTransaction.version() < toTransaction.version())) { forwardTransactions.add(toTransaction.deltas()); @@ -72,7 +75,7 @@ public class VersionedMapStoreDeltaImpl implements VersionedMapStore fromTransaction = fromTransaction.parent(); } } - return toTransaction; + return target; } -- cgit v1.2.3-70-g09d2 From 6598f296d79382a7eaf6ec42819d0123b0acc0d1 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Tue, 14 Feb 2023 00:43:00 +0100 Subject: Test environment cannot rely upon the order of elements in a map since VersionedMapDelta appeared. --- .../store/map/tests/utils/MapTestEnvironment.java | 38 +++++++++------------- 1 file changed, 15 insertions(+), 23 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java index 30f38201..69ae811e 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java @@ -55,23 +55,9 @@ public class MapTestEnvironment { public static void compareTwoMaps(String title, VersionedMap map1, VersionedMap map2, List errors) { + map1.checkIntegrity(); + map2.checkIntegrity(); assertEqualsList(map1.getSize(), map2.getSize(), title + ": Sizes not equal", errors); - - Cursor cursor1 = map1.getAll(); - Cursor cursor2 = map2.getAll(); - while (!cursor1.isTerminated()) { - if (cursor2.isTerminated()) { - fail("cursor 2 terminated before cursor1"); - } - assertEqualsList(cursor1.getKey(), cursor2.getKey(), title + ": Keys not equal", errors); - assertEqualsList(cursor2.getValue(), cursor2.getValue(), title + ": Values not equal", errors); - cursor1.move(); - cursor2.move(); - } - if (!cursor2.isTerminated()) { - fail("cursor 1 terminated before cursor 2"); - } - for (var mode : ContentHashCode.values()) { assertEqualsList(map1.contentHashCode(mode), map2.contentHashCode(mode), title + ": " + mode + " hashCode check", errors); @@ -107,29 +93,35 @@ public class MapTestEnvironment { } } - public VersionedMapImpl sut; - Map oracle = new HashMap(); + final private VersionedMap sut; + final private V defaultValue; + Map oracle = new HashMap<>(); - public MapTestEnvironment(VersionedMapImpl sut) { + public MapTestEnvironment(VersionedMap sut) { this.sut = sut; + this.defaultValue = sut.getDefaultValue(); } public void put(K key, V value) { V oldSutValue = sut.put(key, value); V oldOracleValue; - if (value != sut.getDefaultValue()) { + if (value != defaultValue) { oldOracleValue = oracle.put(key, value); } else { oldOracleValue = oracle.remove(key); } - if (oldSutValue == sut.getDefaultValue() && oldOracleValue != null) { + if (oldSutValue == defaultValue && oldOracleValue != null) { fail("After put, SUT old nodeId was default, but oracle old value was " + oldOracleValue); } - if (oldSutValue != sut.getDefaultValue()) { + if (oldSutValue != defaultValue) { assertEquals(oldOracleValue, oldSutValue); } } + public long commit(){ + return sut.commit(); + } + public void checkEquivalence(String title) { // 0. Checking integrity try { @@ -176,7 +168,7 @@ public class MapTestEnvironment { long sutSize = sut.getSize(); if (oracleSize != sutSize || oracleSize != elementsInSutEntrySet) { printComparison(); - fail(title + ": Non-equivalent size() result: SUT.getSize()=" + sutSize + ", SUT.entryset.size=" + fail(title + ": Non-equivalent size() result: SUT.getSize()=" + sutSize + ", SUT.entrySet.size=" + elementsInSutEntrySet + ", Oracle=" + oracleSize + "!"); } } -- cgit v1.2.3-70-g09d2 From 189d1181052fc014830ac53d0090d7f3cfbc36aa Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Tue, 14 Feb 2023 00:46:26 +0100 Subject: Fuzz test environment is parametrized by VersionedMapStoreBuilder configurations --- .../store/map/tests/fuzz/CommitFuzzTest.java | 34 +++++++-------- .../map/tests/fuzz/ContentEqualsFuzzTest.java | 37 ++++++++-------- .../store/map/tests/fuzz/DiffCursorFuzzTest.java | 50 ++++++++++------------ .../store/map/tests/fuzz/MultiThreadFuzzTest.java | 42 +++++++++--------- .../map/tests/fuzz/MultiThreadTestRunnable.java | 22 +++++++--- .../store/map/tests/fuzz/MutableFuzzTest.java | 35 +++++++-------- .../fuzz/MutableImmutableCompareFuzzTest.java | 2 +- .../store/map/tests/fuzz/RestoreFuzzTest.java | 32 +++++++------- .../store/map/tests/fuzz/SharedStoreFuzzTest.java | 2 +- .../map/tests/fuzz/utils/FuzzTestCollections.java | 40 +++++++++++++++-- 10 files changed, 161 insertions(+), 135 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java index b61152f5..14a9e2e0 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java @@ -11,10 +11,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import tools.refinery.store.map.ContinousHashProvider; import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreImpl; -import tools.refinery.store.map.internal.VersionedMapImpl; +import tools.refinery.store.map.VersionedMapStoreBuilder; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; @@ -23,13 +21,11 @@ import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; class CommitFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, - boolean nullDefault, int commitFrequency, - boolean evilHash) { + boolean nullDefault, int commitFrequency, VersionedMapStoreBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); - VersionedMapImpl sut = (VersionedMapImpl) store.createMap(); + VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); + var sut = store.createMap(); MapTestEnvironment e = new MapTestEnvironment<>(sut); Random r = new Random(seed); @@ -52,37 +48,37 @@ class CommitFuzzTest { } MapTestEnvironment.printStatus(scenario, index, steps, null); if (index % commitFrequency == 0) { - e.sut.commit(); + e.commit(); } } } - @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + - "seed={6} evil-hash={7}") + public static final String title = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + + "seed={6} config={7}"; + + @ParameterizedTest(name = title) @MethodSource @Timeout(value = 10) @Tag("fuzz") void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, - boolean evilHash) { + int seed, VersionedMapStoreBuilder builder) { runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - nullDefault, commitFrequency, evilHash); + nullDefault, commitFrequency, builder); } static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, - commitFrequencyOptions, randomSeedOptions, evilHashOptions); + commitFrequencyOptions, randomSeedOptions, storeConfigs); } - @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + - "seed={6} evil-hash={7}") + @ParameterizedTest(name = title) @MethodSource @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, boolean evilHash) { + int seed, VersionedMapStoreBuilder builder) { runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - nullDefault, commitFrequency, evilHash); + nullDefault, commitFrequency, builder); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index c17b0a95..b462ed40 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java @@ -6,7 +6,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import tools.refinery.store.map.*; -import tools.refinery.store.map.internal.VersionedMapImpl; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; @@ -22,20 +21,19 @@ import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; class ContentEqualsFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, - boolean nullDefault, int commitFrequency, - boolean evilHash) { + boolean nullDefault, int commitFrequency, VersionedMapStoreBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); + Random r = new Random(seed); - iterativeRandomPutsAndCommitsThenCompare(scenario, chp, steps, maxKey, values, r, commitFrequency); + iterativeRandomPutsAndCommitsThenCompare(scenario, builder, steps, maxKey, values, r, commitFrequency); } - private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider chp, + private void iterativeRandomPutsAndCommitsThenCompare(String scenario, VersionedMapStoreBuilder builder, int steps, int maxKey, String[] values, Random r, int commitFrequency) { - VersionedMapStore store1 = new VersionedMapStoreImpl<>(chp, values[0]); + VersionedMapStore store1 = builder.setDefaultValue(values[0]).buildOne(); VersionedMap sut1 = store1.createMap(); // Fill one map @@ -65,7 +63,7 @@ class ContentEqualsFuzzTest { // Randomize the order of the content Collections.shuffle(content, r); - VersionedMapStore store2 = new VersionedMapStoreImpl<>(chp, values[0]); + VersionedMapStore store2 = builder.setDefaultValue(values[0]).buildOne(); VersionedMap sut2 = store2.createMap(); int index2 = 1; for (SimpleEntry entry : content) { @@ -75,38 +73,39 @@ class ContentEqualsFuzzTest { } // Check the integrity of the maps - ((VersionedMapImpl) sut1).checkIntegrity(); - ((VersionedMapImpl) sut2).checkIntegrity(); + sut1.checkIntegrity(); + sut2.checkIntegrity(); // Compare the two maps MapTestEnvironment.compareTwoMaps(scenario, sut1, sut2); } - @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit frequency={5}" + - "seed={6} evil-hash={7}") + public static final String title = "Compare {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit frequency={5}" + + "seed={6} config={7}"; + + @ParameterizedTest(name = title) @MethodSource @Timeout(value = 10) @Tag("fuzz") void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, boolean evilHash) { + int seed, VersionedMapStoreBuilder builder) { runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - nullDefault, commitFrequency, evilHash); + nullDefault, commitFrequency, builder); } static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, - commitFrequencyOptions, randomSeedOptions, evilHashOptions); + commitFrequencyOptions, randomSeedOptions, storeConfigs); } - @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit frequency={5}" + - "seed={6} evil-hash={7}") + @ParameterizedTest(name = title) @MethodSource @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency, - int seed, boolean evilHash) { + int seed, VersionedMapStoreBuilder builder) { runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - defaultNull, commitFrequency, evilHash); + defaultNull, commitFrequency, builder); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java index 90aa8e01..bf409a74 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java @@ -1,33 +1,26 @@ package tools.refinery.store.map.tests.fuzz; -import static org.junit.jupiter.api.Assertions.fail; -import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; - -import java.util.Random; -import java.util.stream.Stream; - import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; - -import tools.refinery.store.map.ContinousHashProvider; -import tools.refinery.store.map.DiffCursor; -import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreImpl; -import tools.refinery.store.map.internal.VersionedMapImpl; +import tools.refinery.store.map.*; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; +import java.util.Random; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.fail; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; + class DiffCursorFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, - boolean nullDefault, int commitFrequency, - boolean evilHash) { + boolean nullDefault, int commitFrequency, VersionedMapStoreBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); + VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); iterativeRandomPutsAndCommitsThenDiffCursor(scenario, store, steps, maxKey, values, seed, commitFrequency); } @@ -35,7 +28,7 @@ class DiffCursorFuzzTest { int steps, int maxKey, String[] values, int seed, int commitFrequency) { // 1. build a map with versions Random r = new Random(seed); - VersionedMapImpl versioned = (VersionedMapImpl) store.createMap(); + VersionedMap versioned = store.createMap(); int largestCommit = -1; for (int i = 0; i < steps; i++) { @@ -56,7 +49,7 @@ class DiffCursorFuzzTest { System.out.println(scenario + ":" + index + "/" + steps + " building finished"); } // 2. create a non-versioned map, - VersionedMapImpl moving = (VersionedMapImpl) store.createMap(); + VersionedMap moving = store.createMap(); Random r2 = new Random(seed + 1); final int diffTravelFrequency = commitFrequency * 2; @@ -88,31 +81,32 @@ class DiffCursorFuzzTest { } - @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + - "commit frequency={5} seed={6} evil-hash={7}") + public static final String title = "DiffCursor {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + + "commit frequency={5} seed={6} config={7}"; + + @ParameterizedTest(name = title) @MethodSource @Timeout(value = 10) @Tag("fuzz") void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, boolean evilHash) { + int seed, VersionedMapStoreBuilder builder) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, - noKeys, noValues, nullDefault, commitFrequency, evilHash); + noKeys, noValues, nullDefault, commitFrequency, builder); } static Stream parametrizedFuzz() { - return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, - commitFrequencyOptions, randomSeedOptions, evilHashOptions); + return FuzzTestUtils.permutationWithSize(new Object[]{100}, keyCounts, valueCounts, nullDefaultOptions, + commitFrequencyOptions, randomSeedOptions, storeConfigs); } - @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + - "commit frequency={5} seed={6} evil-hash={7}") + @ParameterizedTest(name = title) @MethodSource @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, boolean evilHash) { + int seed, VersionedMapStoreBuilder builder) { runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - nullDefault, commitFrequency, evilHash); + nullDefault, commitFrequency, builder); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java index 9325a938..ec2224b4 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java @@ -15,27 +15,24 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import tools.refinery.store.map.ContinousHashProvider; import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreImpl; +import tools.refinery.store.map.VersionedMapStoreBuilder; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; class MultiThreadFuzzTest { - public static final int noThreads = 32; + public static final int noThreads = 10; - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, - boolean nullDefault, int commitFrequency, - boolean evilHash) { + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); + VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); // initialize runnables MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads]; for (int i = 0; i < noThreads; i++) { - runnables[i] = new MultiThreadTestRunnable(scenario + "-T" + (i + 1), store, steps, maxKey, values, seed, commitFrequency); + runnables[i] = new MultiThreadTestRunnable(scenario + "-T" + (i + 1), store, steps, maxKey, values, seed + , commitFrequency); } // initialize threads @@ -46,7 +43,8 @@ class MultiThreadFuzzTest { // start threads; for (int i = 0; i < noThreads; i++) { - threads[i].start(); + runnables[i].run(); + //threads[i].start(); } // wait all the threads; @@ -67,32 +65,32 @@ class MultiThreadFuzzTest { assertEquals(Collections.EMPTY_LIST, errors); } - @ParameterizedTest(name = "MultiThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + - "frequency={5} seed={6} evil-hash={7}") + static final String title = "MultiThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + + "frequency={5} seed={6} config={7}"; + + @ParameterizedTest(name = title) @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency, - int seed, boolean evilHash) { + void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, + int commitFrequency, int seed, VersionedMapStoreBuilder builder) { runFuzzTest("MultiThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency + - "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, evilHash); + "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, builder); } static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, - new Object[]{10, 100}, randomSeedOptions, - evilHashOptions); + new Object[]{10, 100}, randomSeedOptions, storeConfigs); } - @ParameterizedTest(name = "MultiThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + - "frequency={5} seed={6} evil-hash={7}") + @ParameterizedTest(name = title) @MethodSource @Tag("fuzz") @Tag("slow") - void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, - boolean evilHash) { + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, + int commitFrequency, int seed, VersionedMapStoreBuilder builder) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - nullDefault, commitFrequency, evilHash); + nullDefault, commitFrequency, builder); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java index 4415e4e5..f449ca97 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java @@ -8,8 +8,8 @@ import java.util.List; import java.util.Map; import java.util.Random; +import tools.refinery.store.map.VersionedMap; import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.internal.VersionedMapImpl; import tools.refinery.store.map.tests.utils.MapTestEnvironment; public class MultiThreadTestRunnable implements Runnable { @@ -45,9 +45,17 @@ public class MultiThreadTestRunnable implements Runnable { @Override public void run() { + try{ + task(); + } catch(Exception e) { + e.printStackTrace(); + } + } + + private void task() { // 1. build a map with versions Random r = new Random(seed); - VersionedMapImpl versioned = (VersionedMapImpl) store.createMap(); + VersionedMap versioned = store.createMap(); Map index2Version = new HashMap<>(); for (int i = 0; i < steps; i++) { @@ -67,7 +75,7 @@ public class MultiThreadTestRunnable implements Runnable { MapTestEnvironment.printStatus(scenario, index, steps, "building"); } // 2. create a non-versioned - VersionedMapImpl reference = (VersionedMapImpl) store.createMap(); + VersionedMap reference = store.createMap(); r = new Random(seed); Random r2 = new Random(seed + 1); @@ -84,13 +92,17 @@ public class MultiThreadTestRunnable implements Runnable { // go back to an existing state and compare to the reference if (index % (commitFrequency) == 0) { versioned.restore(index2Version.get(i)); - MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned, errors); + MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned, null); // go back to a random state (probably created by another thread) List states = new ArrayList<>(store.getStates()); + states.sort(Long::compare); Collections.shuffle(states, r2); for (Long state : states.subList(0, Math.min(states.size(), 100))) { - versioned.restore(state); + long x = state; + versioned.restore(x); + var clean = store.createMap(x); + MapTestEnvironment.compareTwoMaps(scenario + ":" + index, clean, versioned, null); } versioned.restore(index2Version.get(i)); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java index ab37ef83..bdf72ce4 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java @@ -12,21 +12,17 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import tools.refinery.store.map.ContinousHashProvider; -import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreImpl; -import tools.refinery.store.map.internal.VersionedMapImpl; +import tools.refinery.store.map.*; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; class MutableFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, - boolean nullDefault, boolean evilHash) { + boolean nullDefault, VersionedMapStoreBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); - VersionedMapImpl sut = (VersionedMapImpl) store.createMap(); + VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); + VersionedMap sut = store.createMap(); MapTestEnvironment e = new MapTestEnvironment<>(sut); Random r = new Random(seed); @@ -52,33 +48,34 @@ class MutableFuzzTest { } } - @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} seed={5} " + - "evil-hash={6}") + final String title = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} seed={5} " + + "config={6}"; + + @ParameterizedTest(name = title) @MethodSource @Timeout(value = 10) @Tag("fuzz") void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int seed, - boolean evilHash) { + VersionedMapStoreBuilder builder) { runFuzzTest( - "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), - seed, steps, noKeys, noValues, defaultNull, evilHash); + "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, + seed, steps, noKeys, noValues, defaultNull, builder); } static Stream parametrizedFuzz() { return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, - randomSeedOptions, evilHashOptions); + randomSeedOptions, storeConfigs); } - @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} seed={5} " + - "evil-hash={6}") + @ParameterizedTest(name = title) @MethodSource @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int seed, - boolean evilHash) { + VersionedMapStoreBuilder builder) { runFuzzTest( - "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), - seed, steps, noKeys, noValues, nullDefault, evilHash); + "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, + seed, steps, noKeys, noValues, nullDefault, builder); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java index b58b06f9..cee15fe1 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java @@ -71,7 +71,7 @@ class MutableImmutableCompareFuzzTest { static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, - commitFrequencyOptions, randomSeedOptions, evilHashOptions); + commitFrequencyOptions, randomSeedOptions, new Object[]{false, true}); } @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java index 77b26c41..568aaac9 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java @@ -14,9 +14,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import tools.refinery.store.map.ContinousHashProvider; -import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreImpl; +import tools.refinery.store.map.*; import tools.refinery.store.map.internal.VersionedMapImpl; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; @@ -24,11 +22,10 @@ import tools.refinery.store.map.tests.utils.MapTestEnvironment; class RestoreFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, - boolean evilHash) { + VersionedMapStoreBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - ContinousHashProvider chp = MapTestEnvironment.prepareHashProvider(evilHash); - VersionedMapStore store = new VersionedMapStoreImpl<>(chp, values[0]); + VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); iterativeRandomPutsAndCommitsThenRestore(scenario, store, steps, maxKey, values, seed, commitFrequency); } @@ -37,7 +34,7 @@ class RestoreFuzzTest { int steps, int maxKey, String[] values, int seed, int commitFrequency) { // 1. build a map with versions Random r = new Random(seed); - VersionedMapImpl versioned = (VersionedMapImpl) store.createMap(); + VersionedMap versioned = store.createMap(); Map index2Version = new HashMap<>(); for (int i = 0; i < steps; i++) { @@ -57,7 +54,7 @@ class RestoreFuzzTest { MapTestEnvironment.printStatus(scenario, index, steps, "building"); } // 2. create a non-versioned and - VersionedMapImpl reference = (VersionedMapImpl) store.createMap(); + VersionedMap reference = store.createMap(); r = new Random(seed); for (int i = 0; i < steps; i++) { @@ -79,31 +76,32 @@ class RestoreFuzzTest { } - @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5}" + - " seed={6} evil-hash={7}") + public static final String title = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + + "seed={6} config={7}"; + + @ParameterizedTest(name = title) @MethodSource @Timeout(value = 10) @Tag("smoke") void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, boolean evilHash) { + int seed, VersionedMapStoreBuilder builder) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - nullDefault, commitFrequency, evilHash); + nullDefault, commitFrequency, builder); } static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, - commitFrequencyOptions, randomSeedOptions, evilHashOptions); + commitFrequencyOptions, randomSeedOptions, storeConfigs); } - @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5}" + - " seed={6} evil-hash={7}") + @ParameterizedTest(name = title) @MethodSource @Tag("smoke") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, boolean evilHash) { + int seed, VersionedMapStoreBuilder builder) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - nullDefault, commitFrequency, evilHash); + nullDefault, commitFrequency, builder); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java index 4462c55b..0544687a 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java @@ -96,7 +96,7 @@ class SharedStoreFuzzTest { static Stream parametrizedFastFuzz() { return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, - commitFrequencyOptions, randomSeedOptions, evilHashOptions); + commitFrequencyOptions, randomSeedOptions, new Object[]{false, true}); } @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit " + diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java index add4ca5d..fb6b28d8 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java @@ -1,11 +1,43 @@ package tools.refinery.store.map.tests.fuzz.utils; +import tools.refinery.store.map.VersionedMapStoreBuilder; +import tools.refinery.store.map.tests.utils.MapTestEnvironment; + public final class FuzzTestCollections { public static final Object[] stepCounts = {FuzzTestUtils.FAST_STEP_COUNT}; - public static final Object[] keyCounts = {3, 32, 32 * 32}; + public static final Object[] keyCounts = {1, 32, 32 * 32}; public static final Object[] valueCounts = {2, 3}; public static final Object[] nullDefaultOptions = {false, true}; - public static final Object[] commitFrequencyOptions = {1, 10, 100}; - public static final Object[] randomSeedOptions = {1, 2, 3}; - public static final Object[] evilHashOptions = {false, true}; + public static final Object[] commitFrequencyOptions = {10, 10, 100}; + public static final Object[] randomSeedOptions = {1/*, 2, 3*/}; + public static final Object[] storeConfigs = { + // State based + VersionedMapStoreBuilder.builder() + .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) + .setStateBasedImmutableWhenCommitting(true) + .setHashProvider(MapTestEnvironment.prepareHashProvider(false)) + .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.SHARED_NODE_CACHE), + VersionedMapStoreBuilder.builder() + .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) + .setStateBasedImmutableWhenCommitting(true) + .setHashProvider(MapTestEnvironment.prepareHashProvider(true)) + .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.SHARED_NODE_CACHE), + VersionedMapStoreBuilder.builder() + .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) + .setStateBasedImmutableWhenCommitting(false) + .setHashProvider(MapTestEnvironment.prepareHashProvider(false)) + .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.SHARED_NODE_CACHE), + VersionedMapStoreBuilder.builder() + .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) + .setStateBasedImmutableWhenCommitting(false) + .setHashProvider(MapTestEnvironment.prepareHashProvider(false)) + .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.NO_NODE_CACHE), + // Delta based + VersionedMapStoreBuilder.builder() + .setStrategy(VersionedMapStoreBuilder.StoreStrategy.DELTA) + .setDeltaStorageStrategy(VersionedMapStoreBuilder.DeltaStorageStrategy.SET), + VersionedMapStoreBuilder.builder() + .setStrategy(VersionedMapStoreBuilder.StoreStrategy.DELTA) + .setDeltaStorageStrategy(VersionedMapStoreBuilder.DeltaStorageStrategy.LIST) + }; } -- cgit v1.2.3-70-g09d2 From f0f04091e31f80f253f9129ca3a7191d0af6af1e Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Thu, 16 Feb 2023 00:41:09 +0100 Subject: Additional tests for delta restoration --- .../refinery/store/map/tests/MapUnitTests.java | 72 ++++++++++++++++++++++ .../store/map/tests/fuzz/SingleThreadFuzzTest.java | 61 ++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java (limited to 'subprojects/store') diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java index 77c62305..2216db76 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java @@ -2,6 +2,7 @@ package tools.refinery.store.map.tests; import org.junit.jupiter.api.Test; import tools.refinery.store.map.VersionedMapStore; +import tools.refinery.store.map.VersionedMapStoreBuilder; import tools.refinery.store.map.VersionedMapStoreImpl; import tools.refinery.store.model.TupleHashProvider; import tools.refinery.store.tuple.Tuple; @@ -18,4 +19,75 @@ class MapUnitTests { var out2 = map.put(Tuple.of(1), true); assertEquals(false, out2); } + + @Test + void deltaRestoreTest() { + VersionedMapStore store = + VersionedMapStoreBuilder.builder().setDefaultValue("x").buildOne(); + var map = store.createMap(); + map.put(1,"val"); + var version1 = map.commit(); + map.put(1,"x"); + map.restore(version1); + System.out.println(map.getSize()); + assertEquals(1,map.getSize()); + } + + @Test + void deltaRestoreTest2() { + VersionedMapStore store = + VersionedMapStoreBuilder.builder().setDefaultValue("x").buildOne(); + var map = store.createMap(); + map.put(1,"x"); + var version1 = map.commit(); + map.put(1,"1"); + map.restore(version1); + System.out.println(map.getSize()); + assertEquals(0,map.getSize()); + } + @Test + void deltaRestoreTest3() { + VersionedMapStore store = + VersionedMapStoreBuilder.builder().setDefaultValue("x").buildOne(); + var map = store.createMap(); + map.commit(); + map.put(1,"1"); + map.put(2,"x"); + assertEquals(1,map.getSize()); + var version1 = map.commit(); + map.put(1,"x"); + assertEquals(0,map.getSize()); + map.put(2,"2"); + assertEquals(1,map.getSize()); + map.put(2,"x"); + assertEquals(0,map.getSize()); + var version2 = map.commit(); + map.restore(version1); + assertEquals(1,map.getSize()); + map.restore(version2); + assertEquals(0,map.getSize()); + } + + @Test + void deltaRestoreTest4() { + VersionedMapStore store = + VersionedMapStoreBuilder.builder().setDefaultValue("x").buildOne(); + var map = store.createMap(); + map.commit(); + map.put(1,"1"); + map.put(2,"x"); + assertEquals(1,map.getSize()); + var version1 = map.commit(); + map.put(1,"x"); + assertEquals(0,map.getSize()); + map.put(2,"2"); + assertEquals(1,map.getSize()); + map.put(2,"x"); + assertEquals(0,map.getSize()); + var version2 = map.commit(); + map.restore(version1); + assertEquals(1,map.getSize()); + map.restore(version2); + assertEquals(0,map.getSize()); + } } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java new file mode 100644 index 00000000..e7d49227 --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java @@ -0,0 +1,61 @@ +package tools.refinery.store.map.tests.fuzz; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import tools.refinery.store.map.VersionedMapStore; +import tools.refinery.store.map.VersionedMapStoreBuilder; +import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; +import tools.refinery.store.map.tests.utils.MapTestEnvironment; + +import java.util.stream.Stream; + +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; + +class SingleThreadFuzzTest { + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreBuilder builder) { + String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); + + VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); + + // initialize runnables + MultiThreadTestRunnable runnable = new MultiThreadTestRunnable(scenario, store, steps, maxKey, values, seed, commitFrequency); + + // start threads; + runnable.run(); + } + + static final String title = "SingleThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + + "frequency={5} seed={6} config={7}"; + + @ParameterizedTest(name = title) + @MethodSource + @Timeout(value = 10) + @Tag("fuzz") + void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, + int commitFrequency, int seed, VersionedMapStoreBuilder builder) { + runFuzzTest("SingleThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency + + "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, builder); + } + + static Stream parametrizedFastFuzz() { + return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, + new Object[]{10, 100}, randomSeedOptions, storeConfigs); + } + + @ParameterizedTest(name = title) + @MethodSource + @Tag("fuzz") + @Tag("slow") + void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, + int commitFrequency, int seed, VersionedMapStoreBuilder builder) { + runFuzzTest("SingleThreadS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, + nullDefault, commitFrequency, builder); + } + + static Stream parametrizedSlowFuzz() { + return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1); + } +} -- cgit v1.2.3-70-g09d2 From 44c4c918d7e34cada66f6cbe523a3357a83c9b77 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Mon, 20 Feb 2023 01:29:45 +0100 Subject: Initialization bugs with empty DeltaDiffCursor fixed --- .../refinery/store/map/internal/DeltaDiffCursor.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java index 49ea1f67..8ddca8ec 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java @@ -11,6 +11,7 @@ public class DeltaDiffCursor implements DiffCursor { final List[]> backwardTransactions; final List[]> forwardTransactions; + boolean started; /** * Denotes the direction of traversal. False means backwards, true means * forward. @@ -35,6 +36,7 @@ public class DeltaDiffCursor implements DiffCursor { direction = true; listIndex = -1; } + started = false; } protected MapDelta getCurrentDelta() { @@ -65,7 +67,10 @@ public class DeltaDiffCursor implements DiffCursor { @Override public boolean move() { - if (isTerminated()) { + if(!started) { + started = true; + return !isTerminated(); + } else if (isTerminated()) { return false; } else { if (this.direction) { @@ -119,11 +124,19 @@ public class DeltaDiffCursor implements DiffCursor { @Override public V getFromValue() { - return getCurrentDelta().getOldValue(); + if(this.direction) { + return getCurrentDelta().getOldValue(); + } else { + return getCurrentDelta().getNewValue(); + } } @Override public V getToValue() { - return getCurrentDelta().getNewValue(); + if(this.direction) { + return getCurrentDelta().getNewValue(); + } else { + return getCurrentDelta().getOldValue(); + } } } -- cgit v1.2.3-70-g09d2 From 89e142514ae45d793c7dbe38f728b33451261338 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Tue, 18 Jul 2023 15:38:59 +0200 Subject: Fixing long-standing bug with state based diff cursor. By implementing an InOrderMapCursor cursor, and a MapDiffCursor that synchronize two cursors. --- .../refinery/store/map/VersionedMapStoreImpl.java | 17 +- .../refinery/store/map/internal/ImmutableNode.java | 74 ++++- .../store/map/internal/InOrderMapCursor.java | 141 +++++++++ .../refinery/store/map/internal/MapCursor.java | 59 ---- .../refinery/store/map/internal/MapDiffCursor.java | 316 ++++++++++++--------- .../refinery/store/map/internal/MutableNode.java | 111 +++++--- .../tools/refinery/store/map/internal/Node.java | 2 + .../store/map/internal/VersionedMapImpl.java | 20 +- .../model/internal/VersionedInterpretation.java | 15 +- .../store/map/tests/InOrderCursorTest.java | 49 ++++ .../store/map/tests/fuzz/DiffCursorFuzzTest.java | 128 +++++---- .../map/tests/fuzz/utils/FuzzTestCollections.java | 12 +- .../store/map/tests/utils/MapTestEnvironment.java | 10 +- 13 files changed, 611 insertions(+), 343 deletions(-) create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/InOrderMapCursor.java create mode 100644 subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java index 113874e7..beeed110 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java @@ -1,9 +1,6 @@ package tools.refinery.store.map; -import tools.refinery.store.map.internal.ImmutableNode; -import tools.refinery.store.map.internal.MapDiffCursor; -import tools.refinery.store.map.internal.Node; -import tools.refinery.store.map.internal.VersionedMapImpl; +import tools.refinery.store.map.internal.*; import java.util.*; @@ -93,7 +90,7 @@ public class VersionedMapStoreImpl implements VersionedMapStore { } else { ArrayList existingKeys = new ArrayList<>(states.keySet()); Collections.sort(existingKeys); - throw new IllegalArgumentException("Store does not contain state " + state + "! Avaliable states: " + throw new IllegalArgumentException("Store does not contain state " + state + "! Available states: " + Arrays.toString(existingKeys.toArray())); } } @@ -118,10 +115,10 @@ public class VersionedMapStoreImpl implements VersionedMapStore { @Override public DiffCursor getDiffCursor(long fromState, long toState) { - VersionedMap map1 = createMap(fromState); - VersionedMap map2 = createMap(toState); - Cursor cursor1 = map1.getAll(); - Cursor cursor2 = map2.getAll(); - return new MapDiffCursor<>(this.hashProvider, this.defaultValue, cursor1, cursor2); + VersionedMapImpl map1 = (VersionedMapImpl) createMap(fromState); + VersionedMapImpl map2 = (VersionedMapImpl) createMap(toState); + InOrderMapCursor cursor1 = new InOrderMapCursor<>(map1); + InOrderMapCursor cursor2 = new InOrderMapCursor<>(map2); + return new MapDiffCursor<>(this.defaultValue, cursor1, cursor2); } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java index 914bab08..92446711 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java @@ -15,7 +15,7 @@ public class ImmutableNode extends Node { */ final int nodeMap; /** - * Stores Keys, Values, and subnodes. Structure: (K,V)*,NODE; NODES are stored + * Stores Keys, Values, and sub-nodes. Structure: (K,V)*,NODE; NODES are stored * backwards. */ final Object[] content; @@ -65,24 +65,24 @@ public class ImmutableNode extends Node { int resultDataMap = 0; int resultNodeMap = 0; final Object[] resultContent = new Object[size]; - int bitposition = 1; + int bitPosition = 1; for (int i = 0; i < FACTOR; i++) { Object key = node.content[i * 2]; if (key != null) { - resultDataMap |= bitposition; + resultDataMap |= bitPosition; resultContent[datas * 2] = key; resultContent[datas * 2 + 1] = node.content[i * 2 + 1]; datas++; } else { @SuppressWarnings("unchecked") var subnode = (Node) node.content[i * 2 + 1]; if (subnode != null) { - ImmutableNode immutableSubnode = subnode.toImmutable(cache); - resultNodeMap |= bitposition; - resultContent[size - 1 - nodes] = immutableSubnode; + ImmutableNode immutableSubNode = subnode.toImmutable(cache); + resultNodeMap |= bitPosition; + resultContent[size - 1 - nodes] = immutableSubNode; nodes++; } } - bitposition <<= 1; + bitPosition <<= 1; } final int resultHash = node.hashCode(); var newImmutable = new ImmutableNode(resultDataMap, resultNodeMap, resultContent, resultHash); @@ -130,9 +130,9 @@ public class ImmutableNode extends Node { @Override public Node putValue(K key, V value, OldValueBox oldValue, ContinousHashProvider hashProvider, V defaultValue, int hash, int depth) { int selectedHashFragment = hashFragment(hash, shiftDepth(depth)); - int bitposition = 1 << selectedHashFragment; - if ((dataMap & bitposition) != 0) { - int keyIndex = 2 * index(dataMap, bitposition); + int bitPosition = 1 << selectedHashFragment; + if ((dataMap & bitPosition) != 0) { + int keyIndex = 2 * index(dataMap, bitPosition); @SuppressWarnings("unchecked") K keyCandidate = (K) content[keyIndex]; if (keyCandidate.equals(key)) { if (value == defaultValue) { @@ -159,8 +159,8 @@ public class ImmutableNode extends Node { return mutable.putValue(key, value, oldValue, hashProvider, defaultValue, hash, depth); } } - } else if ((nodeMap & bitposition) != 0) { - int keyIndex = content.length - 1 - index(nodeMap, bitposition); + } else if ((nodeMap & bitPosition) != 0) { + int keyIndex = content.length - 1 - index(nodeMap, bitPosition); @SuppressWarnings("unchecked") var subNode = (ImmutableNode) content[keyIndex]; int newDepth = incrementDepth(depth); int newHash = newHash(hashProvider, key, hash, newDepth); @@ -253,6 +253,49 @@ public class ImmutableNode extends Node { } } + @Override + @SuppressWarnings("unchecked") + boolean moveToNextInorder(InOrderMapCursor cursor) { + if(cursor.nodeIndexStack.peek()==null) { + throw new IllegalStateException("Cursor moved to the next state when the state is empty."); + } + + int position = cursor.nodeIndexStack.peek(); + for (int index = position + 1; index < FACTOR; index++) { + final int mask = 1< subnode = (Node) this.content[this.content.length - 1 - index(nodeMap, mask)]; + cursor.nodeIndexStack.pop(); + cursor.nodeIndexStack.push(index); + cursor.nodeIndexStack.push(InOrderMapCursor.INDEX_START); + cursor.nodeStack.push(subnode); + + return subnode.moveToNextInorder(cursor); + } + } + + // nothing found + cursor.nodeStack.pop(); + cursor.nodeIndexStack.pop(); + if (!cursor.nodeStack.isEmpty()) { + Node supernode = cursor.nodeStack.peek(); + return supernode.moveToNextInorder(cursor); + } else { + cursor.key = null; + cursor.value = null; + return false; + } + } + @Override public void prettyPrint(StringBuilder builder, int depth, int code) { builder.append("\t".repeat(Math.max(0, depth))); @@ -348,8 +391,8 @@ public class ImmutableNode extends Node { var mutableSubnode = (Node) mutable.content[i * 2 + 1]; if (mutableSubnode != null) { if (datas * 2 + nodes + 1 <= immutableLength) { - Object immutableSubnode = immutable.content[immutableLength - 1 - nodes]; - if (!mutableSubnode.equals(immutableSubnode)) { + Object immutableSubNode = immutable.content[immutableLength - 1 - nodes]; + if (!mutableSubnode.equals(immutableSubNode)) { return false; } nodes++; @@ -359,6 +402,7 @@ public class ImmutableNode extends Node { } } } - return true; + + return datas * 2 + nodes == immutable.content.length; } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/InOrderMapCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/InOrderMapCursor.java new file mode 100644 index 00000000..c559d9ad --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/InOrderMapCursor.java @@ -0,0 +1,141 @@ +package tools.refinery.store.map.internal; + +import tools.refinery.store.map.AnyVersionedMap; +import tools.refinery.store.map.ContentHashCode; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.map.VersionedMap; + +import java.util.*; + +public class InOrderMapCursor implements Cursor { + // Constants + static final int INDEX_START = -1; + + // Tree stack + ArrayDeque> nodeStack; + ArrayDeque nodeIndexStack; + + + // Values + K key; + V value; + + // Hash code for checking concurrent modifications + final VersionedMap map; + final int creationHash; + + public InOrderMapCursor(VersionedMapImpl map) { + // Initializing tree stack + super(); + this.nodeStack = new ArrayDeque<>(); + this.nodeIndexStack = new ArrayDeque<>(); + if (map.root != null) { + this.nodeStack.add(map.root); + this.nodeIndexStack.push(INDEX_START); + } + + // Initializing cache + this.key = null; + this.value = null; + + // Initializing state + this.map = map; + this.creationHash = map.contentHashCode(ContentHashCode.APPROXIMATE_FAST); + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + public boolean isTerminated() { + return this.nodeStack.isEmpty(); + } + + public boolean move() { + if (isDirty()) { + throw new ConcurrentModificationException(); + } + if (!isTerminated()) { + var node = this.nodeStack.peek(); + if (node == null) { + throw new IllegalStateException("Cursor is not terminated but the current node is missing"); + } + boolean result = node.moveToNextInorder(this); + if (this.nodeIndexStack.size() != this.nodeStack.size()) { + throw new IllegalArgumentException("Node stack is corrupted by illegal moves!"); + } + return result; + } + return false; + } + + public boolean skipCurrentNode() { + nodeStack.pop(); + nodeIndexStack.pop(); + return move(); + } + + @Override + public boolean isDirty() { + return this.map.contentHashCode(ContentHashCode.APPROXIMATE_FAST) != this.creationHash; + } + + @Override + public Set getDependingMaps() { + return Set.of(this.map); + } + + public static boolean sameSubNode(InOrderMapCursor cursor1, InOrderMapCursor cursor2) { + Node nodeOfCursor1 = cursor1.nodeStack.peek(); + Node nodeOfCursor2 = cursor2.nodeStack.peek(); + return Objects.equals(nodeOfCursor1, nodeOfCursor2); + } + + /** + * Compares the state of two cursors started on two {@link VersionedMap} of the same + * {@link tools.refinery.store.map.VersionedMapStore}. + * @param Key type + * @param Value type + * @param cursor1 first cursor + * @param cursor2 second cursor + * @return Positive number if cursor 1 is behind, negative number if cursor 2 is behind, and 0 if they are at the + * same position. + */ + public static int comparePosition(InOrderMapCursor cursor1, InOrderMapCursor cursor2) { + // If the state does not determine the order, then compare @nodeIndexStack. + Iterator nodeIndexStack1 = cursor1.nodeIndexStack.descendingIterator(); + Iterator nodeIndexStack2 = cursor2.nodeIndexStack.descendingIterator(); + + while(nodeIndexStack1.hasNext() && nodeIndexStack2.hasNext()){ + final int index1 = nodeIndexStack1.next(); + final int index2 = nodeIndexStack2.next(); + if(index1 < index2) { + return 1; + } else if(index1 > index2) { + return -1; + } + } + + return 0; + } + + /** + * Compares the depth of two cursors started on @{@link VersionedMap} of the same + * {@link tools.refinery.store.map.VersionedMapStore}. + * @param Key type + * @param Value type + * @param cursor1 first cursor + * @param cursor2 second cursor + * @return Positive number if cursor 1 is deeper, negative number if cursor 2 is deeper, and 0 if they are at the + * same depth. + */ + public static int compareDepth(InOrderMapCursor cursor1, InOrderMapCursor cursor2) { + int d1 = cursor1.nodeIndexStack.size(); + int d2 = cursor2.nodeIndexStack.size(); + return Integer.compare(d1, d2); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java index 50fcfcd3..7e4f82e8 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java @@ -7,7 +7,6 @@ import tools.refinery.store.map.VersionedMap; import java.util.ArrayDeque; import java.util.ConcurrentModificationException; -import java.util.Iterator; import java.util.Set; public class MapCursor implements Cursor { @@ -79,13 +78,6 @@ public class MapCursor implements Cursor { return false; } - public boolean skipCurrentNode() { - nodeStack.pop(); - nodeIndexStack.pop(); - dataIndex = INDEX_FINISH; - return move(); - } - @Override public boolean isDirty() { return this.map.contentHashCode(ContentHashCode.APPROXIMATE_FAST) != this.creationHash; @@ -95,55 +87,4 @@ public class MapCursor implements Cursor { public Set getDependingMaps() { return Set.of(this.map); } - - public static boolean sameSubNode(MapCursor cursor1, MapCursor cursor2) { - Node nodeOfCursor1 = cursor1.nodeStack.peek(); - Node nodeOfCursor2 = cursor2.nodeStack.peek(); - if (nodeOfCursor1 != null && nodeOfCursor2 != null) { - return nodeOfCursor1.equals(nodeOfCursor2); - } else { - return false; - } - } - - /** - * Compares the state of two cursors started on two @{@link VersionedMap of the }same - * {@link tools.refinery.store.map.VersionedMapStore}. - * @param Key type - * @param Value type - * @param cursor1 first cursor - * @param cursor2 second cursor - * @return Positive number if cursor 1 is behind, negative number if cursor 2 is behind, and 0 if they are at the - * same position. - */ - public static int compare(MapCursor cursor1, MapCursor cursor2) { - // Checking the state of the cursors - if(!cursor1.isTerminated() && cursor2.isTerminated()) return -1; - else if(cursor1.isTerminated() && !cursor2.isTerminated()) return 1; - else if(cursor1.isTerminated() && cursor2.isTerminated()) return 0; - - // If the state does not determine the order, then compare @nodeIndexStack. - Iterator stack1 = cursor1.nodeIndexStack.descendingIterator(); - Iterator stack2 = cursor2.nodeIndexStack.descendingIterator(); - if (stack1.hasNext()) { - if (!stack2.hasNext()) { - // stack 2 has no more element, thus stack 1 is deeper - return 1; - } - int val1 = stack1.next(); - int val2 = stack2.next(); - if (val1 < val2) { - return -1; - } else if (val2 < val1) { - return 1; - } - } - if (stack2.hasNext()) { - // stack 2 has more element, thus stack 2 is deeper - return 1; - } - - // two cursors are equally deep decide by data index - return Integer.compare(cursor1.dataIndex, cursor2.dataIndex); - } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java index 6c076ce5..59e8d738 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java @@ -1,7 +1,6 @@ package tools.refinery.store.map.internal; import tools.refinery.store.map.AnyVersionedMap; -import tools.refinery.store.map.ContinousHashProvider; import tools.refinery.store.map.Cursor; import tools.refinery.store.map.DiffCursor; @@ -14,37 +13,78 @@ import java.util.stream.Stream; * A cursor representing the difference between two states of a map. * * @author Oszkar Semerath - * */ public class MapDiffCursor implements DiffCursor, Cursor { + private enum State { + /** + * initialized state. + */ + INIT, + /** + * Unstable state. + */ + MOVING_MOVING_SAME_KEY_SAME_VALUE, + /** + * Both cursors are moving, and they are on the same sub-node. + */ + MOVING_MOVING_SAME_NODE, + /** + * Both cursors are moving, cursor 1 is behind. + */ + MOVING_MOVING_BEHIND1, + /** + * Both cursors are moving, cursor 2 is behind. + */ + MOVING_MOVING_BEHIND2, + /** + * Both cursors are moving, cursor 1 is on the same key as cursor 2, values are different + */ + MOVING_MOVING_SAME_KEY_DIFFERENT_VALUE, + /** + * Cursor 1 is moving, Cursor 2 is terminated. + */ + MOVING_TERMINATED, + /** + * Cursor 1 is terminated , Cursor 2 is moving. + */ + TERMINATED_MOVING, + /** + * Both cursors are terminated. + */ + TERMINATED_TERMINATED, + /** + * Both Cursors are moving, and they are on an incomparable position. + * It is resolved by showing Cursor 1. + */ + MOVING_MOVING_HASH1, + /** + * Both Cursors are moving, and they are on an incomparable position. + * It is resolved by showing Cursor 2. + */ + MOVING_MOVING_HASH2 + } + /** * Default nodeId representing missing elements. */ private final V defaultValue; - private final MapCursor cursor1; - private final MapCursor cursor2; - private final ContinousHashProvider hashProvider; + private final InOrderMapCursor cursor1; + private final InOrderMapCursor cursor2; + + // State + State state = State.INIT; // Values private K key; private V fromValue; private V toValue; - // State - /** - * Positive number if cursor 1 is behind, negative number if cursor 2 is behind, - * and 0 if they are at the same position. - */ - private int cursorRelation; - private HashClash hashClash = HashClash.NONE; - public MapDiffCursor(ContinousHashProvider hashProvider, V defaultValue, Cursor cursor1, - Cursor cursor2) { + public MapDiffCursor(V defaultValue, InOrderMapCursor cursor1, InOrderMapCursor cursor2) { super(); - this.hashProvider = hashProvider; this.defaultValue = defaultValue; - this.cursor1 = (MapCursor) cursor1; - this.cursor2 = (MapCursor) cursor2; + this.cursor1 = cursor1; + this.cursor2 = cursor2; } @Override @@ -68,7 +108,7 @@ public class MapDiffCursor implements DiffCursor, Cursor { } public boolean isTerminated() { - return cursor1.isTerminated() && cursor2.isTerminated(); + return this.state == State.TERMINATED_TERMINATED; } @Override @@ -78,148 +118,142 @@ public class MapDiffCursor implements DiffCursor, Cursor { @Override public Set getDependingMaps() { - return Stream.concat(cursor1.getDependingMaps().stream(), cursor2.getDependingMaps().stream()) - .map(AnyVersionedMap.class::cast) - .collect(Collectors.toUnmodifiableSet()); - } - - protected void updateState() { - if (!isTerminated()) { - this.cursorRelation = MapCursor.compare(cursor1, cursor2); - if (cursorRelation > 0 || cursor2.isTerminated()) { - this.key = cursor1.getKey(); - this.fromValue = cursor1.getValue(); - this.toValue = defaultValue; - } else if (cursorRelation < 0 || cursor1.isTerminated()) { - this.key = cursor2.getKey(); - this.fromValue = defaultValue; - this.toValue = cursor1.getValue(); - } else { - // cursor1 = cursor2 - if (cursor1.getKey().equals(cursor2.getKey())) { - this.key = cursor1.getKey(); - this.fromValue = cursor1.getValue(); - this.toValue = defaultValue; - } else { - resolveHashClashWithFirstEntry(); - } - } - } + return Stream.concat(cursor1.getDependingMaps().stream(), cursor2.getDependingMaps().stream()).map(AnyVersionedMap.class::cast).collect(Collectors.toUnmodifiableSet()); } - protected void resolveHashClashWithFirstEntry() { - int compareResult = this.hashProvider.compare(cursor1.key, cursor2.key); - if (compareResult < 0) { - this.hashClash = HashClash.STUCK_CURSOR_2; - this.cursorRelation = 0; - this.key = cursor1.key; - this.fromValue = cursor1.value; - this.toValue = defaultValue; - } else if (compareResult > 0) { - this.hashClash = HashClash.STUCK_CURSOR_1; - this.cursorRelation = 0; - this.key = cursor2.key; - this.fromValue = defaultValue; - this.toValue = cursor2.value; - } else { - throw new IllegalArgumentException("Inconsistent compare result for diffCursor"); - } + private boolean isInStableState() { + return this.state != State.MOVING_MOVING_SAME_KEY_SAME_VALUE + && this.state != State.MOVING_MOVING_SAME_NODE && this.state != State.INIT; } - protected boolean isInHashClash() { - return this.hashClash != HashClash.NONE; + private boolean updateAndReturnWithResult() { + return switch (this.state) { + case INIT -> throw new IllegalStateException("DiffCursor terminated without starting!"); + case MOVING_MOVING_SAME_KEY_SAME_VALUE, MOVING_MOVING_SAME_NODE -> + throw new IllegalStateException("DiffCursor terminated in unstable state!"); + case MOVING_MOVING_BEHIND1, MOVING_TERMINATED, MOVING_MOVING_HASH1 -> { + this.key = this.cursor1.getKey(); + this.fromValue = this.cursor1.getValue(); + this.toValue = this.defaultValue; + yield true; + } + case MOVING_MOVING_BEHIND2, TERMINATED_MOVING, MOVING_MOVING_HASH2 -> { + this.key = this.cursor2.getKey(); + this.fromValue = this.defaultValue; + this.toValue = cursor2.getValue(); + yield true; + } + case MOVING_MOVING_SAME_KEY_DIFFERENT_VALUE -> { + this.key = this.cursor1.getKey(); + this.fromValue = this.cursor1.getValue(); + this.toValue = this.cursor2.getValue(); + yield true; + } + case TERMINATED_TERMINATED -> { + this.key = null; + this.fromValue = null; + this.toValue = null; + yield false; + } + }; } - protected void resolveHashClashWithSecondEntry() { - switch (this.hashClash) { - case STUCK_CURSOR_1 -> { - this.hashClash = HashClash.NONE; - this.cursorRelation = 0; - this.key = cursor1.key; - this.fromValue = cursor1.value; - this.toValue = defaultValue; - } - case STUCK_CURSOR_2 -> { - this.hashClash = HashClash.NONE; - this.cursorRelation = 0; - this.key = cursor2.key; - this.fromValue = defaultValue; - this.toValue = cursor2.value; - } - default -> throw new IllegalArgumentException("Inconsistent compare result for diffCursor"); - } + public boolean move() { + do { + this.state = moveOne(this.state); + } while (!isInStableState()); + return updateAndReturnWithResult(); } - /** - * Checks if two states has the same values, i.e., there is no difference. - * @return whether two states has the same values - */ - protected boolean sameValues() { - if(cursor1.isTerminated() || cursor2.isTerminated()) return false; - else return Objects.equals(this.fromValue, this.toValue); + private State moveOne(State currentState) { + return switch (currentState) { + case INIT, MOVING_MOVING_HASH2, MOVING_MOVING_SAME_KEY_SAME_VALUE, MOVING_MOVING_SAME_KEY_DIFFERENT_VALUE -> { + boolean cursor1Moved = cursor1.move(); + boolean cursor2Moved = cursor2.move(); + yield recalculateStateAfterCursorMovement(cursor1Moved, cursor2Moved); + } + case MOVING_MOVING_SAME_NODE -> { + boolean cursor1Moved = cursor1.skipCurrentNode(); + boolean cursor2Moved = cursor2.skipCurrentNode(); + yield recalculateStateAfterCursorMovement(cursor1Moved, cursor2Moved); + } + case MOVING_MOVING_BEHIND1 -> { + boolean cursorMoved = cursor1.move(); + if (cursorMoved) { + yield recalculateStateBasedOnCursorRelation(); + } else { + yield State.TERMINATED_MOVING; + } + } + case MOVING_MOVING_BEHIND2 -> { + boolean cursorMoved = cursor2.move(); + if (cursorMoved) { + yield recalculateStateBasedOnCursorRelation(); + } else { + yield State.MOVING_TERMINATED; + } + } + case TERMINATED_MOVING -> { + boolean cursorMoved = cursor2.move(); + if (cursorMoved) { + yield State.TERMINATED_MOVING; + } else { + yield State.TERMINATED_TERMINATED; + } + } + case MOVING_TERMINATED -> { + boolean cursorMoved = cursor1.move(); + if (cursorMoved) { + yield State.MOVING_TERMINATED; + } else { + yield State.TERMINATED_TERMINATED; + } + } + case MOVING_MOVING_HASH1 -> State.MOVING_MOVING_HASH2; + case TERMINATED_TERMINATED -> throw new IllegalStateException("Trying to move while terminated!"); + }; } - protected boolean moveOne() { - if (isTerminated()) { - return false; - } - if (this.cursorRelation > 0 || cursor2.isTerminated()) { - return cursor1.move(); - } else if (this.cursorRelation < 0 || cursor1.isTerminated()) { - return cursor2.move(); + private State recalculateStateAfterCursorMovement(boolean cursor1Moved, boolean cursor2Moved) { + if (cursor1Moved && cursor2Moved) { + return recalculateStateBasedOnCursorRelation(); + } else if (cursor1Moved) { + return State.MOVING_TERMINATED; + } else if (cursor2Moved) { + return State.TERMINATED_MOVING; } else { - boolean moved1 = cursor1.move(); - boolean moved2 = cursor2.move(); - return moved1 && moved2; + return State.TERMINATED_TERMINATED; } } - private boolean skipNode() { - if (isTerminated()) { - throw new IllegalStateException("DiffCursor tries to skip when terminated!"); - } - boolean update1 = cursor1.skipCurrentNode(); - boolean update2 = cursor2.skipCurrentNode(); - updateState(); - return update1 && update2; - } + private State recalculateStateBasedOnCursorRelation() { + final int relation = InOrderMapCursor.comparePosition(cursor1, cursor2); - protected boolean moveToConsistentState() { - if (!isTerminated()) { - boolean changed; - boolean lastResult = true; - do { - changed = false; - if (MapCursor.sameSubNode(cursor1, cursor2)) { - lastResult = skipNode(); - changed = true; - } - if (sameValues()) { - lastResult = moveOne(); - changed = true; - } - updateState(); - } while (changed && !isTerminated()); - return lastResult; - } else { - return false; + if (relation > 0) { + return State.MOVING_MOVING_BEHIND1; + } else if (relation < 0) { + return State.MOVING_MOVING_BEHIND2; } - } - public boolean move() { - if (!isTerminated()) { - if (isInHashClash()) { - this.resolveHashClashWithSecondEntry(); - return true; + if (InOrderMapCursor.sameSubNode(cursor1, cursor2)) { + return State.MOVING_MOVING_SAME_NODE; + } else if (Objects.equals(cursor1.getKey(), cursor2.getKey())) { + if (Objects.equals(cursor1.getValue(), cursor2.getValue())) { + return State.MOVING_MOVING_SAME_KEY_SAME_VALUE; } else { - if (moveOne()) { - return moveToConsistentState(); - } else { - return false; - } + return State.MOVING_MOVING_SAME_KEY_DIFFERENT_VALUE; } + } + + final int depth = InOrderMapCursor.compareDepth(cursor1, cursor2); + + if (depth > 0) { + return State.MOVING_MOVING_BEHIND1; + } else if (depth < 0) { + return State.MOVING_MOVING_BEHIND2; + } else { + return State.MOVING_MOVING_HASH1; + } - } else - return false; } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java index cdc66a10..81bf6188 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java @@ -39,12 +39,12 @@ public class MutableNode extends Node { int dataUsed = 0; int nodeUsed = 0; for (int i = 0; i < FACTOR; i++) { - int bitposition = 1 << i; - if ((node.dataMap & bitposition) != 0) { + int bitPosition = 1 << i; + if ((node.dataMap & bitPosition) != 0) { content[2 * i] = node.content[dataUsed * 2]; content[2 * i + 1] = node.content[dataUsed * 2 + 1]; dataUsed++; - } else if ((node.nodeMap & bitposition) != 0) { + } else if ((node.nodeMap & bitPosition) != 0) { content[2 * i + 1] = node.content[node.content.length - 1 - nodeUsed]; nodeUsed++; } @@ -80,7 +80,7 @@ public class MutableNode extends Node { int selectedHashFragment = hashFragment(hash, shiftDepth(depth)); @SuppressWarnings("unchecked") K keyCandidate = (K) content[2 * selectedHashFragment]; if (keyCandidate != null) { - // If has key + // If it has key if (keyCandidate.equals(key)) { // The key is equals to an existing key -> update entry if (value == defaultValue) { @@ -101,24 +101,22 @@ public class MutableNode extends Node { return moveDownAndSplit(hashProvider, key, value, keyCandidate, hash, depth, selectedHashFragment); } } + } + // If it does not have key, check for value + @SuppressWarnings("unchecked") var nodeCandidate = (Node) content[2 * selectedHashFragment + 1]; + if (nodeCandidate != null) { + // If it has value, it is a sub-node -> update that + int newDepth = incrementDepth(depth); + var newNode = nodeCandidate.putValue(key, value, oldValueBox, hashProvider, defaultValue, newHash(hashProvider, key, hash, newDepth), newDepth); + return updateWithSubNode(selectedHashFragment, newNode, (value == null && defaultValue == null) || (value != null && value.equals(defaultValue))); } else { - // If it does not have key, check for value - @SuppressWarnings("unchecked") var nodeCandidate = (Node) content[2 * selectedHashFragment + 1]; - if (nodeCandidate != null) { - // If it has value, it is a subnode -> upate that - int newDepth = incrementDepth(depth); - var newNode = nodeCandidate.putValue(key, value, oldValueBox, hashProvider, defaultValue, newHash(hashProvider, key, hash, newDepth), newDepth); - return updateWithSubNode(selectedHashFragment, newNode, (value == null && defaultValue == null) || (value != null && value.equals(defaultValue))); + // If it does not have value, put it in the empty place + if (value == defaultValue) { + // don't need to add new key-value pair + oldValueBox.setOldValue(defaultValue); + return this; } else { - // If it does not have value, put it in the empty place - if (value == defaultValue) { - // dont need to add new key-value pair - oldValueBox.setOldValue(defaultValue); - return this; - } else { - return addEntry(key, value, oldValueBox, selectedHashFragment, defaultValue); - } - + return addEntry(key, value, oldValueBox, selectedHashFragment, defaultValue); } } } @@ -170,7 +168,7 @@ public class MutableNode extends Node { if (immutableNewNode != null) { int orphaned = immutableNewNode.isOrphaned(); if (orphaned >= 0) { - // orphan subnode data is replaced with data + // orphan sub-node data is replaced with data content[2 * selectedHashFragment] = immutableNewNode.content[orphaned * 2]; content[2 * selectedHashFragment + 1] = immutableNewNode.content[orphaned * 2 + 1]; invalidateHash(); @@ -227,11 +225,11 @@ public class MutableNode extends Node { // Pass everything as parameters for performance. @SuppressWarnings("squid:S107") - private MutableNode newNodeWithTwoEntries(ContinousHashProvider hashProvider, K key1, V value1, int oldHash1, K key2, V value2, int oldHash2, int newdepth) { - int newHash1 = newHash(hashProvider, key1, oldHash1, newdepth); - int newHash2 = newHash(hashProvider, key2, oldHash2, newdepth); - int newFragment1 = hashFragment(newHash1, shiftDepth(newdepth)); - int newFragment2 = hashFragment(newHash2, shiftDepth(newdepth)); + private MutableNode newNodeWithTwoEntries(ContinousHashProvider hashProvider, K key1, V value1, int oldHash1, K key2, V value2, int oldHash2, int newDepth) { + int newHash1 = newHash(hashProvider, key1, oldHash1, newDepth); + int newHash2 = newHash(hashProvider, key2, oldHash2, newDepth); + int newFragment1 = hashFragment(newHash1, shiftDepth(newDepth)); + int newFragment2 = hashFragment(newHash2, shiftDepth(newDepth)); MutableNode subNode = new MutableNode<>(); if (newFragment1 != newFragment2) { @@ -241,7 +239,7 @@ public class MutableNode extends Node { subNode.content[newFragment2 * 2] = key2; subNode.content[newFragment2 * 2 + 1] = value2; } else { - MutableNode subSubNode = newNodeWithTwoEntries(hashProvider, key1, value1, newHash1, key2, value2, newHash2, incrementDepth(newdepth)); + MutableNode subSubNode = newNodeWithTwoEntries(hashProvider, key1, value1, newHash1, key2, value2, newHash2, incrementDepth(newDepth)); subNode.content[newFragment1 * 2 + 1] = subSubNode; } subNode.invalidateHash(); @@ -305,13 +303,13 @@ public class MutableNode extends Node { cursor.dataIndex = MapCursor.INDEX_FINISH; } - // 2. look inside the subnodes + // 2. look inside the sub-nodes if(cursor.nodeIndexStack.peek()==null) { throw new IllegalStateException("Cursor moved to the next state when the state is empty."); } for (int index = cursor.nodeIndexStack.peek() + 1; index < FACTOR; index++) { if (this.content[index * 2] == null && this.content[index * 2 + 1] != null) { - // 2.1 found next subnode, move down to the subnode + // 2.1 found next sub-node, move down to the sub-node Node subnode = (Node) this.content[index * 2 + 1]; cursor.dataIndex = MapCursor.INDEX_START; @@ -323,7 +321,7 @@ public class MutableNode extends Node { return subnode.moveToNext(cursor); } } - // 3. no subnode found, move up + // 3. no sub-node found, move up cursor.nodeStack.pop(); cursor.nodeIndexStack.pop(); if (!cursor.nodeStack.isEmpty()) { @@ -336,6 +334,49 @@ public class MutableNode extends Node { } } + @Override + @SuppressWarnings("unchecked") + boolean moveToNextInorder(InOrderMapCursor cursor) { + if(cursor.nodeIndexStack.peek()==null || cursor.nodeStack.peek()==null) { + throw new IllegalStateException("Cursor moved to the next state when the state is empty."); + } + + int position = cursor.nodeIndexStack.peek(); + + for (int index = position + 1; index < FACTOR; index++) { + // data found + if (this.content[index * 2] != null) { + cursor.nodeIndexStack.pop(); + cursor.nodeIndexStack.push(index); + + cursor.key = (K) this.content[index * 2]; + cursor.value = (V) this.content[index * 2 + 1]; + return true; + } else if (this.content[index * 2 +1] != null) { + // sub-node found + Node subnode = (Node) this.content[index * 2 +1]; + cursor.nodeIndexStack.pop(); + cursor.nodeIndexStack.push(index); + cursor.nodeIndexStack.push(InOrderMapCursor.INDEX_START); + cursor.nodeStack.push(subnode); + + return subnode.moveToNextInorder(cursor); + } + } + + // nothing found + cursor.nodeStack.pop(); + cursor.nodeIndexStack.pop(); + if (!cursor.nodeStack.isEmpty()) { + Node supernode = cursor.nodeStack.peek(); + return supernode.moveToNextInorder(cursor); + } else { + cursor.key = null; + cursor.value = null; + return false; + } + } + @Override public void prettyPrint(StringBuilder builder, int depth, int code) { builder.append("\t".repeat(Math.max(0, depth))); @@ -361,7 +402,7 @@ public class MutableNode extends Node { } } builder.append(")"); - // print subnodes + // print sub-nodes for (int i = 0; i < FACTOR; i++) { if (content[2 * i] == null && content[2 * i + 1] != null) { @SuppressWarnings("unchecked") Node subNode = (Node) content[2 * i + 1]; @@ -397,7 +438,7 @@ public class MutableNode extends Node { } } } - // check subnodes + // check sub-nodes for (int i = 0; i < FACTOR; i++) { if (this.content[2 * i + 1] != null && this.content[2 * i] == null) { @SuppressWarnings("unchecked") var subNode = (Node) this.content[2 * i + 1]; @@ -421,13 +462,11 @@ public class MutableNode extends Node { @Override public int hashCode() { - if (this.cachedHashValid) { - return this.cachedHash; - } else { + if (!this.cachedHashValid) { this.cachedHash = Arrays.hashCode(content); this.cachedHashValid = true; - return this.cachedHash; } + return this.cachedHash; } @Override diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java index c49be280..3dd332da 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java @@ -108,10 +108,12 @@ public abstract class Node { * @return Whether there was a next value to move on. */ abstract boolean moveToNext(MapCursor cursor); + abstract boolean moveToNextInorder(InOrderMapCursor cursor); ///////// FOR printing public abstract void prettyPrint(StringBuilder builder, int depth, int code); + @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java index fb359431..2ceca463 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java @@ -75,7 +75,9 @@ public class VersionedMapImpl implements VersionedMap { Iterator keyIterator = keys.iterator(); Iterator valueIterator = values.iterator(); while (keyIterator.hasNext()) { - this.put(keyIterator.next(), valueIterator.next()); + var key = keyIterator.next(); + var value = valueIterator.next(); + this.put(key,value); } } else { while (cursor.move()) { @@ -109,12 +111,10 @@ public class VersionedMapImpl implements VersionedMap { @Override public DiffCursor getDiffCursor(long toVersion) { - - Cursor fromCursor = this.getAll(); - VersionedMap toMap = this.store.createMap(toVersion); - Cursor toCursor = toMap.getAll(); - return new MapDiffCursor<>(this.hashProvider, this.defaultValue, fromCursor, toCursor); - + InOrderMapCursor fromCursor = new InOrderMapCursor<>(this); + VersionedMapImpl toMap = (VersionedMapImpl) this.store.createMap(toVersion); + InOrderMapCursor toCursor = new InOrderMapCursor<>(toMap); + return new MapDiffCursor<>(this.defaultValue, fromCursor, toCursor); } @@ -152,7 +152,11 @@ public class VersionedMapImpl implements VersionedMap { @Override public int contentHashCode(ContentHashCode mode) { // Calculating the root hashCode is always fast, because {@link Node} caches its hashCode. - return Objects.hashCode(root); + if(root == null) { + return 0; + } else { + return root.hashCode(); + } } @Override diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java index 6d82f5d7..c850d334 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java @@ -4,11 +4,9 @@ import tools.refinery.store.map.Cursor; import tools.refinery.store.map.DiffCursor; import tools.refinery.store.map.VersionedMap; import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.internal.MapDiffCursor; import tools.refinery.store.model.Interpretation; import tools.refinery.store.model.InterpretationListener; import tools.refinery.store.model.Model; -import tools.refinery.store.model.TupleHashProvider; import tools.refinery.store.representation.AnySymbol; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; @@ -19,16 +17,13 @@ import java.util.List; public class VersionedInterpretation implements Interpretation { private final ModelImpl model; private final Symbol symbol; - private final VersionedMapStore store; private final VersionedMap map; private final List> listeners = new ArrayList<>(); private final List> restoreListeners = new ArrayList<>(); - private VersionedInterpretation(ModelImpl model, Symbol symbol, VersionedMapStore store, - VersionedMap map) { + private VersionedInterpretation(ModelImpl model, Symbol symbol, VersionedMap map) { this.model = model; this.symbol = symbol; - this.store = store; this.map = map; } @@ -111,9 +106,7 @@ public class VersionedInterpretation implements Interpretation { @Override public DiffCursor getDiffCursor(long to) { - var fromCursor = getAll(); - var toCursor = store.createMap(to).getAll(); - return new MapDiffCursor<>(TupleHashProvider.INSTANCE, symbol.defaultValue(), fromCursor, toCursor); + return map.getDiffCursor(to); } public long commit() { @@ -148,7 +141,7 @@ public class VersionedInterpretation implements Interpretation { @SuppressWarnings("unchecked") var typedSymbol = (Symbol) symbol; var map = store.createMap(); - return new VersionedInterpretation<>(model, typedSymbol, store, map); + return new VersionedInterpretation<>(model, typedSymbol, map); } static VersionedInterpretation of(ModelImpl model, AnySymbol symbol, VersionedMapStore store, @@ -156,6 +149,6 @@ public class VersionedInterpretation implements Interpretation { @SuppressWarnings("unchecked") var typedSymbol = (Symbol) symbol; var map = store.createMap(state); - return new VersionedInterpretation<>(model, typedSymbol, store, map); + return new VersionedInterpretation<>(model, typedSymbol, map); } } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java new file mode 100644 index 00000000..05cf5a74 --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java @@ -0,0 +1,49 @@ +package tools.refinery.store.map.tests; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.map.VersionedMapStoreBuilder; +import tools.refinery.store.map.internal.InOrderMapCursor; +import tools.refinery.store.map.internal.VersionedMapImpl; +import tools.refinery.store.map.tests.utils.MapTestEnvironment; + +import static org.junit.jupiter.api.Assertions.*; + +class InOrderCursorTest { + @Test + void testCursor() { + var store = VersionedMapStoreBuilder.builder() + .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) + .setStateBasedImmutableWhenCommitting(true) + .setHashProvider(MapTestEnvironment.prepareHashProvider(false)) + .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.SHARED_NODE_CACHE) + .setDefaultValue("x") + .buildOne(); + + VersionedMapImpl map = (VersionedMapImpl) store.createMap(); + checkMove(map,0); + + map.put(1,"A"); + map.commit(); + checkMove(map,1); + + + map.put(2,"B"); + map.commit(); + checkMove(map,2); + + map.put(3,"C"); + map.commit(); + checkMove(map,3); + + } + + private void checkMove(VersionedMapImpl map, int num) { + InOrderMapCursor cursor = new InOrderMapCursor<>(map); + for(int i=0; i builder) { + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, + int commitFrequency, boolean commitBeforeDiffCursor, + VersionedMapStoreBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); - iterativeRandomPutsAndCommitsThenDiffCursor(scenario, store, steps, maxKey, values, seed, commitFrequency); + iterativeRandomPutsAndCommitsThenDiffCursor(scenario, store, steps, maxKey, values, seed, commitFrequency, + commitBeforeDiffCursor); } private void iterativeRandomPutsAndCommitsThenDiffCursor(String scenario, VersionedMapStore store, - int steps, int maxKey, String[] values, int seed, int commitFrequency) { - // 1. build a map with versions - Random r = new Random(seed); - VersionedMap versioned = store.createMap(); + int steps, int maxKey, String[] values, int seed, + int commitFrequency, boolean commitBeforeDiffCursor) { + int largestCommit = -1; - for (int i = 0; i < steps; i++) { - int index = i + 1; - int nextKey = r.nextInt(maxKey); - String nextValue = values[r.nextInt(values.length)]; - try { - versioned.put(nextKey, nextValue); - } catch (Exception exception) { - exception.printStackTrace(); - fail(scenario + ":" + index + ": exception happened: " + exception); - } - if (index % commitFrequency == 0) { - long version = versioned.commit(); - largestCommit = (int) version; - } - if (index % 10000 == 0) - System.out.println(scenario + ":" + index + "/" + steps + " building finished"); - } - // 2. create a non-versioned map, - VersionedMap moving = store.createMap(); - Random r2 = new Random(seed + 1); - - final int diffTravelFrequency = commitFrequency * 2; - for (int i = 0; i < steps; i++) { - int index = i + 1; - if (index % diffTravelFrequency == 0) { - // diff-travel - long travelToVersion = r2.nextInt(largestCommit + 1); - DiffCursor diffCursor = moving.getDiffCursor(travelToVersion); - moving.putAll(diffCursor); - - } else { - // random puts - int nextKey = r2.nextInt(maxKey); - String nextValue = values[r2.nextInt(values.length)]; + { + // 1. build a map with versions + Random r = new Random(seed); + VersionedMap versioned = store.createMap(); + for (int i = 0; i < steps; i++) { + int index = i + 1; + int nextKey = r.nextInt(maxKey); + String nextValue = values[r.nextInt(values.length)]; try { - moving.put(nextKey, nextValue); + versioned.put(nextKey, nextValue); } catch (Exception exception) { exception.printStackTrace(); fail(scenario + ":" + index + ": exception happened: " + exception); } if (index % commitFrequency == 0) { - versioned.commit(); + long version = versioned.commit(); + largestCommit = (int) version; } if (index % 10000 == 0) System.out.println(scenario + ":" + index + "/" + steps + " building finished"); } } + { + // 2. create a non-versioned map, + VersionedMap moving = store.createMap(); + Random r2 = new Random(seed + 1); + + final int diffTravelFrequency = commitFrequency * 2; + for (int i = 0; i < steps; i++) { + int index = i + 1; + if (index % diffTravelFrequency == 0) { + // diff-travel + long travelToVersion = r2.nextInt(largestCommit + 1); + + VersionedMap oracle = store.createMap(travelToVersion); + + if(commitBeforeDiffCursor) { + moving.commit(); + } + DiffCursor diffCursor = moving.getDiffCursor(travelToVersion); + moving.putAll(diffCursor); + moving.commit(); + + MapTestEnvironment.compareTwoMaps(scenario + ":c" + index, oracle, moving); + + moving.restore(travelToVersion); + + } else { + // random puts + int nextKey = r2.nextInt(maxKey); + String nextValue = values[r2.nextInt(values.length)]; + try { + moving.put(nextKey, nextValue); + } catch (Exception exception) { + exception.printStackTrace(); + fail(scenario + ":" + index + ": exception happened: " + exception); + } + if (index % 10000 == 0) + System.out.println(scenario + ":" + index + "/" + steps + " building finished"); + } + } + } } public static final String title = "DiffCursor {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + - "commit frequency={5} seed={6} config={7}"; + "commit frequency={5} seed={6} commit before diff={7} config={8}"; @ParameterizedTest(name = title) @MethodSource @Timeout(value = 10) @Tag("fuzz") - void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, VersionedMapStoreBuilder builder) { - runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, - noKeys, noValues, nullDefault, commitFrequency, builder); + void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, + int commitFrequency, int seed, boolean commitBeforeDiffCursor, + VersionedMapStoreBuilder builder) { + runFuzzTest("DiffCursorS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, + noKeys, noValues, nullDefault, commitFrequency, commitBeforeDiffCursor, builder); } static Stream parametrizedFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{100}, keyCounts, valueCounts, nullDefaultOptions, - commitFrequencyOptions, randomSeedOptions, storeConfigs); + return FuzzTestUtils.permutationWithSize(new Object[]{500}, keyCounts, valueCounts, nullDefaultOptions, + commitFrequencyOptions, randomSeedOptions, new Object[]{false,true}, storeConfigs); } @ParameterizedTest(name = title) @@ -104,9 +124,9 @@ class DiffCursorFuzzTest { @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, VersionedMapStoreBuilder builder) { - runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, - nullDefault, commitFrequency, builder); + int seed, boolean commitBeforeDiffCursor, VersionedMapStoreBuilder builder) { + runFuzzTest("DiffCursorS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, + nullDefault, commitFrequency, commitBeforeDiffCursor, builder); } static Stream parametrizedSlowFuzz() { diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java index fb6b28d8..b344d9b9 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java @@ -5,23 +5,25 @@ import tools.refinery.store.map.tests.utils.MapTestEnvironment; public final class FuzzTestCollections { public static final Object[] stepCounts = {FuzzTestUtils.FAST_STEP_COUNT}; - public static final Object[] keyCounts = {1, 32, 32 * 32}; + public static final Object[] keyCounts = {1 , 32, 32 * 32}; public static final Object[] valueCounts = {2, 3}; public static final Object[] nullDefaultOptions = {false, true}; - public static final Object[] commitFrequencyOptions = {10, 10, 100}; - public static final Object[] randomSeedOptions = {1/*, 2, 3*/}; + public static final Object[] commitFrequencyOptions = {1, 10, 100}; + public static final Object[] randomSeedOptions = {1}; public static final Object[] storeConfigs = { // State based VersionedMapStoreBuilder.builder() .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) .setStateBasedImmutableWhenCommitting(true) .setHashProvider(MapTestEnvironment.prepareHashProvider(false)) - .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.SHARED_NODE_CACHE), + .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy + .SHARED_NODE_CACHE), VersionedMapStoreBuilder.builder() .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) .setStateBasedImmutableWhenCommitting(true) .setHashProvider(MapTestEnvironment.prepareHashProvider(true)) - .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.SHARED_NODE_CACHE), + .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy + .SHARED_NODE_CACHE), VersionedMapStoreBuilder.builder() .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) .setStateBasedImmutableWhenCommitting(false) diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java index 69ae811e..0e695aaa 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java @@ -57,13 +57,15 @@ public class MapTestEnvironment { VersionedMap map2, List errors) { map1.checkIntegrity(); map2.checkIntegrity(); + + assertContentEqualsList(map1, map2, title + ": map1.contentEquals(map2)", errors); + assertContentEqualsList(map2, map1, title + ": map2.contentEquals(map1)", errors); assertEqualsList(map1.getSize(), map2.getSize(), title + ": Sizes not equal", errors); + for (var mode : ContentHashCode.values()) { assertEqualsList(map1.contentHashCode(mode), map2.contentHashCode(mode), title + ": " + mode + " hashCode check", errors); } - assertContentEqualsList(map1, map2, title + ": map1.contentEquals(map2)", errors); - assertContentEqualsList(map2, map1, title + ": map2.contentEquals(map1)", errors); } private static void assertEqualsList(Object o1, Object o2, String message, List errors) { @@ -177,7 +179,8 @@ public class MapTestEnvironment { K previous = null; Cursor cursor = versionedMap.getAll(); while (cursor.move()) { - System.out.println(cursor.getKey() + " " + ((VersionedMapImpl) versionedMap).getHashProvider().getHash(cursor.getKey(), 0)); + //System.out.println(cursor.getKey() + " " + ((VersionedMapImpl) versionedMap).getHashProvider() + // .getHash(cursor.getKey(), 0)); if (previous != null) { int comparisonResult = ((VersionedMapImpl) versionedMap).getHashProvider().compare(previous, cursor.getKey()); @@ -185,7 +188,6 @@ public class MapTestEnvironment { } previous = cursor.getKey(); } - System.out.println(); } public void printComparison() { -- cgit v1.2.3-70-g09d2 From a6dcff6293e960b420e26c57374a281467821556 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Fri, 21 Jul 2023 20:27:30 +0200 Subject: VersionedMapStoreFactoryBuilder.java is introduced, all tests are updated. VersionedMapStoreBuilder.java is removed. --- .../refinery/store/map/VersionedMapStore.java | 20 ++-- .../store/map/VersionedMapStoreBuilder.java | 130 -------------------- .../store/map/VersionedMapStoreFactory.java | 19 +++ .../store/map/VersionedMapStoreFactoryBuilder.java | 24 ++++ .../DeltaBasedVersionedMapStoreFactory.java | 34 ++++++ .../StateBasedVersionedMapStoreFactory.java | 33 ++++++ .../VersionedMapStoreFactoryBuilderImpl.java | 132 +++++++++++++++++++++ .../store/map/tests/InOrderCursorTest.java | 18 +-- .../refinery/store/map/tests/MapUnitTests.java | 9 +- .../store/map/tests/fuzz/CommitFuzzTest.java | 21 ++-- .../map/tests/fuzz/ContentEqualsFuzzTest.java | 20 ++-- .../store/map/tests/fuzz/DiffCursorFuzzTest.java | 10 +- .../store/map/tests/fuzz/MultiThreadFuzzTest.java | 29 +++-- .../store/map/tests/fuzz/MutableFuzzTest.java | 8 +- .../store/map/tests/fuzz/RestoreFuzzTest.java | 30 ++--- .../store/map/tests/fuzz/SingleThreadFuzzTest.java | 10 +- .../map/tests/fuzz/utils/FuzzTestCollections.java | 52 ++++---- 17 files changed, 357 insertions(+), 242 deletions(-) delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactory.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaBasedVersionedMapStoreFactory.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/StateBasedVersionedMapStoreFactory.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java index a8d7fb1a..7768287a 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java @@ -1,14 +1,20 @@ package tools.refinery.store.map; +import tools.refinery.store.map.internal.VersionedMapStoreFactoryBuilderImpl; + import java.util.Set; public interface VersionedMapStore { - - public VersionedMap createMap(); - public VersionedMap createMap(long state); - - public Set getStates(); + VersionedMap createMap(); + + VersionedMap createMap(long state); + + Set getStates(); + + DiffCursor getDiffCursor(long fromState, long toState); - public DiffCursor getDiffCursor(long fromState, long toState); -} \ No newline at end of file + static VersionedMapStoreFactoryBuilder builder() { + return new VersionedMapStoreFactoryBuilderImpl<>(); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java deleted file mode 100644 index 1a9aa0b3..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreBuilder.java +++ /dev/null @@ -1,130 +0,0 @@ -package tools.refinery.store.map; - -import java.util.ArrayList; -import java.util.List; - -public class VersionedMapStoreBuilder { - public enum StoreStrategy { - STATE, DELTA - } - - public enum DeltaStorageStrategy { - LIST, SET - } - - public enum StateStorageStrategy { - NO_NODE_CACHE, SHARED_NODE_CACHE, SHARED_NODE_CACHE_IN_GROUP - } - - public static VersionedMapStoreBuilder builder() { - return new VersionedMapStoreBuilder<>(); - } - protected VersionedMapStoreBuilder() { - } - protected VersionedMapStoreBuilder(VersionedMapStoreBuilder other) { - this.defaultValue = other.defaultValue; - this.defaultSet = other.defaultSet; - this.strategy = other.strategy; - this.stateBasedImmutableWhenCommitting = other.stateBasedImmutableWhenCommitting; - this.stateBasedNodeSharingStrategy = other.stateBasedNodeSharingStrategy; - this.hashProvider = other.hashProvider; - this.deltaStorageStrategy = other.deltaStorageStrategy; - } - protected boolean defaultSet = false; - protected V defaultValue = null; - protected StoreStrategy strategy = StoreStrategy.DELTA; - protected Boolean stateBasedImmutableWhenCommitting = false; - protected StateStorageStrategy stateBasedNodeSharingStrategy = StateStorageStrategy.SHARED_NODE_CACHE_IN_GROUP; - protected ContinousHashProvider hashProvider = null; - protected DeltaStorageStrategy deltaStorageStrategy = DeltaStorageStrategy.LIST; - - public VersionedMapStoreBuilder setDefaultValue(V defaultValue) { - var result = new VersionedMapStoreBuilder<>(this); - result.defaultValue = defaultValue; - result.defaultSet = true; - return result; - } - - public VersionedMapStoreBuilder setStrategy(StoreStrategy strategy) { - var result = new VersionedMapStoreBuilder<>(this); - result.strategy = strategy; - return result; - } - - public VersionedMapStoreBuilder setHashProvider(ContinousHashProvider hashProvider) { - var result = new VersionedMapStoreBuilder<>(this); - result.hashProvider = hashProvider; - return result; - } - - public VersionedMapStoreBuilder setStateBasedImmutableWhenCommitting(boolean toImmutableWhenCommitting) { - var result = new VersionedMapStoreBuilder<>(this); - result.stateBasedImmutableWhenCommitting = toImmutableWhenCommitting; - return result; - } - - public VersionedMapStoreBuilder setStateBasedNodeSharingStrategy(StateStorageStrategy strategy) { - var result = new VersionedMapStoreBuilder<>(this); - result.stateBasedNodeSharingStrategy = strategy; - return result; - } - - public VersionedMapStoreBuilder setDeltaStorageStrategy(DeltaStorageStrategy deltaStorageStrategy) { - var result = new VersionedMapStoreBuilder<>(this); - result.deltaStorageStrategy = deltaStorageStrategy; - return result; - } - - public VersionedMapStore buildOne() { - if(!defaultSet) { - throw new IllegalStateException("Default value is missing!"); - } - return switch (strategy) { - case DELTA -> new VersionedMapStoreDeltaImpl<>( - this.deltaStorageStrategy == DeltaStorageStrategy.SET, - this.defaultValue); - case STATE -> new VersionedMapStoreImpl<>( - this.hashProvider, - this.defaultValue, - new VersionedMapStoreConfiguration( - this.stateBasedImmutableWhenCommitting, - this.stateBasedNodeSharingStrategy != StateStorageStrategy.NO_NODE_CACHE, - this.stateBasedNodeSharingStrategy == StateStorageStrategy.SHARED_NODE_CACHE_IN_GROUP)); - }; - } - - public List> buildGroup(int amount) { - if(!defaultSet) { - throw new IllegalStateException("Default value is missing!"); - } - if (this.strategy == StoreStrategy.STATE && - this.stateBasedNodeSharingStrategy == StateStorageStrategy.SHARED_NODE_CACHE_IN_GROUP) { - return VersionedMapStoreImpl.createSharedVersionedMapStores( - amount, - this.hashProvider, - this.defaultValue, - new VersionedMapStoreConfiguration( - this.stateBasedImmutableWhenCommitting, - true, - true)); - } else { - List> result = new ArrayList<>(amount); - for (int i = 0; i < amount; i++) { - result.add(buildOne()); - } - return result; - } - } - - @Override - public String toString() { - return "VersionedMapStoreBuilder{" + - "defaultValue=" + defaultValue + - ", strategy=" + strategy + - ", stateBasedImmutableWhenCommitting=" + stateBasedImmutableWhenCommitting + - ", stateBasedNodeSharingStrategy=" + stateBasedNodeSharingStrategy + - ", hashProvider=" + hashProvider + - ", deltaStorageStrategy=" + deltaStorageStrategy + - '}'; - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactory.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactory.java new file mode 100644 index 00000000..5f882a3a --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactory.java @@ -0,0 +1,19 @@ +package tools.refinery.store.map; + +import java.util.List; + +public interface VersionedMapStoreFactory { + /** + * Constructs a new instance of {@link VersionedMap}. + * @return The new instance. + */ + VersionedMapStore createOne(); + + /** + * Constructs a group of {@link VersionedMap}s with the same configuration. If possible, the stores share + * resources with each other. + * @param amount The amount of new instances to be created. + * @return A list of new stores with the given number of elements. + */ + List> createGroup(int amount); +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java new file mode 100644 index 00000000..9cf17b49 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java @@ -0,0 +1,24 @@ +package tools.refinery.store.map; + +public interface VersionedMapStoreFactoryBuilder { + enum StoreStrategy { + STATE, DELTA + } + + enum DeltaTransactionStrategy { + LIST, SET + } + + enum SharingStrategy { + NO_NODE_CACHE, SHARED_NODE_CACHE, SHARED_NODE_CACHE_IN_GROUP + } + + VersionedMapStoreFactoryBuilder defaultValue(V defaultValue); + VersionedMapStoreFactoryBuilder strategy(StoreStrategy strategy); + VersionedMapStoreFactoryBuilder stateBasedImmutableWhenCommitting(boolean transformToImmutable); + VersionedMapStoreFactoryBuilder stateBasedSharingStrategy(SharingStrategy sharingStrategy); + VersionedMapStoreFactoryBuilder stateBasedHashProvider(ContinousHashProvider hashProvider); + VersionedMapStoreFactoryBuilder deltaTransactionStrategy(DeltaTransactionStrategy deltaStrategy); + + VersionedMapStoreFactory build(); +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaBasedVersionedMapStoreFactory.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaBasedVersionedMapStoreFactory.java new file mode 100644 index 00000000..29ec0da1 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaBasedVersionedMapStoreFactory.java @@ -0,0 +1,34 @@ +package tools.refinery.store.map.internal; + +import tools.refinery.store.map.VersionedMapStore; +import tools.refinery.store.map.VersionedMapStoreDeltaImpl; +import tools.refinery.store.map.VersionedMapStoreFactory; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; + +import java.util.ArrayList; +import java.util.List; + +public class DeltaBasedVersionedMapStoreFactory implements VersionedMapStoreFactory { + private final V defaultValue; + private final boolean summarizeChanges; + + public DeltaBasedVersionedMapStoreFactory(V defaultValue, + VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy deltaTransactionStrategy) { + this.defaultValue = defaultValue; + this.summarizeChanges = deltaTransactionStrategy == VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.SET; + } + + @Override + public VersionedMapStore createOne() { + return new VersionedMapStoreDeltaImpl<>(summarizeChanges, defaultValue); + } + + @Override + public List> createGroup(int amount) { + List> result = new ArrayList<>(amount); + for(int i=0; i(summarizeChanges,defaultValue)); + } + return result; + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/StateBasedVersionedMapStoreFactory.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/StateBasedVersionedMapStoreFactory.java new file mode 100644 index 00000000..80dc347f --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/StateBasedVersionedMapStoreFactory.java @@ -0,0 +1,33 @@ +package tools.refinery.store.map.internal; + +import tools.refinery.store.map.*; + +import java.util.List; + +public class StateBasedVersionedMapStoreFactory implements VersionedMapStoreFactory { + private final V defaultValue; + private final ContinousHashProvider continousHashProvider; + private final VersionedMapStoreConfiguration config; + + public StateBasedVersionedMapStoreFactory(V defaultValue, Boolean transformToImmutable, VersionedMapStoreFactoryBuilder.SharingStrategy sharingStrategy, ContinousHashProvider continousHashProvider) { + this.defaultValue = defaultValue; + this.continousHashProvider = continousHashProvider; + + this.config = new VersionedMapStoreConfiguration( + transformToImmutable, + sharingStrategy == VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE || sharingStrategy == VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE_IN_GROUP, + sharingStrategy == VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE_IN_GROUP); + } + + @Override + public VersionedMapStore createOne() { + return new VersionedMapStoreImpl<>(continousHashProvider, defaultValue, config); + + } + + @Override + public List> createGroup(int amount) { + return VersionedMapStoreImpl.createSharedVersionedMapStores(amount, continousHashProvider, defaultValue, + config); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java new file mode 100644 index 00000000..3719eef5 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java @@ -0,0 +1,132 @@ +package tools.refinery.store.map.internal; + +import tools.refinery.store.map.ContinousHashProvider; +import tools.refinery.store.map.VersionedMapStoreFactory; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; + +public class VersionedMapStoreFactoryBuilderImpl implements VersionedMapStoreFactoryBuilder { + + private boolean defaultSet = false; + private V defaultValue; + private StoreStrategy strategy = null; + private Boolean transformToImmutable = null; + private SharingStrategy sharingStrategy = null; + private ContinousHashProvider continousHashProvider = null; + private DeltaTransactionStrategy deltaTransactionStrategy = null; + + private StoreStrategy checkStrategy() { + StoreStrategy currentStrategy = strategy; + currentStrategy = mergeStrategies(currentStrategy, transformToImmutable, StoreStrategy.STATE); + currentStrategy = mergeStrategies(currentStrategy, sharingStrategy, StoreStrategy.STATE); + currentStrategy = mergeStrategies(currentStrategy, continousHashProvider, StoreStrategy.STATE); + currentStrategy = mergeStrategies(currentStrategy, deltaTransactionStrategy, StoreStrategy.DELTA); + return currentStrategy; + } + + private StoreStrategy mergeStrategies(StoreStrategy old, StoreStrategy newStrategy) { + if (old != null && newStrategy != null && old != newStrategy) { + throw new IllegalArgumentException("Mixed strategy parametrization in VersionedMap builder!"); + } + + if (old != null) { + return old; + } else { + return newStrategy; + } + } + + private StoreStrategy mergeStrategies(StoreStrategy old, Object parameter, StoreStrategy newStrategy) { + if (parameter != null) { + return mergeStrategies(old, newStrategy); + } else { + return old; + } + } + + @Override + public VersionedMapStoreFactoryBuilder defaultValue(V defaultValue) { + this.defaultSet = true; + this.defaultValue = defaultValue; + return this; + } + + @Override + public VersionedMapStoreFactoryBuilder strategy(StoreStrategy strategy) { + this.strategy = strategy; + checkStrategy(); + return this; + } + + @Override + public VersionedMapStoreFactoryBuilder stateBasedImmutableWhenCommitting(boolean transformToImmutable) { + this.transformToImmutable = transformToImmutable; + checkStrategy(); + return this; + } + + @Override + public VersionedMapStoreFactoryBuilder stateBasedSharingStrategy(SharingStrategy sharingStrategy) { + this.sharingStrategy = sharingStrategy; + checkStrategy(); + return this; + } + + @Override + public VersionedMapStoreFactoryBuilder stateBasedHashProvider(ContinousHashProvider hashProvider) { + this.continousHashProvider = hashProvider; + checkStrategy(); + return this; + } + + @Override + public VersionedMapStoreFactoryBuilder deltaTransactionStrategy(DeltaTransactionStrategy deltaTransactionStrategy) { + this.deltaTransactionStrategy = deltaTransactionStrategy; + checkStrategy(); + return this; + } + + private T getOrDefault(T value, T defaultValue) { + if(value != null) { + return value; + } else { + return defaultValue; + } + } + + @Override + public VersionedMapStoreFactory build() { + if (!defaultSet) { + throw new IllegalArgumentException("Default value is missing!"); + } + var strategyToUse = checkStrategy(); + if (strategyToUse == null) { + return new DeltaBasedVersionedMapStoreFactory<>(defaultValue, + getOrDefault(deltaTransactionStrategy, DeltaTransactionStrategy.LIST)); + } + return switch (strategyToUse) { + case STATE -> { + if(continousHashProvider == null) { + throw new IllegalArgumentException("Continuous hash provider is missing!"); + } + yield new StateBasedVersionedMapStoreFactory<>(defaultValue, + getOrDefault(transformToImmutable,true), + getOrDefault(sharingStrategy, SharingStrategy.SHARED_NODE_CACHE_IN_GROUP), + continousHashProvider); + } + case DELTA -> new DeltaBasedVersionedMapStoreFactory<>(defaultValue, + getOrDefault(deltaTransactionStrategy, DeltaTransactionStrategy.LIST)); + }; + } + + @Override + public String toString() { + return "VersionedMapStoreBuilder{" + + "defaultValue=" + defaultValue + + ", strategy=" + strategy + + ", stateBasedImmutableWhenCommitting=" + transformToImmutable + + ", stateBasedNodeSharingStrategy=" + sharingStrategy + + ", hashProvider=" + continousHashProvider + + ", deltaStorageStrategy=" + deltaTransactionStrategy + + '}'; + } +} diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java index 05cf5a74..993e5531 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java @@ -1,7 +1,8 @@ package tools.refinery.store.map.tests; import org.junit.jupiter.api.Test; -import tools.refinery.store.map.VersionedMapStoreBuilder; +import tools.refinery.store.map.VersionedMapStore; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; import tools.refinery.store.map.internal.InOrderMapCursor; import tools.refinery.store.map.internal.VersionedMapImpl; import tools.refinery.store.map.tests.utils.MapTestEnvironment; @@ -11,13 +12,14 @@ import static org.junit.jupiter.api.Assertions.*; class InOrderCursorTest { @Test void testCursor() { - var store = VersionedMapStoreBuilder.builder() - .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) - .setStateBasedImmutableWhenCommitting(true) - .setHashProvider(MapTestEnvironment.prepareHashProvider(false)) - .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.SHARED_NODE_CACHE) - .setDefaultValue("x") - .buildOne(); + var store = VersionedMapStore.builder() + .strategy(VersionedMapStoreFactoryBuilder.StoreStrategy.STATE) + .stateBasedImmutableWhenCommitting(true) + .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) + .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE) + .defaultValue("x") + .build() + .createOne(); VersionedMapImpl map = (VersionedMapImpl) store.createMap(); checkMove(map,0); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java index 2216db76..6889fd07 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java @@ -2,7 +2,6 @@ package tools.refinery.store.map.tests; import org.junit.jupiter.api.Test; import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreBuilder; import tools.refinery.store.map.VersionedMapStoreImpl; import tools.refinery.store.model.TupleHashProvider; import tools.refinery.store.tuple.Tuple; @@ -23,7 +22,7 @@ class MapUnitTests { @Test void deltaRestoreTest() { VersionedMapStore store = - VersionedMapStoreBuilder.builder().setDefaultValue("x").buildOne(); + VersionedMapStore.builder().defaultValue("x").build().createOne(); var map = store.createMap(); map.put(1,"val"); var version1 = map.commit(); @@ -36,7 +35,7 @@ class MapUnitTests { @Test void deltaRestoreTest2() { VersionedMapStore store = - VersionedMapStoreBuilder.builder().setDefaultValue("x").buildOne(); + VersionedMapStore.builder().defaultValue("x").build().createOne(); var map = store.createMap(); map.put(1,"x"); var version1 = map.commit(); @@ -48,7 +47,7 @@ class MapUnitTests { @Test void deltaRestoreTest3() { VersionedMapStore store = - VersionedMapStoreBuilder.builder().setDefaultValue("x").buildOne(); + VersionedMapStore.builder().defaultValue("x").build().createOne(); var map = store.createMap(); map.commit(); map.put(1,"1"); @@ -71,7 +70,7 @@ class MapUnitTests { @Test void deltaRestoreTest4() { VersionedMapStore store = - VersionedMapStoreBuilder.builder().setDefaultValue("x").buildOne(); + VersionedMapStore.builder().defaultValue("x").build().createOne(); var map = store.createMap(); map.commit(); map.put(1,"1"); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java index 14a9e2e0..7977f772 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java @@ -1,30 +1,29 @@ package tools.refinery.store.map.tests.fuzz; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.Random; -import java.util.stream.Stream; - import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; - import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreBuilder; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; +import java.util.Random; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.fail; import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; class CommitFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, - boolean nullDefault, int commitFrequency, VersionedMapStoreBuilder builder) { + boolean nullDefault, int commitFrequency, + VersionedMapStoreFactoryBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); + VersionedMapStore store = builder.defaultValue(values[0]).build().createOne(); var sut = store.createMap(); MapTestEnvironment e = new MapTestEnvironment<>(sut); @@ -61,7 +60,7 @@ class CommitFuzzTest { @Timeout(value = 10) @Tag("fuzz") void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, VersionedMapStoreBuilder builder) { + int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, builder); } @@ -76,7 +75,7 @@ class CommitFuzzTest { @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, VersionedMapStoreBuilder builder) { + int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, builder); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index b462ed40..99e76649 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java @@ -5,7 +5,10 @@ import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import tools.refinery.store.map.*; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.map.VersionedMap; +import tools.refinery.store.map.VersionedMapStore; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; @@ -16,12 +19,13 @@ import java.util.List; import java.util.Random; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.fail; import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; class ContentEqualsFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, - boolean nullDefault, int commitFrequency, VersionedMapStoreBuilder builder) { + boolean nullDefault, int commitFrequency, + VersionedMapStoreFactoryBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); @@ -30,10 +34,10 @@ class ContentEqualsFuzzTest { iterativeRandomPutsAndCommitsThenCompare(scenario, builder, steps, maxKey, values, r, commitFrequency); } - private void iterativeRandomPutsAndCommitsThenCompare(String scenario, VersionedMapStoreBuilder builder, + private void iterativeRandomPutsAndCommitsThenCompare(String scenario, VersionedMapStoreFactoryBuilder builder, int steps, int maxKey, String[] values, Random r, int commitFrequency) { - VersionedMapStore store1 = builder.setDefaultValue(values[0]).buildOne(); + VersionedMapStore store1 = builder.defaultValue(values[0]).build().createOne(); VersionedMap sut1 = store1.createMap(); // Fill one map @@ -63,7 +67,7 @@ class ContentEqualsFuzzTest { // Randomize the order of the content Collections.shuffle(content, r); - VersionedMapStore store2 = builder.setDefaultValue(values[0]).buildOne(); + VersionedMapStore store2 = builder.defaultValue(values[0]).build().createOne(); VersionedMap sut2 = store2.createMap(); int index2 = 1; for (SimpleEntry entry : content) { @@ -88,7 +92,7 @@ class ContentEqualsFuzzTest { @Timeout(value = 10) @Tag("fuzz") void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, VersionedMapStoreBuilder builder) { + int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, builder); } @@ -103,7 +107,7 @@ class ContentEqualsFuzzTest { @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency, - int seed, VersionedMapStoreBuilder builder) { + int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, builder); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java index b087906d..3a8852a9 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.params.provider.MethodSource; import tools.refinery.store.map.DiffCursor; import tools.refinery.store.map.VersionedMap; import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreBuilder; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; @@ -21,10 +21,10 @@ import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; class DiffCursorFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, boolean commitBeforeDiffCursor, - VersionedMapStoreBuilder builder) { + VersionedMapStoreFactoryBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); + VersionedMapStore store = builder.defaultValue(values[0]).build().createOne(); iterativeRandomPutsAndCommitsThenDiffCursor(scenario, store, steps, maxKey, values, seed, commitFrequency, commitBeforeDiffCursor); } @@ -109,7 +109,7 @@ class DiffCursorFuzzTest { @Tag("fuzz") void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, int seed, boolean commitBeforeDiffCursor, - VersionedMapStoreBuilder builder) { + VersionedMapStoreFactoryBuilder builder) { runFuzzTest("DiffCursorS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, commitBeforeDiffCursor, builder); } @@ -124,7 +124,7 @@ class DiffCursorFuzzTest { @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, boolean commitBeforeDiffCursor, VersionedMapStoreBuilder builder) { + int seed, boolean commitBeforeDiffCursor, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("DiffCursorS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, commitBeforeDiffCursor, builder); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java index ec2224b4..ea58e1b7 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java @@ -1,32 +1,31 @@ package tools.refinery.store.map.tests.fuzz; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; -import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Stream; - import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; - import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreBuilder; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; + class MultiThreadFuzzTest { public static final int noThreads = 10; - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreBuilder builder) { + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreFactoryBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); + VersionedMapStore store = builder.defaultValue(values[0]).build().createOne(); // initialize runnables MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads]; @@ -73,7 +72,7 @@ class MultiThreadFuzzTest { @Timeout(value = 10) @Tag("fuzz") void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, - int commitFrequency, int seed, VersionedMapStoreBuilder builder) { + int commitFrequency, int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("MultiThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency + "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, builder); } @@ -88,7 +87,7 @@ class MultiThreadFuzzTest { @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, - int commitFrequency, int seed, VersionedMapStoreBuilder builder) { + int commitFrequency, int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, builder); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java index bdf72ce4..61b17362 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java @@ -18,10 +18,10 @@ import tools.refinery.store.map.tests.utils.MapTestEnvironment; class MutableFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, - boolean nullDefault, VersionedMapStoreBuilder builder) { + boolean nullDefault, VersionedMapStoreFactoryBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); + VersionedMapStore store = builder.defaultValue(values[0]).build().createOne(); VersionedMap sut = store.createMap(); MapTestEnvironment e = new MapTestEnvironment<>(sut); @@ -56,7 +56,7 @@ class MutableFuzzTest { @Timeout(value = 10) @Tag("fuzz") void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int seed, - VersionedMapStoreBuilder builder) { + VersionedMapStoreFactoryBuilder builder) { runFuzzTest( "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, defaultNull, builder); @@ -72,7 +72,7 @@ class MutableFuzzTest { @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int seed, - VersionedMapStoreBuilder builder) { + VersionedMapStoreFactoryBuilder builder) { runFuzzTest( "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, builder); diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java index 568aaac9..1661cccb 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java @@ -1,31 +1,31 @@ package tools.refinery.store.map.tests.fuzz; -import static org.junit.jupiter.api.Assertions.fail; -import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; - -import java.util.HashMap; -import java.util.Map; -import java.util.Random; -import java.util.stream.Stream; - import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; - -import tools.refinery.store.map.*; -import tools.refinery.store.map.internal.VersionedMapImpl; +import tools.refinery.store.map.VersionedMap; +import tools.refinery.store.map.VersionedMapStore; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.fail; +import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; + class RestoreFuzzTest { private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, - VersionedMapStoreBuilder builder) { + VersionedMapStoreFactoryBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); + VersionedMapStore store = builder.defaultValue(values[0]).build().createOne(); iterativeRandomPutsAndCommitsThenRestore(scenario, store, steps, maxKey, values, seed, commitFrequency); } @@ -84,7 +84,7 @@ class RestoreFuzzTest { @Timeout(value = 10) @Tag("smoke") void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, VersionedMapStoreBuilder builder) { + int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, builder); } @@ -99,7 +99,7 @@ class RestoreFuzzTest { @Tag("smoke") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, - int seed, VersionedMapStoreBuilder builder) { + int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, builder); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java index e7d49227..0e1f9f9f 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import tools.refinery.store.map.VersionedMapStore; -import tools.refinery.store.map.VersionedMapStoreBuilder; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; import tools.refinery.store.map.tests.utils.MapTestEnvironment; @@ -15,10 +15,10 @@ import java.util.stream.Stream; import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; class SingleThreadFuzzTest { - private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreBuilder builder) { + private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreFactoryBuilder builder) { String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); - VersionedMapStore store = builder.setDefaultValue(values[0]).buildOne(); + VersionedMapStore store = builder.defaultValue(values[0]).build().createOne(); // initialize runnables MultiThreadTestRunnable runnable = new MultiThreadTestRunnable(scenario, store, steps, maxKey, values, seed, commitFrequency); @@ -35,7 +35,7 @@ class SingleThreadFuzzTest { @Timeout(value = 10) @Tag("fuzz") void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, - int commitFrequency, int seed, VersionedMapStoreBuilder builder) { + int commitFrequency, int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("SingleThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency + "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, builder); } @@ -50,7 +50,7 @@ class SingleThreadFuzzTest { @Tag("fuzz") @Tag("slow") void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, - int commitFrequency, int seed, VersionedMapStoreBuilder builder) { + int commitFrequency, int seed, VersionedMapStoreFactoryBuilder builder) { runFuzzTest("SingleThreadS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, nullDefault, commitFrequency, builder); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java index b344d9b9..94c9cba7 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java @@ -1,6 +1,7 @@ package tools.refinery.store.map.tests.fuzz.utils; -import tools.refinery.store.map.VersionedMapStoreBuilder; +import tools.refinery.store.map.VersionedMapStore; +import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; import tools.refinery.store.map.tests.utils.MapTestEnvironment; public final class FuzzTestCollections { @@ -12,34 +13,27 @@ public final class FuzzTestCollections { public static final Object[] randomSeedOptions = {1}; public static final Object[] storeConfigs = { // State based - VersionedMapStoreBuilder.builder() - .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) - .setStateBasedImmutableWhenCommitting(true) - .setHashProvider(MapTestEnvironment.prepareHashProvider(false)) - .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy - .SHARED_NODE_CACHE), - VersionedMapStoreBuilder.builder() - .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) - .setStateBasedImmutableWhenCommitting(true) - .setHashProvider(MapTestEnvironment.prepareHashProvider(true)) - .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy - .SHARED_NODE_CACHE), - VersionedMapStoreBuilder.builder() - .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) - .setStateBasedImmutableWhenCommitting(false) - .setHashProvider(MapTestEnvironment.prepareHashProvider(false)) - .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.SHARED_NODE_CACHE), - VersionedMapStoreBuilder.builder() - .setStrategy(VersionedMapStoreBuilder.StoreStrategy.STATE) - .setStateBasedImmutableWhenCommitting(false) - .setHashProvider(MapTestEnvironment.prepareHashProvider(false)) - .setStateBasedNodeSharingStrategy(VersionedMapStoreBuilder.StateStorageStrategy.NO_NODE_CACHE), + VersionedMapStore.builder() + .stateBasedImmutableWhenCommitting(true) + .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) + .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), + VersionedMapStore.builder() + .stateBasedImmutableWhenCommitting(true) + .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(true)) + .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), + VersionedMapStore.builder() + .stateBasedImmutableWhenCommitting(false) + .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) + .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), + VersionedMapStore.builder() + .stateBasedImmutableWhenCommitting(false) + .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) + .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.NO_NODE_CACHE), + // Delta based - VersionedMapStoreBuilder.builder() - .setStrategy(VersionedMapStoreBuilder.StoreStrategy.DELTA) - .setDeltaStorageStrategy(VersionedMapStoreBuilder.DeltaStorageStrategy.SET), - VersionedMapStoreBuilder.builder() - .setStrategy(VersionedMapStoreBuilder.StoreStrategy.DELTA) - .setDeltaStorageStrategy(VersionedMapStoreBuilder.DeltaStorageStrategy.LIST) + VersionedMapStore.builder() + .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.SET), + VersionedMapStore.builder() + .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.LIST) }; } -- cgit v1.2.3-70-g09d2 From 04860420ded195f9434477dab33309da61edc7e9 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Fri, 21 Jul 2023 21:14:18 +0200 Subject: Improved tuple hash calculation - by special handling of unary and binary relations - introducing murmur32Scramble --- .../refinery/store/model/TupleHashProvider.java | 125 +++++++++++++++------ 1 file changed, 91 insertions(+), 34 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java index 4bcf9ff4..1183b8f2 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java @@ -2,39 +2,43 @@ package tools.refinery.store.model; import tools.refinery.store.map.ContinousHashProvider; import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.Tuple1; +import tools.refinery.store.tuple.Tuple2; public class TupleHashProvider implements ContinousHashProvider { - protected static final int[] primes = new int[] { 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, - 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, - 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, - 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, - 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, - 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, - 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, - 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, - 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, - 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, - 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, - 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, - 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, - 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, - 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, - 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, - 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, - 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, - 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, - 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, - 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, - 2797, 2801, 2803, 2819, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, - 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, - 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, - 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, - 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, - 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911 }; - - public static final long LARGEST_PRIME_30_BITS = 1073741789; - - public static final int MAX_MODEL_SIZE = (int) LARGEST_PRIME_30_BITS; + protected static final int[] primes = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, + 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, + 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, + 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, + 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, + 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, + 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, + 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, + 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, + 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, + 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, + 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, + 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, + 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, + 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, + 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, + 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, + 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, + 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, + 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, + 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, + 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, + 3907, 3911 }; + + protected static final long LARGEST_PRIME_30_BITS_LONG = 1073741789; + protected static final int LARGEST_PRIME_30_BITS_INTEGER = 1073741789; + protected static final int LARGEST_BINARY_INDEX_1 = LARGEST_PRIME_30_BITS_INTEGER / 4; + public static final int MAX_MODEL_SIZE = LARGEST_PRIME_30_BITS_INTEGER; public static final TupleHashProvider INSTANCE = new TupleHashProvider(); @@ -47,15 +51,68 @@ public class TupleHashProvider implements ContinousHashProvider { @Override public int getHash(Tuple key, int index) { - if (index >= primes.length) { - throw new IllegalArgumentException("Not enough prime numbers to support index"); + if(key instanceof Tuple1 t1) { + return t1.value0(); + } else if(key instanceof Tuple2 t2){ + if(index == 0) { + return murmur3T2(t2.value0(), t2.value1()); + } else if(index == 1) { + return lagrangeT2I0Quick(t2); + } else if(index == 2) { + return lagrangeT2I1Quick(t2); + } else { + return lagrangeTXIX(key, index-1); + } + } else { + return lagrangeTXIX(key, index); } + + } + + private static int lagrangeT2I0Quick(Tuple2 t2) { + int result = 2 * t2.value0() + t2.value1(); + if (result > LARGEST_PRIME_30_BITS_INTEGER) { + return result % LARGEST_PRIME_30_BITS_INTEGER; + } else + return result; + } + private static int lagrangeT2I1Quick(Tuple2 t2) { + int value0 = t2.value0(); + int value1 = t2.value1(); + if(value0 < LARGEST_BINARY_INDEX_1 && value1 < LARGEST_BINARY_INDEX_1) { + return 3* value0 + value1; + } else { + return lagrangeTXIX(t2, 1); + } + } + + private static int lagrangeTXIX(Tuple key, int index) { long accumulator = 0; final int prime = primes[index]; for (int i = 0; i < key.getSize(); i++) { - accumulator = (prime * accumulator + key.get(i)) % MAX_MODEL_SIZE; + accumulator = (prime * accumulator + key.get(i)) % LARGEST_PRIME_30_BITS_LONG; } return (int) accumulator; } + + private static int murmur3T2(int v0, int v1) + { + int h = 0; + + h = murmur32Scramble(v0, h); + h = murmur32Scramble(v1, h); + + return h; + } + + private static int murmur32Scramble(int k, int h) { + k *= 0xcc9e2d51; + k = (k << 15) | (k >>> 17); + k *= 0x1b873593; + h ^= k; + h = (h << 13) | (h >>> 19); + h = h * 5 + 0xe6546b64; + return h; + } } -- cgit v1.2.3-70-g09d2 From 38c66c13d3003df1f901258b4ffc69b1fac980e8 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Fri, 21 Jul 2023 21:16:43 +0200 Subject: decreasing steps in fast fuzz tests --- .../java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java | 2 +- .../java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'subprojects/store') diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java index 3a8852a9..e02448cf 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java @@ -115,7 +115,7 @@ class DiffCursorFuzzTest { } static Stream parametrizedFuzz() { - return FuzzTestUtils.permutationWithSize(new Object[]{500}, keyCounts, valueCounts, nullDefaultOptions, + return FuzzTestUtils.permutationWithSize(new Object[]{100}, keyCounts, valueCounts, nullDefaultOptions, commitFrequencyOptions, randomSeedOptions, new Object[]{false,true}, storeConfigs); } diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java index 92208e48..89c01690 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java @@ -8,7 +8,7 @@ import java.util.stream.Stream; import org.junit.jupiter.params.provider.Arguments; public final class FuzzTestUtils { - public static final int FAST_STEP_COUNT = 500; + public static final int FAST_STEP_COUNT = 250; public static final int SLOW_STEP_COUNT = 32 * 32 * 32 * 32; private FuzzTestUtils() { -- cgit v1.2.3-70-g09d2 From 3455aeab401aeab4f01d8ef67a73b965b0a0dde0 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Mon, 24 Jul 2023 15:08:46 +0200 Subject: Added missing copyright headers. --- .../java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java | 5 +++++ .../main/java/tools/refinery/store/map/VersionedMapStoreFactory.java | 5 +++++ .../tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java | 5 +++++ .../store/map/internal/DeltaBasedVersionedMapStoreFactory.java | 5 +++++ .../main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java | 5 +++++ .../java/tools/refinery/store/map/internal/InOrderMapCursor.java | 5 +++++ .../java/tools/refinery/store/map/internal/IteratorAsCursor.java | 5 +++++ .../src/main/java/tools/refinery/store/map/internal/MapDelta.java | 5 +++++ .../main/java/tools/refinery/store/map/internal/MapTransaction.java | 5 +++++ .../store/map/internal/StateBasedVersionedMapStoreFactory.java | 5 +++++ .../refinery/store/map/internal/UncommittedDeltaArrayStore.java | 5 +++++ .../tools/refinery/store/map/internal/UncommittedDeltaMapStore.java | 5 +++++ .../tools/refinery/store/map/internal/UncommittedDeltaStore.java | 5 +++++ .../tools/refinery/store/map/internal/VersionedMapDeltaImpl.java | 5 +++++ .../store/map/internal/VersionedMapStoreFactoryBuilderImpl.java | 5 +++++ .../test/java/tools/refinery/store/map/tests/InOrderCursorTest.java | 5 +++++ .../tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java | 5 +++++ .../refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java | 5 +++++ 18 files changed, 90 insertions(+) (limited to 'subprojects/store') diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java index 31cdbf95..0c61bd09 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; import java.util.*; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactory.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactory.java index 5f882a3a..baf6ab50 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactory.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactory.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; import java.util.List; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java index 9cf17b49..6329a2f6 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; public interface VersionedMapStoreFactoryBuilder { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaBasedVersionedMapStoreFactory.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaBasedVersionedMapStoreFactory.java index 29ec0da1..fe490f46 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaBasedVersionedMapStoreFactory.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaBasedVersionedMapStoreFactory.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import tools.refinery.store.map.VersionedMapStore; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java index 8ddca8ec..cc9003e3 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import tools.refinery.store.map.AnyVersionedMap; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/InOrderMapCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/InOrderMapCursor.java index c559d9ad..cb3f366f 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/InOrderMapCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/InOrderMapCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import tools.refinery.store.map.AnyVersionedMap; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java index c1a0aec4..d1ab8bb1 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import java.util.*; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDelta.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDelta.java index 86e9fe62..2674236c 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDelta.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDelta.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; public record MapDelta(K key, V oldValue, V newValue) { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapTransaction.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapTransaction.java index 5996048e..d63522cd 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapTransaction.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapTransaction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import java.util.Arrays; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/StateBasedVersionedMapStoreFactory.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/StateBasedVersionedMapStoreFactory.java index 80dc347f..1c3ab27b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/StateBasedVersionedMapStoreFactory.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/StateBasedVersionedMapStoreFactory.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import tools.refinery.store.map.*; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaArrayStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaArrayStore.java index 3b3f94ae..ba59cfef 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaArrayStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaArrayStore.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import java.util.ArrayList; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java index 31423b1c..61a34351 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import java.util.*; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java index 7b017c8e..438b5561 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; public interface UncommittedDeltaStore { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java index d09e54ba..ae47feda 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import java.util.*; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java index 3719eef5..cf117d95 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import tools.refinery.store.map.ContinousHashProvider; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java index 993e5531..4ada4ea4 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests; import org.junit.jupiter.api.Test; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java index 0e1f9f9f..1337cf3a 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import org.junit.jupiter.api.Tag; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java index 94c9cba7..4c3ecb09 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz.utils; import tools.refinery.store.map.VersionedMapStore; -- cgit v1.2.3-70-g09d2