Package com.alibaba.wasp.fserver

Source Code of com.alibaba.wasp.fserver.SplitTransaction$LoggingProgressable

/**
* Copyright 2010 The Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.alibaba.wasp.fserver;

import com.alibaba.wasp.EntityGroupInfo;
import com.alibaba.wasp.EntityGroupTransaction;
import com.alibaba.wasp.Server;
import com.alibaba.wasp.ServerName;
import com.alibaba.wasp.executor.EventHandler;
import com.alibaba.wasp.meta.FMetaEditor;
import com.alibaba.wasp.zookeeper.ZKAssign;
import com.alibaba.wasp.zookeeper.ZKUtil;
import com.alibaba.wasp.zookeeper.ZooKeeperWatcher;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.CancelableProgressable;
import org.apache.hadoop.hbase.util.HasThread;
import org.apache.hadoop.hbase.util.PairOfSameType;
import org.apache.zookeeper.KeeperException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

/**
* Executes entityGroup split as a "transaction". Call {@link #prepare()} to
* setup the transaction, {@link #execute(com.alibaba.wasp.Server, FServerServices)} to run the
* transaction and {@link #rollback(com.alibaba.wasp.Server, FServerServices)} to cleanup if
* execute fails.
*
* <p>
* Here is an example of how you would use this class:
*
* <pre>
*  SplitTransaction st = new SplitTransaction(this.conf, parent, midKey)
*  if (!st.prepare()) return;
*  try {
*    st.execute(server, services);
*  } catch (IOException ioe) {
*    try {
*      st.rollback(server, services);
*      return;
*    } catch (RuntimeException e) {
*      myAbortable.abort("Failed split, abort");
*    }
*  }
* </Pre>
* <p>
* This class is not thread safe. Caller needs ensure split is run by one thread
* only.
*/
public class SplitTransaction {
  private static final Log LOG = LogFactory.getLog(SplitTransaction.class);
  /*
   * EntityGroup to split
   */
  private final EntityGroup parent;
  private EntityGroupInfo egi_a;
  private EntityGroupInfo egi_b;
  private int znodeVersion = -1;

  /*
   * Row to split around
   */
  private final byte[] splitrow;

  /**
   * Types to add to the transaction journal. Each enum is a step in the split
   * transaction. Used to figure how much we need to rollback.
   */
  enum JournalEntry {
    /**
     * Before creating node in splitting state.
     */
    STARTED_SPLITTING,
      /**
       * Set entityGroup as in transition, set it into SPLITTING state.
       */
      SET_SPLITTING_IN_ZK,
      /**
       * We created the temporary split data directory.
       */
      CREATE_SPLIT_STOREAGE,
      /**
       * Closed the parent entityGroup.
       */
      CLOSED_PARENT_ENTITYGROUP,
      /**
       * The parent has been taken out of the server's online entityGroups list.
       */
      OFFLINED_PARENT,
      /**
       * Started in on creation of the first daughter entityGroup.
       */
      STARTED_ENTITYGROUP_A_CREATION,
      /**
       * Started in on the creation of the second daughter entityGroup.
       */
      STARTED_ENTITYGROUP_B_CREATION,
      /**
       * Point of no return. If we got here, then transaction is not recoverable
       * other than by crashing out the fserver.
       */
      PONR
  }

  /*
   * Journal of how far the split transaction has progressed.
   */
  private final List<JournalEntry> journal = new ArrayList<JournalEntry>();

  private IOException closedByOtherException = new IOException(
      "Failed to close entityGroup: already closed by another thread");

  /**
   * Constructor
   *
   * @param eg
   *          EntityGroup to split
   * @param splitrow
   *          Row to split around
   * @throws java.io.IOException
   */
  // public SplitTransaction(final Configuration conf, final EntityGroup eg,
  // final byte[] splitrow)
  // throws IOException {
  // this(eg, splitrow, conf);
  // }

  public SplitTransaction(final EntityGroup eg, final byte[] splitrow,
      final Configuration conf) throws IOException {
    this.parent = eg;
    this.splitrow = splitrow;
  }

  /**
   * Does checks on split inputs.
   *
   * @return <code>true</code> if the entityGroup is splittable else
   *         <code>false</code> if it is not (e.g. its already closed, etc.).
   */
  public boolean prepare() {
    if (this.parent.isClosed() || this.parent.isClosing()) {
      LOG.info("EntityGroup " + this.parent + " is not splittable,"
          + " opened = " + this.parent.isAvailable());
      return false;
    }
    // Split key can be null if this entityGroup is unsplittable; i.e. has refs.
    if (this.splitrow == null)
      return false;
    EntityGroupInfo egi = this.parent.getEntityGroupInfo();
    // Check splitrow.
    byte[] startKey = egi.getStartKey();
    byte[] endKey = egi.getEndKey();
    if (Bytes.equals(startKey, splitrow)
        || !this.parent.getEntityGroupInfo().containsRow(splitrow)) {
      LOG.info("Split row is not inside entityGroup key range or is equal to "
          + "startkey: " + Bytes.toStringBinary(this.splitrow));
      return false;
    }
    long egid = getDaughterEntityGroupIdTimestamp(egi);
    this.egi_a = new EntityGroupInfo(egi.getTableName(), startKey,
        this.splitrow, false, egid);
    this.egi_b = new EntityGroupInfo(egi.getTableName(), this.splitrow, endKey,
        false, egid);
    return true;
  }

  /**
   * Calculate daughter entityGroupId to use.
   *
   * @param egi
   *          Parent {@link com.alibaba.wasp.EntityGroupInfo}
   * @return Daughter entityGroup id (timestamp) to use.
   */
  private static long getDaughterEntityGroupIdTimestamp(
      final EntityGroupInfo egi) {
    long egid = System.currentTimeMillis();
    // EntityGroupId is timestamp. Can't be less than that of parent else will
    // insert
    // at wrong location in .FMETA.
    if (egid < egi.getEntityGroupId()) {
      LOG.warn("Clock skew; parent entityGroup id is " + egi.getEntityGroupId()
          + " but current time here is " + egid);
      egid = egi.getEntityGroupId() + 1;
    }
    return egid;
  }

  /*
   * Open daughter entityGroup in its own thread. If we fail, abort this hosting
   * server.
   */
  class DaughterOpener extends HasThread {
    private final Server server;
    private final EntityGroup entityGroup;
    private Throwable t = null;

    DaughterOpener(final Server s, final EntityGroup entityGroup) {
      super((s == null ? "null-services" : s.getServerName())
          + "-daughterOpener="
          + entityGroup.getEntityGroupInfo().getEncodedName());
      setDaemon(true);
      this.server = s;
      this.entityGroup = entityGroup;
    }

    /**
     * @return Null if open succeeded else exception that causes us fail open.
     *         Call it after this thread exits else you may get wrong view on
     *         result.
     */
    Throwable getException() {
      return this.t;
    }

    @Override
    public void run() {
      try {
        openDaughterEntityGroup(this.server, entityGroup);
      } catch (Throwable t) {
        this.t = t;
      }
    }
  }

  /**
   * Open daughter entityGroups, add them to online list and update meta.
   *
   * @param server
   * @param daughter
   * @throws java.io.IOException
   * @throws org.apache.zookeeper.KeeperException
   */
  public EntityGroup openDaughterEntityGroup(final Server server,
      final EntityGroup daughter) throws IOException, KeeperException {
    return daughter.openEntityGroup(null);
  }

  static class LoggingProgressable implements CancelableProgressable {
    private final EntityGroupInfo egi;
    private long lastLog = -1;
    private final long interval;

    LoggingProgressable(final EntityGroupInfo egi, final Configuration c) {
      this.egi = egi;
      this.interval = c.getLong(
          "wasp.fserver.split.daughter.open.log.interval", 10000);
    }

    @Override
    public boolean progress() {
      long now = System.currentTimeMillis();
      if (now - lastLog > this.interval) {
        LOG.info("Opening " + this.egi.getEntityGroupNameAsString());
        this.lastLog = now;
      }
      return true;
    }
  }

  /**
   * Run the transaction.
   *
   * @param server
   *          Hosting server instance. Can be null when testing (won't try and
   *          update in zk if a null server)
   * @param services
   *          Used to online/offline entityGroups.
   * @throws java.io.IOException
   *           If thrown, transaction failed. Call
   *           {@link #rollback(com.alibaba.wasp.Server, FServerServices)}
   * @return EntityGroups created
   * @throws java.io.IOException
   * @see #rollback(com.alibaba.wasp.Server, FServerServices)
   */
  public PairOfSameType<EntityGroup> execute(final Server server,
      final FServerServices services) throws IOException {
    PairOfSameType<EntityGroup> entityGroups = createDaughters(server, services);
    openDaughters(server, services, entityGroups.getFirst(),
        entityGroups.getSecond());
    transitionZKNode(server, services, entityGroups.getFirst(),
        entityGroups.getSecond());
    return entityGroups;
  }

  /**
   * Prepare the entityGroups.
   *
   * @param server
   *          Hosting server instance. Can be null when testing (won't try and
   *          update in zk if a null server)
   * @param services
   *          Used to online/offline entityGroups.
   * @throws java.io.IOException
   *           If thrown, transaction failed. Call
   *           {@link #rollback(com.alibaba.wasp.Server, FServerServices)}
   * @return EntityGroups created
   */
  PairOfSameType<EntityGroup> createDaughters(final Server server,
      final FServerServices services) throws IOException {
    LOG.info("Starting split of entityGroup "
        + this.parent.getEntityGroupInfo().toString());
    if ((server != null && server.isStopped())
        || (services != null && services.isStopping())) {
      throw new IOException("Server is stopped or stopping");
    }
    assert !this.parent.lock.writeLock().isHeldByCurrentThread() : "Unsafe to hold write lock while performing RPCs";

    // If true, no cluster to write meta edits to or to update znodes in.
    boolean testing = server == null ? true : server.getConfiguration()
        .getBoolean("wasp.testing.nocluster", false);

    this.journal.add(JournalEntry.STARTED_SPLITTING);
    // Set ephemeral SPLITTING znode up in zk. Mocked servers sometimes don't
    // have zookeeper so don't do zk stuff if server or zookeeper is null
    if (server != null && server.getZooKeeper() != null) {
      try {
        this.znodeVersion = createNodeSplitting(server.getZooKeeper(),
            this.parent.getEntityGroupInfo(), server.getServerName());
      } catch (KeeperException e) {
        throw new IOException("Failed setting SPLITTING znode on "
            + this.parent.getEntityGroupNameAsString(), e);
      }
    }
    this.journal.add(JournalEntry.SET_SPLITTING_IN_ZK);

    this.journal.add(JournalEntry.CREATE_SPLIT_STOREAGE);

    Exception exceptionToThrow = null;
    boolean result = false;
    try {
      result = this.parent.close(false);
    } catch (Exception e) {
      exceptionToThrow = e;
    }
    if (exceptionToThrow == null && !result) {
      // The entityGroup was closed by a concurrent thread. We can't continue
      // with the split, instead we must just abandon the split. If we
      // reopen or split this could cause problems because the entityGroup has
      // probably already been moved to a different server, or is in the
      // process of moving to a different server.
      exceptionToThrow = closedByOtherException;
    }
    if (exceptionToThrow != closedByOtherException) {
      this.journal.add(JournalEntry.CLOSED_PARENT_ENTITYGROUP);
    }
    if (exceptionToThrow != null) {
      if (exceptionToThrow instanceof IOException)
        throw (IOException) exceptionToThrow;
      throw new IOException(exceptionToThrow);
    }

    if (!testing) {
      services.removeFromOnlineEntityGroups(this.parent.getEntityGroupInfo()
          .getEncodedName());
    }
    this.journal.add(JournalEntry.OFFLINED_PARENT);

    // Log to the journal that we are creating entityGroup A, the first daughter
    // entityGroup. We could fail halfway through. If we do, we could have left
    // stuff in fs that needs cleanup -- a storefile or two. Thats why we
    // add entry to journal BEFORE rather than AFTER the change.
    this.journal.add(JournalEntry.STARTED_ENTITYGROUP_A_CREATION);
    EntityGroup a = createDaughterEntityGroup(this.egi_a, this.parent.services);

    // Ditto
    this.journal.add(JournalEntry.STARTED_ENTITYGROUP_B_CREATION);
    EntityGroup b = createDaughterEntityGroup(this.egi_b, this.parent.services);

    // This is the point of no return. Adding subsequent edits to .META. as we
    // do below when we do the daughter opens adding each to .META. can fail in
    // various interesting ways the most interesting of which is a timeout
    // BUT the edits all go through (See HBASE-3872). IF we reach the PONR
    // then subsequent failures need to crash out this entityGroupserver; the
    // server shutdown processing should be able to fix-up the incomplete split.
    // The offlined parent will have the daughters as extra columns. If
    // we leave the daughter entityGroups in place and do not remove them when
    // we
    // crash out, then they will have their references to the parent in place
    // still and the server shutdown fixup of .META. will point to these
    // entityGroups.
    // We should add PONR JournalEntry before offlineParentInMeta,so even if
    // OfflineParentInMeta timeout,this will cause entityGroupserver exit,and
    // then
    // master ServerShutdownHandler will fix daughter & avoid data loss.
    this.journal.add(JournalEntry.PONR);

    // Edit parent in meta. Offlines parent entityGroup and adds splita and
    // splitb.
    if (!testing) {
      FMetaEditor.offlineParentInMeta(server.getConfiguration(),
          this.parent.getEntityGroupInfo(), a.getEntityGroupInfo(),
          b.getEntityGroupInfo());
    }
    return new PairOfSameType<EntityGroup>(a, b);
  }

  /**
   * @param egi
   *          Spec. for daughter entityGroup to open.
   * @return Created daughter EntityGroup.
   * @throws java.io.IOException
   */
  EntityGroup createDaughterEntityGroup(final EntityGroupInfo egi,
      final FServerServices rsServices) throws IOException {
    // Package private so unit tests have access.
    EntityGroup entityGroup = EntityGroup.newEntityGroup(this.parent.getConf(),
        egi, this.parent.getTableDesc(), rsServices);
    entityGroup.readRequestsCount.set(this.parent.getReadRequestsCount() / 2);
    entityGroup.writeRequestsCount.set(this.parent.getWriteRequestsCount() / 2);
    return entityGroup;
  }

  /**
   * Perform time consuming opening of the daughter entityGroups.
   *
   * @param server
   *          Hosting server instance. Can be null when testing (won't try and
   *          update in zk if a null server)
   * @param services
   *          Used to online/offline entityGroups.
   * @param a
   *          first daughter entityGroup
   * @param a
   *          second daughter entityGroup
   * @throws java.io.IOException
   *           If thrown, transaction failed. Call
   *           {@link #rollback(com.alibaba.wasp.Server, FServerServices)}
   */
  void openDaughters(final Server server, final FServerServices services,
      EntityGroup a, EntityGroup b) throws IOException {
    boolean stopped = server != null && server.isStopped();
    boolean stopping = services != null && services.isStopping();
    if (stopped || stopping) {
      LOG.info("Not opening daughters "
          + b.getEntityGroupInfo().getEntityGroupNameAsString() + " and "
          + a.getEntityGroupInfo().getEntityGroupNameAsString()
          + " because stopping=" + stopping + ", stopped=" + stopped);
    } else {
      // Open daughters in parallel.
      DaughterOpener aOpener = new DaughterOpener(server, a);
      DaughterOpener bOpener = new DaughterOpener(server, b);
      aOpener.start();
      bOpener.start();
      try {
        aOpener.join();
        bOpener.join();
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new IOException("Interrupted " + e.getMessage());
      }
      if (aOpener.getException() != null) {
        throw new IOException("Failed " + aOpener.getName(),
            aOpener.getException());
      }
      if (bOpener.getException() != null) {
        throw new IOException("Failed " + bOpener.getName(),
            bOpener.getException());
      }
      if (services != null) {
        // add 2nd daughter first
        services.postOpenDeployTasks(b, true);
        // Should add it to OnlineEntityGroups
        services.addToOnlineEntityGroups(b);
        services.postOpenDeployTasks(a, true);
        services.addToOnlineEntityGroups(a);
      }
    }
  }

  /**
   * Creates a new ephemeral node in the SPLITTING state for the specified
   * entityGroup. Create it ephemeral in case entityGroupserver dies mid-split.
   *
   * <p>
   * Does not transition nodes from other states. If a node already exists for
   * this entityGroup, a
   * {@link org.apache.zookeeper.KeeperException.NodeExistsException} will be
   * thrown.
   *
   * @param zkw
   *          zk reference
   * @param entityGroup
   *          entityGroup to be created as offline
   * @param serverName
   *          server event originates from
   * @return Version of znode created.
   * @throws org.apache.zookeeper.KeeperException
   * @throws java.io.IOException
   */
  int createNodeSplitting(final ZooKeeperWatcher zkw,
      final EntityGroupInfo entityGroup, final ServerName serverName)
      throws KeeperException, IOException {
    LOG.debug(zkw.prefix("Creating ephemeral node for "
        + entityGroup.getEncodedName() + " in SPLITTING state"));
    EntityGroupTransaction data = EntityGroupTransaction
        .createEntityGroupTransition(
            EventHandler.EventType.FSERVER_ZK_ENTITYGROUP_SPLITTING,
            entityGroup.getEntityGroupName(), serverName);
    String node = ZKAssign.getNodeName(zkw, entityGroup.getEncodedName());
    if (!ZKUtil.createEphemeralNodeAndWatch(zkw, node, data.toByteArray())) {
      throw new IOException("Failed create of ephemeral " + node);
    }
    // Transition node from SPLITTING to SPLITTING and pick up version so we
    // can be sure this znode is ours; version is needed deleting.
    return transitionNodeSplitting(zkw, entityGroup, serverName, -1);
  }

  /**
   * Finish off split transaction, transition the zknode
   *
   * @param server
   *          Hosting server instance. Can be null when testing (won't try and
   *          update in zk if a null server)
   * @param services
   *          Used to online/offline entityGroups.
   * @param a
   *          first daughter entityGroup
   * @param a
   *          second daughter entityGroup
   * @throws java.io.IOException
   *           If thrown, transaction failed. Call
   *           {@link #rollback(com.alibaba.wasp.Server, FServerServices)}
   */
  /* package */void transitionZKNode(final Server server,
      final FServerServices services, EntityGroup a, EntityGroup b)
      throws IOException {
    // Tell master about split by updating zk. If we fail, abort.
    if (server != null && server.getZooKeeper() != null) {
      try {
        this.znodeVersion = transitionNodeSplit(server.getZooKeeper(),
            parent.getEntityGroupInfo(), a.getEntityGroupInfo(),
            b.getEntityGroupInfo(), server.getServerName(), this.znodeVersion);

        int spins = 0;
        // Now wait for the master to process the split. We know it's done
        // when the znode is deleted. The reason we keep tickling the znode is
        // that it's possible for the master to miss an event.
        do {
          if (spins % 10 == 0) {
            LOG.debug("Still waiting on the master to process the split for "
                + this.parent.getEntityGroupInfo().getEncodedName());
          }
          Thread.sleep(100);
          // When this returns -1 it means the znode doesn't exist
          this.znodeVersion = tickleNodeSplit(server.getZooKeeper(),
              parent.getEntityGroupInfo(), a.getEntityGroupInfo(),
              b.getEntityGroupInfo(), server.getServerName(), this.znodeVersion);
          spins++;
        } while (this.znodeVersion != -1 && !server.isStopped()
            && !services.isStopping());
      } catch (Exception e) {
        if (e instanceof InterruptedException) {
          Thread.currentThread().interrupt();
        }
        throw new IOException("Failed telling master about split", e);
      }
    }

    // Leaving here, the splitdir with its dross will be in place but since the
    // split was successful, just leave it; it'll be cleaned when parent is
    // deleted and cleaned up.
  }

  /**
   * @param server
   *          Hosting server instance (May be null when testing).
   * @param services
   * @throws java.io.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.
   */
  public boolean rollback(final Server server, final FServerServices services)
      throws IOException {
    boolean result = true;
    ListIterator<JournalEntry> iterator = this.journal
        .listIterator(this.journal.size());
    // Iterate in reverse.
    while (iterator.hasPrevious()) {
      JournalEntry je = iterator.previous();
      switch (je) {

      case STARTED_SPLITTING:
        if (server != null && server.getZooKeeper() != null) {
          cleanZK(server, this.parent.getEntityGroupInfo(), false);
        }
        break;

      case SET_SPLITTING_IN_ZK:
        if (server != null && server.getZooKeeper() != null) {
          cleanZK(server, this.parent.getEntityGroupInfo(), true);
        }
        break;

      case CREATE_SPLIT_STOREAGE:
        this.parent.writestate.writesEnabled = true;
        break;

      case CLOSED_PARENT_ENTITYGROUP:
        try {
          this.parent.initialize();
        } catch (IOException e) {
          LOG.error(
              "Failed rollbacking CLOSED_PARENT_ENTITYGROUP of entityGroup "
                  + this.parent.getEntityGroupNameAsString(), e);
          throw new RuntimeException(e);
        }
        break;

      case STARTED_ENTITYGROUP_A_CREATION:
        break;

      case STARTED_ENTITYGROUP_B_CREATION:
        break;

      case OFFLINED_PARENT:
        if (services != null)
          services.addToOnlineEntityGroups(this.parent);
        break;

      case PONR:
        // We got to the point-of-no-return so we need to just abort. Return
        // immediately. Do not clean up created daughter entityGroups. They need
        // to be in place so we don't delete the parent entityGroup mistakenly.
        // See HBASE-3872.
        return false;

      default:
        throw new RuntimeException("Unhandled journal entry: " + je);
      }
    }
    return result;
  }

  private static void cleanZK(final Server server, final EntityGroupInfo egi,
      boolean abort) {
    try {
      // Only delete if its in expected state; could have been hijacked.
      ZKAssign.deleteNode(server.getZooKeeper(), egi.getEncodedName(),
          EventHandler.EventType.FSERVER_ZK_ENTITYGROUP_SPLITTING);
    } catch (KeeperException.NoNodeException nn) {
      if (abort) {
        server.abort("Failed cleanup of " + egi.getEntityGroupNameAsString(),
            nn);
      }
    } catch (KeeperException e) {
      server.abort("Failed cleanup of " + egi.getEntityGroupNameAsString(), e);
    }
  }

  /**
   * Transitions an existing node for the specified entityGroup which is
   * currently in the SPLITTING state to be in the SPLIT state. Converts the
   * ephemeral SPLITTING znode to an ephemeral SPLIT node. Master cleans up
   * SPLIT znode when it reads it (or if we crash, zk will clean it up).
   *
   * <p>
   * Does not transition nodes from other states. If for some reason the node
   * could not be transitioned, the method returns -1. If the transition is
   * successful, the version of the node after transition is returned.
   *
   * <p>
   * This method can fail and return false for three different reasons:
   * <ul>
   * <li>Node for this entityGroup does not exist</li>
   * <li>Node for this entityGroup is not in SPLITTING state</li>
   * <li>After verifying SPLITTING state, update fails because of wrong version
   * (this should never actually happen since an RS only does this transition
   * following a transition to SPLITTING. if two RS are conflicting, one would
   * fail the original transition to SPLITTING and not this transition)</li>
   * </ul>
   *
   * <p>
   * Does not set any watches.
   *
   * <p>
   * This method should only be used by a FServer when completing the open of a
   * entityGroup.
   *
   * @param zkw
   *          zk reference
   * @param parent
   *          entityGroup to be transitioned to opened
   * @param a
   *          Daughter a of split
   * @param b
   *          Daughter b of split
   * @param serverName
   *          server event originates from
   * @return version of node after transition, -1 if unsuccessful transition
   * @throws org.apache.zookeeper.KeeperException
   *           if unexpected zookeeper exception
   * @throws java.io.IOException
   */
  private static int transitionNodeSplit(ZooKeeperWatcher zkw,
      EntityGroupInfo parent, EntityGroupInfo a, EntityGroupInfo b,
      ServerName serverName, final int znodeVersion) throws KeeperException,
      IOException {
    byte[] payload = EntityGroupInfo.toDelimitedByteArray(a, b);
    return ZKAssign.transitionNode(zkw, parent, serverName,
        EventHandler.EventType.FSERVER_ZK_ENTITYGROUP_SPLITTING,
        EventHandler.EventType.FSERVER_ZK_ENTITYGROUP_SPLIT, znodeVersion,
        payload);
  }

  EntityGroupInfo getFirstDaughter() {
    return egi_a;
  }

  EntityGroupInfo getSecondDaughter() {
    return egi_b;
  }

  /**
   *
   * @param zkw
   *          zk reference
   * @param parent
   *          entityGroup to be transitioned to splitting
   * @param serverName
   *          server event originates from
   * @param version
   *          znode version
   * @return version of node after transition, -1 if unsuccessful transition
   * @throws org.apache.zookeeper.KeeperException
   * @throws java.io.IOException
   */
  int transitionNodeSplitting(final ZooKeeperWatcher zkw,
      final EntityGroupInfo parent, final ServerName serverName,
      final int version) throws KeeperException, IOException {
    return ZKAssign.transitionNode(zkw, parent, serverName,
        EventHandler.EventType.FSERVER_ZK_ENTITYGROUP_SPLITTING,
        EventHandler.EventType.FSERVER_ZK_ENTITYGROUP_SPLITTING, version);
  }

  private static int tickleNodeSplit(ZooKeeperWatcher zkw,
      EntityGroupInfo parent, EntityGroupInfo a, EntityGroupInfo b,
      ServerName serverName, final int znodeVersion) throws KeeperException,
      IOException {
    byte[] payload = EntityGroupInfo.toDelimitedByteArray(a, b);
    return ZKAssign.transitionNode(zkw, parent, serverName,
        EventHandler.EventType.FSERVER_ZK_ENTITYGROUP_SPLIT,
        EventHandler.EventType.FSERVER_ZK_ENTITYGROUP_SPLIT, znodeVersion,
        payload);
  }
}
TOP

Related Classes of com.alibaba.wasp.fserver.SplitTransaction$LoggingProgressable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.