Added support for dynamic discovery of files, https://github.com/OpenHFT/Chronicle-Core/issues/88

This commit is contained in:
Peter Lawrey
2019-08-28 17:59:17 +01:00
parent 1ed31d485c
commit 071bcf1d8e
18 changed files with 301 additions and 24 deletions
@@ -25,6 +25,7 @@ import net.openhft.chronicle.set.ChronicleSet;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
@@ -96,6 +97,11 @@ public interface ChronicleHash<K, E extends HashEntry<K>, SC extends HashSegment
*/
Class<K> keyClass();
/**
* @return Type as a Class or UnresolvedType if unknown.
*/
Type keyType();
/**
* Returns a context to perform arbitrary operations with the given key in this store.
* Conventionally, should be used in a try-with-resources block: <pre>{@code
@@ -38,6 +38,7 @@ import net.openhft.chronicle.map.ChronicleMapBuilder;
import net.openhft.chronicle.values.Values;
import net.openhft.chronicle.wire.Marshallable;
import net.openhft.chronicle.wire.WireIn;
import net.openhft.chronicle.wire.WireInternal;
import net.openhft.chronicle.wire.WireOut;
import org.jetbrains.annotations.NotNull;
@@ -46,6 +47,7 @@ import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.ref.WeakReference;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
@@ -93,7 +95,7 @@ public abstract class VanillaChronicleHash<K,
public transient boolean createdOrInMemory;
/////////////////////////////////////////////////
// Key Data model
public Class<K> keyClass;
public Type keyClass;
public SizeMarshaller keySizeMarshaller;
public SizedReader<K> keyReader;
public DataAccess<K> keyDataAccess;
@@ -247,7 +249,7 @@ public abstract class VanillaChronicleHash<K,
// that doesn't guarantee (?) to initialize fields with default values (false for boolean)
createdOrInMemory = false;
keyClass = wireIn.read(() -> "keyClass").typeLiteral();
keyClass = wireIn.read(() -> "keyClass").lenientTypeLiteral();
keySizeMarshaller = wireIn.read(() -> "keySizeMarshaller").object(SizeMarshaller.class);
keyReader = wireIn.read(() -> "keyReader").object(SizedReader.class);
keyDataAccess = wireIn.read(() -> "keyDataAccess").object(DataAccess.class);
@@ -682,8 +684,10 @@ public abstract class VanillaChronicleHash<K,
}
public final void checkKey(Object key) {
Class<K> keyClass = keyClass();
if (!keyClass.isInstance(key)) {
// key.getClass will cause NPE exactly as needed
if (key == null)
throw new NullPointerException("null key not supported");
throw new ClassCastException(toIdentityString() + ": Key must be a " +
keyClass.getName() + " but was a " + key.getClass());
}
@@ -23,6 +23,8 @@ import net.openhft.chronicle.hash.serialization.DataAccess;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Type;
public class ByteableDataAccess<T extends Byteable> extends InstanceCreatingMarshaller<T>
implements DataAccess<T>, Data<T> {
@@ -31,7 +33,7 @@ public class ByteableDataAccess<T extends Byteable> extends InstanceCreatingMars
*/
private transient T instance;
public ByteableDataAccess(Class<T> tClass) {
public ByteableDataAccess(Type tClass) {
super(tClass);
}
@@ -91,6 +93,6 @@ public class ByteableDataAccess<T extends Byteable> extends InstanceCreatingMars
@Override
public DataAccess<T> copy() {
return new ByteableDataAccess<>(tClass());
return new ByteableDataAccess<>(tType());
}
}
@@ -23,6 +23,8 @@ import net.openhft.chronicle.wire.WireIn;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Type;
import static net.openhft.chronicle.hash.serialization.impl.DefaultElasticBytes.DEFAULT_BYTES_CAPACITY;
public class BytesMarshallableDataAccess<T extends BytesMarshallable>
@@ -42,7 +44,7 @@ public class BytesMarshallableDataAccess<T extends BytesMarshallable>
this(tClass, DEFAULT_BYTES_CAPACITY);
}
private BytesMarshallableDataAccess(Class<T> tClass, long bytesCapacity) {
private BytesMarshallableDataAccess(Type tClass, long bytesCapacity) {
super(tClass);
initTransients(bytesCapacity);
}
@@ -140,6 +142,6 @@ public class BytesMarshallableDataAccess<T extends BytesMarshallable>
@Override
public DataAccess<T> copy() {
return new BytesMarshallableDataAccess<>(tClass(), bytes.realCapacity());
return new BytesMarshallableDataAccess<>(tType(), bytes.realCapacity());
}
}
@@ -27,6 +27,8 @@ import net.openhft.chronicle.wire.WireOut;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Type;
import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNeeded;
import static net.openhft.chronicle.hash.serialization.impl.DefaultElasticBytes.DEFAULT_BYTES_CAPACITY;
@@ -53,7 +55,7 @@ public class ExternalBytesMarshallableDataAccess<T> extends InstanceCreatingMars
}
private ExternalBytesMarshallableDataAccess(
Class<T> tClass, SizedReader<T> reader, BytesWriter<? super T> writer,
Type tClass, SizedReader<T> reader, BytesWriter<? super T> writer,
long bytesCapacity) {
super(tClass);
this.writer = writer;
@@ -125,7 +127,7 @@ public class ExternalBytesMarshallableDataAccess<T> extends InstanceCreatingMars
@Override
public DataAccess<T> copy() {
return new ExternalBytesMarshallableDataAccess<>(
tClass(), copyIfNeeded(reader), copyIfNeeded(writer), bytes.realCapacity());
tType(), copyIfNeeded(reader), copyIfNeeded(writer), bytes.realCapacity());
}
@Override
@@ -26,6 +26,8 @@ import net.openhft.chronicle.wire.WireIn;
import net.openhft.chronicle.wire.WireOut;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Type;
/**
* Holds new instance creation logic, common for many {@link DataAccess} and {@link SizedReader}
* implementations
@@ -34,7 +36,7 @@ import org.jetbrains.annotations.NotNull;
*/
public abstract class InstanceCreatingMarshaller<T> implements Marshallable {
private Class<T> tClass;
private Type tClass;
/**
* Constructor for use in subclasses.
@@ -45,11 +47,19 @@ public abstract class InstanceCreatingMarshaller<T> implements Marshallable {
this.tClass = tClass;
}
protected InstanceCreatingMarshaller(Type tClass) {
this.tClass = tClass;
}
/**
* Returns the class of objects deserialized.
*/
protected Class<T> tClass() {
return tClass;
return (Class<T>) tClass;
}
protected Type tType() {
return tClass;
}
/**
@@ -63,7 +73,7 @@ public abstract class InstanceCreatingMarshaller<T> implements Marshallable {
*/
protected T createInstance() {
try {
return ObjectUtils.newInstance(tClass);
return ObjectUtils.newInstance(tClass());
} catch (Exception e) {
throw new IllegalStateException("Some of default marshallers, chosen for the type\n" +
tClass + " by default, delegate to \n" +
@@ -80,7 +90,7 @@ public abstract class InstanceCreatingMarshaller<T> implements Marshallable {
@Override
public void readMarshallable(@NotNull WireIn wireIn) {
//noinspection unchecked
tClass = wireIn.read(() -> "tClass").typeLiteral();
tClass = wireIn.read(() -> "tClass").lenientTypeLiteral();
}
@Override
@@ -20,13 +20,16 @@ import net.openhft.chronicle.hash.serialization.DataAccess;
import net.openhft.chronicle.hash.serialization.SizedReader;
import net.openhft.chronicle.hash.serialization.SizedWriter;
import java.lang.reflect.Type;
import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNeeded;
import static net.openhft.chronicle.hash.serialization.impl.DefaultElasticBytes.DEFAULT_BYTES_CAPACITY;
public class NotReusingSizedMarshallableDataAccess<T> extends SizedMarshallableDataAccess<T> {
public NotReusingSizedMarshallableDataAccess(
Class<T> tClass, SizedReader<T> sizedReader, SizedWriter<? super T> sizedWriter) {
super(tClass, sizedReader, sizedWriter);
Type tClass, SizedReader<T> sizedReader, SizedWriter<? super T> sizedWriter) {
super(tClass, sizedReader, sizedWriter, DEFAULT_BYTES_CAPACITY);
}
@Override
@@ -37,6 +40,6 @@ public class NotReusingSizedMarshallableDataAccess<T> extends SizedMarshallableD
@Override
public DataAccess<T> copy() {
return new NotReusingSizedMarshallableDataAccess<>(
tClass(), copyIfNeeded(sizedReader()), copyIfNeeded(sizedWriter()));
tType(), copyIfNeeded(sizedReader()), copyIfNeeded(sizedWriter()));
}
}
@@ -26,6 +26,8 @@ import net.openhft.chronicle.wire.WireOut;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Type;
import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNeeded;
import static net.openhft.chronicle.hash.serialization.impl.DefaultElasticBytes.DEFAULT_BYTES_CAPACITY;
@@ -52,8 +54,8 @@ public class SizedMarshallableDataAccess<T> extends InstanceCreatingMarshaller<T
this(tClass, sizedReader, sizedWriter, DEFAULT_BYTES_CAPACITY);
}
private SizedMarshallableDataAccess(
Class<T> tClass, SizedReader<T> sizedReader, SizedWriter<? super T> sizedWriter,
protected SizedMarshallableDataAccess(
Type tClass, SizedReader<T> sizedReader, SizedWriter<? super T> sizedWriter,
long bytesCapacity) {
super(tClass);
this.sizedWriter = sizedWriter;
@@ -151,15 +153,15 @@ public class SizedMarshallableDataAccess<T> extends InstanceCreatingMarshaller<T
@Override
public DataAccess<T> copy() {
return new SizedMarshallableDataAccess<>(
tClass(), copyIfNeeded(sizedReader), copyIfNeeded(sizedWriter),
tType(), copyIfNeeded(sizedReader), copyIfNeeded(sizedWriter),
bytes.realCapacity());
}
@Override
public void readMarshallable(@NotNull WireIn wireIn) {
super.readMarshallable(wireIn);
sizedReader = wireIn.read(() -> "sizedReader").typedMarshallable();
sizedWriter = wireIn.read(() -> "sizedWriter").typedMarshallable();
sizedReader = wireIn.read(() -> "sizedReader").object(SizedReader.class);
sizedWriter = wireIn.read(() -> "sizedWriter").object(SizedWriter.class);
initTransients(DEFAULT_BYTES_CAPACITY);
}
@@ -27,6 +27,7 @@ import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
@@ -207,5 +208,10 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>,
* @return the class of {@code <V>}
*/
Class<V> valueClass();
/**
* @return the value Class or UnresolvedType if unknown.
*/
Type valueType();
}
@@ -44,6 +44,7 @@ import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
@@ -73,7 +74,7 @@ public class VanillaChronicleMap<K, V, R>
public transient DefaultValueProvider<K, V> defaultValueProvider;
/////////////////////////////////////////////////
// Value Data model
Class<V> valueClass;
Type valueClass;
/////////////////////////////////////////////////
// Behavior
transient boolean putReturnsNull;
@@ -116,7 +117,7 @@ public class VanillaChronicleMap<K, V, R>
protected void readMarshallableFields(@NotNull WireIn wireIn) {
super.readMarshallableFields(wireIn);
valueClass = wireIn.read(() -> "valueClass").typeLiteral();
valueClass = wireIn.read(() -> "valueClass").lenientTypeLiteral();
valueSizeMarshaller = wireIn.read(() -> "valueSizeMarshaller").object(SizeMarshaller.class);
valueReader = wireIn.read(() -> "valueReader").object(SizedReader.class);
valueDataAccess = wireIn.read(() -> "valueDataAccess").object(DataAccess.class);
@@ -185,6 +186,7 @@ public class VanillaChronicleMap<K, V, R>
}
public final V checkValue(Object value) {
Class<V> valueClass = valueClass();
if (!valueClass.isInstance(value)) {
throw new ClassCastException(toIdentityString() + ": Value must be a " +
valueClass.getName() + " but was a " + value.getClass());
@@ -206,11 +208,21 @@ public class VanillaChronicleMap<K, V, R>
@Override
public Class<K> keyClass() {
return (Class<K>) keyClass;
}
@Override
public Type keyType() {
return keyClass;
}
@Override
public Class<V> valueClass() {
return (Class<V>) valueClass;
}
@Override
public Type valueType() {
return valueClass;
}
@@ -44,7 +44,7 @@ public class EntryValueBytesData<V> extends AbstractData<V> {
@Stage("CachedEntryValue")
private V cachedEntryValue =
mh.m().valueClass() == CharSequence.class ? (V) new StringBuilder() : null;
mh.m().valueType() == CharSequence.class ? (V) new StringBuilder() : null;
@Stage("CachedEntryValue")
private boolean cachedEntryValueRead = false;
@@ -24,6 +24,7 @@ import net.openhft.chronicle.map.VanillaChronicleMap;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.lang.reflect.Type;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
@@ -134,6 +135,11 @@ class SetFromMap<E> extends AbstractSet<E> implements ChronicleSet<E> {
return m.keyClass();
}
@Override
public Type keyType() {
return m.keyType();
}
// TODO test queryContext methods
@NotNull