######################
Transaction Management
######################

.. toctree::
    :maxdepth: 1
    :titlesonly:
    :hidden:

    bk_ba_tm/bk_ba_single_threaded_graphic_applications
    bk_ba_tm/bk_ba_multi_threaded_performance_critical_applications
    bk_ba_tm/bk_ba_software_rendering_and_parallel_data_edition
    bk_ba_tm/bk_ba_modifying_images_during_a_draw


This chapter will detail the way HOOPS Luminate uses transactions. Transactions are used to record and apply changes to data managed by the engine. This mechanism is at the heart of the HOOPS Luminate design, and all the engine APIs are relying on it. From this, we derive two classic application architectures, detailed in these pages:

    * :doc:`/book/subjects/bk_ba/bk_ba_tm/bk_ba_single_threaded_graphic_applications`: This page covers all the details to build a single threaded UI application interacting with HOOPS Luminate. Most applications can be based on this simple model.
    * :doc:`/book/subjects/bk_ba/bk_ba_tm/bk_ba_multi_threaded_performance_critical_applications`: This page covers in detail the application architecture that can be put in place to sustain the performance needs of a time critical application such as a simulation engine or a video game.

We'll also review some specific points in detail here:

    * :doc:`/book/subjects/bk_ba/bk_ba_tm/bk_ba_software_rendering_and_parallel_data_edition`: a HOOPS Luminate application can render an image in software and continue its work on other data in parallel. All the details are reviewed in this page.
    * :doc:`/book/subjects/bk_ba/bk_ba_tm/bk_ba_modifying_images_during_a_draw`: Images are special HOOPS Luminate objects, that are only enforcing part of the transaction model. Consequently, there are some specifics to be known about images and how they can be edited.


**********************
What is a Transaction?
**********************

A transaction in HOOPS Luminate terminology is 'all what happens' between a ``RED::IResourceManager::BeginState`` and a ``RED::IResourceManager::EndState`` call. The contents of a frame to be rendered is defined by those changes that have happened during the transaction. The ``RED::State`` class is the transaction object that will be used by all API methods to write data to HOOPS Luminate:

.. include:: /tasks/ta_ca/ta_ca_application/tk_writing_to_luminate_objects_using_a_transaction.rst


*********************************************
Using Transactions to Write to HOOPS Luminate
*********************************************

There are two categories of objects in HOOPS Luminate: those that are using transaction and atomic objects that are not using transactions. Generally speaking, atomic objects can be created on the stack and are the parameters manipulated by transactional classes. Let's illustrate this using a simple example with transformation shapes and matrices:

.. code:: cpp 

    // Access our resource manager, create a transaction:
    RED::Object* resmgr = RED::Factory::CreateInstance( CID_REDResourceManager );
    RED::IResourceManager* iresmgr = resmgr->As< RED::IResourceManager >();
    const RED::State& state = iresmgr->BeginState();

    // Assume that 'node' is a transform shape, that has a single teapot as child geometry:
    RED::ITransformShape* inode = node->As< RED::ITransformShape >();

    // Create a matrix on the stack that define a transaction (stateless):
    RED::Matrix matrix;
    matrix.SetTranslation( RED::Vector3( 100.0, 100.0, 0.0 ) );

    // Assign this matrix to the transform using the transaction:
    RC_TEST( inode->SetMatrix( &matrix, state ) );

    // Keep track of the transaction number (will be used later on, not now):
    int num_state = state.GetNumber();

    // Close the transaction to validate the changes before rendering:
    RC_TEST( iresmgr->EndState() );

    // Let be 'iwindow' our RED::IWindow interface. Let's draw:
    RC_TEST( iwindow->FrameDrawing() );

The matrix is a stateless, atomic object. The ``RED::ITransformShape`` interface points to an object which is transaction managed.

.. figure:: using_transactions_good.png 
    :align: center
    
    **Transaction used the right way**

Here, we open the transaction, we do the changes, we close the transaction and we draw. The ``RED::IWindow::FrameDrawing`` call reflect the changes because the transaction was closed before rendering. Now, if we don't close the transaction using ``RED::IResourceManager::EndState`` before drawing, the object will not move!


*****************************************************
Using Transaction Numbers to Read from HOOPS Luminate
*****************************************************

We have seen above how we could write data to HOOPS Luminate using a transaction. For instance, ``RED::ITransformShape::SetMatrix`` uses a ``RED::State`` transaction. Now if we want to query the transformation matrix which is set in the transform shape of our example, how should we proceed? The answer is quite simple:

.. code:: cpp 

    // Access the matrix that was set in the 'node' transformation shape:
    const RED::Matrix* matrix2;
    RC_TEST( inode->GetMatrix( matrix2 ) );

We can use the ``RED::ITransformShape::GetMatrix`` that matches the corresponding Set. This method does not require any parameter other than the matrix that we do want to query. Here, we'll retrieve a 'matrix2' value equal to 'matrix'. However, it has an optional 'iStateNumber' parameter. This parameter is by default set to -1 in all HOOPS Luminate API methods. If set to -1, it indicates to access the most recent version of the matrix that was set in the object. If set to a given transaction number, it can be used to retrieve the node's matrix value that was set in the past:

.. code:: cpp 

    // Same as above, '-1' tells the engine to retrieve the last version of the matrix:
    RC_TEST( inode->GetMatrix( matrix2, -1 ) );

    // Query the older version of the matrix. This is the version of the matrix before 'num_state':
    const RED::Matrix* matrix3;
    RC_TEST( inode->GetMatrix( matrix3, num_state - 1 ) );

We have defined a new matrix with a translation during the transaction 'num_state'. So if we do a query for a transaction number before 'num_state', we'll retrieve the value of the matrix before the operation.

In HOOPS Luminate, all transaction managed objects keep two versions of their data: the current version which is defined during the current transaction, and the previous one. This choice allows a very efficient design for time critical applications, as we'll review here: :doc:`/book/subjects/bk_ba/bk_ba_tm/bk_ba_multi_threaded_performance_critical_applications`.

So, querying at other transaction numbers before 'num_state -1' is pointless. The engine only recall the current and previous version of transaction managed data.


***************************
Transaction Workflow Errors
***************************

The most common mistake in transaction management is generally due to an attempt to write to a HOOPS Luminate object without having an open transaction available. 99.99% of the times, this results in a ``RED_WORKFLOW_ERROR`` being returned by the HOOPS Luminate API. A call to ``RED::IResourceManager::BeginState`` must be done before any change can occur in HOOPS Luminate data.


***************************
Multiple Transaction Errors
***************************

From a strict API standpoint, it's not forbidden to open and close multiple transactions before calling a rendering method, like in the example below:

.. code:: cpp 

    iresmgr->BeginState();
    // Do changes...
    RC_TEST( iresmgr->EndState() );

    iresmgr->BeginState();
    // Do changes...
    RC_TEST( iresmgr->EndState() );

    iresmgr->BeginState();
    // Do changes...
    RC_TEST( iresmgr->EndState() );

    // Draw. This is too late! Two transactions have been wasted!
    RC_TEST( iwindow->FrameDrawing() );

However, this will result in bad performances for the application. Each time ``RED::IResourceManager::EndState`` is being called, the whole engine data cluster is being checked for updates. This can be a time consuming process. So as a general rule, please make sure that every transaction is actually rendered by at least one window, to avoid wasting time. A transaction whose contents are not rendered is useless.


*********************************************
Redundancy in Opening or Closing Transactions
*********************************************

It may be difficult for an application to know whether a transaction is opened or not. For instance, user interface callbacks methods are called after user interactions, so a transaction may be open or not, sometimes, it's not easy to know. In this case, it may be worth mentioning the fact that a transaction can be opened several times or closed several times with no effect:

.. code:: cpp 

    const RED::State& state = iresmgr->BeginState();
    iresmgr->BeginState(); // No effect.
    iresmgr->BeginState(); // No effect.

    // Do changes...

    RC_TEST( iresmgr->EndState() );
    RC_TEST( iresmgr->EndState() ); // No effect
    RC_TEST( iresmgr->EndState() ); // No effect

So instead of calling ``RED::IResourceManager::GetState`` to retrieve the current transaction, if an application method needs to be 100% sure that a transaction is opened, it  can call ``RED::IResourceManager::BeginState``: the call will open the transaction if it's not opened yet, and simply return the current transaction if it's opened already.





