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.io.UncheckedIOException;
022import java.util.List;
023import java.util.Map;
024import java.util.NavigableMap;
025import java.util.UUID;
026import org.apache.hadoop.hbase.Cell;
027import org.apache.hadoop.hbase.CellBuilder;
028import org.apache.hadoop.hbase.CellBuilderType;
029import org.apache.hadoop.hbase.KeyValue;
030import org.apache.hadoop.hbase.io.TimeRange;
031import org.apache.hadoop.hbase.security.access.Permission;
032import org.apache.hadoop.hbase.security.visibility.CellVisibility;
033import org.apache.hadoop.hbase.util.Bytes;
034import org.apache.hadoop.hbase.util.ClassSize;
035import org.apache.yetus.audience.InterfaceAudience;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039/**
040 * Performs Append operations on a single row.
041 * <p>
042 * This operation ensures atomicty to readers. Appends are done under a single row lock, so write
043 * operations to a row are synchronized, and readers are guaranteed to see this operation fully
044 * completed.
045 * <p>
046 * To append to a set of columns of a row, instantiate an Append object with the row to append to.
047 * At least one column to append must be specified using the
048 * {@link #addColumn(byte[], byte[], byte[])} method.
049 */
050@InterfaceAudience.Public
051public class Append extends Mutation {
052  private static final Logger LOG = LoggerFactory.getLogger(Append.class);
053  private static final long HEAP_OVERHEAD = (long) ClassSize.REFERENCE + ClassSize.TIMERANGE;
054  private TimeRange tr = TimeRange.allTime();
055
056  /**
057   * Sets the TimeRange to be used on the Get for this append.
058   * <p>
059   * This is useful for when you have counters that only last for specific periods of time (ie.
060   * counters that are partitioned by time). By setting the range of valid times for this append,
061   * you can potentially gain some performance with a more optimal Get operation. Be careful adding
062   * the time range to this class as you will update the old cell if the time range doesn't include
063   * the latest cells.
064   * <p>
065   * This range is used as [minStamp, maxStamp).
066   * @param minStamp minimum timestamp value, inclusive
067   * @param maxStamp maximum timestamp value, exclusive
068   */
069  public Append setTimeRange(long minStamp, long maxStamp) {
070    tr = TimeRange.between(minStamp, maxStamp);
071    return this;
072  }
073
074  /**
075   * Gets the TimeRange used for this append.
076   */
077  public TimeRange getTimeRange() {
078    return this.tr;
079  }
080
081  @Override
082  protected long extraHeapSize() {
083    return HEAP_OVERHEAD;
084  }
085
086  /**
087   * True (default) if the append operation should return the results. A client that is not
088   * interested in the result can save network bandwidth setting this to false.
089   */
090  @Override
091  public Append setReturnResults(boolean returnResults) {
092    super.setReturnResults(returnResults);
093    return this;
094  }
095
096  /** Returns current setting for returnResults */
097  // This method makes public the superclasses's protected method.
098  @Override
099  public boolean isReturnResults() {
100    return super.isReturnResults();
101  }
102
103  /**
104   * Create a Append operation for the specified row.
105   * <p>
106   * At least one column must be appended to.
107   * @param row row key; makes a local copy of passed in array.
108   */
109  public Append(byte[] row) {
110    this(row, 0, row.length);
111  }
112
113  /**
114   * Copy constructor
115   * @param appendToCopy append to copy
116   */
117  public Append(Append appendToCopy) {
118    super(appendToCopy);
119    this.tr = appendToCopy.getTimeRange();
120  }
121
122  /**
123   * Create a Append operation for the specified row.
124   * <p>
125   * At least one column must be appended to.
126   * @param rowArray Makes a copy out of this buffer.
127   */
128  public Append(final byte[] rowArray, final int rowOffset, final int rowLength) {
129    checkRow(rowArray, rowOffset, rowLength);
130    this.row = Bytes.copy(rowArray, rowOffset, rowLength);
131  }
132
133  /**
134   * Construct the Append with user defined data. NOTED: 1) all cells in the familyMap must have the
135   * Type.Put 2) the row of each cell must be same with passed row.
136   * @param row       row. CAN'T be null
137   * @param ts        timestamp
138   * @param familyMap the map to collect all cells internally. CAN'T be null
139   */
140  public Append(byte[] row, long ts, NavigableMap<byte[], List<Cell>> familyMap) {
141    super(row, ts, familyMap);
142  }
143
144  /**
145   * Add the specified column and value to this Append operation.
146   * @param family    family name
147   * @param qualifier column qualifier
148   * @param value     value to append to specified column
149   */
150  public Append addColumn(byte[] family, byte[] qualifier, byte[] value) {
151    KeyValue kv = new KeyValue(this.row, family, qualifier, this.ts, KeyValue.Type.Put, value);
152    return add(kv);
153  }
154
155  /**
156   * Add column and value to this Append operation.
157   * @return This instance
158   * @deprecated Since 3.0.0, and the method signature will be changed in 4.0.0, where we will throw
159   *             IOException out when the row of the given cell does not match.
160   */
161  @Deprecated
162  @Override
163  public Append add(final Cell cell) {
164    try {
165      super.add(cell);
166    } catch (IOException e) {
167      // we can not simply change the method signature for a IA.Public method, so here we convert it
168      // to an unchecked exception
169      throw new UncheckedIOException(e);
170    }
171    return this;
172  }
173
174  @Override
175  public Append setTimestamp(long timestamp) {
176    super.setTimestamp(timestamp);
177    return this;
178  }
179
180  @Override
181  public Append setAttribute(String name, byte[] value) {
182    return (Append) super.setAttribute(name, value);
183  }
184
185  @Override
186  public Append setId(String id) {
187    return (Append) super.setId(id);
188  }
189
190  @Override
191  public Append setDurability(Durability d) {
192    return (Append) super.setDurability(d);
193  }
194
195  @Override
196  public Append setClusterIds(List<UUID> clusterIds) {
197    return (Append) super.setClusterIds(clusterIds);
198  }
199
200  @Override
201  public Append setCellVisibility(CellVisibility expression) {
202    return (Append) super.setCellVisibility(expression);
203  }
204
205  @Override
206  public Append setACL(String user, Permission perms) {
207    return (Append) super.setACL(user, perms);
208  }
209
210  @Override
211  public Append setACL(Map<String, Permission> perms) {
212    return (Append) super.setACL(perms);
213  }
214
215  @Override
216  public Append setPriority(int priority) {
217    return (Append) super.setPriority(priority);
218  }
219
220  @Override
221  public Append setTTL(long ttl) {
222    return (Append) super.setTTL(ttl);
223  }
224
225  @Override
226  public CellBuilder getCellBuilder(CellBuilderType type) {
227    return getCellBuilder(type, Cell.Type.Put);
228  }
229}