GemFire Cache Transaction Semantics
GemFire Cache Transaction Semantics
GemFire transaction semantics differs in some ways from the semantics of traditional relational databases.
A common database technique to achieve atomicity is two-phase locking on rows. This provides coordination between the current transaction and other transactions with overlapping changes. Holding write locks prevents reads of transactional changes until all changes are complete, providing all or nothing behavior. If problems occur during a transaction, perhaps due to relational constraints or storage limitations, the locks protect other processes from reading until the problems can be resolved. The resolution often involves reverting data back to the original pre-transaction state. Rolling back a database transaction in this case would require releasing write locks.
A common distributed technique for all or nothing behavior is the Two Phase Commit Protocol, which requires all processes participating in the transaction to agree to commit or abort the transaction.
The all or nothing behavior of GemFire transactions is implemented using a per thread transaction state which collects all transactional changes. The set of Entry changes are atomically reserved by a reservation system. The reservation blocks other, intersecting transactions from proceeding, allowing the commit to check for conflicts and reserve resources in an all-or-nothing fashion prior to making changes to the data.
Since GemFire is distributed, the transaction state is distributed to the appropriate members and processed in a batch, to protect against application failure in the middle of the commit. After all changes have been made, locally and remotely, the reservation is released.
Rolling back the transaction is as simple as discarding the transaction state.
Reads do not use the reservation system and so are very fast.
- Each thread can write new versions of entry data without impacting read performance
- Reads view only the most recent committed version of an entry
Database consistency is often described in terms of referential integrity. References between tables are often described in terms of primary and foreign key constraints. A database transaction that updates multiple columns, potentially in different tables, must ensure that all updates are completed to maintain consistency in an atomic fashion.
For GemFire the application controls the consistency between regions and their entries. GemFire transactions use the reservation system to ensure that changes to all entries in all regions are committed. Once a reservation is obtained, GemFire does a conflict check to ensure that the entries scheduled for change are in the same state as they were when the transaction first accessed them.
GemFire isolates transactions at the process thread level. So while a transaction is in progress, its changes are only visible inside the thread that is running the transaction. Threads inside the same process and in other processes do not see the changes until after the commit finishes. Relational database transactions often isolate changes per JDBC connection.
GemFire reads, like get and getEntry, are volatile, meaning they do not use locks. This makes reads very fast with respect to other entry operations. It also allows transactional writes to proceed without being slowed down by in-progress reads.
Visibility, related to isolation, is the atomic nature in which committed writes are viewable by read operations. Reads during a GemFire transaction have repeatable read isolation, so once the committed value reference is read for a given key, it always returns the same reference. If a transaction write, like put or invalidate, deletes a value for a key that has already been read, subsequent reads return the transactional reference.
Relational databases provide durability by using disk storage for recovery and transaction logging. GemFire does not support on-disk or in-memory durability for transactions.