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