added isEmpty()

This commit is contained in:
Rob Austin
2016-03-03 19:24:21 +00:00
parent 0fa83b0b1c
commit 4caeafe275
7 changed files with 137 additions and 144 deletions
@@ -30,21 +30,16 @@ import java.util.Map;
import java.util.concurrent.ConcurrentMap;
/**
* Extension of {@link ConcurrentMap} interface, stores the data off-heap.
* <p>
* <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
* ChronicleMapBuilder} documentation.
* <p>
* <p>Functionally this interface defines some methods supporting garbage-free off-heap programming:
* {@link #getUsing(Object, Object)}, {@link #acquireUsing(Object, Object)}.
* <p>
* <p>Roughly speaking, {@code ChronicleMap} compares keys and values by their binary serialized
* Extension of {@link ConcurrentMap} interface, stores the data off-heap. <p> <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 ChronicleMapBuilder}
* documentation. <p> <p>Functionally this interface defines some methods supporting garbage-free
* off-heap programming: {@link #getUsing(Object, Object)}, {@link #acquireUsing(Object, Object)}.
* <p> <p>Roughly speaking, {@code ChronicleMap} compares keys and values by their binary serialized
* form, that shouldn't necessary be the same equality relation as defined by built-in {@link
* Object#equals(Object)} method, which is prescribed by general {@link Map} contract.
* <p>
* <p>Note that {@code ChronicleMap} extends {@link Closeable}, don't forget to {@linkplain #close()
* close} map when it is no longer needed.
* Object#equals(Object)} method, which is prescribed by general {@link Map} contract. <p> <p>Note
* that {@code ChronicleMap} extends {@link Closeable}, don't forget to {@linkplain #close() close}
* map when it is no longer needed.
*
* @param <K> the map key type
* @param <V> the map value type
@@ -60,11 +55,9 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
/**
* Returns the value to which the specified key is mapped, or {@code null} if this map contains
* no mapping for the key.
* <p>
* <p>If the value class allows reusing, particularly if it is a {@link Byteable} subclass,
* consider {@link #getUsing(Object, Object)} method instead of this to reduce garbage
* creation.
* no mapping for the key. <p> <p>If the value class allows reusing, particularly if it is a
* {@link Byteable} subclass, consider {@link #getUsing(Object, Object)} method instead of this
* to reduce garbage creation.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped after this method call, or {@code
@@ -77,18 +70,15 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
/**
* Returns the value to which the specified key is mapped, read to the provided {@code value}
* object, if possible, or returns {@code null}, if this map contains no mapping for the key.
* <p>
* <p>If the specified key is present in the map, the value data is read to the provided {@code
* value} object via value marshaller's {@link BytesMarshaller#read(Bytes, Object) read(Bytes,
* value)} or value reader's {@link BytesReader#read(Bytes, long, Object) read(Bytes, size,
* value)} method, depending on what deserialization strategy is configured on the builder,
* using which this map was constructed. If the value deserializer is able to reuse the given
* {@code value} object, calling this method instead of {@link #get(Object)} could help to
* reduce garbage creation.
* <p>
* <p>The provided {@code value} object is allowed to be {@code null}, in this case {@code
* map.getUsing(key, null)} call is semantically equivalent to simple {@code map.get(key)}
* call.
* <p> <p>If the specified key is present in the map, the value data is read to the provided
* {@code value} object via value marshaller's {@link BytesMarshaller#read(Bytes, Object)
* read(Bytes, value)} or value reader's {@link BytesReader#read(Bytes, long, Object)
* read(Bytes, size, value)} method, depending on what deserialization strategy is configured on
* the builder, using which this map was constructed. If the value deserializer is able to reuse
* the given {@code value} object, calling this method instead of {@link #get(Object)} could
* help to reduce garbage creation. <p> <p>The provided {@code value} object is allowed to be
* {@code null}, in this case {@code map.getUsing(key, null)} call is semantically equivalent to
* simple {@code map.get(key)} call.
*
* @param key the key whose associated value is to be returned
* @param usingValue the object to read value data in, if possible
@@ -102,20 +92,17 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
/**
* The method is similar {@link V getUsing(K key, V usingValue);} but in addition read locks
* the map segment to operations to be performed atomically. ( see the example below )
* <p>
* the map segment to operations to be performed atomically. ( see the example below ) <p>
* Returns the ReadContext which holds a map segment lock and provides method to get the value
* ( to which the specified key is mapped) atomically ( see example below for an explanation ),
* read to the provided {@code value} object, if possible, or returns {@code null}, if this map
* contains no mapping for the key.
* <p>
* <p>If the specified key is present in the map, the readContext.value() uses the provided
* {@code usingValue} object via value marshaller's {@link BytesMarshaller#read(Bytes, Object)
* read(Bytes, value)} or value reader's {@link BytesReader#read(Bytes, long, Object)
* read(Bytes, size, value)} method, depending on what deserialization strategy is configured on
* the builder, using which this map was constructed. If the value deserializer is able to reuse
* the given {@code usingValue} object, calling this method instead of {@link #get(Object)}
* could help to reduce garbage creation.
* contains no mapping for the key. <p> <p>If the specified key is present in the map, the
* readContext.value() uses the provided {@code usingValue} object via value marshaller's {@link
* BytesMarshaller#read(Bytes, Object) read(Bytes, value)} or value reader's {@link
* BytesReader#read(Bytes, long, Object) read(Bytes, size, value)} method, depending on what
* deserialization strategy is configured on the builder, using which this map was constructed.
* If the value deserializer is able to reuse the given {@code usingValue} object, calling this
* method instead of {@link #get(Object)} could help to reduce garbage creation.
* <pre>{@code
* try (ReadContext rc = map.getUsingLocked(key, bond)) {
* if (rc.present ()) { // check whether the key was present
@@ -127,16 +114,13 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
* } // the read lock is released here
* }</pre>
* To ensure that you can read the 'issueDate' and 'symbol' can be read atomically, these values
* must be read while the segment lock is in place.
* <p>
* <p>
* <p>The provided {@code value} object is allowed to be {@code null}, in this case
* must be read while the segment lock is in place. <p> <p> <p>The provided {@code value} object
* is allowed to be {@code null}, in this case
*
* @param key the key whose associated value is to be returned
* @param usingValue the object to read value data in, if possible
* @return the read context containing the value to which the specified key is mapped
* <p>
* no mapping for the key
* @return the read context containing the value to which the specified key is mapped <p> no
* mapping for the key
* @see #get(Object)
* @see #getUsing(Object, Object)
* @see ChronicleMapBuilder#valueMarshaller(BytesMarshaller)
@@ -145,32 +129,25 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
ReadContext<K, V> getUsingLocked(@NotNull K key, @NotNull V usingValue);
/**
* Acquire a value for a key, creating if absent.
* <p>
* <p>If the specified key is absent in the map, {@linkplain ChronicleMapBuilder#defaultValue(Object)
* default value} is taken or {@linkplain ChronicleMapBuilder#defaultValueProvider(DefaultValueProvider)
* default value provider} is called. Then this object is put to this map for the specified
* key.
* <p>
* <p>Then, either if the key was initially absent in the map or already present, the value is
* Acquire a value for a key, creating if absent. <p> <p>If the specified key is absent in the
* map, {@linkplain ChronicleMapBuilder#defaultValue(Object) default value} is taken or
* {@linkplain ChronicleMapBuilder#defaultValueProvider(DefaultValueProvider) default value
* provider} is called. Then this object is put to this map for the specified key. <p> <p>Then,
* either if the key was initially absent in the map or already present, the value is
* deserialized just as during {@link #getUsing(Object, Object) getUsing(key, usingValue)} call,
* passed the same {@code key} and {@code usingValue} as into this method call. This means, as
* in {@link #getUsing}, {@code usingValue} could safely be {@code null}, in this case a new
* value instance is created to deserialize the data.
* <p>
* In code, {@code acquireUsing} is specified as :
* value instance is created to deserialize the data. <p> In code, {@code acquireUsing} is
* specified as :
* <pre>{@code
* V acquireUsing(K key, V usingValue) {
* if (!containsKey(key))
* put(key, defaultValue(key));
* return getUsing(key, usingValue);
* }}</pre>
* <p>
* <p>
* Where {@code defaultValue(key)} returns either {@linkplain ChronicleMapBuilder#defaultValue(Object)
* default value} or {@link ChronicleMapBuilder#defaultValueProvider(DefaultValueProvider)
* defaultValueProvider.}
* <p>
* <p> <p> Where {@code defaultValue(key)} returns either {@linkplain
* ChronicleMapBuilder#defaultValue(Object) default value} or {@link
* ChronicleMapBuilder#defaultValueProvider(DefaultValueProvider) defaultValueProvider.} <p>
* <p>If the {@code ChronicleMap} is off-heap updatable, i. e. created via {@link
* ChronicleMapBuilder} builder (values are {@link Byteable}), there is one more option of what
* to do if the key is absent in the map. By default, value bytes are just zeroed out, no
@@ -207,8 +184,8 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
V putMapped(K key, @NotNull UnaryOperator<V> unaryOperator);
/**
* A special operation, similar to {@link #replace(Object, Object, Object)
* replace(key, value, value)}, but puts the entry even if it was absent in the map.
* A special operation, similar to {@link #replace(Object, Object, Object) replace(key, value,
* value)}, but puts the entry even if it was absent in the map.
*/
UpdateResult update(K key, V value);
@@ -245,16 +222,12 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
void putAll(File fromFile) throws IOException;
/**
* Creates an empty value instance, which can be used with the
* following methods :
* <p>
* {@link ChronicleMap#getUsing(java.lang.Object, java.lang.Object) }
* {@link ChronicleMap#getUsingLocked(java.lang.Object, java.lang.Object) }
* {@link ChronicleMap#acquireUsing(java.lang.Object, java.lang.Object) }
* {@link ChronicleMap#acquireUsingLocked(java.lang.Object, java.lang.Object) }
* <p>
* for example like this :
* <p>
* Creates an empty value instance, which can be used with the following methods : <p> {@link
* ChronicleMap#getUsing(java.lang.Object, java.lang.Object) } {@link
* ChronicleMap#getUsingLocked(java.lang.Object, java.lang.Object) } {@link
* ChronicleMap#acquireUsing(java.lang.Object, java.lang.Object) } {@link
* ChronicleMap#acquireUsingLocked(java.lang.Object, java.lang.Object) } <p> for example like
* this : <p>
* <pre>{@code
* V value = map.newValueInstance();
* try (ReadContext rc = map.getUsingLocked(key, value)) {
@@ -271,16 +244,12 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
V newValueInstance();
/**
* Creates an empty value instance, which can be used with the
* following methods :
* <p>
* {@link ChronicleMap#getUsing(java.lang.Object, java.lang.Object) }
* {@link ChronicleMap#getUsingLocked(java.lang.Object, java.lang.Object) }
* {@link ChronicleMap#acquireUsing(java.lang.Object, java.lang.Object) }
* {@link ChronicleMap#acquireUsingLocked(java.lang.Object, java.lang.Object) }
* <p>
* for example like this :
* <p>
* Creates an empty value instance, which can be used with the following methods : <p> {@link
* ChronicleMap#getUsing(java.lang.Object, java.lang.Object) } {@link
* ChronicleMap#getUsingLocked(java.lang.Object, java.lang.Object) } {@link
* ChronicleMap#acquireUsing(java.lang.Object, java.lang.Object) } {@link
* ChronicleMap#acquireUsingLocked(java.lang.Object, java.lang.Object) } <p> for example like
* this : <p>
* <pre>{@code
* K key = map.newKeyInstance();
* key.setMyStringField("some key");
@@ -311,5 +280,10 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
* @return the class of {@code <V>}
*/
Class<V> valueClass();
/**
* the name of the map
*/
String name();
}
@@ -71,26 +71,21 @@ import static net.openhft.lang.model.DataValueGenerator.firstPrimitiveFieldType;
* <p>
* ChronicleMap<Key, Value> map1 = builder.create();
* ChronicleMap<Key, Value> map2 = builder.create();}</pre>
* i. e. created {@code ChronicleMap} instances don't depend on the builder.
* <p>
* <p>{@code ChronicleMapBuilder} is mutable, see a note in {@link ChronicleHashBuilder} interface
* documentation.
* <p>
* <p>Later in this documentation, "ChronicleMap" means "ChronicleMaps, created by {@code
* ChronicleMapBuilder}", unless specified different, because theoretically someone might provide
* {@code ChronicleMap} implementations with completely different properties.
* <p>
* <p>{@code ChronicleMap} ("ChronicleMaps, created by {@code ChronicleMapBuilder}") currently
* doesn't support resizing. That is why you <i>must</i> configure {@linkplain #entries(long) number
* of entries} you are going to insert into the created map <i>at most</i>. See {@link
* #entries(long)} method documentation for more information on this.
* <p>
* <p>If you key or value type is not constantly sized and known to {@code ChronicleHashBuilder}, i.
* e. it is not a boxed primitive, data value generated interface, {@link Byteable}, etc. (see the
* complete list TODO insert the link to the complete list), you <i>must</i> provide the {@code
* ChronicleHashBuilder} with some information about you keys or values: if they are
* constantly-sized, call {@link #constantKeySizeBySample(Object)}, otherwise {@link
* ChronicleHashBuilder#averageKeySize(double)} method, accordingly for values.
* i. e. created {@code ChronicleMap} instances don't depend on the builder. <p> <p>{@code
* ChronicleMapBuilder} is mutable, see a note in {@link ChronicleHashBuilder} interface
* documentation. <p> <p>Later in this documentation, "ChronicleMap" means "ChronicleMaps, created
* by {@code ChronicleMapBuilder}", unless specified different, because theoretically someone might
* provide {@code ChronicleMap} implementations with completely different properties. <p> <p>{@code
* ChronicleMap} ("ChronicleMaps, created by {@code ChronicleMapBuilder}") currently doesn't support
* resizing. That is why you <i>must</i> configure {@linkplain #entries(long) number of entries} you
* are going to insert into the created map <i>at most</i>. See {@link #entries(long)} method
* documentation for more information on this. <p> <p>If you key or value type is not constantly
* sized and known to {@code ChronicleHashBuilder}, i. e. it is not a boxed primitive, data value
* generated interface, {@link Byteable}, etc. (see the complete list TODO insert the link to the
* complete list), you <i>must</i> provide the {@code ChronicleHashBuilder} with some information
* about you keys or values: if they are constantly-sized, call {@link
* #constantKeySizeBySample(Object)}, otherwise {@link ChronicleHashBuilder#averageKeySize(double)}
* method, accordingly for values.
*
* @param <K> key type of the maps, produced by this builder
* @param <V> value type of the maps, produced by this builder
@@ -208,6 +203,15 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
return ((dividend - 1L) / divisor) + 1L;
}
public String name() {
return name;
}
public ChronicleMapBuilder name(String name) {
this.name = name;
return this;
}
private static String pretty(int value) {
return value > 0 ? value + "" : "not configured";
}
@@ -325,9 +329,8 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
}
/**
* {@inheritDoc}
* <p>
* <p>Example: if keys in your map(s) are English words in {@link String} form, average English
* {@inheritDoc} <p> <p>Example: if keys in your map(s) are English words in {@link String}
* form, average English
* word length is 5.1, configure average key size of 6: <pre>{@code
* ChronicleMap<String, LongValue> wordFrequencies = ChronicleMapBuilder
* .of(String.class, LongValue.class)
@@ -354,8 +357,7 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
}
/**
* {@inheritDoc}
* <p>
* {@inheritDoc} <p>
* <p>For example, if your keys are Git commit hashes:<pre>{@code
* Map<byte[], String> gitCommitMessagesByHash =
* ChronicleMapBuilder.of(byte[].class, String.class)
@@ -379,17 +381,15 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
/**
* Configures the average number of bytes, taken by serialized form of values, put into maps,
* created by this builder. If value size is always the same, call {@link
* #constantValueSizeBySample(Object)} method instead of this one.
* <p>
* <p>{@code ChronicleHashBuilder} implementation heuristically chooses {@linkplain
* #actualChunkSize(int) the actual chunk size} based on this configuration and the key size,
* that, however, might result to quite high internal fragmentation, i. e. losses because only
* integral number of chunks could be allocated for the entry. If you want to avoid this, you
* should manually configure the actual chunk size in addition to this average value size
* configuration, which is anyway needed.
* <p>
* <p>If values are of boxed primitive type or {@link Byteable} subclass, i. e. if value size is
* known statically, it is automatically accounted and shouldn't be specified by user.
* #constantValueSizeBySample(Object)} method instead of this one. <p> <p>{@code
* ChronicleHashBuilder} implementation heuristically chooses {@linkplain #actualChunkSize(int)
* the actual chunk size} based on this configuration and the key size, that, however, might
* result to quite high internal fragmentation, i. e. losses because only integral number of
* chunks could be allocated for the entry. If you want to avoid this, you should manually
* configure the actual chunk size in addition to this average value size configuration, which
* is anyway needed. <p> <p>If values are of boxed primitive type or {@link Byteable} subclass,
* i. e. if value size is known statically, it is automatically accounted and shouldn't be
* specified by user.
*
* @param averageValueSize number of bytes, taken by serialized form of values
* @return this builder back
@@ -410,13 +410,11 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
/**
* Configures the constant number of bytes, taken by serialized form of values, put into maps,
* created by this builder. This is done by providing the {@code sampleValue}, all values should
* take the same number of bytes in serialized form, as this sample object.
* <p>
* <p>If values are of boxed primitive type or {@link Byteable} subclass, i. e. if value size is
* known statically, it is automatically accounted and this method shouldn't be called.
* <p>
* <p>If value size varies, method {@link #averageValueSize(double)} should be called instead of
* this one.
* take the same number of bytes in serialized form, as this sample object. <p> <p>If values are
* of boxed primitive type or {@link Byteable} subclass, i. e. if value size is known
* statically, it is automatically accounted and this method shouldn't be called. <p> <p>If
* value size varies, method {@link #averageValueSize(double)} should be called instead of this
* one.
*
* @param sampleValue the sample value
* @return this builder back
@@ -600,18 +598,14 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
/**
* Configures alignment strategy of address in memory of entries and independently of address in
* memory of values within entries in ChronicleMaps, created by this builder.
* <p>
* <p>Useful when values of the map are updated intensively, particularly fields with volatile
* access, because it doesn't work well if the value crosses cache lines. Also, on some
* (nowadays rare) architectures any misaligned memory access is more expensive than aligned.
* <p>
* <p>If values couldn't reference off-heap memory (i. e. it is not {@link Byteable} or "data
* value generated"), alignment configuration makes no sense and forbidden.
* <p>
* <p>Default is {@link Alignment#NO_ALIGNMENT} if values couldn't reference off-heap memory,
* otherwise chosen heuristically (configure explicitly for being sure and to compare
* performance in your case).
* memory of values within entries in ChronicleMaps, created by this builder. <p> <p>Useful when
* values of the map are updated intensively, particularly fields with volatile access, because
* it doesn't work well if the value crosses cache lines. Also, on some (nowadays rare)
* architectures any misaligned memory access is more expensive than aligned. <p> <p>If values
* couldn't reference off-heap memory (i. e. it is not {@link Byteable} or "data value
* generated"), alignment configuration makes no sense and forbidden. <p> <p>Default is {@link
* Alignment#NO_ALIGNMENT} if values couldn't reference off-heap memory, otherwise chosen
* heuristically (configure explicitly for being sure and to compare performance in your case).
*
* @param alignment the new alignment of the maps constructed by this builder
* @return this {@code ChronicleMapOnHeapUpdatableBuilder} back
@@ -174,6 +174,11 @@ class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
@Override
public long lastModificationTime(byte remoteIdentifier) {
if (remoteIdentifier == this.identifier()) {
System.out.println("remoteIdentifier=" + remoteIdentifier);
}
assert remoteIdentifier != this.identifier();
// purposely not volatile as this will impact performance,
@@ -198,6 +198,11 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
return vClass;
}
@Override
public String name() {
throw new UnsupportedOperationException("todo");
}
private void checkTimeout(long timeoutTime) {
if (timeoutTime < System.currentTimeMillis())
throw new RemoteCallTimeoutException();
@@ -93,6 +93,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
private final long lockTimeOutNS;
private final int segmentHeaderSize;
private final HashSplitting hashSplitting;
private final String name;
transient MapEventListener<K, V> eventListener;
transient BytesMapEventListener bytesEventListener;
@@ -174,11 +175,15 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
this.metaDataBytes = builder.metaDataBytes();
this.segmentHeaderSize = builder.segmentHeaderSize(replicated);
this.maxChunksPerEntry = builder.maxChunksPerEntry();
this.name = builder.name();
hashSplitting = HashSplitting.Splitting.forSegments(actualSegments);
initTransients(builder);
}
public String name() {
return name;
}
static <T> T newInstance(Class<T> aClass, boolean isKey) {
try {
return isKey ? DataValueClasses.newInstance(aClass) :
@@ -272,6 +272,11 @@ public class ReplicationCheckingMap<K, V> implements ChronicleMap<K, V> {
return map1.valueClass();
}
@Override
public String name() {
throw new UnsupportedOperationException("todo");
}
@Override
public V acquireUsing(@NotNull K key, V usingValue) {
return map1.acquireUsing(key, usingValue);
@@ -224,6 +224,11 @@ public class StatelessChronicleMapTest extends JSR166TestCase {
return d.valueClass();
}
@Override
public String name() {
throw new UnsupportedOperationException("todo");
}
@Override
public V putIfAbsent(K key, V value) {
return d.putIfAbsent(key, value);