...
ID | IEP-97 | ||||||||
Author | Anton Vinogradov | ||||||||
Sponsor | |||||||||
Created |
| ||||||||
Status |
|
...
...
Code Block | ||||
---|---|---|---|---|
| ||||
protected byte[] valueBytesFromValue(CacheObjectValueContext ctx) throws IgniteCheckedException { byte[] bytes = ctx.kernalContext().cacheObjects().marshal(ctx, val); return CacheObjectTransformerCacheObjectTransformerUtils.transformIfNecessary(bytes, ctx); } protected Object valueFromValueBytes(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { byte[] bytes = CacheObjectTransformerCacheObjectTransformerUtils.restoreIfNecessary(valBytes, ctx); return ctx.kernalContext().cacheObjects().unmarshal(ctx, bytes, ldr); } public void prepareMarshal(CacheObjectValueContext ctx) throws IgniteCheckedException { if (valBytes == null) valBytes = valueBytesFromValue(ctx); } public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { if (val == null) val = valueFromValueBytes(ctx, ldr); } |
...
It's not possible to just replace arr with valBytes because, unlike , for example, from CacheObjectImpl arr is not just a mashalled bytes, it's an object's value that is required, for example, to provide hashCode/schemaId/typeId/objectField, and we must keep it as is.
...
Code Block | ||||
---|---|---|---|---|
| ||||
private byte[] arrayFromValueBytes(CacheObjectValueContext ctx) { return CacheObjectTransformerCacheObjectTransformerUtils.restoreIfNecessary(valBytes, ctx); } private byte[] valueBytesFromArray(CacheObjectValueContext ctx) { return CacheObjectTransformerCacheObjectTransformerUtils.transformIfNecessary(arr, start, arr.length, ctx); } public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { if (arr == null) arr = arrayFromValueBytes(ctx); } public void prepareMarshal(CacheObjectValueContext ctx) { if (valBytes == null) valBytes = valueBytesFromArray(ctx); } |
...
Some customers may want to encrypt the data, some to compress it, while some just keep it as is.
So, we must provide a simple way to append any transformation.
...
Code Block | ||||
---|---|---|---|---|
| ||||
public interface CacheObjectTransformerSpiCacheObjectTransformerManager extends IgniteSpiGridCacheSharedManager { /** Additional space required to store the transformed data. */ public int OVERHEAD = 6; /** * Transforms the data. * * @param bytes Byte array contains the original Original data. * @param offset Data offset. * @param length Data length. * @return Byte array contains the transformed data @return Transformed data (started with non-filled area with {@link #OVERHEADGridBinaryMarshaller#TRANSFORMED} when size.restorable) * @throws IgniteCheckedExceptionor {@code null} when transformation is not possible/suitable. */ public byte[]@Nullable ByteBuffer transform(byte[] bytes, int offset, int length) throws IgniteCheckedException; ByteBuffer original); /** * Restores the data. * * @param bytes Byte array ending with the transformed data. * @param offset Transformed data offset. * @return Byte array contains the restored Restored data. */ public byte[]ByteBuffer restore(byte[] bytes, int offsetByteBuffer transformed); } |
...
Every customer may implement this interface in a proper way if necessary and specify it in the via plugin configuration:
Code Block | ||||
---|---|---|---|---|
| ||||
IgniteConfiguration getConfiguration() { IgniteConfiguration cfg = ... cfg.setCacheObjectTransformerSpisetPluginProviders(new XXXTransformerSpiXXXPluginProvider()); return // Which provides some XXXCacheObjectTransformerManager() return cfg; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
public abstract class CacheObjectTransformerSpiAdapterCompressionTransformer extends IgniteSpiAdapter implements CacheObjectTransformerSpiCacheObjectTransformerAdapter { ... /** * Transforms the data. protected ByteBuffer transform(ByteBuffer original) throws IgniteCheckedException { * * @param original Original data. int overhead = 5; // *Transformed @returnflag Transformed+ datalength. * @throws IgniteCheckedException whenint transformationorigSize is not possible/suitable.= original.remaining(); */ int protectedlim abstract= ByteBufferorigSize transform(ByteBuffer original) throws IgniteCheckedException;- overhead; /** * Restores the data. *if (lim <= 0) * @param transformed Transformed data. * @return Restored data. return null; // Compression is not profitable. */ ByteBuffer compressed protected= abstractbyteBuffer(overhead ByteBuffer restore(ByteBuffer transformed); } |
Code Block | ||||
---|---|---|---|---|
| ||||
class CompressionTransformerSpi extends CacheObjectTransformerSpiAdapter { private static final LZ4Factory lz4Factory = LZ4Factory.fastestInstance(); protected ByteBuffer transform(ByteBuffer original) throws IgniteCheckedException { int lim = original.remaining() - CacheObjectTransformerSpi.OVERHEAD; if (lim <= 0+ (int)Zstd.compressBound(origSize)); compressed.put(TRANSFORMED); compressed.putInt(origSize); int size = Zstd.compress(compressed, original, 1); if (size >= lim) return null; throw new IgniteCheckedException("// Compression is not profitable."); ByteBuffer compressed = byteBuffer(lim); Zstd.compress(compressed, original, 1); compressed compressed.flip(); return compressed; } protected ByteBuffer restore(ByteBuffer transformed, int length) { ByteBuffer restored = byteBuffer(lengthtransformed.getInt()); Zstd.decompress(restored, transformed); restored.flip(); return restored; } } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
class EncryptionTransformerSpiEncryptionTransformer extends CacheObjectTransformerSpiAdapterCacheObjectTransformerAdapter { private static final int SHIFT = 42; // Secret! protected ByteBuffer transform(ByteBuffer original) throws IgniteCheckedException { ByteBuffer transformed = byteBuffer(original.remaining() + 1); // Same capacity is required. transformed.put(TRANSFORMED); while (original.hasRemaining()) transformed.put((byte)(original.get() + SHIFT)); transformed.flip(); return transformed; } protected ByteBuffer restore(ByteBuffer transformed, int length) { ByteBuffer restored = byteBuffer(lengthtransformed.remaining()); // Same size. while (transformed.hasRemaining()) restored.put((byte)(transformed.get() - SHIFT)); restored.flip(); return restored; } } |
...