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