Specification - aboudnik/kv-framework GitHub Wiki

The purpose

The core KV framework is an extremely simplistic implementation of consistent storage for POJOs. It provides an opportunity to use various JSR-107 providers or even jdbc to build a transactional system to store objects in a key-value format.

Principles

Strong architectural principles make possible the minimalism in design:

simplicity

clean API, lambda transaction, no state machine, no annotations, persistent references, no concurrency

portability

no vendor-locks; works on any JSR-107 or even on jdbc data sources

consistency

coherency cache, ACID behavior for associated objects, supports rollback, optimistic execution

Statechart

Statechart

Getting started

Before start, you need to initialize the context, which is the interface for interaction with various providers such as Ignite:

Class[] classes = {ComplexRefTestEntry.class, ComplexTestEntry.class, ComplexTestEntry2.class, MutableTestEntry.class,
 RefTestEntry.class, TestEntry.class, Person.class};

TransactionFactory.getOrCreateTransaction(IgniteTransaction.class,
    () -> new IgniteTransaction(Ignition.getOrStart(new IgniteConfiguration())), true)
                .withCache(classes);

or Hazelcast

TransactionFactory.getOrCreateTransaction(HazelcastTransaction.class, 
    () -> new HazelcastTransaction(Hazelcast.newHazelcastInstance()), true);

After that we can start transaction like this:

Context tx = Context.instance();

By using open transaction we can:

  • save objects in persistent storage:
tx.transaction(new TestEntry("key"));

or

tx.transaction(() -> {
                new TestEntry("key").save();
            });

if we need to add additional logic

  • search for objects in it by class (used as the class of object stored in value) and key:
TestEntry actual = tx.get(TestEntry.class, "key");
  • as well as delete previously saved objects:
TestEntry entry = tx.get(TestEntry.class, "key");
tx.transaction(entry::delete); 

After describing required actions with object, transaction may be closed in two ways: saving the state of the objects after the actions described in the transaction are done (commit) or going back to the state before transaction begins (rollback). Transactions in framework made autoclosable, so there is no need to close them intentionally. In case of an unexpected error, an exception is thrown during the execution of actions and a rollback occurs. User still can initiate rollback manually, using rollback method on Context object:

tx.rollback();

After completion of commit, all changes made are saved in the persistent storage in a key-value format, where the current state of the object is the value and the key is the result of the operation for obtaining the key called on this object (usually this is some value stored in one of the object fields). Example of simple getKey() method:

@Override
public String getKey() {
    return url;
}

In case of rollback, no changes are made to the data stored in persistent storage.
For the convenience of the user, links are implemented - objects that store the class and object of this class - assumed that it may be used as reference to an object

Assumptions:

Framework has been built on top either one:

  • Key-Value storage (JSR-107 compatible) implementation
  • jdbc data source

Working with Java Beans implementing interface OBJ:

  • It means that we have default constructor

All code samples provided above and simple use cases may be founded in kv-test module of kv-framework.