Improve documentation

This commit is contained in:
leventov
2016-03-23 20:09:43 +07:00
parent ca5a988873
commit 739796b90d
24 changed files with 509 additions and 80 deletions
@@ -16,8 +16,6 @@
package net.openhft.chronicle.hash;
import net.openhft.chronicle.bytes.RandomDataInput;
/**
* Defines reasonable defaults for {@code Data}'s {@code equals()}, {@code hashCode()} and
* {@code toString()}. They should be default implementations in the {@code Data} interface itself,
@@ -18,10 +18,16 @@ package net.openhft.chronicle.hash;
import net.openhft.chronicle.map.MapAbsentEntry;
import net.openhft.chronicle.map.MapEntry;
import net.openhft.chronicle.set.SetEntry;
/**
* Abstracts entries of hash containers, created by {@link ChronicleHashBuilder}s
* with {@link ChronicleHashBuilder#checksumEntries(boolean)} configured to {@code true}.
* with {@link ChronicleHashBuilder#checksumEntries(boolean)} configured to {@code true}. There is
* no method that returns {@code ChecksumEntry}, {@link MapEntry} or {@link SetEntry} could be
* <i>casted</i> to {@code ChecksumEntry} to access it's methods.
*
* <p>See <a href="https://github.com/OpenHFT/Chronicle-Map#entry-checksums">Entry checksums</a>
* section in the Chronicle Map tutorial for usage examples of this interface.
*/
public interface ChecksumEntry {
@@ -29,8 +29,7 @@ import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* This interface defines common {@link ChronicleMap} and {@link ChronicleSet}, related to off-heap
* memory management and file-mapping. Not usable by itself.
* Common base interface for {@link ChronicleMap} and {@link ChronicleSet}.
*/
public interface ChronicleHash<K, E extends HashEntry<K>, SC extends HashSegmentContext<K, ?>,
EQC extends ExternalHashQueryContext<K>> extends Closeable {
@@ -45,6 +44,11 @@ public interface ChronicleHash<K, E extends HashEntry<K>, SC extends HashSegment
*/
File file();
/**
* Returns the number of entries in this store.
*
* @return the number of entries in this store
*/
long longSize();
/**
@@ -53,13 +57,16 @@ public interface ChronicleHash<K, E extends HashEntry<K>, SC extends HashSegment
Class<K> keyClass();
/**
* Returns the context to perform arbitrary operations with the given key in this map.
* Conventionally, try-with-resources block should wrap the returned context: <pre>{@code
* 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
* try (ExternalHashQueryContext<K> q = hash.queryContext(key)) {
* // ... do something
* }}</pre>
* See {@link HashQueryContext} and {@link MapMethods} for a lot of inspiration about using this
* functionality.
*
* <p>See documentation to {@link HashQueryContext} interface and methods in {@link MapMethods}
* interface for examples of using contexts. Also see <a href="
* https://github.com/OpenHFT/Chronicle-Map#working-with-an-entry-within-a-context-section">
* Working with an entry within a context</a> section in the Chronicle Map tutorial.
*
* @param key the queried key
* @return the context to perform operations with the key
@@ -72,9 +79,16 @@ public interface ChronicleHash<K, E extends HashEntry<K>, SC extends HashSegment
EQC queryContext(K key);
/**
* Equivalent to {@link #queryContext(Object)}, but accepts {@code Data} instead of key as
* an object. Useful, when you already have {@code Data}, calling this method instead of {@link
* #queryContext(Object)} might help to avoid unnecessary deserialization.
* Returns a context to perform arbitrary operations with the given key, provided in
* {@link Data} form. Equivalent to {@link #queryContext(Object)}, but accepts {@code Data}
* instead of object key. This method is useful, when you already have {@code Data}, calling
* this method instead of {@link #queryContext(Object)} might help to avoid unnecessary
* deserialization.
*
* <p>See documentation to {@link HashQueryContext} interface and methods in {@link MapMethods}
* interface for examples of using contexts. Also see <a href="
* https://github.com/OpenHFT/Chronicle-Map#working-with-an-entry-within-a-context-section">
* Working with an entry within a context</a> section in the Chronicle Map tutorial.
*
* @param key the queried key as {@code Data}
* @return the context to perform operations with the key
@@ -82,19 +96,19 @@ public interface ChronicleHash<K, E extends HashEntry<K>, SC extends HashSegment
@NotNull EQC queryContext(Data<K> key);
/**
* Returns the context to perform arbitrary operations with the given key, provided in the
* Returns a context to perform arbitrary operations with the given key, provided in the
* serialized form. See {@link #queryContext(Object)} and {@link #queryContext(Data)} for more
* information on contexts semantics and usage patterns.
*
* @param keyBytes the bytes store with the key bytes to query
* @param offset actual offset of the key bytes within the given BytesStore
* @param size length of the key bytes sequence
* @param size length of the key bytes sequence within the given BytesStore
* @return the context to perform operations with the key
*/
@NotNull EQC queryContext(BytesStore keyBytes, long offset, long size);
/**
* Returns the context of the segment with the given index. Segments are indexed from 0 to
* Returns a context of the segment with the given index. Segments are indexed from 0 to
* {@link #segments()}{@code - 1}.
*
* @see HashSegmentContext
@@ -150,10 +164,6 @@ public interface ChronicleHash<K, E extends HashEntry<K>, SC extends HashSegment
* collection. This could be a problem if, for example, you target rare garbage collections,
* but load and drop {@code ChronicleHash}es regularly.
*
* <p>
* TODO what about commit guarantees, when ChronicleMap is used with memory-mapped files, if
* {@code ChronicleMap}/{@code ChronicleSet} closed/not?
*
* <p>After this method call behaviour of <i>all</i> methods of {@code ChronicleMap}
* or {@code ChronicleSet} is undefined. <i>Any</i> method call on the map might throw
* <i>any</i> exception, or even JVM crash. Shortly speaking, don't call use map closing.
@@ -33,8 +33,8 @@ import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
/**
* This interface defines the meaning of configurations, common to {@link ChronicleMapBuilder} and
* {@link ChronicleSetBuilder}, i. e. <i>Chronicle hash container</i> configurations.
* Base interface for {@link ChronicleMapBuilder} and {@link ChronicleSetBuilder}, i. e. defines
* <i>Chronicle hash container</i> configurations.
*
* <p>{@code ChronicleHashBuilder} is mutable. Configuration methods mutate the builder and return
* <i>the builder itself</i> back to support chaining pattern, rather than the builder copies with
@@ -17,45 +17,63 @@
package net.openhft.chronicle.hash;
import net.openhft.chronicle.algo.hashing.LongHashFunction;
import net.openhft.chronicle.bytes.BytesStore;
import net.openhft.chronicle.bytes.BytesUtil;
import net.openhft.chronicle.bytes.RandomDataInput;
import net.openhft.chronicle.bytes.RandomDataOutput;
import net.openhft.chronicle.map.ChronicleMap;
import net.openhft.chronicle.map.MapEntry;
import net.openhft.chronicle.map.MapQueryContext;
import net.openhft.chronicle.set.ChronicleSet;
import org.jetbrains.annotations.Nullable;
import static net.openhft.chronicle.algo.bytes.Access.checkedRandomDataInputAccess;
/**
* Dual bytes/object access to keys/values/elements.
* Dual bytes/object access to keys or values (for {@link ChronicleMap}) and elements (for {@link
* ChronicleSet}) throughout the Chronicle Map library.
*
* <p>Bytes access: {@link #bytes()} + {@link #offset()} + {@link #size()}.
*
* <p>Object access: {@link #get()}.
*
* <p>In most cases, each particular value wraps either some object or some bytes. Object
* <p>In most cases, each particular {@code Data} wraps either some object or some bytes. Object
* is marshalled to bytes lazily on demand, and bytes are lazily deserialized to object,
* accordingly.
* accordingly.
*
* @param <T> type of the accessed objects
*/
public interface Data<T> {
/**
* Returns the accessor object to the {@code Data}'s bytes. For safety, this interface returns
* read-only object, because this object could expose bytes source that must be immutable, e. g.
* an array behind {@code String} object.
* Returns the accessor object to the {@code Data}'s bytes.
*
* <p>If this {@code Data} wraps some bytes, this method just returns a reference to that bytes.
*
* <p>If this {@code Data} wraps an object, this method performs serialization internally and
* returns a reference to the output buffer, caching the result for subsequent calls of this
* method.
*
* <p>For safety, this interface returns read-only object, because it could expose bytes source
* that must be immutable, e. g. a `char[]` array behind a {@code String}. But in cases when the
* {@code Data} instance wraps off-heap bytes, e. g. {@link MapEntry#value()}, it is allowed to
* cast the object, returned from this method, to {@link BytesStore}, and write into the
* off-heap memory. You should only ensure that current context (e. g. {@link MapQueryContext})
* is locked exclusively, in order to avoid data races.
*/
RandomDataInput bytes();
/**
* Returns the offset to the {@code Data}'s bytes sequence, within the {@link #bytes()} object.
* For example, the first byte of the bytes representation of this {@code Data} instance is
* {@code data.bytes().readByte(data.offset())}.
* Returns the offset to the {@code Data}'s bytes sequence within the {@link RandomDataInput},
* returned from {@link #bytes()} method. For example, the first byte of the bytes
* representation of some {@code data} is {@code data.bytes().readByte(data.offset())}.
*/
long offset();
/**
* Returns the size of this {@code Data}'s bytes sequence. It spans from {@link #offset()} to
* {@code offset() + size() - 1} bytes within the {@link #bytes()} object.
* {@code offset() + size() - 1} bytes within the {@link RandomDataInput}, returned from
* {@link #bytes()} method.
*/
long size();
@@ -76,7 +94,7 @@ public interface Data<T> {
*
* <p>Default implementation compares {@link #bytes()} of this {@code Data}, but custom
* implementation may only check if {@linkplain #get() object} of this {@code Data} <i>would</i>
* be serialized to the same bytes sequence, if this {@code Data} is object-based and obtaining
* be serialized to the same bytes sequence, if this {@code Data} wraps an object and obtaining
* {@link #bytes()} requires serialization internally.
*
* @param source the bytes source, to compare this {@code Data}'s bytes with
@@ -106,16 +124,25 @@ public interface Data<T> {
}
/**
* Returns "cached" object, generally not eligible for using outside some context, or a block,
* synchronized with locks, or lambda, etc.
*
* <p>If the {@code Data} is object wrapper -- this method just returns this object.
* Returns object view of this {@code Data}.
*
* <p>If this {@code Data} wraps some object, this method just returns that object.
*
* <p>If this {@code Data} wraps some bytes, this method performs deserialization internally
* and returns the resulting on-heap object, caching it for subsequent calls of this method. The
* returned object could be reused, therefore it is <i>generally disallowed</i> to use the
* object, returned from this method, <i>outside</i> some context, or a block, synchronized with
* locks, or lambda, etc., which provided the access to this {@code Data} instance.
*/
T get();
/**
* Reads the object from the value's bytes, trying to reuse the given object (might be {@code
* null}).
* Deserialize and return an object from the {@code Data}'s bytes, trying to reuse the given
* {@code using} object (might be {@code null}). This method either returns the given {@code
* using} object back (if reuse is possible) or creates a new object, rather than some
* internally cached and reused one, therefore it is <i>always allowed</i> to use the object,
* returned from this method, <i>outside</i> some context, or a block, synchronized with locks,
* or lambda, etc., which provided the access to this {@code Data} instance.
*/
T getUsing(@Nullable T using);
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2015 higherfrequencytrading.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Contains abstractions of <i>inter-process</i> locks, used in Chronicle Map.
*/
package net.openhft.chronicle.hash.locks;
@@ -36,14 +36,12 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe
* README section</a>.
*
* <p>Usage: <pre>{@code
* ListMarshaller<Integer> valueMarshaller = new ListMarshaller<>(
* IntegerMarshaller.INSTANCE, IntegerMarshaller.INSTANCE);
* ChronicleMap<String, List<Integer>> regNumbers = ChronicleMap
* .of(String.class, (Class<List<Integer>>) (Class) List.class)
* .entries(10_000)
* .averageKey("John Smith")
* .valueMarshaller(valueMarshaller)
* .valueMarshaller(ListMarshaller.of(IntegerMarshaller.INSTANCE))
* .averageValue(ImmutableList.of(1, 2, 3))
* .entries(10_000)
* .create();
* }</pre>
*
@@ -38,14 +38,14 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe
* README section</a>.
*
* <p>Usage: <pre>{@code
* SetMarshaller<String> valueMarshaller = new SetMarshaller<>(
* SetMarshaller<String> valueMarshaller = SetMarshaller.of(
* new StringBytesReader(), CharSequenceBytesWriter.INSTANCE);
* ChronicleMap<String, Set<String>> map = ChronicleMap
* .of(String.class, (Class<Set<String>>) (Class) Set.class)
* .entries(10_000)
* .averageKey("fruits")
* .valueMarshaller(valueMarshaller)
* .averageValue(ImmutableSet.of("apples", "bananas", "grapes"))
* .entries(10_000)
* .create();
* }</pre>
*
@@ -15,7 +15,7 @@
*/
/**
* The package contains interfaces for serializing objects between Java heap and {@link
* Contains interfaces for serializing objects between Java heap and {@link
* net.openhft.chronicle.bytes.Bytes} or {@link net.openhft.chronicle.bytes.BytesStore}, used by
* Chronicle Map to store objects off-heap, and read them back from off-heap memory to on-heap
* objects.
@@ -28,7 +28,8 @@ import java.util.Map;
import java.util.concurrent.ConcurrentMap;
/**
* Extension of {@link ConcurrentMap} interface, stores the data off-heap.
* {@code ChronicleMap} provides concurrent access to a <i>Chronicle Map key-value store</i> from a
* JVM process.
*
* <p>For information on <ul> <li>how to construct a {@code ChronicleMap}</li> <li>{@code
* ChronicleMap} flavors and properties</li> <li>available configurations</li> </ul> see {@link
@@ -1777,7 +1777,7 @@ public final class ChronicleMapBuilder<K, V> implements
/**
* Inject your SPI code around basic {@code ChronicleMap}'s operations with entries:
* removing entries, replacing the entries' value and inserting the new entry.
* removing entries, replacing entries' value and inserting new entries.
*
* <p>This affects behaviour of ordinary map.put(), map.remove(), etc. calls, as well as removes
* and replacing values <i>during iterations</i>, <i>remote map calls</i> and
@@ -108,7 +108,9 @@ public interface MapEntryOperations<K, V, R> {
* @implNote default implementation calls {@link MapEntry#doRemove()} on the given entry
* and returns {@code null}.
*
* @param entry the entry to remove
* @param entry the entry to remove
* @return result of operation, understandable by higher-level SPIs, e. g. custom
* {@link MapMethods} implementation
* @throws IllegalStateException if some locking/state conditions required to perform remove
* operation are not met
* @throws RuntimeException if removal was unconditionally unsuccessful due to any reason
@@ -125,6 +127,8 @@ public interface MapEntryOperations<K, V, R> {
* entry.doReplaceValue(newValue)} and returns {@code null}.
*
* @param entry the entry to replace the value in
* @return result of operation, understandable by higher-level SPIs, e. g. custom
* {@link MapMethods} implementation
* @throws IllegalStateException if some locking/state conditions required to perform replace
* operation are not met
* @throws RuntimeException if value replacement was unconditionally unsuccessful due
@@ -142,6 +146,8 @@ public interface MapEntryOperations<K, V, R> {
* @implNote default implementation calls {@link MapAbsentEntry#doInsert(Data)
* absentEntry.doInsert(value)} and returns {@code null}.
*
* @return result of operation, understandable by higher-level SPIs, e. g. custom
* {@link MapMethods} implementation
* @throws IllegalStateException if some locking/state conditions required to perform insertion
* operation are not met
* @throws RuntimeException if insertion was unconditionally unsuccessful due to any reason
@@ -32,6 +32,13 @@ import static net.openhft.chronicle.map.MapMethodsSupport.tryReturnCurrentValueI
*/
public interface MapMethods<K, V, R> {
/**
* Backing {@link ChronicleMap#containsKey(Object)} method.
*
* @implNote the default implementation is equivalent to <pre>{@code
* return q.entry() != null;
* }</pre>
*/
default boolean containsKey(MapQueryContext<K, V, R> q) {
return q.entry() != null;
}
@@ -19,6 +19,27 @@ package net.openhft.chronicle.map;
import net.openhft.chronicle.hash.Data;
import org.jetbrains.annotations.NotNull;
/**
* Abstracts returning a value from a query to a {@link ChronicleMap}, used in {@link MapMethods}.
* This interface is not supposed to be implemented in user code.
*
* @param <V> the type of values in the {@code ChronicleMap}
*/
public interface ReturnValue<V> {
/**
* Calling this method on a {@code ReturnValue} object, provided as an argument in a method from
* {@link MapMethods}, designates that the {@code ChronicleMap}'s method (backed by this
* {@code MapMethods}'s method) should return the given {@code value}.
*
* <p>It is not allowed to call {@code returnValue()} twice during a single {@code MapMethods}'s
* method call.
*
* <p>Not calling {@code returnValue()} during {@code MapMethods}'s method call will make the
* backed {@code ChronicleMap}'s method to return {@code null}.
*
* @param value a {@code Data} object wrapping a value, which should be returned from a
* {@code ChronicleMap}'s method, backed by the {@code MapMethods}'s method, to
* which this {@code ReturnValue} instance was passed as an argument
*/
void returnValue(@NotNull Data<V> value);
}
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2015 higherfrequencytrading.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Contains {@link net.openhft.chronicle.map.ChronicleMap} interface, {@code ChronicleMap} context
* interfaces, {@link net.openhft.chronicle.map.ChronicleMapBuilder} class and related stuff.
*/
package net.openhft.chronicle.map;
@@ -20,10 +20,24 @@ import net.openhft.chronicle.hash.ChronicleHash;
import java.util.Set;
/**
* {@code ChronicleSet} provides concurrent access to a <i>Chronicle Map key-value store</i> with
* zero-sized values from a JVM process, wrapped as an extension of {@link Set} interface.
*
* @param <K> the set key type
* @see net.openhft.chronicle.map.ChronicleMap
*/
public interface ChronicleSet<K>
extends Set<K>, ChronicleHash<K, SetEntry<K>, SetSegmentContext<K, ?>,
ExternalSetQueryContext<K, ?>> {
/**
* Delegates to {@link ChronicleSetBuilder#of(Class)} for convenience.
*
* @param keyClass class of the key type of the {@code ChronicleSet} to create
* @param <K> the key type of the {@code ChronicleSet} to create
* @return a new {@code ChronicleSetBuilder} for the given key class
*/
static <K> ChronicleSetBuilder<K> of(Class<K> keyClass) {
return ChronicleSetBuilder.of(keyClass);
}
@@ -55,6 +55,15 @@ public final class ChronicleSetBuilder<K>
chronicleMapBuilder.privateAPI());
}
/**
* Returns a new {@code ChronicleSetBuilder} instance which is able to {@linkplain #create()
* create} sets with the specified key class.
*
* @param keyClass class object used to infer key type and discover it's properties via
* reflection
* @param <K> key type of the sets, created by the returned builder
* @return a new builder for the given key class
*/
public static <K> ChronicleSetBuilder<K> of(Class<K> keyClass) {
return new ChronicleSetBuilder<>(keyClass);
}
@@ -250,6 +259,14 @@ public final class ChronicleSetBuilder<K>
return this;
}
/**
* Inject your SPI code around basic {@code ChronicleSet}'s operations with entries:
* removing entries and inserting new entries.
*
* <p>This affects behaviour of ordinary set.add(), set.remove(), calls, as well as removes
* <i>during iterations</i>, updates during <i>remote calls</i> and
* <i>internal replication operations</i>.
*/
public ChronicleSetBuilder<K> entryOperations(SetEntryOperations<K, ?> entryOperations) {
chronicleMapBuilder.entryOperations(new MapEntryOperations<K, DummyValue, Object>() {
@Override
@@ -18,15 +18,47 @@ package net.openhft.chronicle.set;
import org.jetbrains.annotations.NotNull;
/**
* SPI interface fro customizing "low-level" modification operations on {@link ChronicleSet}
* entries.
*
* @param <K> the set key type
* @param <R> methods return type, used for communication between lower- and higher-level SPI
* @see ChronicleSetBuilder#entryOperations(SetEntryOperations)
*/
public interface SetEntryOperations<K, R> {
/**
* Removes the given entry from the set.
*
* @implNote default implementation calls {@link SetEntry#doRemove()} on the given entry and
* returns {@code null}.
*
* @param entry the entry to remove
* @return result of operation, understandable by higher-level SPIs
* @throws IllegalStateException if some locking/state conditions required to perform remove
* operation are not met
* @throws RuntimeException if removal was unconditionally unsuccessful due to any reason
*/
default R remove(@NotNull SetEntry<K> entry) {
entry.doRemove();
return null;
}
default R insert(@NotNull SetAbsentEntry<K> entry) {
entry.doInsert();
/**
* Inserts the new entry into the set, of {@link SetAbsentEntry#absentKey() the key} from
* the given insertion context (<code>absentEntry</code>).
*
* @implNote default implementation calls {@link SetAbsentEntry#doInsert()} and returns
* {@code null}.
*
* @return result of operation, understandable by higher-level SPIs
* @throws IllegalStateException if some locking/state conditions required to perform insertion
* operation are not met
* @throws RuntimeException if insertion was unconditionally unsuccessful due to any reason
*/
default R insert(@NotNull SetAbsentEntry<K> absentEntry) {
absentEntry.doInsert();
return null;
}
}
@@ -15,7 +15,7 @@
*/
/**
* Contains {@link net.openhft.chronicle.set.ChronicleSet} interface and
* {@link net.openhft.chronicle.set.ChronicleSetBuilder} class.
* Contains {@link net.openhft.chronicle.set.ChronicleSet} interface, {@code ChronicleSet} context
* interfaces and {@link net.openhft.chronicle.set.ChronicleSetBuilder} class.
*/
package net.openhft.chronicle.set;