From: Robert Varga Date: Mon, 2 Jan 2017 22:25:14 +0000 (+0100) Subject: BUG-7464: Split TrieMap into read-only and read-write X-Git-Tag: release/carbon~126 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F51%2F49951%2F12;p=yangtools.git BUG-7464: Split TrieMap into read-only and read-write Having inter-twined mutable and immutable implementations is a maintenance and performance drag, because mutable version is checking for read-only on each mutation and also everytime it needs to CAS_ROOT. On the other hand, the immutable implementation does not need to care about RDCSS, as it never updates its root -- and can in fact have it non-volatile. Split the implementation into three classes, with TrieMap definining the API contract and holding common bits, MutableTrieMap encapsulating RDCSS and mutation bits and ImmutableTrieMap having simple guards against mutation. Change-Id: Icae923d6312901b37252af80b03b0a0912cacaec Signed-off-by: Robert Varga --- diff --git a/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/ImmutableTrieMap.java b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/ImmutableTrieMap.java new file mode 100644 index 0000000000..4ea607e5c0 --- /dev/null +++ b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/ImmutableTrieMap.java @@ -0,0 +1,130 @@ +/* + * (C) Copyright 2016 Pantheon Technologies, s.r.o. and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opendaylight.yangtools.triemap; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * An immutable TrieMap + * + * @author Robert Varga + * + * @param the type of keys maintained by this map + * @param the type of mapped values + */ +@Beta +public final class ImmutableTrieMap extends TrieMap { + private final INode root; + + ImmutableTrieMap(final INode root, final Equivalence equiv) { + super(equiv); + this.root = checkNotNull(root); + } + + @Override + public void clear() { + throw unsupported(); + } + + @Override + public V compute(final K key, final BiFunction remappingFunction) { + throw unsupported(); + } + + @Override + public V computeIfAbsent(final K key, final Function mappingFunction) { + throw unsupported(); + } + + @Override + public V computeIfPresent(final K key, final BiFunction remappingFunction) { + throw unsupported(); + } + + @Override + public V merge(final K key, final V value, final BiFunction remappingFunction) { + throw unsupported(); + } + + @Override + public V put(final K key, final V value) { + throw unsupported(); + } + + @Override + public void putAll(final Map m) { + throw unsupported(); + } + + @Override + public V putIfAbsent(final K key, final V value) { + throw unsupported(); + } + + @Override + public V remove(final Object key) { + throw unsupported(); + } + + @Override + public boolean remove(final Object key, final Object value) { + throw unsupported(); + } + + @Override + public boolean replace(final K key, final V oldValue, final V newValue) { + throw unsupported(); + } + + @Override + public V replace(final K key, final V value) { + throw unsupported(); + } + + @Override + public int size() { + return root.cachedSize(this); + } + + @Override + public final TrieMap mutableSnapshot() { + return new MutableTrieMap<>(equiv(), new INode<>(new Gen(), root.gcasRead(this))); + } + + @Override + public ImmutableTrieMap immutableSnapshot() { + return this; + } + + @Override + boolean isReadOnly() { + return true; + } + + @Override + INode RDCSS_READ_ROOT(final boolean abort) { + return root; + } + + private static UnsupportedOperationException unsupported() { + return new UnsupportedOperationException("Attempted to modify a read-only view"); + } +} diff --git a/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/MutableTrieMap.java b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/MutableTrieMap.java new file mode 100644 index 0000000000..95151cdbf6 --- /dev/null +++ b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/MutableTrieMap.java @@ -0,0 +1,253 @@ +/* + * (C) Copyright 2016 Pantheon Technologies, s.r.o. and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opendaylight.yangtools.triemap; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static org.opendaylight.yangtools.triemap.PresencePredicate.ABSENT; +import static org.opendaylight.yangtools.triemap.PresencePredicate.PRESENT; + +import com.google.common.annotations.Beta; +import com.google.common.base.Verify; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +/** + * A mutable TrieMap. + * + * @author Robert Varga + * + * @param the type of keys maintained by this map + * @param the type of mapped values + */ +@Beta +final class MutableTrieMap extends TrieMap { + @SuppressWarnings("rawtypes") + private static final AtomicReferenceFieldUpdater ROOT_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(MutableTrieMap.class, Object.class, "root"); + + private volatile Object root; + + MutableTrieMap(final Equivalence equiv) { + this(equiv, newRootNode()); + } + + MutableTrieMap(final Equivalence equiv, final INode root) { + super(equiv); + this.root = checkNotNull(root); + } + + @Override + public void clear() { + boolean success; + do { + final INode r = RDCSS_READ_ROOT(); + success = RDCSS_ROOT(r, r.gcasRead(this), newRootNode()); + } while (!success); + } + + @Override + public V put(final K key, final V value) { + final K k = checkNotNull(key); + return toNullable(insertifhc(k, computeHash(k), checkNotNull(value), null)); + } + + @Override + public V putIfAbsent(final K key, final V value) { + final K k = checkNotNull(key); + return toNullable(insertifhc(k, computeHash(k), checkNotNull(value), ABSENT)); + } + + @Override + public V remove(final Object key) { + @SuppressWarnings("unchecked") + final K k = (K) checkNotNull(key); + return toNullable(removehc(k, null, computeHash(k))); + } + + @Override + public boolean remove(final Object key, final Object value) { + @SuppressWarnings("unchecked") + final K k = (K) checkNotNull(key); + return removehc(k, checkNotNull(value), computeHash(k)).isPresent(); + } + + @Override + public boolean replace(final K key, final V oldValue, final V newValue) { + final K k = checkNotNull(key); + return insertifhc(k, computeHash(k), checkNotNull(newValue), checkNotNull(oldValue)).isPresent(); + } + + @Override + public V replace(final K key, final V value) { + final K k = checkNotNull(key); + return toNullable(insertifhc(k, computeHash(k), checkNotNull(value), PRESENT)); + } + + @Override + public int size() { + return immutableSnapshot().size(); + } + + @Override + public ImmutableTrieMap immutableSnapshot() { + while (true) { + final INode r = RDCSS_READ_ROOT(); + final MainNode expmain = r.gcasRead(this); + if (RDCSS_ROOT(r, expmain, r.copyToGen (new Gen(), this))) { + return new ImmutableTrieMap<>(r, equiv()); + } + + // Tail recursion: return readOnlySnapshot(); + } + } + + @Override + public MutableTrieMap mutableSnapshot() { + while (true) { + final INode r = RDCSS_READ_ROOT(); + final MainNode expmain = r.gcasRead(this); + if (RDCSS_ROOT(r, expmain, r.copyToGen(new Gen(), this))) { + return new MutableTrieMap<>(equiv(), r.copyToGen(new Gen(), this)); + } + + // Tail recursion: return snapshot(); + } + } + + @Override + boolean isReadOnly() { + return false; + } + + @Override + INode RDCSS_READ_ROOT(final boolean abort) { + final Object r = /* READ */ root; + if (r instanceof INode) { + return (INode) r; + } + + checkState(r instanceof RDCSS_Descriptor, "Unhandled root %s", r); + return RDCSS_Complete(abort); + } + + void add(final K key, final V value) { + final K k = checkNotNull(key); + inserthc(k, computeHash(k), checkNotNull(value)); + } + + private static INode newRootNode() { + final Gen gen = new Gen(); + return new INode<>(gen, new CNode<>(gen)); + } + + private void inserthc(final K k, final int hc, final V v) { + // TODO: this is called from serialization only, which means we should not be observing any races, + // hence we should not need to pass down the entire tree, just equality (I think). + final boolean success = RDCSS_READ_ROOT().rec_insert(k, v, hc, 0, null, this); + Verify.verify(success, "Concurrent modification during serialization of map %s", this); + } + + private Optional insertifhc(final K k, final int hc, final V v, final Object cond) { + Optional res; + do { + // Keep looping as long as we do not get a reply + res = RDCSS_READ_ROOT().rec_insertif(k, v, hc, cond, 0, null, this); + } while (res == null); + + return res; + } + + private Optional removehc(final K k, final Object cond, final int hc) { + Optional res; + do { + // Keep looping as long as we do not get a reply + res = RDCSS_READ_ROOT().rec_remove(k, cond, hc, 0, null, this); + } while (res == null); + + return res; + } + + private boolean CAS_ROOT(final Object ov, final Object nv) { + return ROOT_UPDATER.compareAndSet(this, ov, nv); + } + + private boolean RDCSS_ROOT(final INode ov, final MainNode expectedmain, final INode nv) { + final RDCSS_Descriptor desc = new RDCSS_Descriptor<> (ov, expectedmain, nv); + if (CAS_ROOT(ov, desc)) { + RDCSS_Complete(false); + return /* READ */desc.committed; + } + + return false; + } + + private INode RDCSS_Complete(final boolean abort) { + while (true) { + final Object r = /* READ */ root; + if (r instanceof INode) { + return (INode) r; + } + + checkState(r instanceof RDCSS_Descriptor, "Unhandled root %s", r); + @SuppressWarnings("unchecked") + final RDCSS_Descriptor desc = (RDCSS_Descriptor) r; + final INode ov = desc.old; + final MainNode exp = desc.expectedmain; + final INode nv = desc.nv; + + if (abort) { + if (CAS_ROOT(desc, ov)) { + return ov; + } + + // Tail recursion: return RDCSS_Complete(abort); + continue; + } + + final MainNode oldmain = ov.gcasRead(this); + if (oldmain == exp) { + if (CAS_ROOT(desc, nv)) { + desc.committed = true; + return nv; + } + + // Tail recursion: return RDCSS_Complete(abort); + continue; + } + + if (CAS_ROOT(desc, ov)) { + return ov; + } + + // Tail recursion: return RDCSS_Complete(abort); + } + } + + private static final class RDCSS_Descriptor { + final INode old; + final MainNode expectedmain; + final INode nv; + + volatile boolean committed = false; + + RDCSS_Descriptor (final INode old, final MainNode expectedmain, final INode nv) { + this.old = old; + this.expectedmain = expectedmain; + this.nv = nv; + } + } +} diff --git a/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/ExternalForm.java b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/SerializationProxy.java similarity index 74% rename from third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/ExternalForm.java rename to third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/SerializationProxy.java index dbf171ddfe..67a6b80374 100644 --- a/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/ExternalForm.java +++ b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/SerializationProxy.java @@ -15,7 +15,9 @@ */ package org.opendaylight.yangtools.triemap; -import com.google.common.base.Preconditions; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.common.base.Verify; import java.io.Externalizable; import java.io.IOException; @@ -30,20 +32,20 @@ import java.util.Map.Entry; * * @author Robert Varga */ -final class ExternalForm implements Externalizable { +final class SerializationProxy implements Externalizable { private static final long serialVersionUID = 1L; private TrieMap map; private boolean readOnly; - public ExternalForm() { + public SerializationProxy() { // For Externalizable } @SuppressWarnings({ "unchecked", "rawtypes" }) - ExternalForm(final TrieMap map) { - this.map = ((TrieMap)map).readOnlySnapshot(); - this.readOnly = map.isReadOnly(); + SerializationProxy(final ImmutableTrieMap map, final boolean readOnly) { + this.map = (TrieMap) checkNotNull(map); + this.readOnly = readOnly; } @Override @@ -61,18 +63,20 @@ final class ExternalForm implements Externalizable { public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { @SuppressWarnings("unchecked") final Equivalence equiv = (Equivalence) in.readObject(); - Preconditions.checkArgument(equiv != null); - map = new TrieMap<>(equiv); + checkArgument(equiv != null); + final MutableTrieMap tmp = new MutableTrieMap<>(equiv); final int size = in.readInt(); + checkArgument(size >= 0); + for (int i = 0; i < size; ++i) { - map.add(in.readObject(), in.readObject()); + tmp.add(in.readObject(), in.readObject()); } - readOnly = in.readBoolean(); + map = in.readBoolean() ? tmp.immutableSnapshot() : tmp; } private Object readResolve() throws ObjectStreamException { - return Verify.verifyNotNull(readOnly ? map.readOnlySnapshot() : map); + return Verify.verifyNotNull(map); } } diff --git a/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/TrieMap.java b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/TrieMap.java index e8818a4b1e..94347299a0 100644 --- a/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/TrieMap.java +++ b/third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/TrieMap.java @@ -18,11 +18,8 @@ package org.opendaylight.yangtools.triemap; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static org.opendaylight.yangtools.triemap.LookupResult.RESTART; -import static org.opendaylight.yangtools.triemap.PresencePredicate.ABSENT; -import static org.opendaylight.yangtools.triemap.PresencePredicate.PRESENT; -import com.google.common.base.Verify; -import com.google.common.collect.Iterators; +import com.google.common.annotations.Beta; import java.io.ObjectStreamException; import java.io.Serializable; import java.util.AbstractMap; @@ -34,21 +31,20 @@ import java.util.NoSuchElementException; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; /*** * This is a port of Scala's TrieMap class from the Scala Collections library. This implementation does not support * null keys nor null values. * - * @author Roman Levenstein <romixlev@gmail.com> + * @author Aleksandar Prokopec (original Scala implementation) + * @author Roman Levenstein (original Java 6 port) + * @author Robert Varga * * @param the type of keys maintained by this map * @param the type of mapped values */ -public final class TrieMap extends AbstractMap implements ConcurrentMap, Serializable { - @SuppressWarnings("rawtypes") - private static final AtomicReferenceFieldUpdater ROOT_UPDATER = - AtomicReferenceFieldUpdater.newUpdater(TrieMap.class, Object.class, "root"); +@Beta +public abstract class TrieMap extends AbstractMap implements ConcurrentMap, Serializable { private static final long serialVersionUID = 1L; /** @@ -56,174 +52,15 @@ public final class TrieMap extends AbstractMap implements Concurrent */ private final EntrySet entrySet = new EntrySet(); private final Equivalence equiv; - private final boolean readOnly; - - private volatile Object root; - - private TrieMap(final INode r, final Equivalence equiv, final boolean readOnly) { - this.root = r; - this.equiv = equiv; - this.readOnly = readOnly; - } TrieMap(final Equivalence equiv) { - this(newRootNode(), equiv, false); - } - - public TrieMap() { - this(Equivalence.equals()); - } - - /* internal methods */ - - final Equivalence equiv() { - return equiv; - } - - private static INode newRootNode() { - final Gen gen = new Gen(); - return new INode<>(gen, new CNode<>(gen)); - } - - private boolean CAS_ROOT(final Object ov, final Object nv) { - checkState(!readOnly, "Attempted to modify a read-only snapshot"); - return ROOT_UPDATER.compareAndSet(this, ov, nv); - } - - final INode readRoot() { - return RDCSS_READ_ROOT(false); - } - - // FIXME: abort = false by default - final INode readRoot(final boolean abort) { - return RDCSS_READ_ROOT(abort); - } - - private final INode RDCSS_READ_ROOT() { - return RDCSS_READ_ROOT(false); - } - - private final INode RDCSS_READ_ROOT(final boolean abort) { - final Object r = /* READ */ root; - if (r instanceof INode) { - return (INode) r; - } - - checkState(r instanceof RDCSS_Descriptor, "Unhandled root %s", r); - return RDCSS_Complete(abort); - } - - private INode RDCSS_Complete(final boolean abort) { - while (true) { - final Object r = /* READ */ root; - if (r instanceof INode) { - return (INode) r; - } - - checkState(r instanceof RDCSS_Descriptor, "Unhandled root %s", r); - @SuppressWarnings("unchecked") - final RDCSS_Descriptor desc = (RDCSS_Descriptor) r; - final INode ov = desc.old; - final MainNode exp = desc.expectedmain; - final INode nv = desc.nv; - - if (abort) { - if (CAS_ROOT(desc, ov)) { - return ov; - } - - // Tail recursion: return RDCSS_Complete(abort); - continue; - } - - final MainNode oldmain = ov.gcasRead(this); - if (oldmain == exp) { - if (CAS_ROOT(desc, nv)) { - desc.committed = true; - return nv; - } - - // Tail recursion: return RDCSS_Complete(abort); - continue; - } - - if (CAS_ROOT(desc, ov)) { - return ov; - } - - // Tail recursion: return RDCSS_Complete(abort); - } - } - - private boolean RDCSS_ROOT(final INode ov, final MainNode expectedmain, final INode nv) { - final RDCSS_Descriptor desc = new RDCSS_Descriptor<> (ov, expectedmain, nv); - if (CAS_ROOT(ov, desc)) { - RDCSS_Complete(false); - return /* READ */desc.committed; - } - - return false; - } - - private void inserthc(final K k, final int hc, final V v) { - // TODO: this is called from serialization only, which means we should not be observing any races, - // hence we should not need to pass down the entire tree, just equality (I think). - final boolean success = RDCSS_READ_ROOT().rec_insert(k, v, hc, 0, null, this); - Verify.verify(success, "Concurrent modification during serialization of map %s", this); - } - - void add(final K key, final V value) { - final K k = checkNotNull(key); - inserthc(k, computeHash(k), checkNotNull(value)); - } - - private Optional insertifhc(final K k, final int hc, final V v, final Object cond) { - Optional res; - do { - // Keep looping as long as we do not get a reply - res = RDCSS_READ_ROOT().rec_insertif(k, v, hc, cond, 0, null, this); - } while (res == null); - - return res; - } - - @SuppressWarnings("unchecked") - private V lookuphc(final K k, final int hc) { - Object res; - do { - // Keep looping as long as RESTART is being indicated - res = RDCSS_READ_ROOT().rec_lookup(k, hc, 0, null, this); - } while (res == RESTART); - - return (V) res; - } - - private Optional removehc(final K k, final Object cond, final int hc) { - Optional res; - do { - // Keep looping as long as we do not get a reply - res = RDCSS_READ_ROOT().rec_remove(k, cond, hc, 0, null, this); - } while (res == null); - - return res; - } - - /** - * Ensure this instance is read-write, throw UnsupportedOperationException - * otherwise. Used by Map-type methods for quick check. - */ - private void ensureReadWrite() { - if (readOnly) { - throw new UnsupportedOperationException("Attempted to modify a read-only view"); - } + this.equiv = equiv; } - boolean isReadOnly() { - return readOnly; + public static TrieMap create() { + return new MutableTrieMap<>(Equivalence.equals()); } - /* public methods */ - /** * Returns a snapshot of this TrieMap. This operation is lock-free and * linearizable. @@ -234,17 +71,7 @@ public final class TrieMap extends AbstractMap implements Concurrent * distributed across all the threads doing updates or accesses subsequent * to the snapshot creation. */ - public TrieMap snapshot() { - while (true) { - final INode r = RDCSS_READ_ROOT(); - final MainNode expmain = r.gcasRead(this); - if (RDCSS_ROOT(r, expmain, r.copyToGen(new Gen(), this))) { - return new TrieMap<> (r.copyToGen(new Gen(), this), equiv, readOnly); - } - - // Tail recursion: return snapshot(); - } - } + public abstract TrieMap mutableSnapshot(); /** * Returns a read-only snapshot of this TrieMap. This operation is lock-free @@ -259,97 +86,112 @@ public final class TrieMap extends AbstractMap implements Concurrent * * This method is used by other methods such as `size` and `iterator`. */ - public TrieMap readOnlySnapshot() { - // Is it a snapshot of a read-only snapshot? - if (readOnly) { - return this; - } - - while (true) { - final INode r = RDCSS_READ_ROOT(); - final MainNode expmain = r.gcasRead(this); - if (RDCSS_ROOT(r, expmain, r.copyToGen (new Gen(), this))) { - return new TrieMap<>(r, equiv, true); - } - - // Tail recursion: return readOnlySnapshot(); - } - } + public abstract ImmutableTrieMap immutableSnapshot(); @Override - public void clear() { - boolean success; - do { - final INode r = RDCSS_READ_ROOT(); - success = RDCSS_ROOT(r, r.gcasRead(this), newRootNode()); - } while (!success); + public final boolean containsKey(final Object key) { + return get(key) != null; } - int computeHash(final K k) { - return equiv.hash(k); + @Override + public final boolean containsValue(final Object value) { + return super.containsValue(checkNotNull(value)); } - boolean equal(final K k1, final K k2) { - return equiv.equivalent(k1, k2); + @Override + public final Set> entrySet() { + return entrySet; } @Override - public V get(final Object key) { + public final V get(final Object key) { @SuppressWarnings("unchecked") final K k = (K) checkNotNull(key); return lookuphc(k, computeHash(k)); } + @Override + public abstract void clear(); + + @Override + public abstract V put(K key, V value); + + @Override + public abstract V putIfAbsent(K key, V value); + + @Override + public abstract V remove(Object key); + + @Override + public abstract boolean remove(Object key, Object value); + + @Override + public abstract boolean replace(K key, V oldValue, V newValue); + + @Override + public abstract V replace(K key, V value); + + @Override + public abstract int size(); + + /* internal methods implemented by subclasses */ + + abstract boolean isReadOnly(); + + abstract INode RDCSS_READ_ROOT(boolean abort); + + /* internal methods provided for subclasses */ + @SuppressWarnings("null") - private static V toNullable(final Optional opt) { + static V toNullable(final Optional opt) { return opt.orElse(null); } - @Override - public V put(final K key, final V value) { - ensureReadWrite(); - final K k = checkNotNull(key); - return toNullable(insertifhc(k, computeHash(k), checkNotNull(value), null)); + final int computeHash(final K k) { + return equiv.hash(k); } - @Override - public V remove(final Object key) { - ensureReadWrite(); - @SuppressWarnings("unchecked") - final K k = (K) checkNotNull(key); - return toNullable(removehc(k, null, computeHash(k))); + final Object writeReplace() throws ObjectStreamException { + return new SerializationProxy(immutableSnapshot(), isReadOnly()); } - @Override - public V putIfAbsent(final K key, final V value) { - ensureReadWrite(); - final K k = checkNotNull(key); - return toNullable(insertifhc(k, computeHash(k), checkNotNull(value), ABSENT)); + /* package-protected utility methods */ + + final Equivalence equiv() { + return equiv; } - @Override - public boolean remove(final Object key, final Object v) { - ensureReadWrite(); - @SuppressWarnings("unchecked") - final K k = (K) checkNotNull(key); - return removehc(k, checkNotNull(v), computeHash(k)).isPresent(); + final INode readRoot() { + return RDCSS_READ_ROOT(false); } - @Override - public boolean replace(final K key, final V oldValue, final V newValue) { - ensureReadWrite(); - final K k = checkNotNull(key); - return insertifhc(k, computeHash(k), checkNotNull(newValue), checkNotNull(oldValue)).isPresent(); + // FIXME: abort = false by default + final INode readRoot(final boolean abort) { + return RDCSS_READ_ROOT(abort); } - @Override - public V replace(final K key, final V value) { - ensureReadWrite(); - final K k = checkNotNull(key); - return toNullable(insertifhc(k, computeHash(k), checkNotNull(value), PRESENT)); + final INode RDCSS_READ_ROOT() { + return RDCSS_READ_ROOT(false); } - /*** + final boolean equal(final K k1, final K k2) { + return equiv.equivalent(k1, k2); + } + + /* private implementation methods */ + + @SuppressWarnings("unchecked") + private V lookuphc(final K k, final int hc) { + Object res; + do { + // Keep looping as long as RESTART is being indicated + res = RDCSS_READ_ROOT().rec_lookup(k, hc, 0, null, this); + } while (res == RESTART); + + return (V) res; + } + + /** * Return an iterator over a TrieMap. * * If this is a read-only snapshot, it would return a read-only iterator. @@ -360,56 +202,21 @@ public final class TrieMap extends AbstractMap implements Concurrent * @return */ Iterator> iterator() { - return readOnly ? new TrieMapReadOnlyIterator<>(0, this) : new TrieMapIterator<>(0, this); + // FIXME: it would be nice to have a ReadWriteTrieMap with read-only iterator + return isReadOnly() ? new TrieMapReadOnlyIterator<>(0, this) : new TrieMapIterator<>(0, this); } - /*** + /** * Return an iterator over a TrieMap. * This is a read-only iterator. * * @return */ - Iterator> readOnlyIterator() { - return new TrieMapReadOnlyIterator<>(0, readOnly ? this : readOnlySnapshot()); - } - - private int cachedSize() { - return RDCSS_READ_ROOT().cachedSize (this); - } - - @Override - public int size() { - return readOnly ? cachedSize() : readOnlySnapshot().size(); - } - - @Override - public boolean containsKey(final Object key) { - return get(key) != null; - } - - @Override - public Set> entrySet() { - return entrySet; + final Iterator> readOnlyIterator() { + return new TrieMapReadOnlyIterator<>(0, immutableSnapshot()); } - private Object writeReplace() throws ObjectStreamException { - return new ExternalForm(this); - } - - private static final class RDCSS_Descriptor { - INode old; - MainNode expectedmain; - INode nv; - volatile boolean committed = false; - - RDCSS_Descriptor (final INode old, final MainNode expectedmain, final INode nv) { - this.old = old; - this.expectedmain = expectedmain; - this.nv = nv; - } - } - - /*** + /** * This iterator is a read-only one and does not allow for any update * operations on the underlying data structure. * @@ -690,7 +497,7 @@ public final class TrieMap extends AbstractMap implements Concurrent @Override public final int size () { - return Iterators.size(iterator()); + return TrieMap.this.size(); } @Override diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/SnapshotTest.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/SnapshotTest.java new file mode 100644 index 0000000000..bed17f245e --- /dev/null +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/SnapshotTest.java @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2017 Pantheon Technologies, s.r.o. and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opendaylight.yangtools.triemap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Map; +import org.junit.Before; +import org.junit.Test; + +public class SnapshotTest { + private TrieMap map; + + @Before + public void setUp() { + map = TrieMap.create(); + map.put("k1", "v1"); + map.put("k2", "v2"); + } + + private static void assertMutableIsolation(final Map m1, final Map m2) { + assertTrue(m2.containsKey("k1")); + assertTrue(m2.containsKey("k2")); + + m1.remove("k1"); + assertFalse(m1.containsKey("k1")); + assertTrue(m2.containsKey("k1")); + + m2.remove("k2"); + assertFalse(m1.containsKey("k1")); + assertTrue(m2.containsKey("k1")); + + assertEquals(1, m1.size()); + assertEquals(1, m2.size()); + } + + @Test + public void testMutableSnapshotIsolation() { + assertMutableIsolation(map, map.mutableSnapshot()); + } + + @Test + public void testMutableSnapshotIsolationAcrossImmutable() { + final TrieMap snap = map.immutableSnapshot(); + assertTrue(snap.containsKey("k1")); + assertTrue(snap.containsKey("k2")); + + assertMutableIsolation(map, snap.mutableSnapshot()); + + assertTrue(snap.containsKey("k1")); + assertTrue(snap.containsKey("k2")); + + } +} diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestCNodeFlagCollision.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestCNodeFlagCollision.java index 081a6f8f33..39233deb6a 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestCNodeFlagCollision.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestCNodeFlagCollision.java @@ -24,7 +24,7 @@ import org.junit.Test; public class TestCNodeFlagCollision { @Test public void testCNodeFlagCollision () { - final Map map = new TrieMap<>(); + final Map map = TrieMap.create(); final Integer z15169 = Integer.valueOf(15169); final Integer z28336 = Integer.valueOf(28336); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestCNodeInsertionIncorrectOrder.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestCNodeInsertionIncorrectOrder.java index 1ab4c4be27..078b4cba40 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestCNodeInsertionIncorrectOrder.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestCNodeInsertionIncorrectOrder.java @@ -24,7 +24,7 @@ public class TestCNodeInsertionIncorrectOrder { @Test public void testCNodeInsertionIncorrectOrder () { - final Map map = new TrieMap<>(); + final Map map = TrieMap.create(); final Integer z3884 = Integer.valueOf(3884); final Integer z4266 = Integer.valueOf(4266); map.put(z3884, z3884); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapPutIfAbsent.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapPutIfAbsent.java index 1eb6f2cacc..c8cbcb5c7b 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapPutIfAbsent.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapPutIfAbsent.java @@ -28,7 +28,7 @@ public class TestConcurrentMapPutIfAbsent { @Test public void testConcurrentMapPutIfAbsent () { - final ConcurrentMap map = new TrieMap<>(); + final ConcurrentMap map = TrieMap.create(); for (int i = 0; i < COUNT; i++) { assertNull(map.putIfAbsent (i, i)); @@ -46,7 +46,7 @@ public class TestConcurrentMapPutIfAbsent { final ZeroHashInt v2 = new ZeroHashInt(5); final ZeroHashInt v3 = new ZeroHashInt(6); - final Map map = new TrieMap<>(); + final Map map = TrieMap.create(); // Pre-populate an LNode assertNull(map.putIfAbsent(k1, v1)); assertNull(map.putIfAbsent(k2, v2)); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapRemove.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapRemove.java index a0143a649b..0c7d4248f5 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapRemove.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapRemove.java @@ -28,7 +28,7 @@ public class TestConcurrentMapRemove { @Test public void testConcurrentMapRemove () { - final ConcurrentMap map = new TrieMap<>(); + final ConcurrentMap map = TrieMap.create(); for (int i = 128; i < COUNT; i++) { assertFalse(map.remove(i, i)); @@ -52,7 +52,7 @@ public class TestConcurrentMapRemove { final ZeroHashInt v3 = new ZeroHashInt(6); final ZeroHashInt v3dup = new ZeroHashInt(6); - final Map map = new TrieMap<>(); + final Map map = TrieMap.create(); // Pre-populate an LNode assertNull(map.putIfAbsent(k1, v1)); assertNull(map.putIfAbsent(k2, v2)); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapReplace.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapReplace.java index 6f47372e19..6299ba063d 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapReplace.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestConcurrentMapReplace.java @@ -29,7 +29,7 @@ public class TestConcurrentMapReplace { @Test public void testConcurrentMapReplace () { - final ConcurrentMap map = new TrieMap<>(); + final ConcurrentMap map = TrieMap.create(); for (int i = 0; i < COUNT; i++) { assertNull(map.replace(i, "lol")); @@ -53,7 +53,7 @@ public class TestConcurrentMapReplace { final ZeroHashInt v3dup = new ZeroHashInt(6); final ZeroHashInt k4 = new ZeroHashInt(7); - final Map map = new TrieMap<>(); + final Map map = TrieMap.create(); assertNull(map.put(k3, v3)); // First check for SNode diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestDelete.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestDelete.java index 98e7e27fef..29454cdae2 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestDelete.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestDelete.java @@ -24,27 +24,27 @@ import org.junit.Test; public class TestDelete { @Test(expected = NullPointerException.class) public void testNullSimple() { - new TrieMap<>().remove(null); + TrieMap.create().remove(null); } @Test(expected = NullPointerException.class) public void testNullKey() { - new TrieMap<>().remove(null, ""); + TrieMap.create().remove(null, ""); } @Test(expected = NullPointerException.class) public void testNullValue() { - new TrieMap<>().remove("", null); + TrieMap.create().remove("", null); } @Test(expected = NullPointerException.class) public void testNullBoth() { - new TrieMap<>().remove(null, null); + TrieMap.create().remove(null, null); } @Test public void testClear() { - final TrieMap bt = new TrieMap<>(); + final TrieMap bt = TrieMap.create(); bt.put(1, 1); bt.clear(); assertTrue(bt.isEmpty()); @@ -53,7 +53,7 @@ public class TestDelete { @Test public void testDelete () { - final TrieMap bt = new TrieMap<> (); + final TrieMap bt = TrieMap.create(); for (int i = 0; i < 10000; i++) { assertNull(bt.put(Integer.valueOf(i), Integer.valueOf(i))); @@ -79,7 +79,7 @@ public class TestDelete { */ @Test public void testRemoveObjectLNode() { - final TrieMap bt = new TrieMap<> (); + final TrieMap bt = TrieMap.create(); for (int i = 0; i < 100; i++) { final ZeroHashInt v = new ZeroHashInt(i); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisions.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisions.java index 5ed9fd1bc6..f866673105 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisions.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisions.java @@ -24,7 +24,7 @@ import org.junit.Test; public class TestHashCollisions { @Test public void testHashCollisions () { - final TrieMap bt = new TrieMap<>(); + final TrieMap bt = TrieMap.create(); insertStrings(bt); insertChars(bt); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisionsRemove.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisionsRemove.java index 64abfe44ab..74ae1f9b79 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisionsRemove.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisionsRemove.java @@ -26,7 +26,7 @@ public class TestHashCollisionsRemove { @Test public void testHashCollisionsRemove() { - final Map bt = new TrieMap<>(); + final Map bt = TrieMap.create(); for (int j = 0; j < COUNT; j++) { for (final Object o : TestMultiThreadMapIterator.getObjects(j)) { diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisionsRemoveIterator.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisionsRemoveIterator.java index a58d3ba350..2b5f5f21d2 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisionsRemoveIterator.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestHashCollisionsRemoveIterator.java @@ -30,7 +30,7 @@ public class TestHashCollisionsRemoveIterator { @Test public void testHashCollisionsRemoveIterator () { - final Map bt = new TrieMap<>(); + final Map bt = TrieMap.create(); for (int j = 0; j < COUNT; j++) { bt.put(Integer.valueOf(j), Integer.valueOf(j)); } diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestInsert.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestInsert.java index bf3813b7f7..aefaf1d6ee 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestInsert.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestInsert.java @@ -23,7 +23,7 @@ import org.junit.Test; public class TestInsert { @Test public void testInsert () { - final TrieMap bt = new TrieMap<>(); + final TrieMap bt = TrieMap.create(); assertNull(bt.put("a", "a")); assertNull(bt.put("b", "b")); assertNull(bt.put("c", "b")); @@ -41,16 +41,16 @@ public class TestInsert { @Test(expected = NullPointerException.class) public void testNullKey() { - new TrieMap<>().put(null, ""); + TrieMap.create().put(null, ""); } @Test(expected = NullPointerException.class) public void testNullValue() { - new TrieMap<>().put("", null); + TrieMap.create().put("", null); } @Test(expected = NullPointerException.class) public void testNullBoth() { - new TrieMap<>().put(null, null); + TrieMap.create().put(null, null); } } diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestInstantiationSpeed.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestInstantiationSpeed.java index 9424d07224..52166037c7 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestInstantiationSpeed.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestInstantiationSpeed.java @@ -33,7 +33,7 @@ public class TestInstantiationSpeed { final Stopwatch watch = Stopwatch.createStarted(); for (int i = 0; i < COUNT; ++i) { - maps[i] = new TrieMap<>(); + maps[i] = TrieMap.create(); } watch.stop(); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMapIterator.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMapIterator.java index 7d8e549014..36fc3587b1 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMapIterator.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMapIterator.java @@ -36,7 +36,7 @@ public class TestMapIterator { final Random random = new Random(); for (int i = 0; i < 60 * 1000; i+= 400 + random.nextInt(400)) { - final Map bt = new TrieMap <>(); + final Map bt = TrieMap.create(); for (int j = 0; j < i; j++) { assertNull(bt.put(Integer.valueOf(j), Integer.valueOf(j))); } @@ -84,16 +84,16 @@ public class TestMapIterator { @Test(expected = NoSuchElementException.class) public void testEmptyIterator() { - failAdvance(new TrieMap<>().iterator()); + failAdvance(TrieMap.create().iterator()); } @Test(expected = NoSuchElementException.class) public void testEmptyReadOnlyIterator() { - failAdvance(new TrieMap<>().readOnlyIterator()); + failAdvance(TrieMap.create().readOnlyIterator()); } @Test(expected = NoSuchElementException.class) public void testEmptyReadOnlySnapshotIterator() { - failAdvance(new TrieMap<>().readOnlySnapshot().iterator()); + failAdvance( TrieMap.create().immutableSnapshot().iterator()); } } diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadAddDelete.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadAddDelete.java index c298aaf26b..71034c7a0c 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadAddDelete.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadAddDelete.java @@ -33,7 +33,7 @@ public class TestMultiThreadAddDelete { @Test public void testMultiThreadAddDelete () throws InterruptedException { for (int j = 0; j < RETRIES; j++) { - final Map bt = new TrieMap<>(); + final Map bt = TrieMap.create(); { final ExecutorService es = Executors.newFixedThreadPool(N_THREADS); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadInserts.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadInserts.java index b80a94921f..019240f69d 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadInserts.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadInserts.java @@ -27,7 +27,7 @@ public class TestMultiThreadInserts { public void testMultiThreadInserts () throws InterruptedException{ final int nThreads = 2; final ExecutorService es = Executors.newFixedThreadPool(nThreads); - final TrieMap bt = new TrieMap<>(); + final TrieMap bt = TrieMap.create(); for (int i = 0; i < nThreads; i++) { final int threadNo = i; es.execute (() -> { diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadMapIterator.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadMapIterator.java index 6bc635779e..e7f91fed54 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadMapIterator.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestMultiThreadMapIterator.java @@ -34,7 +34,7 @@ public class TestMultiThreadMapIterator { @Test public void testMultiThreadMapIterator () throws InterruptedException { - final Map bt = new TrieMap<>(); + final Map bt = TrieMap.create(); for (int j = 0; j < 50 * 1000; j++) { for (final Object o : getObjects(j)) { bt.put (o, o); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestReadOnlyAndUpdatableIterators.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestReadOnlyAndUpdatableIterators.java index b3f7bb12a1..15a658e21e 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestReadOnlyAndUpdatableIterators.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestReadOnlyAndUpdatableIterators.java @@ -36,7 +36,7 @@ public class TestReadOnlyAndUpdatableIterators { @Before public void setUp() { - bt = new TrieMap<>(); + bt = TrieMap.create(); for (int j = 0; j < MAP_SIZE; j++) { assertNull(bt.put(Integer.valueOf(j), Integer.valueOf(j))); } @@ -63,22 +63,22 @@ public class TestReadOnlyAndUpdatableIterators { @Test(expected = UnsupportedOperationException.class) public void testReadOnlySnapshotReadOnlyIteratorSet() { - trySet(bt.readOnlySnapshot().readOnlyIterator()); + trySet(bt.immutableSnapshot().readOnlyIterator()); } @Test(expected = UnsupportedOperationException.class) public void testReadOnlySnapshotReadOnlyIteratorRemove() { - tryRemove(bt.readOnlySnapshot().readOnlyIterator()); + tryRemove(bt.immutableSnapshot().readOnlyIterator()); } @Test(expected = UnsupportedOperationException.class) public void testReadOnlySnapshotIteratorSet() { - trySet(bt.readOnlySnapshot().iterator()); + trySet(bt.immutableSnapshot().iterator()); } @Test(expected = UnsupportedOperationException.class) public void testReadOnlySnapshotIteratorRemove() { - tryRemove(bt.readOnlySnapshot().iterator()); + tryRemove(bt.immutableSnapshot().iterator()); } @Test @@ -93,7 +93,7 @@ public class TestReadOnlyAndUpdatableIterators { @Test public void testSnapshotIterator () { - TrieMap snapshot = bt.snapshot(); + TrieMap snapshot = bt.mutableSnapshot(); Iterator> it = snapshot.iterator(); it.next().setValue(0); it.remove(); diff --git a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestSerialization.java b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestSerialization.java index ed7a11eab7..0af3568abe 100644 --- a/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestSerialization.java +++ b/third-party/triemap/src/test/java/org/opendaylight/yangtools/triemap/TestSerialization.java @@ -26,14 +26,14 @@ import org.junit.Test; public class TestSerialization { @Test public void testSerialization() throws IOException, ClassNotFoundException { - TrieMap map = new TrieMap<>(); + TrieMap map = TrieMap.create(); map.put("dude-0", "tom"); map.put("dude-1", "john"); map.put("dude-3", "ravi"); map.put("dude-4", "alex"); - TrieMap expected = map.readOnlySnapshot(); + TrieMap expected = map.immutableSnapshot(); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final ObjectOutputStream oos = new ObjectOutputStream(bos);