Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GEODE-5296 Rewrite introductory prose on transactions #2056

Merged
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
165 changes: 132 additions & 33 deletions geode-docs/developing/transactions/about_transactions.html.md.erb
Expand Up @@ -22,61 +22,160 @@ limitations under the License.
<a id="topic_jbt_2y4_wk"></a>


This section covers the features of <%=vars.product_name%> transactions.
This section introduces <%=vars.product_name%> transactions.
Geode offers an API for client applications that do transactional work.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

product name?

While the implementation of the API does not provide
applications a rigid adherence to all the ACID properties of transactions,
it handles many situations.
It is fast in comparison to the slow,
locking methods of a traditional database.

## Overview of the Application's Transaction

There are two ways that an application can run a transaction:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The developer is still using the transaction API in function, so I would not call them two different ways.


- The application uses the transaction API.
Here is a code fragment to show the structure of a basic transaction,
with its `begin` to start the transaction and `commit` to end the transaction.

``` pre
CacheTransactionManager txManager =
cache.getCacheTransactionManager();

try {
txManager.begin();
// ... do work
txManager.commit();
} catch (CommitConflictException conflict) {
// ... do necessary work for a transaction that failed on commit
}
```

- Use functions.
Two approaches combine functions with transactions.
Section [Transactions and Functions](working_with_transactions.html)
details the interaction.
The use of a function can have performance benefits,
as compared to the application directly using the transaction API.
The performance benefit results from both the functions
and the region data residing on servers.
As the function invokes region operations,
those operations on region entries stay on the server,
so there is no network round trip time to do get or put
operations on region data.

- A function invocation is embedded in a transaction.
The application starts the transaction by invoking `begin`,
invokes the function within the transaction,
and then does the `commit` to end the transaction.
- A transaction is embedded in a function.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not impart performance benefits that we talk about previously, so I don't how much value add this is.

The application invokes the function,
and the function contains the transaction that does the `begin`,
the region operations, and the `commit`.

## Adherence to ACID Promises

<%=vars.product_name%> transaction semantics do not offer
the identical Atomicity-Consistency-Isolation-Durability (ACID) semantics
of a traditional relational database.
This <%=vars.product_name%> implementation choice results in
much higher transaction performance without sacrificing ACID promises.
<%=vars.product_name%> transactions do not adhere to ACID constraints
by default,
but they can be configured for ACID support.

<%=vars.product_name%> transactions provide the following features:
### <a id="transaction_semantics__section_8362ACD06C784B5BBB0B7E986F760169" class="no-quick-link"></a>Atomicity

- Basic transaction properties: atomicity, consistency, isolation, and durability
- Rollback and commit operations along with standard <%=vars.product_name%> cache operations
- Ability to suspend and resume transactions
- High concurrency and high performance
- Transaction statistics gathering and archiving
- Compatibility with Java Transaction API (JTA) transactions, using either <%=vars.product_name%> JTA or a third-party implementation
- Ability to use <%=vars.product_name%> as a “last resource” in JTA transactions with multiple data sources to guarantee transactional consistency
Atomicity is “all or nothing” behavior: a transaction completes successfully only when all of the operations it contains complete successfully. If problems occur during a transaction, perhaps due to other transactions with overlapping changes, the transaction cannot successfully complete until the problems are resolved.

## Types of Transactions
<%=vars.product_name%> transactions provide atomicity and realize speed by using a reservation system, instead of using the traditional relational database technique of a two-phase locking of rows. The reservation prevents other, intersecting transactions from completing, allowing the commit to check for conflicts and to reserve resources in an all-or-nothing fashion prior to making changes to the data. After all changes have been made, locally and remotely, the reservation is released. With the reservation system, an intersecting transaction is simply discarded. The serialization of obtaining locks is avoided. See [Committing Transactions](how_cache_transactions_work.html#concept_sbj_lj1_wk) for details on the two-phase commit protocol that implements the reservation system.

<%=vars.product_name%> supports two kinds of transactions: **<%=vars.product_name%> cache transactions** and **JTA global transactions**.
### <a id="transaction_semantics__section_7C287DA4A5134780B3199CE074E3F890" class="no-quick-link"></a>Consistency

<%=vars.product_name%> cache transactions are used to group the execution of cache operations and to gain the control offered by transactional commit and rollback. Applications create cache transactions by using an instance of the <%=vars.product_name%> `CacheTransactionManager`. During a transaction, cache operations are performed and distributed through <%=vars.product_name%> as usual. See [<%=vars.product_name%> Cache Transactions](cache_transactions.html#topic_e15_mr3_5k) for details on <%=vars.product_name%> cache transactions and how these transactions work.
Consistency requires that data written within a transaction must observe the key and value constraints established for the affected region. Note that validity of the transaction is the responsibility of the application.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also want to say listeners/writers? ( like triggers in RDBMS)


JTA global transactions allow you to use the standard JTA interface to coordinate <%=vars.product_name%> transactions with JDBC transactions. When performing JTA global transactions, you have the option of using <%=vars.product_name%>’s own implementation of JTA or a third party’s implementation (typically application servers such as WebLogic or JBoss) of JTA. In addition, some third party JTA implementations allow you to set <%=vars.product_name%> as a “last resource” to ensure transactional consistency across data sources in the event that <%=vars.product_name%> or another data source becomes unavailable. For global transactions, applications use `java:/UserTransaction` to start and terminate transactions while <%=vars.product_name%> cache operations are performed in the same manner as regular <%=vars.product_name%> cache transactions. See [JTA Global Transactions with <%=vars.product_name%>](JTA_transactions.html) for details on JTA Global transactions.
### <a id="transaction_semantics__section_126A24EC499D4CF39AE766A0B526A9A5" class="no-quick-link"></a>Isolation

You can also coordinate a <%=vars.product_name%> cache transaction with an external database by specifying database operations within cache and transaction application plug-ins (CacheWriters/CacheListeners and TransactionWriters/TransactionListeners.) This is an alternative to using JTA transactions. See [How to Run a <%=vars.product_name%> Cache Transaction that Coordinates with an External Database](run_a_cache_transaction_with_external_db.html#task_sdn_2qk_2l).
Isolation assures that operations will see either the pre-transaction state
or the post-transaction state,
but not the transitional state that occurs while a transaction is in progress.
Write operations in a transaction are always confirmed to ensure that stale
values are not written.
<%=vars.product_name%>'s performance focus results in a default configuration
that does not enforce read isolation.
Transaction have repeatable read isolation,
so once the committed value is read for a given key,
it always returns that same value.
If a transaction write, such as put or invalidate,
deletes a value for a key that has already been read,
subsequent reads return the transactional reference.

At a deeper explanation level, the default configuration isolates
transactions at the process thread level.
While a transaction is in progress,
its changes are visible only inside the thread that is running the transaction.
Other threads within that same process and threads in other processes
cannot see changes until after the commit operation begins.
After beginning the commit, the changes are visible in the cache,
but other threads that access the changing data might see
partial results of the transaction, leading to a dirty read.

An application requiring the more strict, but slower isolation model
(such that dirty reads of transitional states are not allowed),
sets a property and encpsulates read operations within the transaction.
Configure this strict isolation model with the property:

`-Dgemfire.detectReadConflicts=true`

## Application of ACID Semantics
This property causes read operations to succeed only when they read
a consistent pre- or post-transactional state.
If not consistent,
<%=vars.product_name%> throws a `CommitConflictException`.

<%=vars.product_name%> transaction semantics differ in some ways from the Atomicity-Consistency-Isolation-Durability (ACID) semantics of traditional relational databases. For performance reasons, <%=vars.product_name%> transactions do not adhere to ACID constraints by default, but can be configured for ACID support as described in this section.
### <a id="transaction_semantics__section_F092E368724945BCBF8E5DCB36B97EB4" class="no-quick-link"></a>Durability

### <a id="transaction_semantics__section_8362ACD06C784B5BBB0B7E986F760169" class="no-quick-link"></a>Atomicity
Relational databases provide durability by using disk storage for
recovery and transaction logging.
<%=vars.product_name%> is optimized for performance
and does not support on-disk or in-memory durability for transactions.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in-memory by definition is not durable, so I think it should be removed.


Atomicity is “all or nothing” behavior: a transaction completes successfully only when all of the operations it contains complete successfully. If problems occur during a transaction, perhaps due to other transactions with overlapping changes, the transaction cannot successfully complete until the problems are resolved.
The implementation of the durability promise prohibits
regions with persistence from participating in transactions.
The invocation of a persistent region operation within a transaction
will throw an `UnsupportedOperationException` with an associated message of

<%=vars.product_name%> transactions provide atomicity and realize speed by using a reservation system, instead of using the traditional relational database technique of a two-phase locking of rows. The reservation prevents other, intersecting transactions from completing, allowing the commit to check for conflicts and to reserve resources in an all-or-nothing fashion prior to making changes to the data. After all changes have been made, locally and remotely, the reservation is released. With the reservation system, an intersecting transaction is simply discarded. The serialization of obtaining locks is avoided. See [Committing Transactions](how_cache_transactions_work.html#concept_sbj_lj1_wk) for details on the two-phase commit protocol that implements the reservation system.

### <a id="transaction_semantics__section_7C287DA4A5134780B3199CE074E3F890" class="no-quick-link"></a>Consistency
``` pre
Operations on persist-backup regions are not allowed because this thread
has an active transaction
```

Consistency requires that data written within a transaction must observe the key and value constraints established for the affected region. Note that validity of the transaction is the responsibility of the application.
An application that wishes to allow operations on a persistent region during
a transaction can set this system property:

### <a id="transaction_semantics__section_126A24EC499D4CF39AE766A0B526A9A5" class="no-quick-link"></a>Isolation
`-Dgemfire.ALLOW_PERSISTENT_TRANSACTIONS=true`

Isolation assures that operations will see either the pre-transaction state of the system or its post-transaction state, but not the transitional state that occurs while a transaction is in progress. Write operations in a transaction are always confirmed to ensure that stale values are not written. As a distributed cache-based system optimized for performance, <%=vars.product_name%> in its default configuration does not enforce read isolation. <%=vars.product_name%> transactions support repeatable read isolation, so once the committed value is read for a given key, it always returns that same value. If a transaction write, such as put or invalidate, deletes a value for a key that has already been read, subsequent reads return the transactional reference.
Setting this system property eliminates the exception.
It does not provide durability.
See [Transactions and Persistent Regions](cache_transactions_by_region_type.html#concept_omy_341_wk) for more detail on the interaction of persistence
and durability.

In the default configuration, <%=vars.product_name%> isolates transactions at the process thread level, so while a transaction is in progress, its changes are visible only inside the thread that is running the transaction. Threads inside the same process and in other processes cannot see changes until after the commit operation begins. At this point, the changes are visible in the cache, but other threads that access the changing data might see only partial results of the transaction leading to a dirty read.
## Types of Transactions

If an application requires the slower conventional isolation model (such that dirty reads of transitional states are not allowed), read operations must be encapsulated within transactions and the `gemfire.detectReadConflicts` parameter must be set to ‘true’:
<%=vars.product_name%> supports two kinds of transactions: **<%=vars.product_name%> cache transactions** and **JTA global transactions**.

`-Dgemfire.detectReadConflicts=true`
<%=vars.product_name%> cache transactions are used to group the execution of cache operations and to gain the control offered by transactional commit and rollback. Applications create cache transactions by using an instance of the <%=vars.product_name%> `CacheTransactionManager`. During a transaction, cache operations are performed and distributed through <%=vars.product_name%> as usual. See [<%=vars.product_name%> Cache Transactions](cache_transactions.html#topic_e15_mr3_5k) for details on <%=vars.product_name%> cache transactions and how these transactions work.

This parameter causes read operations to succeed only when they read a consistent pre- or post-transactional state. If not, a `CommitConflictException` is thrown to the calling application.
JTA global transactions allow you to use the standard JTA interface to coordinate <%=vars.product_name%> transactions with JDBC transactions. When performing JTA global transactions, you have the option of using <%=vars.product_name%>’s own implementation of JTA or a third party’s implementation (typically application servers such as WebLogic or JBoss) of JTA. In addition, some third party JTA implementations allow you to set <%=vars.product_name%> as a “last resource” to ensure transactional consistency across data sources in the event that <%=vars.product_name%> or another data source becomes unavailable. For global transactions, applications use `java:/UserTransaction` to start and terminate transactions while <%=vars.product_name%> cache operations are performed in the same manner as regular <%=vars.product_name%> cache transactions. See [JTA Global Transactions with <%=vars.product_name%>](JTA_transactions.html) for details on JTA Global transactions.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily only JDBC, you can have message queues and other no-relational data stores too. I would say "to coordinate with other XA datastores".
Please remove references to Geod's own implementation of JTA.


### <a id="transaction_semantics__section_F092E368724945BCBF8E5DCB36B97EB4" class="no-quick-link"></a>Durability
You can also coordinate a <%=vars.product_name%> cache transaction with an external database by specifying database operations within cache and transaction application plug-ins (CacheWriters/CacheListeners and TransactionWriters/TransactionListeners.) This is an alternative to using JTA transactions. See [How to Run a <%=vars.product_name%> Cache Transaction that Coordinates with an External Database](run_a_cache_transaction_with_external_db.html#task_sdn_2qk_2l).

Relational databases provide durability by using disk storage for recovery and transaction logging. As a distributed cache-based system optimized for performance, <%=vars.product_name%> does not support on-disk or in-memory durability for transactions.
## Other Features of <%=vars.product_name%> Transactions

Applications can emulate the conventional disk-based durability model by setting the `gemfire.ALLOW_PERSISTENT_TRANSACTIONS` parameter to ‘true’.
- Additional way of doing transactions with JTA.
Compatibility with Java Transaction API (JTA) transactions, using either <%=vars.product_name%> JTA or a third-party implementation.
Ability to use <%=vars.product_name%> as a “last resource” in JTA transactions with multiple data sources to guarantee transactional consistency.

`-Dgemfire.ALLOW_PERSISTENT_TRANSACTIONS=true`
- Additional capabilities offered with Geode
- suspend and resume
- transactions statistics

This allows permanent regions to participate in transactions, thus providing disk-based durability. See [Transactions and Persistent Regions](cache_transactions_by_region_type.html#concept_omy_341_wk) for more detail on the use of this parameter.