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.Arrays;
023import java.util.Collections;
024import java.util.List;
025
026import org.apache.hadoop.hbase.util.Bytes;
027import org.apache.yetus.audience.InterfaceAudience;
028
029import org.apache.hbase.thirdparty.org.apache.commons.collections4.CollectionUtils;
030
031/**
032 * Performs multiple mutations atomically on a single row.
033 * Currently {@link Put} and {@link Delete} are supported.
034 *
035 * The mutations are performed in the order in which they
036 * were added.
037 *
038 * <p>We compare and equate mutations based off their row so be careful putting RowMutations
039 * into Sets or using them as keys in Maps.
040 */
041@InterfaceAudience.Public
042public class RowMutations implements Row {
043
044  /**
045   * Create a {@link RowMutations} with the specified mutations.
046   * @param mutations the mutations to send
047   * @return RowMutations
048   * @throws IOException if any row in mutations is different to another
049   */
050  public static RowMutations of(List<? extends Mutation> mutations) throws IOException {
051    if (CollectionUtils.isEmpty(mutations)) {
052      throw new IllegalArgumentException("Cannot instantiate a RowMutations by empty list");
053    }
054    return new RowMutations(mutations.get(0).getRow(), mutations.size())
055        .add(mutations);
056  }
057
058  private final List<Mutation> mutations;
059  private final byte [] row;
060
061  public RowMutations(byte [] row) {
062    this(row, -1);
063  }
064  /**
065   * Create an atomic mutation for the specified row.
066   * @param row row key
067   * @param initialCapacity the initial capacity of the RowMutations
068   */
069  public RowMutations(byte [] row, int initialCapacity) {
070    this.row = Bytes.copy(Mutation.checkRow(row));
071    if (initialCapacity <= 0) {
072      this.mutations = new ArrayList<>();
073    } else {
074      this.mutations = new ArrayList<>(initialCapacity);
075    }
076  }
077
078  /**
079   * Add a {@link Put} operation to the list of mutations
080   * @param p The {@link Put} to add
081   * @throws IOException if the row of added mutation doesn't match the original row
082   * @deprecated since 2.0 version and will be removed in 3.0 version.
083   *             use {@link #add(Mutation)}
084   */
085  @Deprecated
086  public void add(Put p) throws IOException {
087    add((Mutation) p);
088  }
089
090  /**
091   * Add a {@link Delete} operation to the list of mutations
092   * @param d The {@link Delete} to add
093   * @throws IOException if the row of added mutation doesn't match the original row
094   * @deprecated since 2.0 version and will be removed in 3.0 version.
095   *             use {@link #add(Mutation)}
096   */
097  @Deprecated
098  public void add(Delete d) throws IOException {
099    add((Mutation) d);
100  }
101
102  /**
103   * Currently only supports {@link Put} and {@link Delete} mutations.
104   *
105   * @param mutation The data to send.
106   * @throws IOException if the row of added mutation doesn't match the original row
107   */
108  public RowMutations add(Mutation mutation) throws IOException {
109    return add(Collections.singletonList(mutation));
110  }
111
112  /**
113   * Currently only supports {@link Put} and {@link Delete} mutations.
114   *
115   * @param mutations The data to send.
116   * @throws IOException if the row of added mutation doesn't match the original row
117   */
118  public RowMutations add(List<? extends Mutation> mutations) throws IOException {
119    for (Mutation mutation : mutations) {
120      if (!Bytes.equals(row, mutation.getRow())) {
121        throw new WrongRowIOException("The row in the recently added Put/Delete <" +
122          Bytes.toStringBinary(mutation.getRow()) + "> doesn't match the original one <" +
123          Bytes.toStringBinary(this.row) + ">");
124      }
125    }
126    this.mutations.addAll(mutations);
127    return this;
128  }
129
130  /**
131   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
132   *             Use {@link Row#COMPARATOR} instead
133   */
134  @Deprecated
135  @Override
136  public int compareTo(Row i) {
137    return Bytes.compareTo(this.getRow(), i.getRow());
138  }
139
140  /**
141   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
142   *             No replacement
143   */
144  @Deprecated
145  @Override
146  public boolean equals(Object obj) {
147    if (obj == this) return true;
148    if (obj instanceof RowMutations) {
149      RowMutations other = (RowMutations)obj;
150      return compareTo(other) == 0;
151    }
152    return false;
153  }
154
155  /**
156   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
157   *             No replacement
158   */
159  @Deprecated
160  @Override
161  public int hashCode(){
162    return Arrays.hashCode(row);
163  }
164
165  @Override
166  public byte[] getRow() {
167    return row;
168  }
169
170  /**
171   * @return An unmodifiable list of the current mutations.
172   */
173  public List<Mutation> getMutations() {
174    return Collections.unmodifiableList(mutations);
175  }
176
177  public int getMaxPriority() {
178    int maxPriority = Integer.MIN_VALUE;
179    for (Mutation mutation : mutations) {
180      maxPriority = Math.max(maxPriority, mutation.getPriority());
181    }
182    return maxPriority;
183  }
184}