blog

Business Processes Modeling and Execution using Mercury

The Mercury platform can be employed to model and execute business processes. Features such as transaction handling, the Nitrox container, persistency and messaging allow the rapid implementation of  business processes. Complex cases, including asynchronous task-execution and adaptable processes, are natively supported. Mercury serves as a Nitrox container that hosts and executes the business processes. It is the core application infrastructure to orchestrate various services into a single application. Since a process is composed of services it can span over multiple nodes and include remote components. In this post we will show how business processes are supported by Mercury.

General Concepts

To provide a flexible, event based implementation of processes that can be adapted during runtime we make use of principles behind Service Component Architecture (SCA) and Service Oriented Business Applications (SOBA). SCA defines a general architecture approach while SOBA describes the composition of services using SCA into a single business application.

The SCA specifications define how to create service-components and how to combine those components into complete applications. The principles behind SCA include:

  • Independence of programming language or underlying implementation
  • Independence of host container technology and loose coupling between the components
  • Metadata vendor-independence
  • Security, transaction and reliability modeled as policies
  • Recursive composition

Gartner’s Roadmap to SOA provides the following description: “SOBAs are business applications structured (in whole or part) using an SOA. SOBAs use Web service standards for Web-based messaging, application access and interfacing, and business process transactions. The majority of initial SOBAs are limited transformations of established applications that provide access to some functionality via service interfaces. New SOBAs will be constructed purely within an SOA. As services with standardized interfaces become more widely available, application functionality will be delivered by combining services to meet the needs of a particular user organization. These services may come from multiple suppliers.”

A possible use case is an Enterprise Resource Planning (ERP) System which is composed of various loose-coupled services. A business process can be part of such an application and is defined as a composition of tasks which are processed in a specific order. Compared to other systems, in Mercury no special business process engine is required for the execution of a process. Tasks are active and independent units which are executed asynchronously and if possible in parallel. In Mercury the underlying transaction system ensures consistency over the whole infrastructure during concurrent execution. Furthermore persistency of a process is automatically guaranteed at any stage, without mappings to a database system. Local tasks are implemented using Mercury’s native language Nitrox. This enables the implementation using standard object oriented software design. For remote components Mercury does not rely on any specific programming language or host container technology as long as the connectivity protocols are supported.

In Mercury a process is the equivalent to the SCA Domain. Each task corresponds to a component which can be addressed individually. Each class in Mercury corresponds to a service and each object to an addressable, remotely accessible service instance.

Setup

As an example we use a simple use case, the booking of a flight ticket. This will illustrate the ease of implementation and execution of a process in Mercury. The inputs to the process are one specific flight and a specific customer. Our process will span across three different nodes. The Mercury node is responsible to orchestrate the process, start the intermediate tasks and generate the final confirmation of the flight ticket. The second node, B is responsible to provide the current currency exchange rates required for billing. The third node, C will book the flight using a legacy application. This process under discussion is fully automatic and does not involve any human interaction.

 

SCA
Implementation

We begin by first modeling the process which will be decomposed into tasks with specific functionality that will be implemented. Tasks can be wired using delegates within the system or by messaging across nodes. Each task has to contain a delegate that will be invoked on completion and will be invoking the following remaining tasks. The interface of the delegate provides a constraint on how tasks can be composed into a process.

The implementation of the tasks will be conducted using the IDE plugin of the Mercury Workbench. For our example we first create the remote tasks to receive the currency rate and to book the flight. We then create a local task that will be executed if the two prior tasks succeed. This final task will simply send an e-mail to the customer that confirms the flight and its booking.

Once all tasks are implemented, the orchestration of the components is implemented too in the process class.

public Orchestrate(Flight flight,Customer customer){
    // instantiate the tasks
    currencyRateTask = new GetCurrencyRateTask(customer.DefaultCurrency);
    bookFlightTask = new BookFlightTask(flight,customer);
    sendConfirmationTask = new SendConfirmationTask();

    // Assemble the process
    Run += currencyRateTask.Run;
    Run += bookFlightTask.Run;
    currencyRateTask.InvokeNext += sendConfirmationTask.ConfirmRate;
    bookFlightTask.InvokeNext += sendConfirmationTask.ConfirmBooking;

    // Set the error handler
    bookFlightTask.onError += ErrorHandler;
    currencyRateTask.onError += ErrorHandler;
    sendConfirmationTask.onError += ErrorHandler;
}

Once a process is instantiated the whole event graph is generated. We have chosen to hard-code the orchestration of the components, but the same could be accomplished by defining a template process which would then be copied before execution.

After the implementation of internal and remote components, code for external tasks can be generated using our code generator. The code generator creates the logic that is required to interact with Mercury including messaging , access to parameters and properties and to return results from a remote component. Once the code is generated, as a final step, the remote tasks have to be implemented in any language of choice.

Execution

The execution of the process is started by creating a new instance of the Process and invoking its Start method. By doing this, all tasks are invoked by events that propagate trough the process. External events are invoked using messaging. The Process keeps an internal state that reflects the current state of the process such as NEW, READY, RUNNING, PROCESSED or FAILED. If a process state is PROCESSED or FAILED the execution came to a halt.

When the process is being executed, behind the scene the following takes place:

  1. A new Instance of the process is instantiated. This is done using the constructor of the Process class.
  2. The Start method of the process instance is invoked. Now the process is actually being executed. The process will now switch to the RUNNING state. The process first orchestrates the components and wires them using delegates to build an event graph before executing the Start method of the initial Tasks are are invoked.
  3. The process invokes the initial tasks, and as a consequence each task is being invoked. Once a task is completed, the delegate method starting the following task needs to be invoked.
  4. If an external task is being invoked the remote service will receive a message identifying the task that will be executed. After the task completes, the remote task switches its state to COMPLETED which then will notify the the next component to start its execution.
  5. After the process completes successfully the process will enter the PROCESSED state.

A process can be managed or monitored using any technology which is able to interact with Mercury. We envision REST over HTTP and Web 2.0 front ends as the technology of choice for this task.

Conclusion

The advantages of employing Mercury are manifold:

  • In mercury no distinction is made between remote or local service invocation since every object in Mercury is a service instance.
  • Communication within the system is very fast but still flexible.
  • Components can easily be exchanged for testing or migration.
  • Components can be reused and recursively composed.
  • There is little vendor lock in as components can be distributed over multiple nodes.
  • Applications are non-monolithic.
  • Legacy applications can easily integrated.
  • Multiple approaches for business process composition (Orchestration vs. Templates) can be applied.

Its native functionality makes Mercury a powerful application infrastructure to automate business processes. Many salient features support advanced business process management including case management, ad hoc processes, asynchronous execution or monitoring of processes. Using Mercury as the central system to implement business processes will speed up the development and provides a great environment to execute dynamic processes.


Mercury’s Nitrox Language & Compiler

Mercury’s Nitrox Language

One of the core components of the mercury system, is its compiler service. The ultimate goal of the compiler is to render nitrox programs into native machine code. All parts of mercury can be configured and extended through the nitrox language. Custom logic can be integrated on top of the database layer of mercury, by means of nitrox code. This exposes a powerful interface for constructing an event-driven model, which can be an integral part of the database, providing building blocks for an endless possibility of applications.

The nitrox language and its syntax attempts to be as much compliant as C# spec 4.0 as possible. The choice was not accidental;  C# is a powerful, expressive modern object oriented language, sporting a host of advanced features, such as delegates, events, dynamic binding or extension methods.

Our implementation closely follows the C# specification, and provides several commonly used parts of the CLR native
library (e.g. Math, DateTime etc.), without though bearing any other parts of a C# interpreter design. Nitrox further
adds several unique language features that are related with the mercury system, one prominent example being transactional code sections.

The role of nitrox in the mercury system, is to provide a uniform configuration and control language, that can be leveraged for any application need. Nitrox is mercury’s embedded extension language.

Mercury exposes an active object database system. Objects can be created through a variety of ways:

  • dynamically, via nitrox code
  • automatically as part of a protocol parser (e.g. FAST, FIX, Netflow)
  • using remote procedure calls

Mercury’s Compiler

The mercury compilation system is responsible for transforming nitrox code into native machine code. The process is comprised of several distinct stages and layers, commonly resembling those of a standalone compiler:

  1. the frontend C#/nitrox parser and lexer, analysing programs and constructing an abstract syntax tree reflecting the code.
  2. a type-resolution phase where all types such as classes, structs, interfaces, delegates and others will be symbolically defined without referencing other types.
  3. a type-completion stage at which all types are defined with a name and can be referenced. At this stage all types will be “completed”, this means resolving inheritance relations, methods, fields and everything else except statements.
  4. the semantic analyzer stage where the semantics and the correctness of types are checked, a symbolic representation of variables is created and all types that will be matched against the mercury type system are calculated.
  5. a mid-level transformation layer, that is able to  construct an intermediate representation of a program given its AST (abstract syntax tree) as an input. The intermediate representation (so-called MIL — Mercury Intermediate Language), embodies basic operations, primitives, statements and expressions, and is designed to closely model the final structure of the code to be transformed. MIL also provides a very cleanly separated abstraction layer between the mercury system and the final transformation layer, and allows for a number of optimizations. It is used internally by mercury, but not exposed externally.
  6. the final layer transforms MIL code into LLVM functions, built from primitives, statements, expressions and various higher-level programming constructs (such as switch statements, loops, conditionals etc)
  7. the last stage involves the LLVM JIT compiler that emits native binary machine code in-memory. This code is then associated with its corresponding method for some mercury class, and can be actively invoked by the runtime system.

There are a few distinct advantages in having a built-in mercury compiler:

  • it allows for complete control of the code,  e.g. dynamic optimizations
  • the integration with the rest of the system (object model, runtime etc), is very tight.
  • the object-model system can be dynamically extended at runtime
  • performance of code is optimal, since it is being transformed into native machine instructions.
  • the compilation of nitrox code can be controlled from nitrox code, a powerful feature usually available in functional programming languages, such as Lisp via its eval function. A similar feature is also currently planned to be provided for .NET via Microsoft’s Roslyn project, and termed “compiler-as-a-service”.
  • machine code is transparently persisted to secondary storage, so no re-compilation is required in case of system restart, avoiding the overhead that would be incurred by that process.
Since compilation in Mercury is based on an internal object model, the compilation process can be also invoked using remote message calls. This is possible from any of the supported languages’ API that mercury currently provides. For simplicity we have developed an IDE that abstracts those calls from the user and provides an Eclipse-like behavior for remote compilation on mercury.


Extending Mercury

By default mercury is equipped with basic models and functionality such as metadata management and possibly other native models, essential for the bootstraping and base operations of the system. To add application-specific behavior and extend mercury, different ways can be chosen. The most convenient and powerful way is to write a solution using our native language that we call Nitrox. Since mercury is a headless system the code will be written on a local client which connects to mercury and allows remote compilation and deployment of the custom code. The whole compilation infrastructure is modeled in Nitrox and can even be invoked during runtime. This allows to extend the system with dynamically compiled logic, using any of the available APIs, that is able to communicate with mercury.

Nitrox

Nitrox is the language we have implemented to execute individual logic on the server. Code written in Nitrox will be compiled into machine executable instructions similar to C or C++. The same language is used to define a data-model, and respectively the data model is derived from the code. We believe in strong typing and a strict model. Nitrox is a C# 4.0 derivative supporting object oriented programming, instead of declaring tables, triggers and stored procedures. The event driven nature of mercury allows to model behavior that can be commonly implemented using triggers without loosing the benefits of object oriented programming. Additionally to the functionality provided by C# we have further added some new features. In this post I will highlight three of them:

Dangling Code

Compared to C#, Nitrox allows statements and declaration of block fields in the scope of a namespace such as:

namespace Com.Addressbook {

   class Contact {
      private string _name;
      private string _email;
      public List<Contact> friends;

      public Contact ( string name ) {
          _name = name;
      }

      public Contact ( string name, string email ) {
          _name = name;
          _email = email;
      }
   }

   Contact alice = new Contact ( "Alice", "alice@wonderland.com" );
   alice.friends.Add ( new Contact("Bob") );
}

After successfully compiling this portion of code, and adding the new types to the system, Mercury will execute this program once. This will result in a new User object being created at runtime, and made available to interact with the rest of the system. The order in which the code of different namespaces is invoked is not defined. The advantage of this feature is that it can be leveraged to initialize the system during compilation. Dangling code can not be called at any other point during the runtime of the system, since there is no handle to the function and since it is design to be run once.

Object Creation

Objects can be created in multiple ways using Nitrox. To enforce creation constraints a constructor can be added to a class like in any object oriented language. By defining a constructor, objects can only be created using one of the public constructor methods. We have further designed an alternative way, in order to support creation of objects in a database-like manner. If no constructor is defined at all for a class, mercury will allow to derive any possible constructor during runtime. We call those constructors “implicit constructors“, and they are generated by the compiler in order provide additional flexibility.

For example:

namespace Com.Addressbook{

   class Contact {
      public string _name;
      public string _email;
      public List<Contact> friends;
   }

   Contact alice = new Contact(_name:"Alice",_email:"alice@wonderland.com");
   alice.friends.Add(new Contact(_name:"Bob"));
}

To invoke the constructor named parameters can be used, and only the provided values will be set. This has is especially useful to create an object and set multiple fields with a single line of code.

Object Repositories

For every class in Mercury a so-called  object repository exists. A repository allows access to all objects of a type in an object oriented way. Compared to other programming languages, it is possible that objects are not lost if they are not referenced by any other object. For above example all Users objects can be accessed very easily:

foreach(Contact c in Contact.Objects) {
   Console.WriteLine(c._name);
}

Objects is a C# equivalent Property returning a ContactRepository class which implements an enumeration interface.

As a comparison the same in PL/SQL:

CREATE TYPE contact;
CREATE TYPE friend_list AS VARRAY(50) OF contact

CREATE TYPE contact AS OBJECT (
   name VARCHAR2(30),
   email VARCHAR2(20),
   friends REF friend_list;
);

DECLARE

alice contact;

BEGIN

   alice := contact(‘Alice’,‘alice@wonderland.com’);

   alice.friends := friend_list(contact(‘Bob’,));

COMMIT;

END;

or the loop:

DECLARE

CURSOR myCursor IS SELECT * FROM contact;

v_add contact%ROWTYPE;

BEGIN

FOR c IN myCursor LOOP

   dbms_output.put_line(c.name);

END LOOP;

END;

 

In future posts we will dive deeper into Mercury’s compiler infrastructure and further language extensions such as transaction support. Let us know if you would like to hear more about a specific topic.


Building a system from scratch is not “re-inventing the wheel”

Introduction

Mercury is quite a complex system containing many technologically advanced features. People often ask about the idea behind our solution and why it was required to develop a new technology stack from scratch.

In 2006, the initial draft of Mercury was addressing the fact that an operating system adds unnecessary and undesired abstraction layers to a database, a fact that needs to be compensated by carefully designing the application. During the development, influenced by other projects, it became clear that besides performance there are many other shortcomings of traditional database systems. In this post, insight into the approach, rationale and philosophy that drive the development of mercury will be unfolded.

Approach

The approach that was taken to develop mercury is quite radical. An entire technology stack was developed from scratch. Based on proven concepts and own inventions a completely new system emerged, many development cycles took place and parts were reengineered to suit customer needs. During the development of the in-memory database, persistent storage, transaction system, runtime and compiler we always ensured to provide low latency access in an object oriented as well as relational way. For this reason a special memory layout that enables both, data navigation and querying, was chosen. The current implemented model provides the best of both worlds. To ensure that concurrency can be handled transparently we added software transactional memory which is used for database transactions as well to ensure concurrency of program logic. ACID properties are guaranteed by the transaction system and an atomic store that provides persistency to data and logic. Mercury directly persists the memory image removing the requirement to transform data during read or write operations to external disks. To implement extension logic we developed Nitrox, a C# derivative which is compiled directly into machine native executable instructions. The compiler also creates code-wrappers allowing the direct integration of logic into service oriented landscapes. The event driven architecture provides support to execute logic based on internal or external events such as transaction commit status, or timers that expire.

The platform carefully uses only a few posix interfaces to access the operating systems resources. To make the system scale optimally though, and speed up performance-crucial parts, such as transactions, direct access to operating system internals was required. As an example, controlling the demand paging decision logic directly from the platform, also allows the  implementation of optimal and customized paging algorithms that fit our application demands.

In collaboration with ETH Zurich and the help of KTI, the stailaOS project was launched to develop an application specific operating system kernel which provides the flexibility that we required and which is able to support Mercury’s ultimate goal, to add hardware-assisted transactional memory. Working in synergy with stailaOS, Mercury will be the first runtime-extendable kernel that can be programmed from a high level language.

Rationale

Current enterprise database systems have been originally designed three decades ago, and without doubt they represent great engineering work. Their architecture though was laid out for operating systems that where targeting existing hardware, and were faced with several inherent limitations. Since then, new interruptive technology has been developed, including SSD devices that allow fast random access to persisted data, or many-core processors that allow the parallel execution of logic. Operating systems support these technologies; but the existing architectures of legacy database systems are unable to utilize them to their full benefit. Michael Stonebreaker even states that relational database systems should be considered legacy technology. Further, any high-performance system that runs on top of a general-purpose OS kernel, usually suffers from overhead induced by system calls that add up latency, and from multiple layers of buffer management and caching of the operating system, which needs to be tuned carefully in order to minimize the performance impact. Also, database techniques such as pointer-swizzling add much latency when data is paged-in or out. There are many other such constraints that guided us in our work.

Database applications often use logic such as triggers or stored procedures which are directly implemented on top of the relational database system. Definition of such logic happens using legacy languages that are not reflecting a modern development environment. Furthermore databases allow the declarative definition of logic and hinder the use of a single programming model that can be used over several system components. Using relational mappers or model driven development does also not provide the ideal solution since code must still be touched and maintained.  Mercury provides a NoSQL-like approach to applications, but in an enterprise-grade fashion.

A new technology stack needs to emerge for event driven solutions. We believe that Mercury is that stack.

Our Philosophy

It is the philosophy behind Mercury to provide customers a whole new experience when developing applications. We want customers to spend their time on their core business without facing technological hurdles. The Mercury platform is a great solution for rapidly developing fast running applications.

To achieve this, just another database is not good enough. We believe that some major paradigms need to be shifted to allow this. Not only parallel applications should be easy to write, but further the development of business logic needs to be as smooth as possible, and there should be no need to worry about persistency, mapping and data-access. The modularity of such a system should be much higher than what current solutions provide. The development of a fast application should not be difficult even if there is database access involved. A system should run without major maintenance and up keep. For providing all of this, only a single, unified programming model should be required. The problems that mercury addresses are manifold; clearly a system that enables customers to write fast applications is delivered. But performance increase is not the only advantage, reducing the impedance mismatch of a database and a programming language and providing the highest degree of flexibility that is expected when developing and extending a system.

This all makes Mercury a one-stop to develop fast event driven database applications. And this is why.


Mercury: An Alternative to Application Server and Relational Database

Introduction

Mercury is a low-level modular enterprise platform based on state-of-art technology, written in C. At its core, it contains a tightly integrated fail-safe persistence module, transactional memory support, an inbuilt compiler which is part of the runtime system, an in-memory database and messaging functionality. It is a promising technology that can replace traditional application servers and relational databases thereby reducing development cost and overall cost of ownership.  The following sections describe how Mercury, staila technologies’ flagship product, can make a difference and how it can prove to be a disruptive technology.

Unification of Application and Database

Mercury is a hybrid between an application server and a database. The data is viewed as objects as well stored as objects. A major benefit of this approach is the unification of the application and database development into a seamless data model and language environment. As a result, applications require less code, use more natural data modeling, and code bases are easier to maintain. The developers can write complete database applications with a modest amount of additional effort.

No Mapping Layer

Another direct impact of the unified application and database model is that Mercury does not have to convert objects to serialized ASCII formats or break them down to fit into rigid row and column constructs while storing or retrieving data. It stores objects and their complex relationships, such as many-to-many or network relationships, to the database eliminating the need for JOIN tables. By removing the mapping layer, it not only saves programming time but it also makes data storage and retrieval faster spending fewer CPU cycles. Thus an application’s throughput, capacity and scalability are enhanced to a great extend. Mercury enables real time management for applications rich in complex inter-related data analysis and display possible.

Time complexity of retrieving N objects related to an object A in Mercury and in a Relational Database.

  • RDBMS  O(N * LogN)
  • Mercury O(N + LogN)

Managing Complex Data

Mercury is a perfect system for handling complex data and their complex relationships, where the traditional databases fail to give predictable performance. The data that contains variable length attributes and fields, such as multi-dimensional arrays, do not naturally fit into the design of a relational database. Such data have to be flattened to fit into a row-and-columns paradigm, which wastes lot of valuable CPU cycles and application time. Also the complex relationship among data, such as many-to-many relationships, can not be handled by a relational database without using costly JOIN operations.

High Scalability

The object oriented nature of the data storage and the use of optimistic transactional memory for concurrency control gives Mercury high scalability. A large number of threads access the system in parallel without blocking or serializing the queries. On a commodity hardware we have been able to achieve more than 50,000 object inserts per second.

In-memory Data Management

In Mercury, all data is always present in main memory unlike other system where only hot data is cached and kept in main memory. Thus, no matter in what pattern the data is accessed it is always served from the main memory and the system’s throughput is improved by an order of magnitude. Notably, it takes 10 CPU cycles to read a byte from the main memory while it takes almost 1000 CPU cycles to read the same byte from a hard disk. This feature makes Mercury to perform even better than regular object oriented databases.

Persistence

Mercury manages data in main memory but it still provides ACID guarantees along with efficient persistency. It is optimized for modern SSD drives and has all the desired features that a database administrator wants, like crash recovery, check-pointing, consistency checks etc.

Multiple Programming Language Support

Mercury supports multiple programming languages like Java and C#. Connectors are available even for Matlab and C. An XML extension is also available, which means data can be uploaded and downloaded in the form of XML files, containing object descriptions.

Platform Independent Development

Mercury client is a platform independent software than be installed on any operating system and can be even extended by the user.

Conclusion

The above discussed features of Mercury makes it better suited for applications such as financial portfolio risk analysis systems, telecommunications service applications, world wide web document structures, design and manufacturing systems, and hospital patient record systems, which have complex relationships between data and yet are  performance critical.


Error Handling in C without using goto

What is error handling?

In a programming language like C where there is no support for exception handling and garbage collection, the programmers have to make sure that a program comes out of an error condition gracefully. On encountering an error a program must rollback and free-up various resources allocated during the course of execution. Ideally, the program should get back to a state where it was consistent before the error happened.

 

Why error handling is important?

Absence of error handling or a buggy error handling can lead a program or the system as whole to an inconsistent state. Often many fatal programming bugs such as memory leaks, dead locks, data race conditions etc. are the results of an improper error handling. Especially in a programming environment where resources are scarce and margin of error is thin adapting to a good error handling technique becomes even more important.

 

Common error handling techniques

There are mainly two techniques used by professional C programmers to handle errors. The first one is where a program on encountering an error un-dos the changes and returns from the same code location. As a sample following is a C function that inserts some string in a linked list node if the string is already not present. It returns pointer to head of the linked list in case of success or NULL otherwise. Notice the error handling technique used in the program.

struct lnode {
        char *str;
        struct lnode *next;
};

struct lnode *insert(char *data, int len, struct lnode *list) {
        struct lnode *p, *q;

        p = (struct lnode *)malloc(sizeof(struct lnode));
        if ( NULL == p ) {
                return NULL;
        }

        p->str = (char *)malloc(sizeof(char)*len);
        if ( NULL == p->str ) {
                // free node before returning.
                free ( p );
                return NULL;
        }

        memcpy ( p->str, data, len );

        if(NULL == list) {
                p->next = NULL;
                list = p;
        } else {
                q = list;
                while(q->next != NULL) {
                        // check for duplicates
                        if (0 == strcmp(q->str,p->str)) {
                                // free string and node
                                free(p->str);
                                free(p);
                                return NULL;
                        }
                        q = q->next;
                }
                p->next = q->next;
                q->next = p;
        }
        return list;
}

In this case error is handled by freeing up memory allocated so far and returning from the same place. It is a very simple way of handling error gracefully but it has several demerits. It makes the function look complicated as it has multiple exit points (return statements). In this approach if the error handling part of the code grows large then the code can become really unmanageable. Thus such a technique of error handling can be used, at the most, only in functions which are quite small in size.

The second type of error handling technique, which is very popular among Linux Kernel developers, is implemented by using C statement goto. In case of an error the program control jumps to a suitable error handling block of the function, does necessary cleanup and returns from there. The same list insert sample function has been modified to show the goto error handling technique, following is the modified code.

struct lnode *insert(char *data, int len, struct lnode *list) {
        struct lnode *p, *q;

        p = (struct lnode *)malloc(sizeof(struct lnode));
        if ( NULL == p ) {
                // unable to allocate
                goto out;
        }

        p->str = (char *)malloc(sizeof(char)*len);
        if ( NULL == p->str ) {
                // unable to allcoate
                goto out_free_p;
        }

        memcpy ( p->str, data, len );

        if(NULL == list) {
                p->next = NULL;
                list = p;
        } else {
                q = list;
                while(q->next != NULL) {
                        // check for duplicates
                        if (0 == strcmp(q->str,p->str)) {
                                //duplicate entry found
                                goto out_free_str;
                        }
                        q = q->next;
                }
                p->next = q->next;
                q->next = p;
        }

        // we are here that  means success
        return list;

out_free_str:
        free(p->str);
out_free_p:
        free(p);
out:
        return NULL;
}

The biggest advantage of this technique over the previous one is that it has a separate block where all error handling code is kept and  has a single exit point. This makes code quite readable as well (of course with the help of nice lable names). While writing an error handling block the order in which cleanup has to be done should be taken in account (this is true for all error handling techniques). An incorrect order can lead to problems like memory leak or even deadlocks. The thumb rule is that the cleanup should be done in exactly the reverse order as compared to the normal flow of program. Thus a programmer adding a new block of code that allocates some resource has to make sure that he adds a corresponding error handling block taking care of the order in which resources were allocated. Often in large functions this ordering is not noticed correctly thereby introducing nasty bugs! .

Error handling in C without goto

It is possible to write error handling code without using goto statement yet preserving all the advantages of the previous error handling techniques. Let us start rewriting our sample C function using new error handling method. To start with, let us have a local varibale, sayuint8_t good, to keep track of the current state of the program in the current function. Also, let us have a structure, say struct cleanup, that keeps track of all allocated resources in the current function.

        uint8_t good;
        struct {
                uint8_t alloc_node : 1;
                uint8_t alloc_str : 1;
        } cleanup = { 0, 0 };

All the fields of the cleanup structure is cleared in the beginning. The fields are set one by one as soon as the corresponding resource is allocated. At the same time the state tracking variable good is set or unset according to success or failure in acquiring that resource. In our linked list example the code to allocate memory for linked list node will look like this

       p = (struct lnode *)malloc(sizeof(struct lnode));
       good = cleanup.alloc_node = (p != NULL);

As you can see the variable good is set or cleared automatically depending upon return value of the malloc function. Thus it correctly stores the current state of program (ie. good or not good). The program should proceed only if the current is good. Hence the code that allocates memory for string in our program should look like this

       if (good) {
                p->str = (char *)malloc(sizeof(char)*len);
                good = cleanup.alloc_str = (p->str != NULL);
        }

In the end just before returning from the current function there has to be an error handling block that takes care of cleanup if the program is not in good state.

      if(!good) {
                if(cleanup.alloc_str)   free(p->str);
                if(cleanup.alloc_node)  free(p);
        }

        // good? return list or else return NULL
        return (good? list: NULL);

Though the order in which the cleanup is done in the error handling block is still important. But in this technique there is one advantage, a programmer can easily verify the order of resource allocation by looking at the cleanup structure field (provided that they are in correct order). The final code rewritten looks like this:-

struct lnode *insert(char *data, int len, struct lnode *list) {
        struct lnode *p, *q;
        uint8_t good;
        struct {
                uint8_t alloc_node : 1;
                uint8_t alloc_str : 1;
        } cleanup = { 0, 0 };

        // allocate node.
        p = (struct lnode *)malloc(sizeof(struct lnode));
        good = cleanup.alloc_node = (p != NULL);

        // good? then allocate str
        if (good) {
                p->str = (char *)malloc(sizeof(char)*len);
                good = cleanup.alloc_str = (p->str != NULL);
        }

        // good? copy data
        if(good) {
                memcpy ( p->str, data, len );
        }

        // still good? insert in list
        if(good) {
                if(NULL == list) {
                        p->next = NULL;
                        list = p;
                } else {
                        q = list;
                        while(q->next != NULL && good) {
                                // duplicate found--not good
                                good = (strcmp(q->str,p->str) != 0);
                                q = q->next;
                        }
                        if (good) {
                                p->next = q->next;
                                q->next = p;
                        }
                }
        }

        // not-good? cleanup.
        if(!good) {
                if(cleanup.alloc_str)   free(p->str);
                if(cleanup.alloc_node)  free(p);
        }

        // good? return list or else return NULL
        return (good? list: NULL);
}

 

Conclusion

To summarize, there are several advantages of using using above described error handling technique. The important ones are mentioned below:-

  • It eliminates goto statement from the program.
  • Determining order of cleanup becomes easier.
  • There is only one exit point in the function, even if there is an error.
  • It makes the code more readable and intuitive.

stailaOS: A high performance Operating System

Introduction

stailaOS is a high performance application-specific operating system developed in collaboration with Native Systems Group of ETH Zurich (Swiss Federal Institute of Technology). It can be seen as an OS that hosts an application server and an in-memory database natively in its kernel space thereby providing sustained and predictable performance. stailaOS is going to give a new dimension to in-memory data management technology.

The OS is designed to be lightweight and supports only the minimal set of required devices, like SATA disks and network interfaces. The applications running on stailaOS are able to avoid overheads incurred in a general purpose operating system. As an example, there is no system call overhead in stailaOS, the applications can access low level resources without switching to kernel mode. This results in increased responsiveness of the application and it is able to deliver predictable performance.

Technology

Single process, Multithreaded System

stailaOS is a single process and multithreaded system which means all the threads share the same address space (vitrual adress space and page table is shared). This design helps in minimizing the context switch delays. Time taken by a context switch in an OS becomes even more critical in a parallel system where the number of threads exceeds the number of logical CPUs. Thus lowering this delay decreases the application’s latency.

Scalable and optimized for modern multicore architectures

The core datastructres of stailaOS are designed keeping in mind the ccNUMA properties of  modern processors. The kernel data structures are partitioned between cores taking care of various levels of CPU caches and memory interconnects. The critical OS resources are distributed in nature and are available with least contention to applications. This distributed resource model not only reduces latency but also helps in reducing overall inter-CPU traffic generated during runtime. We plan to further enhance and fine tune the kernel data structures. The thread scheduling algorithm of the OS is cache-aware too, which makes the system more efficiently scalable.

Hardware Assisted Transactional Memory System

A unique hardware assisted Transactional Memory System is integrated into stailaOS.  The  system is built around processor’s MMU and virtualization support. It aims to achieve the performance of fine grained locking with the flexiblity and ease of  traditional database transactions. It is a suitable tool for parallel data procressing.

Specialized Memory Managers

Any complex system, such as a high performance data processing application, needs different types of specialized memory managers for different types of memory usage behaviour.  stailaOS includes a set of specialized memory managers for different subsystem needs. As an example, each running transaction uses a specialized stack based memory manager where it needs to allocate memory regions of different sizes during it’s lifetime, and free them when the transaction commits.

Storage Engine

stailaOS has an inbuilt storage engine for supporting data persistence in the system. It is roughly analogous to a file system but, additionally, it is ACID complaint (the semantics are borrowed from database theory), and in contrast to a regular file system it does not need to provide the abstraction of a file-based hierarchical arrangement. The storage engine can write large number of blocks atomically yet in parallel to a raw disk. It is optimized to achieve maximum performance with modern SSDs.

Conclusion

stailaOS has the potential to solve many real world problems. It is an ideal solution for applications like real-time analytics, high frequency trading systems and many more.

 


Redesigning System for In-memory Data Management

In-memory Data Management

There was a time when DRAM was a costly electronic item and even high-end computers were able to accommodate only a few GBs of DRAM. But today the DRAM chips have become much cheaper ($10 per GB or so) and even a standard commodity computer has a capacity to load 100-200GB of DRAM. Moreover with the advent of Nehalem (and its successors) based processors, the distance between main memory and CPU cores have decreased drastically (the memory controller is in the same package where processor cores are). Thus, it’s time to change–change the way data is managed. Replacing traditional storage disks (and even modern SSDs) with DRAM has more than one advantage viz. (i) real time information retrieval (ii) real-time analytics and on-the-fly computation (iii) low total cost of ownership.

Since long the main memory is being used by traditional DBMS for data caching and data processing. The idea of in-memory data management is not new, some of the big names in the industry are using traditional databases for their data management while they use software layers like memcached for caching objects and data processing. However, such techniques are able to solve speed and latency problem only up to a certain extent.

Media Price ($/GB) Bandwidth BW:Price (GBps/$ )
HDD 0.10 50MB/s 0.488
SSD 1.5 2GB/s 1.33
DRAM 8 20GB/s 2.5

The applications that need consistent and predictable performance must change their data management technology so that they can take advantage of modern hardware advancements.

Redesigning Architecture

We, at staila technogies, have designed and implemented a unique solution to manage and process data completely in the main memory and persisting it on SSDs. We came up with an object-oriented in-memory database accompanied with a storage engine. It simplifies data management and removes unnecessary complexities of a traditional database, file system and swaping engine. On the one hand it has all the advantages of an in-memory database while on the other hand it can persist data across the boots. An inbuilt transaction engine provides much needed consistency to the system.

The transaction engine is a hybrid between a software transactional memory (STM) and a relational database transaction manager. It helps in maintaining consistency and also provides a tool to make the system highly parallel. Each running thread starts a new transaction and then updates shared memory in isolation under this transaction. In this way threads run and update data optimistically without being blocked.

The underlying storage engine is designed to replace the filesystem as well as the swaping system of the OS. As all the data and code (logic) are supposed to reside in the main memory, it is not a good idea to convert the data and code residing in memory first into “files” and then write them to the disk like done in regular databases. In case of memory crunch the system starts freeing up memory by swaping out content of the main memory to the disk. This involves complex book keeping and going through the file system layer. The storage engine solves both these problems by mapping virtual memory address to physical disk blocks (blocks of SSD) at page level granularity. Even in case of memory pressure instead of invoking swaping engine, the memory pages can be written to disk directly using storage engine.

The object-oriented nature of the database makes it perfectly suitable for realtime Online Analytical Processing (OLAP) while the transactional engine support makes it suitable for Online Transaction Processing (OLTP), too. It is a perfect platform for implementing business applications (such as ERP or BBMP) and real-time data analysis tools.


Welcome to staila technologies

After developing for a long time behind hidden walls, staila has decided to share opinions and findings on hot features with interested people. Our posts will cover technology, use-cases, benchmarks and other topics related to our product. For those among you who are not familiar with staila technologies and Mercury, I have the pleasure to give an introduction on both.

staila technologies is an official ETH Zurich (Switzerland) spin-off company, which was founded in January 2009 in Winterthur (Switzerland). Currently the company is located in Zurich (Technopark). A great team of dedicated engineers has built the next generation enterprise system. Currently I have the pleasure to manage the company. I hold a MSc degree in Computer Science from ETH Zurich and have a strong sense for business and experience with various multinational companies.

Mercury, our product, is a low-level, modular enterprise platform written in C. The headless appliance allows to build applications which are able to run as closely as possible to the hardware and hence eliminates performance bottlenecks introduced by various software layers typically present in other systems. Compared to other platform approaches such as FPGA, Mercury does not require a special purpose hardware. It is able to run on commodity 64-bit multicore architectures. Mercury contains many state-of-the-art components and is a hybrid between an application server and a database. The core infrastructure of the platform contains, tightly integrated, a fail-safe persistent storage optimized for SSD, full transaction support, a compiler which is part of the runtime, an in-memory database and messaging functionality.

Today we have a first post on in-memory data management. In the future we will try to publish new posts every two weeks, covering some specific topics related to staila and/or Mercury.

Many thanks for reading us!

Georg