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