From 8ae20aa6ccb953c8afea629c4491ef1074116de2 Mon Sep 17 00:00:00 2001 From: leventov Date: Tue, 14 Oct 2014 00:30:20 +0400 Subject: [PATCH] HCOLL-164 Made ChronicleSet zero overhead by value; fixed ChronicleSet.add() and remove() implementations; added ChronicleMapBuilder.valueMarshallerAndFactory(AgileBytesMarshaller, ObjectFactory) method --- pom.xml | 2 +- .../chronicle/map/ChronicleMapBuilder.java | 8 ++ .../chronicle/map/SerializationBuilder.java | 2 +- .../chronicle/set/ChronicleSetBuilder.java | 114 ++-------------- .../net/openhft/chronicle/set/DummyValue.java | 21 +++ .../chronicle/set/DummyValueMarshaller.java | 71 ++++++++++ .../net/openhft/chronicle/set/SetFromMap.java | 122 ++++++++++++++++++ 7 files changed, 232 insertions(+), 108 deletions(-) create mode 100644 src/main/java/net/openhft/chronicle/set/DummyValue.java create mode 100644 src/main/java/net/openhft/chronicle/set/DummyValueMarshaller.java create mode 100644 src/main/java/net/openhft/chronicle/set/SetFromMap.java diff --git a/pom.xml b/pom.xml index c7e64009f..bb883ecb1 100755 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ net.openhft lang - 6.4.9 + 6.4.10-SNAPSHOT diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index bbcaaa7de..fd3cfdda4 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -20,6 +20,7 @@ import net.openhft.chronicle.ChronicleHashBuilder; import net.openhft.chronicle.ChronicleHashErrorListener; import net.openhft.chronicle.ChronicleHashErrorListeners; import net.openhft.chronicle.TimeProvider; +import net.openhft.chronicle.map.serialization.AgileBytesMarshaller; import net.openhft.chronicle.map.serialization.MetaBytesInterop; import net.openhft.chronicle.map.serialization.MetaBytesWriter; import net.openhft.chronicle.map.serialization.MetaProvider; @@ -638,6 +639,13 @@ public class ChronicleMapBuilder implements Cloneable, return this; } + public ChronicleMapBuilder valueMarshallerAndFactory( + @NotNull AgileBytesMarshaller valueMarshaller, + @NotNull ObjectFactory valueFactory) { + valueBuilder.agileMarshaller(valueMarshaller, valueFactory); + return this; + } + public ChronicleMapBuilder valueFactory(@NotNull ObjectFactory valueFactory) { valueBuilder.factory(valueFactory); return this; diff --git a/src/main/java/net/openhft/chronicle/map/SerializationBuilder.java b/src/main/java/net/openhft/chronicle/map/SerializationBuilder.java index c55306fd3..4973970bb 100644 --- a/src/main/java/net/openhft/chronicle/map/SerializationBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/SerializationBuilder.java @@ -80,7 +80,7 @@ final class SerializationBuilder implements Cloneable { if (role == Role.VALUE) { factory = concreteClass(eClass) && marshallerUseFactory(eClass) ? new NewInstanceObjectFactory(eClass) : - NullObjectFactory.INSTANCE; + NullObjectFactory.of(); } if (concreteClass(eClass) && Byteable.class.isAssignableFrom(eClass)) { diff --git a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java index 26a27f8f5..5473edcb5 100644 --- a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java +++ b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java @@ -16,35 +16,30 @@ package net.openhft.chronicle.set; -import net.openhft.chronicle.TimeProvider; -import net.openhft.chronicle.map.Alignment; import net.openhft.chronicle.ChronicleHashBuilder; import net.openhft.chronicle.ChronicleHashErrorListener; +import net.openhft.chronicle.TimeProvider; import net.openhft.chronicle.map.*; import net.openhft.lang.io.serialization.BytesMarshaller; import net.openhft.lang.io.serialization.BytesMarshallerFactory; import net.openhft.lang.io.serialization.ObjectSerializer; +import net.openhft.lang.io.serialization.impl.NullObjectFactory; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; -import java.io.Serializable; -import java.util.AbstractSet; -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; public class ChronicleSetBuilder implements ChronicleHashBuilder, ChronicleSetBuilder> { - private ChronicleMapBuilder chronicleMapBuilder; + private ChronicleMapBuilder chronicleMapBuilder; ChronicleSetBuilder(Class keyClass) { - chronicleMapBuilder = ChronicleMapBuilder.of(keyClass, Void.class) - .entryAndValueAlignment(Alignment.NO_ALIGNMENT); + chronicleMapBuilder = ChronicleMapBuilder.of(keyClass, DummyValue.class) + .entryAndValueAlignment(Alignment.NO_ALIGNMENT) + .valueMarshallerAndFactory(DummyValueMarshaller.INSTANCE, NullObjectFactory.of()); } public static ChronicleSetBuilder of(Class keyClass) { @@ -229,108 +224,15 @@ public class ChronicleSetBuilder @Override public ChronicleSet create(File file) throws IOException { - final ChronicleMap map = chronicleMapBuilder.create(file); + final ChronicleMap map = chronicleMapBuilder.create(file); return new SetFromMap(map); } @Override public ChronicleSet create() throws IOException { - final ChronicleMap map = chronicleMapBuilder.create(); + final ChronicleMap map = chronicleMapBuilder.create(); return new SetFromMap(map); } - private static class SetFromMap extends AbstractSet - implements ChronicleSet, Serializable { - - private final ChronicleMap m; // The backing map - private transient Set s; // Its keySet - - SetFromMap(ChronicleMap map) { - if (!map.isEmpty()) - throw new IllegalArgumentException("Map is non-empty"); - m = map; - s = map.keySet(); - } - - public void clear() { - m.clear(); - } - - public int size() { - return m.size(); - } - - public boolean isEmpty() { - return m.isEmpty(); - } - - public boolean contains(Object o) { - return m.containsKey(o); - } - - public boolean remove(Object o) { - return m.remove(o) != null; - } - - public boolean add(E e) { - return m.put(e, (Void) null) == null; - } - - public Iterator iterator() { - return s.iterator(); - } - - public Object[] toArray() { - return s.toArray(); - } - - public T[] toArray(T[] a) { - return s.toArray(a); - } - - public String toString() { - return s.toString(); - } - - public int hashCode() { - return s.hashCode(); - } - - public boolean equals(Object o) { - return o == this || s.equals(o); - } - - public boolean containsAll(Collection c) { - return s.containsAll(c); - } - - public boolean removeAll(Collection c) { - return s.removeAll(c); - } - - public boolean retainAll(Collection c) { - return s.retainAll(c); - } - // addAll is the only inherited implementation - - private static final long serialVersionUID = 2454657854757543876L; - - private void readObject(java.io.ObjectInputStream stream) - throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - s = m.keySet(); - } - - @Override - public long longSize() { - return m.longSize(); - } - - @Override - public void close() throws IOException { - m.close(); - } - } - } diff --git a/src/main/java/net/openhft/chronicle/set/DummyValue.java b/src/main/java/net/openhft/chronicle/set/DummyValue.java new file mode 100644 index 000000000..1d73a070b --- /dev/null +++ b/src/main/java/net/openhft/chronicle/set/DummyValue.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014 Higher Frequency Trading http://www.higherfrequencytrading.com + * + * 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 net.openhft.chronicle.set; + +enum DummyValue { + DUMMY_VALUE +} diff --git a/src/main/java/net/openhft/chronicle/set/DummyValueMarshaller.java b/src/main/java/net/openhft/chronicle/set/DummyValueMarshaller.java new file mode 100644 index 000000000..85bb16462 --- /dev/null +++ b/src/main/java/net/openhft/chronicle/set/DummyValueMarshaller.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014 Higher Frequency Trading http://www.higherfrequencytrading.com + * + * 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 net.openhft.chronicle.set; + +import net.openhft.chronicle.map.serialization.AgileBytesMarshaller; +import net.openhft.lang.io.Bytes; + +import static net.openhft.chronicle.set.DummyValue.DUMMY_VALUE; + +enum DummyValueMarshaller implements AgileBytesMarshaller { + INSTANCE; + + @Override + public boolean startsWith(Bytes bytes, DummyValue dummyValue) { + throw new UnsupportedOperationException(); + } + + @Override + public long hash(DummyValue dummyValue) { + throw new UnsupportedOperationException(); + } + + @Override + public DummyValue read(Bytes bytes, long size) { + return DUMMY_VALUE; + } + + @Override + public DummyValue read(Bytes bytes, long size, DummyValue dummyValue) { + return DUMMY_VALUE; + } + + @Override + public long size(DummyValue dummyValue) { + return 0L; + } + + @Override + public void write(Bytes bytes, DummyValue dummyValue) { + // do nothing + } + + @Override + public int sizeEncodingSize(long size) { + return 0; + } + + @Override + public void writeSize(Bytes bytes, long size) { + // do nothing + } + + @Override + public long readSize(Bytes bytes) { + return 0L; + } +} diff --git a/src/main/java/net/openhft/chronicle/set/SetFromMap.java b/src/main/java/net/openhft/chronicle/set/SetFromMap.java new file mode 100644 index 000000000..47fd84883 --- /dev/null +++ b/src/main/java/net/openhft/chronicle/set/SetFromMap.java @@ -0,0 +1,122 @@ +/* + * Copyright 2014 Higher Frequency Trading http://www.higherfrequencytrading.com + * + * 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 net.openhft.chronicle.set; + +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.ChronicleSet; + +import java.io.IOException; +import java.io.Serializable; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import static net.openhft.chronicle.set.DummyValue.DUMMY_VALUE; + +class SetFromMap extends AbstractSet + implements ChronicleSet, Serializable { + + private final ChronicleMap m; // The backing map + private transient Set s; // Its keySet + + SetFromMap(ChronicleMap map) { + if (!map.isEmpty()) + throw new IllegalArgumentException("Map is non-empty"); + m = map; + s = map.keySet(); + } + + public void clear() { + m.clear(); + } + + public int size() { + return m.size(); + } + + public boolean isEmpty() { + return m.isEmpty(); + } + + public boolean contains(Object o) { + return m.containsKey(o); + } + + public boolean remove(Object o) { + return m.remove(o) == DUMMY_VALUE; + } + + public boolean add(E e) { + return m.putIfAbsent(e, DUMMY_VALUE) == null; + } + + public Iterator iterator() { + return s.iterator(); + } + + public Object[] toArray() { + return s.toArray(); + } + + public T[] toArray(T[] a) { + return s.toArray(a); + } + + public String toString() { + return s.toString(); + } + + public int hashCode() { + return s.hashCode(); + } + + public boolean equals(Object o) { + return o == this || s.equals(o); + } + + public boolean containsAll(Collection c) { + return s.containsAll(c); + } + + public boolean removeAll(Collection c) { + return s.removeAll(c); + } + + public boolean retainAll(Collection c) { + return s.retainAll(c); + } + // addAll is the only inherited implementation + + private static final long serialVersionUID = 2454657854757543876L; + + private void readObject(java.io.ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + s = m.keySet(); + } + + @Override + public long longSize() { + return m.longSize(); + } + + @Override + public void close() throws IOException { + m.close(); + } +}