1 /*
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002, 2014 Oracle and/or its affiliates.  All rights reserved.
5  *
6  */
7 
8 package com.sleepycat.je;
9 
10 import com.sleepycat.je.txn.Locker;
11 
12 /**
13  * Indicates that a failure has occurred that impacts the current operation
14  * and/or transaction.  For failures that impact the environment as a whole,
15  * see {@link EnvironmentFailureException}.  For an overview of all exceptions
16  * thrown by JE, see {@link DatabaseException}.
17  *
18  * <p>If an explicit transaction applies to a method which threw this
19  * exception, the exception may indicate that {@link Transaction#abort} must be
20  * called, depending on the nature of the failure.  A transaction is applicable
21  * to a method call in two cases.</p>
22  * <ol>
23  * <li>When an explicit (non-null) {@code Transaction} instance is specified.
24  * This applies when the {@code Transaction} is passed as a parameter to the
25  * method that throws the exception, or when the {@code Transaction} is passed
26  * to {@link Database#openCursor} and a {@code Cursor} method throws the
27  * exception.
28  * </li>
29  * <li>When a per-thread {@code Transaction} applies to the method that throws
30  * the exception.  Per-thread transactions apply when using {@link
31  * com.sleepycat.collections persistent collections} with {@link
32  * com.sleepycat.collections.CurrentTransaction} or {@link
33  * com.sleepycat.collections.TransactionRunner}, or when using XA transactions
34  * with {@link XAEnvironment}.
35  * </li>
36  * </ol>
37  *
38  * <p>When a transaction is applicable to a method call, the application should
39  * catch {@code OperationFailureException} and then call {@link
40  * Transaction#isValid}.  If {@code false} is returned, all {@code Cursor}
41  * instances that were created with the transaction must be closed and then
42  * {@link Transaction#abort} must be called.  Also note that {@link
43  * Transaction#isValid} may be called at any time, not just during exception
44  * handling.</p>
45  *
46  * <p>The use of the {@link Transaction#isValid} method allows JE to determine
47  * dynamically whether the failure requires an abort or not, and allows for
48  * this determination to change in future releases. Over time, internal
49  * improvements to error handling may allow more error conditions to be handled
50  * without invalidating the {@code Transaction}.</p>
51  *
52  * <p>The specific handling that is necessary for an {@code
53  * OperationFailureException} depends on the specific subclass thrown.  See the
54  * javadoc for each method for information on which methods throw which {@code
55  * OperationFailureException}s and why.</p>
56  *
57  * <p>If {@link Transaction#abort} is not called after an {@code
58  * OperationFailureException} invalidates the {@code Transaction}, all
59  * subsequent method calls using the {@code Transaction} will throw the same
60  * exception.  This provides more than one opportunity to catch and handle the
61  * specific exception subclass that caused the failure.</p>
62  *
63  * <p>{@code OperationFailureException} is also thrown by methods where no
64  * transaction applies. In most cases the action required to handle the
65  * exception is the same as with a transaction, although of course no abort is
66  * necessary.</p>
67  *
68  * <p>However, please be aware that for some operations on a non-transactional
69  * {@code Database} or {@code EntityStore}, an {@code
70  * OperationFailureException} may cause data corruption.  For example, see
71  * {@link SecondaryReferenceException}.</p>
72  *
73  * <p>There are two groups of operation failure subclasses worth noting since
74  * they apply to many methods: read operation failures and write operation
75  * failures.  These are described below.</p>
76  *
77  * <a name="readFailures"><h3>Read Operation Failures</h3></a>
78  *
79  * <p>Read operations are all those performed by the {@code get} family of
80  * methods, for example, {@link Database#get Database.get}, {@link
81  * Cursor#getNext Cursor.getNext}, {@link com.sleepycat.persist.EntityIndex#get
82  * EntityIndex.get}, {@link com.sleepycat.persist.EntityCursor#next
83  * EntityCursor.next}, {@link com.sleepycat.collections.StoredMap#get
84  * StoredMap.get}, and {@link ForwardCursor#getNext ForwardCursor.getNext}.
85  * These methods may cause the following operation
86  * failures.</p>
87  *
88  * <ul>
89  * <li>{@link OperationFailureException} is the superclass of all read
90  * operation failures.</li>
91  *   <ul>
92  *   <li>{@link LockConflictException} is thrown if a lock conflict prevents
93  *   the operation from completing.  A read operation may be blocked by another
94  *   locker (transaction or non-transactional cursor) that holds a write lock
95  *   on the record.</li>
96  *
97  *     <ul>
98  *     <li>{@link com.sleepycat.je.rep.LockPreemptedException} is a subclass
99  *     of {@code LockConflictException} that is thrown in a replicated
100  *     environment on the Replica node, when the Master node has changed a
101  *     record that was previously locked by the reading transaction or
102  *     cursor.</li>
103  *     </ul>
104  *
105  *   <li>{@link SecondaryIntegrityException} is thrown if a primary-secondary
106  *   relationship integrity problem is detected while reading a primary
107  *   database record via a secondary index.</li>
108  *
109  *   <li>{@link com.sleepycat.je.rep.DatabasePreemptedException} is thrown in a
110  *   replicated environment on the Replica node, when the Master node has
111  *   truncated, removed or renamed the database.</li>
112  *
113  *   <li>Other {@link OperationFailureException} subclasses may be thrown if
114  *   such an exception was thrown earlier and caused the transaction to be
115  *   invalidated.</li>
116  *   </ul>
117  * </ul>
118  *
119  * <a name="writeFailures"><h3>Write Operation Failures</h3></a>
120  *
121  * <p>Write operations are all those performed by the {@code put} and {@code
122  * delete} families of methods, for example, {@link Database#put Database.put},
123  * {@link Cursor#delete Cursor.delete}, {@link
124  * com.sleepycat.persist.PrimaryIndex#put PrimaryIndex.put}, {@link
125  * com.sleepycat.persist.EntityCursor#delete EntityCursor.delete} and {@link
126  * com.sleepycat.collections.StoredMap#put StoredMap.put}.  These methods may
127  * cause the following operation failures, although certain failures are only
128  * caused by {@code put} methods and others only by {@code delete} methods, as
129  * noted below.</p>
130  *
131  * <ul>
132  * <li>{@link OperationFailureException} is the superclass of all write
133  * operation failures.</li>
134  *
135  *   <ul>
136  *   <li>{@link LockConflictException} is thrown if a lock conflict prevents
137  *   the operation from completing.  A write operation may be blocked by
138  *   another locker (transaction or non-transactional cursor) that holds a read
139  *   or write lock on the record.</li>
140  *
141  *   <li>{@link SecondaryConstraintException} is the superclass of all
142  *   exceptions thrown when a write operation fails because of a secondary
143  *   constraint.</li>
144  *
145  *     <ul>
146  *     <li>{@link ForeignConstraintException} is thrown when an attempt to
147  *     write a primary database record would insert a secondary record with a
148  *     key that does not exist in a foreign key database, when the secondary
149  *     key is configured as a foreign key.  This exception is only thrown by
150  *     {@code put} methods.</li>
151  *
152  *     <li>{@link UniqueConstraintException} is thrown when an attempt to write
153  *     a primary database record would insert a secondary record with a
154  *     duplicate key, for secondaries that represent one-to-one and one-to-many
155  *     relationships.  This exception is only thrown by {@code put}
156  *     methods.</li>
157  *
158  *     <li>{@link DeleteConstraintException} is thrown when an attempt is made
159  *     to delete a key from a foreign key database, when that key is referenced
160  *     by a secondary database, and the secondary is configured to cause an
161  *     abort in this situation.  This exception is only thrown by {@code
162  *     delete} methods.</li>
163  *     </ul>
164  *
165  *   <li>{@link SecondaryIntegrityException} is thrown if a primary-secondary
166  *   relationship integrity problem is detected while writing a record in a
167  *   primary database that has one or more secondary indices.
168  *
169  *   <li>{@link com.sleepycat.je.rep.DatabasePreemptedException} is thrown in a
170  *   replicated environment on a Replica node, when the Master node has
171  *   truncated, removed or renamed the database.</li>
172  *
173  *   <li>{@link com.sleepycat.je.rep.ReplicaWriteException} is always thrown in
174  *   a replicated environment on a Replica node, since write operations are not
175  *   allowed on a Replica.</li>
176  *
177  *   <li>Other {@link OperationFailureException} subclasses may be thrown if
178  *   such an exception was thrown earlier and caused the transaction to be
179  *   invalidated.</li>
180  *   </ul>
181  * </ul>
182  *
183  * @since 4.0
184  */
185 public abstract class OperationFailureException extends DatabaseException {
186 
187     private static final long serialVersionUID = 1;
188 
189     /**
190      * For internal use only.
191      * @hidden
192      */
OperationFailureException(Locker locker, boolean abortOnly, String message, Throwable cause)193     public OperationFailureException(Locker locker,
194                                      boolean abortOnly,
195                                      String message,
196                                      Throwable cause) {
197         super(message, cause);
198         if (abortOnly) {
199             assert locker != null;
200             locker.setOnlyAbortable(this);
201         }
202     }
203 
204     /**
205      * For internal use only.
206      * @hidden
207      * Only for use by bind/collection/persist exception subclasses.
208      */
OperationFailureException(String message)209     public OperationFailureException(String message) {
210         this(null /*locker*/, false /*abortOnly*/, message, null /*cause*/);
211     }
212 
213     /**
214      * For internal use only.
215      * @hidden
216      * Only for use by wrapSelf methods.
217      */
OperationFailureException(String message, OperationFailureException cause)218     protected OperationFailureException(String message,
219                                         OperationFailureException cause) {
220         super(message, cause);
221     }
222 
223     /**
224      * For internal use only.
225      * @hidden
226      * Must be implemented by every concrete subclass to return an instance of
227      * its own class, constructed with the given msg and this exception as
228      * parameters, e.g.: return new MyClass(msg, this);
229      */
wrapSelf(String msg)230     public abstract OperationFailureException wrapSelf(String msg);
231 }
232