mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
163 lines
5.9 KiB
Plaintext
163 lines
5.9 KiB
Plaintext
= `DataAccess` and `SizedReader`
|
|
Neil Clifford
|
|
:toc: macro
|
|
:toclevels: 1
|
|
:css-signature: demo
|
|
:toc-placement: macro
|
|
:icons: font
|
|
|
|
toc::[]
|
|
|
|
This pair of interfaces is configured using `ChronicleMapBuilder.keyReaderAndDataAccess()` or
|
|
`valueReaderAndDataAccess()` for the key, or value type, of the map respectively.
|
|
|
|
The reader part, `SizedReader`, is the same as in <<CM_Tutorial_Sized.adoc#,`SizedWriter` and `SizedReader`>> pair. `DataAccess` is an "advanced" interface to replace `SizedWriter`.
|
|
|
|
The main method in `DataAccess` is `Data<T> getData(@NotNull T instance)`. It returns a `Data`
|
|
accessor which is used to write a "serialized" form of the instance to off-heap memory. `Data.size()`
|
|
on the returned `Data` object is used for the same purpose as the `SizedWriter.size()` method in
|
|
the <<CM_Tutorial_Sized.adoc#,`SizedWriter` and `SizedReader`>> pair interfaces. `Data.writeTo()`
|
|
is used instead of `SizedWriter.write()`.
|
|
|
|
`DataAccess` assumes that the `Data` object, returned from the `getData()` method is cached in some way. That is why it also has an `uninit()` method to clear references to the serialized object after a query operation to a Chronicle Map is complete to prevent memory leaks. This, in turn, implies that the `DataAccess` implementation is stateful. Therefore, `DataAccess` is made a sub-interface of
|
|
`StatefulCopyable` to force all `DataAccess` implementations to implement `StatefulCopyable` as well.
|
|
|
|
See <<CM_Tutorial_Understanding.adoc#, Understanding `StatefulCopyable`>> for more infromation
|
|
on this.
|
|
|
|
If your `DataAccess` implementation is not actually stateful, it is free to return `this` from the `StatefulCopyable.copy()` method.
|
|
|
|
The `DataAccess` interface is primarily intended for "serializing" objects that are already sequences of bytes, and in fact do not require serialization; for example, `byte[]`, `ByteBuffer`, arrays of Java
|
|
primitives. For such types of objects, `DataAccess` allows bypassing of the intermediate buffering, copying data directly from objects to Chronicle Map's off-heap memory.
|
|
|
|
For example, look at the `DataAccess` implementation for `byte[]`:
|
|
|
|
```java
|
|
public final class ByteArrayDataAccess extends AbstractData<byte[]> implements DataAccess<byte[]> {
|
|
|
|
/** Cache field */
|
|
private transient HeapBytesStore<byte[]> bs;
|
|
|
|
/** State field */
|
|
private transient byte[] array;
|
|
|
|
public ByteArrayDataAccess() {
|
|
initTransients();
|
|
}
|
|
|
|
private void initTransients() {
|
|
bs = HeapBytesStore.uninitialized();
|
|
}
|
|
|
|
@Override
|
|
public RandomDataInput bytes() {
|
|
return bs;
|
|
}
|
|
|
|
@Override
|
|
public long offset() {
|
|
return bs.start();
|
|
}
|
|
|
|
@Override
|
|
public long size() {
|
|
return bs.capacity();
|
|
}
|
|
|
|
@Override
|
|
public byte[] get() {
|
|
return array;
|
|
}
|
|
|
|
@Override
|
|
public byte[] getUsing(@Nullable byte[] using) {
|
|
if (using == null || using.length != array.length)
|
|
using = new byte[array.length];
|
|
System.arraycopy(array, 0, using, 0, array.length);
|
|
return using;
|
|
}
|
|
|
|
@Override
|
|
public Data<byte[]> getData(@NotNull byte[] instance) {
|
|
array = instance;
|
|
bs.init(instance);
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public void uninit() {
|
|
array = null;
|
|
bs.uninit();
|
|
}
|
|
|
|
@Override
|
|
public DataAccess<byte[]> copy() {
|
|
return new ByteArrayDataAccess();
|
|
}
|
|
|
|
@Override
|
|
public void writeMarshallable(@NotNull WireOut wireOut) {
|
|
// no fields to write
|
|
}
|
|
|
|
@Override
|
|
public void readMarshallable(@NotNull WireIn wireIn) {
|
|
// no fields to read
|
|
initTransients();
|
|
}
|
|
}
|
|
```
|
|
|
|
The `getData()` method returns `this`, and the `DataAccess` implementation implements the `Data` interface as well. This is recommended practice, because it reduces the number of objects involved (hence pointer chasing), and keeps `DataAccess`, and `Data` logic together.
|
|
|
|
The `Data` interface puts constraints on `equals()`, `hashCode()`, and `toString()` implementations. This is why `ByteArrayDataAccess` sub-class'es `AbstractData`, and inherits proper implementations from it.
|
|
A serializer strategy implementation can have `equals()`, `hashCode()`, and `toString()` from a very different domain, because those methods are never called on serializers inside Chronicle Map.
|
|
|
|
The easiest way to implement `equals()`, `hashCode()`, and `toString()` is to extend the `AbstractData` class. If it is not possible (perhaps the `Data` implementation already extends some other class), do this
|
|
by delegating to `dataEquals()`, `dataHashCode()`, and `dataToString()` default methods, provided in the `Data` interface.
|
|
|
|
Corresponding `SizedReader` for `byte[]`:
|
|
|
|
```java
|
|
public final class ByteArraySizedReader
|
|
implements SizedReader<byte[]>, Marshallable, ReadResolvable<ByteArraySizedReader> {
|
|
|
|
public static final ByteArraySizedReader INSTANCE = new ByteArraySizedReader();
|
|
|
|
private ByteArraySizedReader() {}
|
|
|
|
@NotNull
|
|
@Override
|
|
public byte[] read(@NotNull Bytes in, long size, @Nullable byte[] using) {
|
|
if (size < 0L || size > (long) Integer.MAX_VALUE) {
|
|
throw new IORuntimeException("byte[] size should be non-negative int, " +
|
|
size + " given. Memory corruption?");
|
|
}
|
|
int arrayLength = (int) size;
|
|
if (using == null || arrayLength != using.length)
|
|
using = new byte[arrayLength];
|
|
in.read(using);
|
|
return using;
|
|
}
|
|
|
|
@Override
|
|
public void writeMarshallable(@NotNull WireOut wireOut) {
|
|
// no fields to write
|
|
}
|
|
|
|
@Override
|
|
public void readMarshallable(@NotNull WireIn wireIn) {
|
|
// no fields to read
|
|
}
|
|
|
|
@Override
|
|
public ByteArraySizedReader readResolve() {
|
|
return INSTANCE;
|
|
}
|
|
}
|
|
```
|
|
|
|
NOTE: If you configure `byte[]` key, or value type, then this pair of serializers is used as the default.
|
|
|
|
'''
|
|
<<CM_Tutorial.adoc#,Back to Tutorial>> |