summaryrefslogtreecommitdiff
path: root/src/main/java/com/amazon/carbonado/Transaction.java
blob: a216b391af4580fc10ccea213cabafa9d73abcac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 * Copyright 2006-2010 Amazon Technologies, Inc. or its affiliates.
 * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
 * of Amazon Technologies, Inc. or its affiliates.  All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.amazon.carbonado;

import java.util.concurrent.TimeUnit;

/**
 * Transactions define atomic operations which can be committed or aborted as a
 * unit. Transactions are entered by calling {@link Repository#enterTransaction()}.
 * Transactions are thread-local, and so no special action needs to be taken to
 * bind operations to them. Cursors which are opened in the scope of a
 * transaction are automatically closed when the transaction is committed or
 * aborted.
 *
 * <p>Transactions do not exit when they are committed. The transaction is
 * still valid after a commit, but new operations are grouped into a separate
 * atomic unit. The exit method <em>must</em> be invoked on every
 * transaction. The following pattern is recommended:
 *
 * <pre>
 * Transaction txn = repository.enterTransaction();
 * try {
 *     // Make updates to storage layer
 *     ...
 *
 *     // Commit the changes up to this point
 *     txn.commit();
 *
 *     // Optionally make more updates
 *     ...
 *
 *     // Commit remaining changes
 *     txn.commit();
 * } finally {
 *     // Ensure transaction exits, aborting uncommitted changes if an exception was thrown
 *     txn.exit();
 * }
 * </pre>
 *
 * <p>Transactions may be nested. Calling commit or abort on an outer
 * transaction will recursively apply the same operation to all inner
 * transactions as well. All Cursors contained within are also closed.
 *
 * <p>Transaction instances are mutable, but they are thread-safe.
 *
 * @author Brian S O'Neill
 */
public interface Transaction {
    /**
     * If currently in a transaction, commits all changes to the storage layer
     * since the last commit within the transaction.
     *
     * @throws PersistException if storage layer throws an exception
     */
    void commit() throws PersistException;

    /**
     * Closes the current transaction, aborting all changes since the last
     * commit.
     *
     * @throws PersistException if storage layer throws an exception
     */
    void exit() throws PersistException;

    /**
     * Set to true to force all read operations within this transaction to
     * acquire upgradable or write locks. This option eliminates deadlocks that
     * may occur when updating records, except it may increase contention.
     */
    void setForUpdate(boolean forUpdate);

    /**
     * Returns true if this transaction is in update mode, which is adjusted by
     * calling {@link #setForUpdate}.
     */
    boolean isForUpdate();

    /**
     * Specify a desired timeout for aquiring locks within this
     * transaction. Calling this method may have have no effect at all, if the
     * repository does not support this feature. In addition, the lock timeout
     * might not be alterable if the transaction contains uncommitted data.
     *
     * <p>Also, the range of lock timeout values supported might be small. For
     * example, only a timeout value of zero might be supported. In that case,
     * the transaction is configured to not wait at all when trying to acquire
     * locks. Expect immediate timeout exceptions when locks cannot be
     * granted.
     *
     * <p>Nested transactions inherit the desired lock timeout of their
     * parent. Top transactions always begin with the default lock timeout.
     *
     * @param timeout Desired lock timeout. If negative, revert lock timeout to
     * default value.
     * @param unit Time unit for timeout. If null, revert lock timeout to
     * default value.
     */
    void setDesiredLockTimeout(int timeout, TimeUnit unit);

    /**
     * Returns the isolation level of this transaction.
     */
    IsolationLevel getIsolationLevel();

    /**
     * Detaches this transaction from the current thread. It can be attached
     * later, and to any thread which currently has no thread-local
     * transaction.
     *
     * <p>Detaching a transaction also detaches any parent and nested child
     * transactions. Attaching any of them achieves the same result as
     * attaching this transaction.
     *
     * @throws IllegalStateException if transaction is attached to a different
     * thread
     * @since 1.2
     */
    void detach();

    /**
     * Attaches this transaction to the current thread, if it has been
     * detached. Attaching a transaction also attaches any parent and nested
     * child transactions.
     *
     * @throws IllegalStateException if current thread has a different
     * transaction already attached
     * @since 1.2
     */
    void attach();

    /**
     * Calling this method commits all nested child transactions, closes all
     * scoped cursors, and locks out some interactions from other threads. The
     * commit method must still be called to finish the commit. Most applications
     * have no use for pre-commit and should only ever call commit.
     *
     * <p>The intent of this method is to complete as many operations as
     * possible leading up to the actual commit. If pre-commit succeeds, then
     * commit will most likely succeed as well. While in a pre-commit state, the
     * transaction can still be used by the current thread. Calling pre-commit
     * again ensures that child transactions and cursors are closed.
     *
     * @return false if transaction has exited
     */
    boolean preCommit() throws PersistException;
}