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