Пример #1
0
  private ByteBuffer merge(
      ContextState mergedState, ContextState leftState, ContextState rightState) {
    while (leftState.hasRemaining() && rightState.hasRemaining()) {
      int cmp = leftState.compareIdTo(rightState);
      if (cmp == 0) {
        Relationship rel = compare(leftState, rightState);
        if (rel == Relationship.DISJOINT) // two local shards
        mergedState.writeLocal(
              leftState.getCounterId(),
              leftState.getClock() + rightState.getClock(),
              leftState.getCount() + rightState.getCount());
        else if (rel == Relationship.GREATER_THAN) leftState.copyTo(mergedState);
        else // EQUAL or LESS_THAN
        rightState.copyTo(mergedState);

        rightState.moveToNext();
        leftState.moveToNext();
      } else if (cmp > 0) {
        rightState.copyTo(mergedState);
        rightState.moveToNext();
      } else // cmp < 0
      {
        leftState.copyTo(mergedState);
        leftState.moveToNext();
      }
    }

    while (leftState.hasRemaining()) {
      leftState.copyTo(mergedState);
      leftState.moveToNext();
    }

    while (rightState.hasRemaining()) {
      rightState.copyTo(mergedState);
      rightState.moveToNext();
    }

    return mergedState.context;
  }
Пример #2
0
  /**
   * Return a context w/ an aggregated count for each counter id.
   *
   * @param left counter context.
   * @param right counter context.
   */
  public ByteBuffer merge(ByteBuffer left, ByteBuffer right) {
    boolean leftIsSuperSet = true;
    boolean rightIsSuperSet = true;

    int globalCount = 0;
    int localCount = 0;
    int remoteCount = 0;

    ContextState leftState = ContextState.wrap(left);
    ContextState rightState = ContextState.wrap(right);

    while (leftState.hasRemaining() && rightState.hasRemaining()) {
      int cmp = leftState.compareIdTo(rightState);
      if (cmp == 0) {
        Relationship rel = compare(leftState, rightState);
        if (rel == Relationship.GREATER_THAN) rightIsSuperSet = false;
        else if (rel == Relationship.LESS_THAN) leftIsSuperSet = false;
        else if (rel == Relationship.DISJOINT) leftIsSuperSet = rightIsSuperSet = false;

        if (leftState.isGlobal() || rightState.isGlobal()) globalCount += 1;
        else if (leftState.isLocal() || rightState.isLocal()) localCount += 1;
        else remoteCount += 1;

        leftState.moveToNext();
        rightState.moveToNext();
      } else if (cmp > 0) {
        leftIsSuperSet = false;

        if (rightState.isGlobal()) globalCount += 1;
        else if (rightState.isLocal()) localCount += 1;
        else remoteCount += 1;

        rightState.moveToNext();
      } else // cmp < 0
      {
        rightIsSuperSet = false;

        if (leftState.isGlobal()) globalCount += 1;
        else if (leftState.isLocal()) localCount += 1;
        else remoteCount += 1;

        leftState.moveToNext();
      }
    }

    if (leftState.hasRemaining()) rightIsSuperSet = false;
    else if (rightState.hasRemaining()) leftIsSuperSet = false;

    // if one of the contexts is a superset, return it early.
    if (leftIsSuperSet) return left;
    else if (rightIsSuperSet) return right;

    while (leftState.hasRemaining()) {
      if (leftState.isGlobal()) globalCount += 1;
      else if (leftState.isLocal()) localCount += 1;
      else remoteCount += 1;

      leftState.moveToNext();
    }

    while (rightState.hasRemaining()) {
      if (rightState.isGlobal()) globalCount += 1;
      else if (rightState.isLocal()) localCount += 1;
      else remoteCount += 1;

      rightState.moveToNext();
    }

    leftState.reset();
    rightState.reset();

    return merge(
        ContextState.allocate(globalCount, localCount, remoteCount), leftState, rightState);
  }
Пример #3
0
  /**
   * Determine the count relationship between two contexts.
   *
   * <p>EQUAL: Equal set of nodes and every count is equal. GREATER_THAN: Superset of nodes and
   * every count is equal or greater than its corollary. LESS_THAN: Subset of nodes and every count
   * is equal or less than its corollary. DISJOINT: Node sets are not equal and/or counts are not
   * all greater or less than.
   *
   * <p>Strategy: compare node logical clocks (like a version vector).
   *
   * @param left counter context.
   * @param right counter context.
   * @return the Relationship between the contexts.
   */
  public Relationship diff(ByteBuffer left, ByteBuffer right) {
    Relationship relationship = Relationship.EQUAL;
    ContextState leftState = ContextState.wrap(left);
    ContextState rightState = ContextState.wrap(right);

    while (leftState.hasRemaining() && rightState.hasRemaining()) {
      // compare id bytes
      int compareId = leftState.compareIdTo(rightState);
      if (compareId == 0) {
        long leftClock = leftState.getClock();
        long rightClock = rightState.getClock();
        long leftCount = leftState.getCount();
        long rightCount = rightState.getCount();

        // advance
        leftState.moveToNext();
        rightState.moveToNext();

        // process clock comparisons
        if (leftClock == rightClock) {
          if (leftCount != rightCount) {
            // Inconsistent shard (see the corresponding code in merge()). We return DISJOINT in
            // this
            // case so that it will be treated as a difference, allowing read-repair to work.
            return Relationship.DISJOINT;
          }
        } else if ((leftClock >= 0 && rightClock > 0 && leftClock > rightClock)
            || (leftClock < 0 && (rightClock > 0 || leftClock < rightClock))) {
          if (relationship == Relationship.EQUAL) relationship = Relationship.GREATER_THAN;
          else if (relationship == Relationship.LESS_THAN) return Relationship.DISJOINT;
          // relationship == Relationship.GREATER_THAN
        } else {
          if (relationship == Relationship.EQUAL) relationship = Relationship.LESS_THAN;
          else if (relationship == Relationship.GREATER_THAN) return Relationship.DISJOINT;
          // relationship == Relationship.LESS_THAN
        }
      } else if (compareId > 0) {
        // only advance the right context
        rightState.moveToNext();

        if (relationship == Relationship.EQUAL) relationship = Relationship.LESS_THAN;
        else if (relationship == Relationship.GREATER_THAN) return Relationship.DISJOINT;
        // relationship == Relationship.LESS_THAN
      } else // compareId < 0
      {
        // only advance the left context
        leftState.moveToNext();

        if (relationship == Relationship.EQUAL) relationship = Relationship.GREATER_THAN;
        else if (relationship == Relationship.LESS_THAN) return Relationship.DISJOINT;
        // relationship == Relationship.GREATER_THAN
      }
    }

    // check final lengths
    if (leftState.hasRemaining()) {
      if (relationship == Relationship.EQUAL) return Relationship.GREATER_THAN;
      else if (relationship == Relationship.LESS_THAN) return Relationship.DISJOINT;
    }

    if (rightState.hasRemaining()) {
      if (relationship == Relationship.EQUAL) return Relationship.LESS_THAN;
      else if (relationship == Relationship.GREATER_THAN) return Relationship.DISJOINT;
    }

    return relationship;
  }