Property Storage Adapters

Overview

If you need to transform data (for example, compress or encrypt the value of a property) when it is copied from the user object to the SpaceClosed Where GigaSpaces data is stored. It is the logical cache that holds data objects in memory and might also hold them in layered in tiering. Data is hosted from multiple SoRs, consolidated as a unified data model., or vice versa, one way is to apply a storage adapter.

GigaSpaces provides a Property Storage Adapter API to create and denote a storage adapter for a property, as well as several general-purpose, built-in adapters that you can use out of the box, or extend to suit your needs.

The following built-in adapters are available:

  • BinaryAdapter - stores values in binary serialized format.
  • ZipAdapter - applies compression/decompression using the Zip algorithm.
  • AesCbcAdapter/AesGcmAdapter - encrypts/decrypts values using AES.

These adapters are described in more detail later on this page.

Applying a Property Storage Adapter

Use the @SpacePropertyStorageAdapter annotation to specify a storage adapter for a property. For example, suppose you have a class called Message with a string property called text, and you want to compress it before storing it in the Space, and decompress it when retrieving it. You can use the ZipAdapter built-in adapter as follows:

public class Message {
   // Additional properties and metadata are omitted for brevity
   private String text;

   @SpacePropertyStorageAdapter(ZipAdapter.class)
   public String getText() {
       return text;
   }
   public void setText(String text) {
       this.text = text;
   }
}

Alternatively, if you’re using a Space document and need to introduce the type explicitly, do the following:

SpaceTypeDescriptor typeDesc = new SpaceTypeDescriptorBuilder("Message")
       // Additional properties and metadata are omitted for brevity
       .addFixedProperty("text", String.class, ZipAdapter.class)
       .create();

Queries and Indexes

Querying Transformed Data

Storage adapters usually transform the property value, so naive matching of the query parameters against the Space value will yield incorrect results. For query execution to work correctly, the following conditions must exist:

  • The query parameters should undergo the same transformation as the property values. This is handled by the GigaSpaces query executor.

  • The transformation should be deterministic.

    For security reasons, the encryption adapter transformation is non-deterministic by default.

  • For equality matching, the stored value should override hashcode() and equals(). GigaSpaces provides a binary wrapper to facilitate storing byte arrays such as compressed or encrypted data.

  • For ordered matching, the stored value should preserve the original ordering.

    Compression and encryption don't support ordered matching.

When executing a query, the GigaSpaces query executor checks each property’s storage adapter (if any). If the storage adapter supports the query operation (equality/order), it performs the transformation, otherwise it throws an exception with an explanatory error message.

Each storage adapter indicates whether it supports matching using the supportsEqualsMatching() and supportsOrderedMatching() methods.

Indexing Property Storage Adapters

A property storage adapter can be indexed if the storage adapter supports the relevant matching. If the matching isn't supported, an exception is thrown with the appropriate error message.

Built-In Storage Adapters

The following storage adapters are provided with GigaSpaces.

You can extend the built-in storage adapters as needed, or add your own custom storage adapter as explained further down on this page.

Compression Storage Adapters

BinaryAdapter

The BinaryAdapter stores property values in binary serialized form. This has the following benefits:

  • Schema evolution support - The property is not deserialized in the Space, which allows users to incorporate application-specific schema evolution.
  • Smaller footprint - For some values/types, storing data in serialized form can reduce the memory footprint.
  • Lower CPU requirements - Values are stored in serialized form, so there’s no need to deserialize/re-serialize them when writing/reading from the Space.

ZipAdapter

The ZipAdapter compresses/decompresses properties using the Zip algorithm. The benefits of this storage adapter are the similar to those of the BinaryAdapter, with the following differences:

  • Smallest footprint - The memory footprint will likely be smaller than what is achieved with the BinaryAdapter storage adapter, depending on how well the value can be compressed.
  • Higher CPU requirements - This storage adapter requires more CPU resources to perform compression/decompression.

Encryption (AES) Storage Adapters

The encryption storage adapters provide encryption/decryption using the AES block cipher algorithm, which requires choosing a block cipher mode. GigaSpaces supports two common block cipher modes; CBC via the AesCbcAdapter, and GCM via the AesGcmAdapter.

Key/Passphrase

Even a strong encryption algorithm is vulnerable if the encryption key is leaked, and the question of how to store and protect this key is a common dilemma when dealing with encryption.

The GigaSpaces AES adapters derive the encryption key (and authentication key, if needed) from a passphrase provided by the user. The passphrase can be provided using one of the following properties:

  • com.gs.property-storage.aes.passphrase - provides the passphrase directly.
  • com.gs.property-storage.aes.passphrase-path - provides the path to a file containing the passphrase.

As we know, storing secrets in system properties is not recommended because of the ease with which they can be read from another process. As such, the passphrase property should be used for only for testing purposes. The passphrase-path property is more secure, assuming the access to the path is restricted. Alternatively, if you have a more secure means for storing and retrieving the passphrase, you can override the getPassPhrase() method to retrieve the passphrase accordingly.

Matching

As noted above, the GigaSpaces encryption storage adapters don't support matching by default for security reasons. A common rule of thumb in security is that encrypting the same plaintext multiple times produces different ciphertext each time, to prevent attackers from obtaining the information they need to crack the encryption or gain access to sensitive data.

For example, let's say that you have a Space class with a password property , and you encrypt it using an AES storage adapter. If the encryption is deterministic, an attacker can query the Space and request entries that are secured with password “123456”, and receive those entries, etc. In order to prevent this scenario, the AES algorithm scrambles the encryption with an additional component called an initialization vector, which is randomly generated.

If your use case requires matching encrypted content, and the potential risk inherent with deterministic encryption is acceptable, you can extend the relevant GigaSpaces encyption adapter (preferably CBC, because GCM is more vulnerable to non-unique initialization vectors), and do the following:

  • Override supportsEqualsMatching and set it to true.
  • Override generateInitializationVector(int length) and generate a non-random initialization vector (either empty or fixed).

Co-Located Execution

Storage adapters are triggered by the Space proxy. But in co-located execution (namely Processing UnitsClosed This is the unit of packaging and deployment in the GigaSpaces Data Grid, and is essentially the main GigaSpaces service. The Processing Unit (PU) itself is typically deployed onto the Service Grid. When a Processing Unit is deployed, a Processing Unit instance is the actual runtime entity. or Space tasks), the Space proxy is co-located with the Space on the server side, which may not have access to the encryption key. If this is the case, you can't write or read encrypted data. You can, however, use projections to read unencrypted properties, and perform change operations to change unencrypted properties.

Implementing a Custom Storage Adapter

To implement a custom storage adapter, you can create a class that extends the PropertyStorageAdapter. There are two abstract methods that you have to implement (toSpace and fromSpace), and everything else is optional.

Use the following guidelines for implementing a custom storage adapter:

Replacing the GigaSpaces StorageType

If you’re currently using the GigaSpaces Storage Types feature and want to use a property storage adapter instead, use the following guidelines to migrate between storage methods:

  • Replace @SpaceStorageType(storageType=StorageType.BINARY) with @SpacePropertyStorageAdapter(BinaryAdapter.class)
  • Replace @SpaceStorageType(storageType=StorageType.COMPRESSED) with @SpacePropertyStorageAdapter(ZipAdapter.class)
  • StorageType is not supported for primitive or String properties. GigaSpaces storage adapters are generic and therefore not limited to specific types, but in some cases implementing an adapter may not provide any benefit (for example, compressing short strings may result in longer strings after transformation).
  • StorageType can be set on classes, and then applied only to properties of that class with supported type. The GigaSpaces storage adapters don't have supported types but instead are set on properties, so they can't be set on the class level.

Limitations