001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client;
019
020import java.io.IOException;
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.List;
024
025import org.apache.hadoop.hbase.util.Bytes;
026import org.apache.yetus.audience.InterfaceAudience;
027
028import org.apache.hbase.thirdparty.org.apache.commons.collections4.CollectionUtils;
029
030/**
031 * Performs multiple mutations atomically on a single row.
032 *
033 * The mutations are performed in the order in which they
034 * were added.
035 *
036 * <p>We compare and equate mutations based off their row so be careful putting RowMutations
037 * into Sets or using them as keys in Maps.
038 */
039@InterfaceAudience.Public
040public class RowMutations implements Row {
041
042  /**
043   * Create a {@link RowMutations} with the specified mutations.
044   * @param mutations the mutations to send
045   * @return RowMutations
046   * @throws IOException if any row in mutations is different to another
047   */
048  public static RowMutations of(List<? extends Mutation> mutations) throws IOException {
049    if (CollectionUtils.isEmpty(mutations)) {
050      throw new IllegalArgumentException("Cannot instantiate a RowMutations by empty list");
051    }
052    return new RowMutations(mutations.get(0).getRow(), mutations.size())
053        .add(mutations);
054  }
055
056  private final List<Mutation> mutations;
057  private final byte [] row;
058
059  public RowMutations(byte [] row) {
060    this(row, -1);
061  }
062  /**
063   * Create an atomic mutation for the specified row.
064   * @param row row key
065   * @param initialCapacity the initial capacity of the RowMutations
066   */
067  public RowMutations(byte [] row, int initialCapacity) {
068    this.row = Bytes.copy(Mutation.checkRow(row));
069    if (initialCapacity <= 0) {
070      this.mutations = new ArrayList<>();
071    } else {
072      this.mutations = new ArrayList<>(initialCapacity);
073    }
074  }
075
076  /**
077   * @param mutation The data to send.
078   * @throws IOException if the row of added mutation doesn't match the original row
079   */
080  public RowMutations add(Mutation mutation) throws IOException {
081    return add(Collections.singletonList(mutation));
082  }
083
084  /**
085   * @param mutations The data to send.
086   * @throws IOException if the row of added mutation doesn't match the original row
087   */
088  public RowMutations add(List<? extends Mutation> mutations) throws IOException {
089    for (Mutation mutation : mutations) {
090      if (!Bytes.equals(row, mutation.getRow())) {
091        throw new WrongRowIOException("The row in the recently added Mutation <" +
092          Bytes.toStringBinary(mutation.getRow()) + "> doesn't match the original one <" +
093          Bytes.toStringBinary(this.row) + ">");
094      }
095    }
096    this.mutations.addAll(mutations);
097    return this;
098  }
099
100  @Override
101  public byte[] getRow() {
102    return row;
103  }
104
105  /**
106   * @return An unmodifiable list of the current mutations.
107   */
108  public List<Mutation> getMutations() {
109    return Collections.unmodifiableList(mutations);
110  }
111
112  public int getMaxPriority() {
113    int maxPriority = Integer.MIN_VALUE;
114    for (Mutation mutation : mutations) {
115      maxPriority = Math.max(maxPriority, mutation.getPriority());
116    }
117    return maxPriority;
118  }
119}