View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.regionserver;
19  
20  import java.io.IOException;
21  import java.util.List;
22  
23  import org.apache.hadoop.hbase.HBaseInterfaceAudience;
24  import org.apache.hadoop.hbase.Server;
25  import org.apache.hadoop.hbase.classification.InterfaceAudience;
26  import org.apache.hadoop.hbase.classification.InterfaceStability;
27  import org.apache.hadoop.hbase.util.PairOfSameType;
28  
29  /**
30   * Executes region split as a "transaction".  Call {@link #prepare()} to setup
31   * the transaction, {@link #execute(Server, RegionServerServices)} to run the
32   * transaction and {@link #rollback(Server, RegionServerServices)} to cleanup if execute fails.
33   *
34   * <p>Here is an example of how you would use this interface:
35   * <pre>
36   *  SplitTransactionFactory factory = new SplitTransactionFactory(conf);
37   *  SplitTransaction st = factory.create(parent, midKey)
38   *    .registerTransactionListener(new TransactionListener() {
39   *       public void transition(SplitTransaction transaction, SplitTransactionPhase from,
40   *           SplitTransactionPhase to) throws IOException {
41   *         // ...
42   *       }
43   *       public void rollback(SplitTransaction transaction, SplitTransactionPhase from,
44   *           SplitTransactionPhase to) {
45   *         // ...
46   *       }
47   *    });
48   *  if (!st.prepare()) return;
49   *  try {
50   *    st.execute(server, services);
51   *  } catch (IOException e) {
52   *    try {
53   *      st.rollback(server, services);
54   *      return;
55   *    } catch (RuntimeException e) {
56   *      // abort the server
57   *    }
58   *  }
59   * </Pre>
60   * <p>A split transaction is not thread safe.  Callers must ensure a split is run by
61   * one thread only.
62   */
63  @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
64  @InterfaceStability.Evolving
65  public interface SplitTransaction {
66  
67    /**
68     * Each enum is a step in the split transaction.
69     */
70    public enum SplitTransactionPhase {
71      /**
72       * Started
73       */
74      STARTED,
75      /**
76       * Prepared
77       */
78      PREPARED,
79      /**
80       * Before preSplit coprocessor hook
81       */
82      BEFORE_PRE_SPLIT_HOOK,
83      /**
84       * After preSplit coprocessor hook
85       */
86      AFTER_PRE_SPLIT_HOOK,
87      /**
88       * Set region as in transition, set it into SPLITTING state.
89       */
90      SET_SPLITTING,
91      /**
92       * We created the temporary split data directory.
93       */
94      CREATE_SPLIT_DIR,
95      /**
96       * Closed the parent region.
97       */
98      CLOSED_PARENT_REGION,
99      /**
100      * The parent has been taken out of the server's online regions list.
101      */
102     OFFLINED_PARENT,
103     /**
104      * Started in on creation of the first daughter region.
105      */
106     STARTED_REGION_A_CREATION,
107     /**
108      * Started in on the creation of the second daughter region.
109      */
110     STARTED_REGION_B_CREATION,
111     /**
112      * Opened the first daughter region
113      */
114     OPENED_REGION_A,
115     /**
116      * Opened the second daughter region
117      */
118     OPENED_REGION_B,
119     /**
120      * Point of no return.
121      * If we got here, then transaction is not recoverable other than by
122      * crashing out the regionserver.
123      */
124     PONR,
125     /**
126      * Before postSplit coprocessor hook
127      */
128     BEFORE_POST_SPLIT_HOOK,
129     /**
130      * After postSplit coprocessor hook
131      */
132     AFTER_POST_SPLIT_HOOK,
133     /**
134      * Completed
135      */
136     COMPLETED
137   }
138 
139   /**
140    * Split transaction journal entry
141    */
142   public interface JournalEntry {
143 
144     /** @return the completed phase marked by this journal entry */
145     SplitTransactionPhase getPhase();
146 
147     /** @return the time of phase completion */
148     long getTimeStamp();
149   }
150 
151   /**
152    * Split transaction listener
153    */
154   public interface TransactionListener {
155 
156     /**
157      * Invoked when transitioning forward from one transaction phase to another
158      * @param transaction the transaction
159      * @param from the current phase
160      * @param to the next phase
161      * @throws IOException listener can throw this to abort
162      */
163     void transition(SplitTransaction transaction, SplitTransactionPhase from,
164         SplitTransactionPhase to) throws IOException;
165 
166     /**
167      * Invoked when rolling back a transaction from one transaction phase to the
168      * previous
169      * @param transaction the transaction
170      * @param from the current phase
171      * @param to the previous phase
172      */
173     void rollback(SplitTransaction transaction, SplitTransactionPhase from,
174         SplitTransactionPhase to);
175   }
176 
177   /**
178    * Check split inputs and prepare the transaction.
179    * @return <code>true</code> if the region is splittable else
180    * <code>false</code> if it is not (e.g. its already closed, etc.).
181    * @throws IOException 
182    */
183   boolean prepare() throws IOException;
184 
185   /**
186    * Run the transaction.
187    * @param server Hosting server instance.  Can be null when testing.
188    * @param services Used to online/offline regions.
189    * @throws IOException If thrown, transaction failed.
190    *          Call {@link #rollback(Server, RegionServerServices)}
191    * @return Regions created
192    * @throws IOException
193    * @see #rollback(Server, RegionServerServices)
194    */
195   PairOfSameType<Region> execute(Server server, RegionServerServices services) throws IOException;
196 
197   /**
198    * Roll back a failed transaction
199    * @param server Hosting server instance (May be null when testing).
200    * @param services
201    * @throws IOException If thrown, rollback failed.  Take drastic action.
202    * @return True if we successfully rolled back, false if we got to the point
203    * of no return and so now need to abort the server to minimize damage.
204    */
205   boolean rollback(Server server, RegionServerServices services) throws IOException;
206 
207   /**
208    * Register a listener for transaction preparation, execution, and possibly
209    * rollback phases.
210    * <p>A listener can abort a transaction by throwing an exception. 
211    * @param listener the listener
212    * @return 'this' for chaining
213    */
214   SplitTransaction registerTransactionListener(TransactionListener listener);
215 
216   /**
217    * Get the journal for the transaction.
218    * <p>Journal entries are an opaque type represented as JournalEntry. They can
219    * also provide useful debugging information via their toString method.
220    * @return the transaction journal
221    */
222   List<JournalEntry> getJournal();
223 
224   /**
225    * Get the Server running the transaction or rollback
226    * @return server instance
227    */
228   Server getServer();
229 
230   /**
231    * Get the RegonServerServices of the server running the transaction or rollback
232    * @return region server services
233    */
234   RegionServerServices getRegionServerServices();
235 }