Merge remote-tracking branch 'origin/master'

This commit is contained in:
Peter Lawrey
2014-10-27 19:49:50 +00:00
35 changed files with 1949 additions and 1153 deletions
@@ -76,6 +76,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
final MetaProvider<V, VW, MVW> metaValueWriterProvider;
final ObjectFactory<V> valueFactory;
final DefaultValueProvider<K, V> defaultValueProvider;
final PrepareValueBytesAsWriter<K> prepareValueBytesAsWriter;
final int metaDataBytes;
// private final int replicas;
@@ -101,7 +102,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
private final HashSplitting hashSplitting;
public VanillaChronicleMap(ChronicleMapBuilder<K, V> builder) throws IOException {
public VanillaChronicleMap(AbstractChronicleMapBuilder<K, V, ?> builder) throws IOException {
SerializationBuilder<K> keyBuilder = builder.keyBuilder;
kClass = keyBuilder.eClass;
@@ -123,6 +124,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
metaValueWriterProvider = (MetaProvider) valueBuilder.metaInteropProvider();
valueFactory = valueBuilder.factory();
defaultValueProvider = builder.defaultValueProvider();
prepareValueBytesAsWriter = builder.prepareValueBytesAsWriter();
lockTimeOutNS = builder.lockTimeOut(TimeUnit.NANOSECONDS);
@@ -356,13 +358,13 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
}
@Override
public V getUsing(K key, V value) {
return lookupUsing(key, value, false);
public V getUsing(K key, V usingValue) {
return lookupUsing(key, usingValue, false);
}
@Override
public V acquireUsing(K key, V value) {
return lookupUsing(key, value, true);
public V acquireUsing(K key, V usingValue) {
return lookupUsing(key, usingValue, true);
}
V lookupUsing(K key, V value, boolean create) {
@@ -713,18 +715,6 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
return (int) (sizeInBytes / entrySize) + 1;
}
/**
* Used to acquire an object of type V from the Segment. {@code usingValue} is reused to read the
* value if key is present in this Segment, if key is absent in this Segment: <ol><li>If {@code
* create == false}, just {@code null} is returned (except when event listener provides a value "on
* get missing" - then it is put into this Segment for the key).</li> <li>If {@code create ==
* true}, {@code usingValue} or a newly created instance of value class, if {@code usingValue ==
* null}, is put into this Segment for the key.</li></ol>
*
* @param hash2 a hash code related to the {@code keyBytes}
* @return the value which is finally associated with the given key in this Segment after execution of
* this method, or {@code null}.
*/
V acquire(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V usingValue,
long hash2, boolean create) {
if (create)
@@ -739,22 +729,23 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
if (offset >= 0L) {
return onKeyPresentOnAcquire(copies, key, usingValue, offset, entry);
} else {
boolean usingValuePassed = usingValue != null;
usingValue = tryObtainUsingValueOnAcquire(key, usingValue, create);
if (usingValue != null) {
// If `create` is false, this method was called from get() or getUsing()
// and non-null `usingValue` was returned by notifyMissed() method.
// This "missed" default value is considered as genuine value
// rather than "using" container to fill up, even if it implements Byteable.
offset = putEntry(copies, metaKeyInterop, keyInterop, key, keySize,
usingValue, create);
incrementSize();
if (usingValuePassed || !create)
notifyPut(offset, true, key, usingValue, posFromOffset(offset));
return usingValue;
} else {
if (!create)
return null;
if (defaultValueProvider != null) {
V defaultValue = defaultValueProvider.get(key);
copies = valueWriterProvider.getCopies(copies);
VW valueWriter = valueWriterProvider.get(copies, originalValueWriter);
copies = metaValueWriterProvider.getCopies(copies);
MetaBytesWriter<V, VW> metaValueWriter = metaValueWriterProvider.get(
copies, originalMetaValueWriter, valueWriter, defaultValue);
offset = putEntry(metaKeyInterop, keyInterop, key, keySize,
metaValueWriter, valueWriter, defaultValue);
} else {
offset = putEntry(metaKeyInterop, keyInterop, key, keySize,
prepareValueBytesAsWriter, null, key);
}
return onKeyAbsentOnAcquire(copies, key, keySize, usingValue, offset);
}
} finally {
if (create)
@@ -782,36 +773,26 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
V onKeyPresentOnAcquire(ThreadLocalCopies copies, K key, V usingValue, long offset,
MultiStoreBytes entry) {
skipReplicationBytes(entry);
V v = readValue(copies, entry, usingValue);
notifyGet(offset, key, v);
return v;
}
V tryObtainUsingValueOnAcquire(K key, V usingValue, boolean create) {
if (create) {
if (usingValue != null) {
return usingValue;
} else {
try {
usingValue = valueFactory.create();
if (usingValue == null) {
throw new IllegalStateException("acquireUsing() method requires" +
"valueFactory.create() result to be non-null. " +
"By default it is so when value class is" +
"a Byteable/BytesMarshallable/Externalizable subclass." +
"Note that acquireUsing() anyway makes very little sense " +
"when value class is not a Byteable subclass.");
}
return usingValue;
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
} else {
if (usingValue instanceof Byteable)
((Byteable) usingValue).bytes(null, 0L);
return defaultValueProvider.get(key, usingValue);
}
V onKeyAbsentOnAcquire(ThreadLocalCopies copies, K key, long keySize, V usingValue,
long offset) {
incrementSize();
MultiStoreBytes entry = entry(offset);
entry.skip(keySizeMarshaller.sizeEncodingSize(keySize) + keySize);
skipReplicationBytes(entry);
V v = readValue(copies, entry, usingValue);
notifyPut(offset, true, key, v, posFromOffset(offset));
notifyGet(offset, key, v);
return v;
}
void skipReplicationBytes(Bytes bytes) {
// don't skip
}
V put(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V value,
@@ -835,8 +816,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
}
}
// key is not found
long offset = putEntry(copies, metaKeyInterop, keyInterop, key, keySize, value,
false);
long offset = putEntry(copies, metaKeyInterop, keyInterop, key, keySize, value);
incrementSize();
notifyPut(offset, true, key, value, posFromOffset(offset));
return null;
@@ -861,37 +841,22 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
return prevValue;
}
/**
* Puts entry. If {@code value} implements {@link Byteable} interface and {@code usingValue} is {@code
* true}, the value is backed with the bytes of this entry.
*
* @param value the value to put
* @param usingValue {@code true} if the value should be backed with the bytes of the entry, if it
* implements {@link Byteable} interface, {@code false} if it should put itself
* @return offset of the written entry in the Segment bytes
*/
private long putEntry(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key,
long keySize, V value, boolean usingValue) {
long keySize, V value) {
copies = valueWriterProvider.getCopies(copies);
VW valueWriter = valueWriterProvider.get(copies, originalValueWriter);
copies = metaValueWriterProvider.getCopies(copies);
MetaBytesWriter<V, VW> metaValueWriter = metaValueWriterProvider.get(
copies, originalMetaValueWriter, valueWriter, value);
// "if-else polymorphism" is not very beautiful, but allows to
// reuse the rest code of this method and doesn't hurt performance.
boolean byteableValue = usingValue && value instanceof Byteable;
long valueSize;
MetaBytesWriter<V, VW> metaValueWriter = null;
VW valueWriter = null;
Byteable valueAsByteable = null;
if (!byteableValue) {
copies = valueWriterProvider.getCopies(copies);
valueWriter = valueWriterProvider.get(copies, originalValueWriter);
copies = metaValueWriterProvider.getCopies(copies);
metaValueWriter = metaValueWriterProvider.get(
copies, originalMetaValueWriter, valueWriter, value);
valueSize = metaValueWriter.size(valueWriter, value);
} else {
valueAsByteable = (Byteable) value;
valueSize = valueAsByteable.maxSize();
}
return putEntry(metaKeyInterop, keyInterop, key, keySize,
metaValueWriter, valueWriter, value);
}
private <E, EW> long putEntry(MKI metaKeyInterop, KI keyInterop, K key, long keySize,
MetaBytesWriter<E, EW> metaElemWriter, EW elemWriter,
E elem) {
long valueSize = metaElemWriter.size(elemWriter, elem);
long entrySize = entrySize(keySize, valueSize);
long pos = alloc(inBlocks(entrySize));
long offset = offsetFromPos(pos);
@@ -900,27 +865,13 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
keySizeMarshaller.writeSize(entry, keySize);
metaKeyInterop.write(keyInterop, entry, key);
writeValueOnPutEntry(valueSize, metaValueWriter, valueWriter, value, valueAsByteable,
entry);
hashLookup.putAfterFailedSearch(pos);
return offset;
}
void writeValueOnPutEntry(long valueSize, MetaBytesWriter<V, VW> metaValueWriter,
VW valueWriter, V value, Byteable valueAsByteable,
NativeBytes entry) {
valueSizeMarshaller.writeSize(entry, valueSize);
alignment.alignPositionAddr(entry);
metaElemWriter.write(elemWriter, entry, elem);
if (metaValueWriter != null) {
metaValueWriter.write(valueWriter, entry, value);
} else {
assert valueAsByteable != null;
long valueOffset = entry.positionAddr() - bytes.address();
bytes.zeroOut(valueOffset, valueOffset + valueSize);
valueAsByteable.bytes(bytes, valueOffset);
}
hashLookup.putAfterFailedSearch(pos);
return offset;
}
void clearMetaData(long offset) {