Apache Geode Native C++ CHANGELOG

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 Geode server, see the Transactions section of the Geode 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 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 a transaction example in ../examples/cpp/transaction.

The example performs a 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.

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();

  cache.getPoolManager()
      .createFactory()
      .addLocator("localhost", 10334)
      .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 a five-attempt retry loop. If all put operations succeed, the application commits the transaction. Otherwise, it retries up to 5 times if necessary.

  auto transactionManager = cache.getCacheTransactionManager();
  auto retries = 5;
  while (retries--) {
    try {
      transactionManager->begin();
      for (auto& key : keys) {
        auto value = getValueFromExternalSystem();
        region->put(key, value);
        }
        transactionManager->commit();
        std::cout << "Committed transaction - exiting" << std::endl;
        break;
      } catch ( ... ) {
      if (transactionManager->exists()){
        transactionManager->rollback();
      }