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   */
156  public Append addColumn(byte[] family, byte[] qualifier, byte[] value) {
157    KeyValue kv = new KeyValue(this.row, family, qualifier, this.ts, KeyValue.Type.Put, value);
158    return add(kv);
159  }
160
161  /**
162   * Add column and value to this Append operation.
163   * @param cell
164   * @return This instance
165   */
166  @SuppressWarnings("unchecked")
167  public Append add(final Cell cell) {
168    try {
169      super.add(cell);
170    } catch (IOException e) {
171      // we eat the exception of wrong row for BC..
172      LOG.error(e.toString(), e);
173    }
174    return this;
175  }
176
177  @Override
178  public Append setTimestamp(long timestamp) {
179    super.setTimestamp(timestamp);
180    return this;
181  }
182
183  @Override
184  public Append setAttribute(String name, byte[] value) {
185    return (Append) super.setAttribute(name, value);
186  }
187
188  @Override
189  public Append setId(String id) {
190    return (Append) super.setId(id);
191  }
192
193  @Override
194  public Append setDurability(Durability d) {
195    return (Append) super.setDurability(d);
196  }
197
198  @Override
199  public Append setClusterIds(List<UUID> clusterIds) {
200    return (Append) super.setClusterIds(clusterIds);
201  }
202
203  @Override
204  public Append setCellVisibility(CellVisibility expression) {
205    return (Append) super.setCellVisibility(expression);
206  }
207
208  @Override
209  public Append setACL(String user, Permission perms) {
210    return (Append) super.setACL(user, perms);
211  }
212
213  @Override
214  public Append setACL(Map<String, Permission> perms) {
215    return (Append) super.setACL(perms);
216  }
217
218  @Override
219  public Append setPriority(int priority) {
220    return (Append) super.setPriority(priority);
221  }
222
223  @Override
224  public Append setTTL(long ttl) {
225    return (Append) super.setTTL(ttl);
226  }
227}