Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Cachalot DB - Very Fast Transactional Database for .NET Applications - Part 3

0.00/5 (No votes)
19 Feb 2019 1  
About transactions

Introduction

This is the third part of a series concerning Cachalot DB. The first part can be found here and the second one here.

Two Stage Transactions

The most important thing to understand about two stage transactions is when you really need them.

Most of the time, you don’t.

An operation that involves one single object (Put, TryAdd, UpdateIf, Delete) is always transactional.

It is durable (operations are synchronously written to an append-only transaction log), and it is atomic. An object will be visible to the rest of the world only fully updated or fully inserted.

On a single-node cluster, operations on multiple objects (PutMany, DeleteMany) are also transactional.

You need two stage transactions only if you must transactionally manipulate multiple objects on a multi-node cluster.

As usual, let’s build a small example: a toy banking system that allows money to be transferred between accounts. There are two types of business objects: Account and AccountOperation.

public class Account
{
   [PrimaryKey(KeyDataType.IntKey)]
   public int Id { get; set; }

   [Index(KeyDataType.IntKey, true)]
   public decimal Balance { get; set; }
}

public class AccountOperation
{
   [PrimaryKey(KeyDataType.IntKey)]
   public int Id { get; set; }

   [Index(KeyDataType.IntKey)]
   public int SourceAccount { get; set; }

   [Index(KeyDataType.IntKey)]
   public int TargetAccount { get; set; }

   [Index(KeyDataType.IntKey, ordered:true)]
   public DateTime Timestamp { get; set; }

   public decimal TransferedAmount { get; set; }
}

Let’s create two accounts. No need for transactions at this stage.

var accountIds = connector.GenerateUniqueIds("account_id", 2);
var accounts = connector.DataSource<Account>();

var account1 = new Account {Id = accountIds[0], Balance = 100};
var account2 = new Account {Id = accountIds[1], Balance = 100};

accounts.Put(account1);
accounts.Put(account2);

When we transfer money between the accounts, we would like to simultaneously (atomically) update the balance of both accounts and to create a new instance of AccountOperation.

This is how the business logic could be implemented:

private static void MoneyTransfer
(Connector connector, Account sourceAccount, Account targetAccount, decimal amount)
{
    sourceAccount.Balance -= amount;
    targetAccount.Balance += amount;

    var tids = connector.GenerateUniqueIds("transaction_id", 1);
    var transfer = new AccountOperation
    {
        Id = tids[0],
        SourceAccount = sourceAccount.Id,
        TargetAccount = targetAccount.Id,
        TransferedAmount = amount
    };
    var transaction = connector.BeginTransaction();
    transaction.Put(sourceAccount);
    transaction.Put(targetAccount);
    transaction.Put(transfer);
    // this is where the two stage transaction happens
    transaction.Commit();
}

The operations allowed inside a transaction are:

  • Put
  • Delete
  • UpdateIf

If a conditional update (UpdateIf) is used and the condition is not satisfied by one object, the whole transaction is rolled back.

In-Process Server

In some cases, especially if the quantity of data is bounded and it can be stored on a single node, you can instantiate a Cachalot server directly inside your server process. This will give blazing fast responses as there is no more network latency involved.

In order to do this, pass an empty client configuration to the Connector constructor. A database server will be instantiated inside the connector object and communications will be done by simple in-process calls, not a TCP channel.

var connector = new Connector(new ClientConfig());

Connector implements IDisposable. Disposing the Connector will graciously stop the server. You need to instantiate the Connector once when the server process starts and dispose it once when the server process stops.

The fully open source code is available at:

    https://github.com/usinesoft/Cachalot

Precompiled binaries (including demo clients) and full documentation are available at:

    https://github.com/usinesoft/Cachalot/releases/latest

The client code is available as nuget package at nuget.org.

To install: Install-Package Cachalot.Client

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here