[ 
https://issues.apache.org/jira/browse/HBASE-12975?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14341164#comment-14341164
 ] 

Andrew Purtell commented on HBASE-12975:
----------------------------------------

Here's what I have for SplitTransaction. RegionMergeTransaction will be 
similar, differing in ways you can infer. 
{code:java}
/**
 * Executes region split as a "transaction".  Call {@link #prepare()} to setup
 * the transaction, {@link #execute(Server, RegionServerServices)} to run the
 * transaction and {@link #rollback(Server, RegionServerServices)} to cleanup 
if execute fails.
 *
 * <p>Here is an example of how you would use this interface:
 * <pre>
 *  SplitTransactionFactory factory = new SplitTransactionFactory(conf);
 *  SplitTransaction st = factory.create(parent, midKey)
 *    .registerTransactionListener(new TransactionListener() {
 *       public void transition(SplitTransaction transaction, 
SplitTransactionPhase from,
 *           SplitTransactionPhase to) throws IOException {
 *         // ...
 *       }
 *       public void rollback(SplitTransaction transaction, 
SplitTransactionPhase from,
 *           SplitTransactionPhase to) {
 *         // ...
 *       }
 *    });
 *  if (!st.prepare()) return;
 *  try {
 *    st.execute(server, services);
 *  } catch (IOException e) {
 *    try {
 *      st.rollback(server, services);
 *      return;
 *    } catch (RuntimeException e) {
 *      // abort the server
 *    }
 *  }
 * </Pre>
 * <p>A split transaction is not thread safe.  Callers must ensure a split is 
run by
 * one thread only.
 */
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
@InterfaceStability.Evolving
public interface SplitTransaction {

  /**
   * Each enum is a step in the split transaction.
   */
  public enum SplitTransactionPhase {
    /**
     * Started
     */
    STARTED,
    /**
     * Prepared (after table lock)
     */
    PREPARED,
    /**
     * Before preSplit coprocessor hook
     */
    BEFORE_PRE_SPLIT_HOOK,
    /**
     * After preSplit coprocessor hook
     */
    AFTER_PRE_SPLIT_HOOK,
    /**
     * Set region as in transition, set it into SPLITTING state.
     */
    SET_SPLITTING,
    /**
     * We created the temporary split data directory.
     */
    CREATE_SPLIT_DIR,
    /**
     * Closed the parent region.
     */
    CLOSED_PARENT_REGION,
    /**
     * The parent has been taken out of the server's online regions list.
     */
    OFFLINED_PARENT,
    /**
     * Started in on creation of the first daughter region.
     */
    STARTED_REGION_A_CREATION,
    /**
     * Started in on the creation of the second daughter region.
     */
    STARTED_REGION_B_CREATION,
    /**
     * Opened the first daughter region
     */
    OPENED_REGION_A,
    /**
     * Opened the second daughter region
     */
    OPENED_REGION_B,
    /**
     * Point of no return.
     * If we got here, then transaction is not recoverable other than by
     * crashing out the regionserver.
     */
    PONR,
    /**
     * Before postSplit coprocessor hook
     */
    BEFORE_POST_SPLIT_HOOK,
    /**
     * After postSplit coprocessor hook
     */
    AFTER_POST_SPLIT_HOOK,
    /**
     * Completed
     */
    COMPLETED
  }

  /**
   * Split transaction journal entry
   */
  public interface JournalEntry {

    /** @return the completed phase marked by this journal entry */
    SplitTransactionPhase getPhase();

    /** @return the time of phase completion */
    long getTimeStamp();
  }

  /**
   * Split transaction listener
   */
  public interface TransactionListener {

    /**
     * Invoked when transitioning forward from one transaction phase to another
     * @param transaction the transaction
     * @param from the current phase
     * @param to the next phase
     * @throws IOException listener can throw this to abort
     */
    void transition(SplitTransaction transaction, SplitTransactionPhase from,
        SplitTransactionPhase to) throws IOException;

    /**
     * Invoked when rolling back a transaction from one transaction phase to the
     * previous
     * @param transaction the transaction
     * @param from the current phase
     * @param to the previous phase
     */
    void rollback(SplitTransaction transaction, SplitTransactionPhase from,
        SplitTransactionPhase to);
  }

  /**
   * Check split inputs and prepare the transaction.
   * @return <code>true</code> if the region is splittable else
   * <code>false</code> if it is not (e.g. its already closed, etc.).
   * @throws IOException 
   */
  boolean prepare() throws IOException;

  /**
   * Run the transaction.
   * @param server Hosting server instance.  Can be null when testing.
   * @param services Used to online/offline regions.
   * @throws IOException If thrown, transaction failed.
   *          Call {@link #rollback(Server, RegionServerServices)}
   * @return Regions created
   * @throws IOException
   * @see #rollback(Server, RegionServerServices)
   */
  PairOfSameType<HRegion> execute(Server server, RegionServerServices services) 
throws IOException;

  /**
   * Roll back a failed transaction
   * @param server Hosting server instance (May be null when testing).
   * @param services
   * @throws IOException If thrown, rollback failed.  Take drastic action.
   * @return True if we successfully rolled back, false if we got to the point
   * of no return and so now need to abort the server to minimize damage.
   */
  boolean rollback(Server server, RegionServerServices services) throws 
IOException;

  /**
   * Register a listener for transaction preparation, execution, and possibly
   * rollback phases.
   * <p>A listener can abort a transaction by throwing an exception. 
   * @param listener the listener
   * @returns 'this' for chaining
   */
  SplitTransaction registerTransactionListener(TransactionListener listener);

  /**
   * Get the journal for the transaction.
   * <p>Journal entries are an opaque type represented as JournalEntry. They can
   * also provide useful debugging information via their toString method.
   * @return the transaction journal
   */
  List<JournalEntry> getJournal();

  /**
   * Get the Server running the transaction or rollback
   * @return server instance
   */
  Server getServer();

  /**
   * Get the RegonServerServices of the server running the transaction or 
rollback
   * @return region server services
   */
  RegionServerServices getRegionServerServices();
}
{code}

Working on RegionMergeTransaction now, then there are a bunch of tests I need 
to clean up.

> Supportable SplitTransaction and RegionMergeTransaction interfaces
> ------------------------------------------------------------------
>
>                 Key: HBASE-12975
>                 URL: https://issues.apache.org/jira/browse/HBASE-12975
>             Project: HBase
>          Issue Type: Improvement
>            Reporter: Rajeshbabu Chintaguntla
>            Assignee: Andrew Purtell
>             Fix For: 2.0.0, 1.1.0
>
>         Attachments: HBASE-12975.patch
>
>
> Making SplitTransaction, RegionMergeTransaction limited private is required 
> to support local indexing feature in Phoenix to ensure regions colocation. 
> We can ensure region split, regions merge in the coprocessors in few method 
> calls without touching internals like creating zk's, file layout changes or 
> assignments.
> 1) stepsBeforePONR, stepsAfterPONR we can ensure split.
> 2) meta entries can pass through coprocessors to atomically update with the 
> normal split/merge.
> 3) rollback on failure.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to