HBASE-21843 RegionGroupingProvider breaks the meta wal file name pattern which may...
[hbase.git] / hbase-server / src / main / java / org / apache / hadoop / hbase / wal / WALEdit.java
blobe9f9af10596fedc640f7c8210e9e273bde12768c
1 /**
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 package org.apache.hadoop.hbase.wal;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.TreeSet;
27 import org.apache.hadoop.hbase.Cell;
28 import org.apache.hadoop.hbase.CellUtil;
29 import org.apache.hadoop.hbase.HBaseInterfaceAudience;
30 import org.apache.hadoop.hbase.KeyValue;
31 import org.apache.hadoop.hbase.PrivateCellUtil;
32 import org.apache.hadoop.hbase.client.RegionInfo;
33 import org.apache.hadoop.hbase.codec.Codec;
34 import org.apache.hadoop.hbase.io.HeapSize;
35 import org.apache.hadoop.hbase.util.Bytes;
36 import org.apache.hadoop.hbase.util.ClassSize;
37 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
38 import org.apache.yetus.audience.InterfaceAudience;
40 import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
42 import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos;
43 import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.CompactionDescriptor;
44 import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor;
45 import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.RegionEventDescriptor;
47 /**
48 * Used in HBase's transaction log (WAL) to represent a collection of edits (Cell/KeyValue objects)
49 * that came in as a single transaction. All the edits for a given transaction are written out as a
50 * single record, in PB format, followed (optionally) by Cells written via the WALCellEncoder.
51 * <p>This class is LimitedPrivate for CPs to read-only. The {@link #add} methods are
52 * classified as private methods, not for use by CPs.</p>
53 * <p>WALEdit will accumulate a Set of all column family names referenced by the Cells
54 * {@link #add(Cell)}'d. This is an optimization. Usually when loading a WALEdit, we have the
55 * column family name to-hand.. just shove it into the WALEdit if available. Doing this, we can
56 * save on a parse of each Cell to figure column family down the line when we go to add the
57 * WALEdit to the WAL file. See the hand-off in FSWALEntry Constructor.
59 // TODO: Do not expose this class to Coprocessors. It has set methods. A CP might meddle.
60 @InterfaceAudience.LimitedPrivate({ HBaseInterfaceAudience.REPLICATION,
61 HBaseInterfaceAudience.COPROC })
62 public class WALEdit implements HeapSize {
64 // TODO: Get rid of this; see HBASE-8457
65 public static final byte [] METAFAMILY = Bytes.toBytes("METAFAMILY");
66 @VisibleForTesting
67 public static final byte [] METAROW = Bytes.toBytes("METAROW");
68 @VisibleForTesting
69 public static final byte[] COMPACTION = Bytes.toBytes("HBASE::COMPACTION");
70 @VisibleForTesting
71 public static final byte [] FLUSH = Bytes.toBytes("HBASE::FLUSH");
72 @VisibleForTesting
73 public static final byte [] REGION_EVENT = Bytes.toBytes("HBASE::REGION_EVENT");
74 @VisibleForTesting
75 public static final byte [] BULK_LOAD = Bytes.toBytes("HBASE::BULK_LOAD");
77 private final boolean replay;
79 private ArrayList<Cell> cells = null;
81 /**
82 * All the Cell families in <code>cells</code>. Updated by {@link #add(Cell)} and
83 * {@link #add(Map)}. This Set is passed to the FSWALEntry so it does not have
84 * to recalculate the Set of families in a transaction; makes for a bunch of CPU savings.
85 * An optimization that saves on CPU-expensive Cell-parsing.
87 private Set<byte []> families = null;
89 public WALEdit() {
90 this(false);
93 /**
94 * @deprecated Since 2.0.1. Use {@link #WALEdit(int, boolean)} instead.
96 @Deprecated
97 public WALEdit(boolean isReplay) {
98 this(1, isReplay);
102 * @deprecated Since 2.0.1. Use {@link #WALEdit(int, boolean)} instead.
104 @Deprecated
105 public WALEdit(int cellCount) {
106 this(cellCount, false);
110 * @param cellCount Pass so can pre-size the WALEdit. Optimization.
112 public WALEdit(int cellCount, boolean isReplay) {
113 this.replay = isReplay;
114 cells = new ArrayList<>(cellCount);
117 private Set<byte[]> getOrCreateFamilies() {
118 if (this.families == null) {
119 this.families = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
121 return this.families;
125 * For use by FSWALEntry ONLY. An optimization.
126 * @return All families in {@link #getCells()}; may be null.
128 public Set<byte []> getFamilies() {
129 return this.families;
133 * @return True is <code>f</code> is {@link #METAFAMILY}
135 public static boolean isMetaEditFamily(final byte [] f) {
136 return Bytes.equals(METAFAMILY, f);
139 public static boolean isMetaEditFamily(Cell cell) {
140 return CellUtil.matchingFamily(cell, METAFAMILY);
143 public boolean isMetaEdit() {
144 for (Cell cell: cells) {
145 if (!isMetaEditFamily(cell)) {
146 return false;
149 return true;
153 * @return True when current WALEdit is created by log replay. Replication skips WALEdits from
154 * replay.
156 public boolean isReplay() {
157 return this.replay;
160 @InterfaceAudience.Private
161 public WALEdit add(Cell cell, byte [] family) {
162 getOrCreateFamilies().add(family);
163 return addCell(cell);
166 @InterfaceAudience.Private
167 public WALEdit add(Cell cell) {
168 // We clone Family each time we add a Cell. Expensive but safe. For CPU savings, use
169 // add(Map) or add(Cell, family).
170 return add(cell, CellUtil.cloneFamily(cell));
173 public boolean isEmpty() {
174 return cells.isEmpty();
177 public int size() {
178 return cells.size();
181 public ArrayList<Cell> getCells() {
182 return cells;
186 * This is not thread safe.
187 * This will change the WALEdit and shouldn't be used unless you are sure that nothing
188 * else depends on the contents being immutable.
190 * @param cells the list of cells that this WALEdit now contains.
192 @InterfaceAudience.Private
193 // Used by replay.
194 public void setCells(ArrayList<Cell> cells) {
195 this.cells = cells;
196 this.families = null;
200 * Reads WALEdit from cells.
201 * @param cellDecoder Cell decoder.
202 * @param expectedCount Expected cell count.
203 * @return Number of KVs read.
205 public int readFromCells(Codec.Decoder cellDecoder, int expectedCount) throws IOException {
206 cells.clear();
207 cells.ensureCapacity(expectedCount);
208 while (cells.size() < expectedCount && cellDecoder.advance()) {
209 cells.add(cellDecoder.current());
211 return cells.size();
214 @Override
215 public long heapSize() {
216 long ret = ClassSize.ARRAYLIST;
217 for (Cell cell : cells) {
218 ret += cell.heapSize();
220 return ret;
223 public long estimatedSerializedSizeOf() {
224 long ret = 0;
225 for (Cell cell: cells) {
226 ret += PrivateCellUtil.estimatedSerializedSizeOf(cell);
228 return ret;
231 @Override
232 public String toString() {
233 StringBuilder sb = new StringBuilder();
235 sb.append("[#edits: " + cells.size() + " = <");
236 for (Cell cell : cells) {
237 sb.append(cell);
238 sb.append("; ");
240 sb.append(">]");
241 return sb.toString();
244 public static WALEdit createFlushWALEdit(RegionInfo hri, FlushDescriptor f) {
245 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, FLUSH,
246 EnvironmentEdgeManager.currentTime(), f.toByteArray());
247 return new WALEdit().add(kv, METAFAMILY);
250 public static FlushDescriptor getFlushDescriptor(Cell cell) throws IOException {
251 if (CellUtil.matchingColumn(cell, METAFAMILY, FLUSH)) {
252 return FlushDescriptor.parseFrom(CellUtil.cloneValue(cell));
254 return null;
257 public static WALEdit createRegionEventWALEdit(RegionInfo hri,
258 RegionEventDescriptor regionEventDesc) {
259 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, REGION_EVENT,
260 EnvironmentEdgeManager.currentTime(), regionEventDesc.toByteArray());
261 return new WALEdit().add(kv, METAFAMILY);
264 public static RegionEventDescriptor getRegionEventDescriptor(Cell cell) throws IOException {
265 if (CellUtil.matchingColumn(cell, METAFAMILY, REGION_EVENT)) {
266 return RegionEventDescriptor.parseFrom(CellUtil.cloneValue(cell));
268 return null;
272 * Create a compaction WALEdit
273 * @param c
274 * @return A WALEdit that has <code>c</code> serialized as its value
276 public static WALEdit createCompaction(final RegionInfo hri, final CompactionDescriptor c) {
277 byte [] pbbytes = c.toByteArray();
278 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, COMPACTION,
279 EnvironmentEdgeManager.currentTime(), pbbytes);
280 return new WALEdit().add(kv, METAFAMILY); //replication scope null so this won't be replicated
283 public static byte[] getRowForRegion(RegionInfo hri) {
284 byte[] startKey = hri.getStartKey();
285 if (startKey.length == 0) {
286 // empty row key is not allowed in mutations because it is both the start key and the end key
287 // we return the smallest byte[] that is bigger (in lex comparison) than byte[0].
288 return new byte[] {0};
290 return startKey;
294 * Deserialized and returns a CompactionDescriptor is the KeyValue contains one.
295 * @param kv the key value
296 * @return deserialized CompactionDescriptor or null.
298 public static CompactionDescriptor getCompaction(Cell kv) throws IOException {
299 if (isCompactionMarker(kv)) {
300 return CompactionDescriptor.parseFrom(CellUtil.cloneValue(kv));
302 return null;
306 * Returns true if the given cell is a serialized {@link CompactionDescriptor}
308 * @see #getCompaction(Cell)
310 public static boolean isCompactionMarker(Cell cell) {
311 return CellUtil.matchingColumn(cell, METAFAMILY, COMPACTION);
315 * Create a bulk loader WALEdit
317 * @param hri The RegionInfo for the region in which we are bulk loading
318 * @param bulkLoadDescriptor The descriptor for the Bulk Loader
319 * @return The WALEdit for the BulkLoad
321 public static WALEdit createBulkLoadEvent(RegionInfo hri,
322 WALProtos.BulkLoadDescriptor bulkLoadDescriptor) {
323 KeyValue kv = new KeyValue(getRowForRegion(hri),
324 METAFAMILY,
325 BULK_LOAD,
326 EnvironmentEdgeManager.currentTime(),
327 bulkLoadDescriptor.toByteArray());
328 return new WALEdit().add(kv, METAFAMILY);
332 * Deserialized and returns a BulkLoadDescriptor from the passed in Cell
333 * @param cell the key value
334 * @return deserialized BulkLoadDescriptor or null.
336 public static WALProtos.BulkLoadDescriptor getBulkLoadDescriptor(Cell cell) throws IOException {
337 if (CellUtil.matchingColumn(cell, METAFAMILY, BULK_LOAD)) {
338 return WALProtos.BulkLoadDescriptor.parseFrom(CellUtil.cloneValue(cell));
340 return null;
344 * Append the given map of family->edits to a WALEdit data structure.
345 * This does not write to the WAL itself.
346 * Note that as an optimization, we will stamp the Set of column families into the WALEdit
347 * to save on our having to calculate it subsequently way down in the actual WAL writing.
349 * @param familyMap map of family->edits
351 public void add(Map<byte[], List<Cell>> familyMap) {
352 for (Map.Entry<byte [], List<Cell>> e: familyMap.entrySet()) {
353 // 'foreach' loop NOT used. See HBASE-12023 "...creates too many iterator objects."
354 int listSize = e.getValue().size();
355 // Add all Cells first and then at end, add the family rather than call {@link #add(Cell)}
356 // and have it clone family each time. Optimization!
357 for (int i = 0; i < listSize; i++) {
358 addCell(e.getValue().get(i));
360 addFamily(e.getKey());
364 private void addFamily(byte [] family) {
365 getOrCreateFamilies().add(family);
368 private WALEdit addCell(Cell cell) {
369 this.cells.add(cell);
370 return this;