Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

IDIEP-97
AuthorAnton Vinogradov 
Sponsor
Created

 

Status

Status
colourGreen
titleactive


Table of Contents

Motivation

Customers may want to 

  • minimize (compress)
  • protect (encrypt)

...

Ignite supports Disk Compression and Transparent Data Encryption, but they are able to transform the data at the persistent layer only.

Description

To cover both layers (network and memory) and make the feature compatible with the existing data, it is proposed to transform/restore CacheObject's bytes on the fly.

A possible solution is to transform the byte arrays they provided during the marshaling/unmarshalling phase. This will cover both layers, messaging (network) and storage (in-memory + persist).

Transformation

GridBinaryMarshaller already transforms objects to bytes. 

...

  • No-Op transformer will produce [-3, 3, 42, 0, 0, 0] or [-3, 9, 11, 0, 0, 0, 84, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103].
  • Pseudo-Crypto transformer, which adds 1 to every original byte, will produce [-3, 4, 43, 1, 1, 1] or [-3, 10, 12, 1, 1, 1, 85, 102, 116, 117, 33, 116, 117, 115, 106, 111, 104]
  • Magic-Compressor will produce [-3, 7] or [-3, 17], where 7 and 17 are the result of a magic compression.

CacheObjects

We need to cover all CacheObjects.

...

Code Block
languagejava
titleCacheObjectAdapter transformation
protected byte[] valueBytesFromValue(CacheObjectValueContext ctx) throws IgniteCheckedException {
    byte[] bytes = ctx.kernalContext().cacheObjects().marshal(ctx, val);

    return CacheObjectTransformerUtils.transformIfNecessary(bytes, ctx);
}


protected Object valueFromValueBytes(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException {
    byte[] bytes = CacheObjectTransformerUtils.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);
}

BinaryObjects

BinaryObject(Impl)s have different structures:

...

Code Block
languagejava
titleBinaryObjectImpl (un)marshalling
private byte[] arrayFromValueBytes(CacheObjectValueContext ctx) {
    return CacheObjectTransformerUtils.restoreIfNecessary(valBytes, ctx);
}

private byte[] valueBytesFromArray(CacheObjectValueContext ctx) {
    return CacheObjectTransformerUtils.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);
}

Transformer

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.

API

Code Block
languagejava
titleInterface
public interface CacheObjectTransformerManager extends GridCacheSharedManager {
    /**
     * Transforms the data.
     *
     * @param original Original data.
     * @return Transformed data (started with {@link GridBinaryMarshaller#TRANSFORMED} when restorable)
     * or {@code null} when transformation is not possible/suitable.
     */
    public @Nullable ByteBuffer transform(ByteBuffer original);

    /**
     * Restores the data.
     *
     * @param transformed Transformed data.
     * @return Restored data.
     */
    public ByteBuffer restore(ByteBuffer transformed);
}

...

Code Block
languagejava
titleCustom transformer
IgniteConfiguration getConfiguration() {
	IgniteConfiguration cfg = ...

	cfg.setPluginProviders(new XXXPluginProvider()); // Which provides some XXXCacheObjectTransformerManager()

    return cfg;
}

Examples

Compression example

Code Block
languagejava
titleCompression
class CompressionTransformer extends CacheObjectTransformerAdapter {
	protected ByteBuffer transform(ByteBuffer original) throws IgniteCheckedException {                     
		int overhead = 5; // Transformed flag + length.

        int origSize = original.remaining();
        int lim = origSize - overhead;              

		if (lim <= 0)             
        	return null; // Compression is not profitable.

        ByteBuffer compressed = byteBuffer(overhead + (int)Zstd.compressBound(origSize));    

		compressed.put(TRANSFORMED);
		compressed.putInt(origSize);    

		int size = Zstd.compress(compressed, original, 1);

 		if (size >= lim)
        	return null; // Compression is not profitable.          

		compressed.flip();          

        return compressed;
    }

    protected ByteBuffer restore(ByteBuffer transformed) {
        ByteBuffer restored = byteBuffer(transformed.getInt());

        Zstd.decompress(restored, transformed);

        restored.flip();
              
        return restored;
    }
}

Encryption example

Code Block
languagejava
titleEncryption
class EncryptionTransformer extends CacheObjectTransformerAdapter {
    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(transformed.remaining()); // Same size.
		
		while (transformed.hasRemaining())
            restored.put((byte)(transformed.get() - SHIFT));

        restored.flip();

        return restored;
    }
}

Risks and Assumptions

Transformation requires additional memory allocation and subsequent GC work.

Transformation requires additional CPU utilization.

Discussion Links

// Links to discussions on the devlist, if applicable.

Reference Links

// Links to various reference documents, if applicable.

Tickets

Jira
serverASF JIRA
columnIdsissuekey,summary,issuetype,updated,assignee,customfield_12311032,customfield_12311037,customfield_12311022,customfield_12311027,priority,status
columnskey,summary,type,updated,assignee,Priority,Priority,Priority,Priority,priority,status
maximumIssues20
jqlQueryproject = Ignite AND labels IN (iep-101) ORDER BY status
serverId5aa69414-a9e9-3523-82ec-879b028fb15b