Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / C#

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

Rate me:
Please Sign up or sign in to vote.
4.00/5 (2 votes)
19 Feb 2019CPOL2 min read 5.1K   4   3
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.

C#
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.

C#
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:

C#
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.

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Europe Europe
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questioncorrections Pin
Nelek19-Feb-19 1:18
protectorNelek19-Feb-19 1:18 
AnswerRe: corrections Pin
Dan Ionescu (USINESOFT)19-Feb-19 23:24
Dan Ionescu (USINESOFT)19-Feb-19 23:24 
GeneralRe: corrections Pin
Nelek20-Feb-19 0:06
protectorNelek20-Feb-19 0:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.