Transactions

The Native Client API runs transactions on the server as if they were local to the client application. Thus, the key to running client transactions lies in making sure the server is properly configured and programmed. For complete information about how transactions are conducted on the GemFire server, see the Transactions section of the GemFire User Guide.

Native Client Transaction APIs

The API for distributed transactions has the familiar relational database methods, begin, commit, and rollback. There are also APIs available to suspend and resume transactions.

The .NET classes for executing transactions are:

  • Apache.Geode.Client.CacheTransactionManager
  • Apache.Geode.Client.TransactionId

The C++ classes for executing transactions are:

  • apache.geode.client.CacheTransactionManager
  • apache.geode.client.TransactionId

Running Native Client Transactions

The syntax for writing client transactions is the same as with server or peer transactions, but when a client performs a transaction, the transaction is delegated to a server that brokers the transaction.

Start each transaction with a begin operation, and end the transaction with a commit or a rollback.

To maintain cache consistency, the local client cache is not used during a transaction. When the transaction completes or is suspended, local cache usage is reinstated.

If the transaction runs on server regions that are a mix of partitioned and replicated regions, perform the first transaction operation on a partitioned region. This sets the server data host for the entire transaction. If you are using PR single-hop, single-hop will be applied as usual to this first operation.

In addition to the failure conditions common to all transactions, client transactions can also fail if the transaction delegate fails. If the delegate performing the transaction fails, the transaction code throws a TransactionException.

Client Transaction Examples

The native client release contains transaction examples written for .NET and C++. The examples are located in ../examples/dotnet/transaction and ../examples/cpp/transaction, respectively.

Both examples perform the same sequence of operations, displaying simple log entries as they run.

  • To run an example, follow the instructions in the README.md file in the example directory.
  • Review the source code in the example directory to see exactly how it operates.

  • You begin by running a script that sets up the server-side environment by invoking gfsh commands to create a region, simply called “exampleRegion.”

  • You run the example client application, which performs the following steps:

    • Connects to the server
    • Begins a transaction
    • Performs some put operations
    • Commits the transaction
  • For this example, the transaction code has these characteristics:

    • To introduce the possibility of failure, values are randomized from 0 to 9, and the 0 values are treated as unsuccessful. The transaction is retried until it succeeds.
    • In case the transaction repeatedly fails, the retry loop uses a counter to set a limit of 5 retries.

.NET Example

This section contains code snippets showing highlights of the .NET transaction example. They are not intended for cut-and-paste execution. For the complete source, see the example source directory.

The .NET example creates a cache, then uses it to create a connection pool.

   var cache = new CacheFactory()
       .Set("log-level", "none").Create();

   var poolFactory = cache.GetPoolFactory()
       .AddLocator("localhost", 10334);

   poolFactory.Create("pool");

   var regionFactory = cache.CreateRegionFactory(RegionShortcut.PROXY)
       .SetPoolName("pool");
   var region = regionFactory.Create<string, int>("exampleRegion");

The example application gets a transaction manager from the cache and begins a transaction.

       cache.CacheTransactionManager.Begin();

Within the transaction, the client populates data store with 10 values associated with Key1 - Key10.

       foreach(var key in keys)
       {
         var value = getValueFromExternalSystem();
         region.Put(key, value);
       }

If all put operations succeed, the application commits the transaction. Otherwise, it retries up to 5 times if necessary.

   var retries = 5;
   while(retries-- > 0)
   {
     try 
     {
       ... // PUT OPERATIONS ...
       cache.CacheTransactionManager.Commit();
       Console.WriteLine("Committed transaction - exiting");
       break;
     } catch
     {
       cache.CacheTransactionManager.Rollback();
       Console.WriteLine("Rolled back transaction - retrying({0})", retries);
     }
   }

C++ Example

This section contains code snippets showing highlights of the C++ transaction example. They are not intended for cut-and-paste execution. For the complete source, see the example source directory.

The C++ example creates a cache, then uses it to create a connection pool.

  auto cache = CacheFactory().set("log-level", "none").create();
  auto poolFactory = cache.getPoolManager().createFactory();

  poolFactory.addLocator("localhost", 10334);
  auto pool = poolFactory.create("pool");
  auto regionFactory = cache.createRegionFactory(RegionShortcut::PROXY);
  auto region = regionFactory.setPoolName("pool").create("exampleRegion");

The example application gets a transaction manager from the cache and begins a transaction.

  auto transactionManager = cache.getCacheTransactionManager();

  transactionManager->begin();

Within the transaction, the client populates data store with 10 values associated with Key1 - Key10.

      for (auto& key : keys) {
        auto value = getValueFromExternalSystem();
        region->put(key, value);
      }

If all put operations succeed, the application commits the transaction. Otherwise, it retries up to 5 times if necessary.

  auto retries = 5;
  while (retries--) {
    try {
      transactionManager->begin();
       ... // PUT OPERATIONS ...
      transactionManager->commit();
      std::cout << "Committed transaction - exiting" << std::endl;
      break;
    } catch ( ... ) {
      transactionManager->rollback();
      std::cout << "Rolled back transaction - retrying(" << retries << ")" << std::endl;
    }
  }