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.regionserver;
019
020import org.apache.hadoop.hbase.HBaseInterfaceAudience;
021import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
022import org.apache.yetus.audience.InterfaceAudience;
023import org.apache.hadoop.hbase.client.Mutation;
024import org.apache.hadoop.hbase.wal.WALEdit;
025
026/**
027 * Wraps together the mutations which are applied as a batch to the region and their operation
028 * status and WALEdits.
029 * @see org.apache.hadoop.hbase.coprocessor.RegionObserver#preBatchMutate(
030 * org.apache.hadoop.hbase.coprocessor.ObserverContext, MiniBatchOperationInProgress)
031 * @see org.apache.hadoop.hbase.coprocessor.RegionObserver#postBatchMutate(
032 * org.apache.hadoop.hbase.coprocessor.ObserverContext, MiniBatchOperationInProgress)
033 * @param T Pair<Mutation, Integer> pair of Mutations and associated rowlock ids .
034 */
035@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
036public class MiniBatchOperationInProgress<T> {
037  private final T[] operations;
038  private Mutation[][] operationsFromCoprocessors;
039  private final OperationStatus[] retCodeDetails;
040  private final WALEdit[] walEditsFromCoprocessors;
041  private final int firstIndex;
042  private final int lastIndexExclusive;
043
044  private int readyToWriteCount = 0;
045  private int cellCount = 0;
046  private int numOfPuts = 0;
047  private int numOfDeletes = 0;
048  private int numOfIncrements = 0;
049  private int numOfAppends = 0;
050
051
052  public MiniBatchOperationInProgress(T[] operations, OperationStatus[] retCodeDetails,
053      WALEdit[] walEditsFromCoprocessors, int firstIndex, int lastIndexExclusive,
054      int readyToWriteCount) {
055    Preconditions.checkArgument(readyToWriteCount <= (lastIndexExclusive - firstIndex));
056    this.operations = operations;
057    this.retCodeDetails = retCodeDetails;
058    this.walEditsFromCoprocessors = walEditsFromCoprocessors;
059    this.firstIndex = firstIndex;
060    this.lastIndexExclusive = lastIndexExclusive;
061    this.readyToWriteCount = readyToWriteCount;
062  }
063
064  /**
065   * @return The number of operations(Mutations) involved in this batch.
066   */
067  public int size() {
068    return this.lastIndexExclusive - this.firstIndex;
069  }
070
071  /**
072   * @param index
073   * @return The operation(Mutation) at the specified position.
074   */
075  public T getOperation(int index) {
076    return operations[getAbsoluteIndex(index)];
077  }
078
079  /**
080   * Sets the status code for the operation(Mutation) at the specified position.
081   * By setting this status, {@link org.apache.hadoop.hbase.coprocessor.RegionObserver}
082   * can make HRegion to skip Mutations.
083   * @param index
084   * @param opStatus
085   */
086  public void setOperationStatus(int index, OperationStatus opStatus) {
087    this.retCodeDetails[getAbsoluteIndex(index)] = opStatus;
088  }
089
090  /**
091   * @param index
092   * @return Gets the status code for the operation(Mutation) at the specified position.
093   */
094  public OperationStatus getOperationStatus(int index) {
095    return this.retCodeDetails[getAbsoluteIndex(index)];
096  }
097
098  /**
099   * Sets the walEdit for the operation(Mutation) at the specified position.
100   * @param index
101   * @param walEdit
102   */
103  public void setWalEdit(int index, WALEdit walEdit) {
104    this.walEditsFromCoprocessors[getAbsoluteIndex(index)] = walEdit;
105  }
106
107  /**
108   * @param index
109   * @return Gets the walEdit for the operation(Mutation) at the specified position.
110   */
111  public WALEdit getWalEdit(int index) {
112    return this.walEditsFromCoprocessors[getAbsoluteIndex(index)];
113  }
114
115  private int getAbsoluteIndex(int index) {
116    if (index < 0 || this.firstIndex + index >= this.lastIndexExclusive) {
117      throw new ArrayIndexOutOfBoundsException(index);
118    }
119    return this.firstIndex + index;
120  }
121
122  /**
123   * Add more Mutations corresponding to the Mutation at the given index to be committed atomically
124   * in the same batch. These mutations are applied to the WAL and applied to the memstore as well.
125   * The timestamp of the cells in the given Mutations MUST be obtained from the original mutation.
126   * <b>Note:</b> The durability from CP will be replaced by the durability of corresponding mutation.
127   * <b>Note:</b> Currently only supports Put and Delete operations.
128   * @param index the index that corresponds to the original mutation index in the batch
129   * @param newOperations the Mutations to add
130   */
131  public void addOperationsFromCP(int index, Mutation[] newOperations) {
132    if (this.operationsFromCoprocessors == null) {
133      // lazy allocation to save on object allocation in case this is not used
134      this.operationsFromCoprocessors = new Mutation[operations.length][];
135    }
136    this.operationsFromCoprocessors[getAbsoluteIndex(index)] = newOperations;
137  }
138
139  public Mutation[] getOperationsFromCoprocessors(int index) {
140    return operationsFromCoprocessors == null ? null :
141        operationsFromCoprocessors[getAbsoluteIndex(index)];
142  }
143
144  public int getReadyToWriteCount() {
145    return readyToWriteCount;
146  }
147
148  public int getLastIndexExclusive() {
149    return lastIndexExclusive;
150  }
151
152  public int getCellCount() {
153    return cellCount;
154  }
155
156  public void addCellCount(int cellCount) {
157    this.cellCount += cellCount;
158  }
159
160  public int getNumOfPuts() {
161    return numOfPuts;
162  }
163
164  public void incrementNumOfPuts() {
165    this.numOfPuts += 1;
166  }
167
168  public int getNumOfDeletes() {
169    return numOfDeletes;
170  }
171
172  public void incrementNumOfDeletes() {
173    this.numOfDeletes += 1;
174  }
175
176  public int getNumOfIncrements() {
177    return numOfIncrements;
178  }
179
180  public void incrementNumOfIncrements() {
181    this.numOfIncrements += 1;
182  }
183
184  public int getNumOfAppends() {
185    return numOfAppends;
186  }
187
188  public void incrementNumOfAppends() {
189    this.numOfAppends += 1;
190  }
191}