1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver.wal;
20
21 import java.io.DataInput;
22 import java.io.DataOutput;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.NavigableMap;
26 import java.util.TreeMap;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.hbase.classification.InterfaceAudience;
31 import org.apache.hadoop.hbase.Cell;
32 import org.apache.hadoop.hbase.CellUtil;
33 import org.apache.hadoop.hbase.HRegionInfo;
34 import org.apache.hadoop.hbase.HBaseInterfaceAudience;
35 import org.apache.hadoop.hbase.KeyValue;
36 import org.apache.hadoop.hbase.KeyValueUtil;
37 import org.apache.hadoop.hbase.codec.Codec;
38 import org.apache.hadoop.hbase.io.HeapSize;
39 import org.apache.hadoop.hbase.protobuf.generated.WALProtos;
40 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.CompactionDescriptor;
41 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.FlushDescriptor;
42 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.RegionEventDescriptor;
43 import org.apache.hadoop.hbase.util.Bytes;
44 import org.apache.hadoop.hbase.util.ClassSize;
45 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
46 import org.apache.hadoop.io.Writable;
47
48 import com.google.common.annotations.VisibleForTesting;
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 @InterfaceAudience.LimitedPrivate({ HBaseInterfaceAudience.REPLICATION,
86 HBaseInterfaceAudience.COPROC })
87 public class WALEdit implements Writable, HeapSize {
88 private static final Log LOG = LogFactory.getLog(WALEdit.class);
89
90
91 public static final byte [] METAFAMILY = Bytes.toBytes("METAFAMILY");
92 static final byte [] METAROW = Bytes.toBytes("METAROW");
93 static final byte[] COMPACTION = Bytes.toBytes("HBASE::COMPACTION");
94 static final byte [] FLUSH = Bytes.toBytes("HBASE::FLUSH");
95 static final byte [] REGION_EVENT = Bytes.toBytes("HBASE::REGION_EVENT");
96 @VisibleForTesting
97 public static final byte [] BULK_LOAD = Bytes.toBytes("HBASE::BULK_LOAD");
98
99 private final int VERSION_2 = -1;
100 private final boolean isReplay;
101
102 private ArrayList<Cell> cells = new ArrayList<Cell>(1);
103
104 public static final WALEdit EMPTY_WALEDIT = new WALEdit();
105
106
107
108
109
110 @Deprecated
111 private NavigableMap<byte[], Integer> scopes;
112
113 private CompressionContext compressionContext;
114
115 public WALEdit() {
116 this(false);
117 }
118
119 public WALEdit(boolean isReplay) {
120 this.isReplay = isReplay;
121 }
122
123
124
125
126
127 public static boolean isMetaEditFamily(final byte [] f) {
128 return Bytes.equals(METAFAMILY, f);
129 }
130
131 public static boolean isMetaEditFamily(Cell cell) {
132 return CellUtil.matchingFamily(cell, METAFAMILY);
133 }
134
135 public boolean isMetaEdit() {
136 for (Cell cell: cells) {
137 if (!isMetaEditFamily(cell)) {
138 return false;
139 }
140 }
141 return true;
142 }
143
144
145
146
147
148 public boolean isReplay() {
149 return this.isReplay;
150 }
151
152 public void setCompressionContext(final CompressionContext compressionContext) {
153 this.compressionContext = compressionContext;
154 }
155
156 public WALEdit add(Cell cell) {
157 this.cells.add(cell);
158 return this;
159 }
160
161 public boolean isEmpty() {
162 return cells.isEmpty();
163 }
164
165 public int size() {
166 return cells.size();
167 }
168
169 public ArrayList<Cell> getCells() {
170 return cells;
171 }
172
173
174
175
176
177
178
179
180 @InterfaceAudience.Private
181 public void setCells(ArrayList<Cell> cells) {
182 this.cells = cells;
183 }
184
185 public NavigableMap<byte[], Integer> getAndRemoveScopes() {
186 NavigableMap<byte[], Integer> result = scopes;
187 scopes = null;
188 return result;
189 }
190
191 @Override
192 public void readFields(DataInput in) throws IOException {
193 cells.clear();
194 if (scopes != null) {
195 scopes.clear();
196 }
197 int versionOrLength = in.readInt();
198
199 if (versionOrLength == VERSION_2) {
200
201 int numEdits = in.readInt();
202 for (int idx = 0; idx < numEdits; idx++) {
203 if (compressionContext != null) {
204 this.add(KeyValueCompression.readKV(in, compressionContext));
205 } else {
206 this.add(KeyValue.create(in));
207 }
208 }
209 int numFamilies = in.readInt();
210 if (numFamilies > 0) {
211 if (scopes == null) {
212 scopes = new TreeMap<byte[], Integer>(Bytes.BYTES_COMPARATOR);
213 }
214 for (int i = 0; i < numFamilies; i++) {
215 byte[] fam = Bytes.readByteArray(in);
216 int scope = in.readInt();
217 scopes.put(fam, scope);
218 }
219 }
220 } else {
221
222
223 this.add(KeyValue.create(versionOrLength, in));
224 }
225 }
226
227 @Override
228 public void write(DataOutput out) throws IOException {
229 LOG.warn("WALEdit is being serialized to writable - only expected in test code");
230 out.writeInt(VERSION_2);
231 out.writeInt(cells.size());
232
233 for (Cell cell : cells) {
234
235 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
236 if (compressionContext != null) {
237 KeyValueCompression.writeKV(out, kv, compressionContext);
238 } else{
239 KeyValue.write(kv, out);
240 }
241 }
242 if (scopes == null) {
243 out.writeInt(0);
244 } else {
245 out.writeInt(scopes.size());
246 for (byte[] key : scopes.keySet()) {
247 Bytes.writeByteArray(out, key);
248 out.writeInt(scopes.get(key));
249 }
250 }
251 }
252
253
254
255
256
257
258
259 public int readFromCells(Codec.Decoder cellDecoder, int expectedCount) throws IOException {
260 cells.clear();
261 cells.ensureCapacity(expectedCount);
262 while (cells.size() < expectedCount && cellDecoder.advance()) {
263 cells.add(cellDecoder.current());
264 }
265 return cells.size();
266 }
267
268 @Override
269 public long heapSize() {
270 long ret = ClassSize.ARRAYLIST;
271 for (Cell cell : cells) {
272 ret += CellUtil.estimatedHeapSizeOf(cell);
273 }
274 if (scopes != null) {
275 ret += ClassSize.TREEMAP;
276 ret += ClassSize.align(scopes.size() * ClassSize.MAP_ENTRY);
277
278 }
279 return ret;
280 }
281
282 @Override
283 public String toString() {
284 StringBuilder sb = new StringBuilder();
285
286 sb.append("[#edits: " + cells.size() + " = <");
287 for (Cell cell : cells) {
288 sb.append(cell);
289 sb.append("; ");
290 }
291 if (scopes != null) {
292 sb.append(" scopes: " + scopes.toString());
293 }
294 sb.append(">]");
295 return sb.toString();
296 }
297
298 public static WALEdit createFlushWALEdit(HRegionInfo hri, FlushDescriptor f) {
299 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, FLUSH,
300 EnvironmentEdgeManager.currentTime(), f.toByteArray());
301 return new WALEdit().add(kv);
302 }
303
304 public static FlushDescriptor getFlushDescriptor(Cell cell) throws IOException {
305 if (CellUtil.matchingColumn(cell, METAFAMILY, FLUSH)) {
306 return FlushDescriptor.parseFrom(cell.getValue());
307 }
308 return null;
309 }
310
311 public static WALEdit createRegionEventWALEdit(HRegionInfo hri,
312 RegionEventDescriptor regionEventDesc) {
313 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, REGION_EVENT,
314 EnvironmentEdgeManager.currentTime(), regionEventDesc.toByteArray());
315 return new WALEdit().add(kv);
316 }
317
318 public static RegionEventDescriptor getRegionEventDescriptor(Cell cell) throws IOException {
319 if (CellUtil.matchingColumn(cell, METAFAMILY, REGION_EVENT)) {
320 return RegionEventDescriptor.parseFrom(cell.getValue());
321 }
322 return null;
323 }
324
325
326
327
328
329
330 public static WALEdit createCompaction(final HRegionInfo hri, final CompactionDescriptor c) {
331 byte [] pbbytes = c.toByteArray();
332 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, COMPACTION,
333 EnvironmentEdgeManager.currentTime(), pbbytes);
334 return new WALEdit().add(kv);
335 }
336
337 private static byte[] getRowForRegion(HRegionInfo hri) {
338 byte[] startKey = hri.getStartKey();
339 if (startKey.length == 0) {
340
341
342 return new byte[] {0};
343 }
344 return startKey;
345 }
346
347
348
349
350
351
352 public static CompactionDescriptor getCompaction(Cell kv) throws IOException {
353 if (CellUtil.matchingColumn(kv, METAFAMILY, COMPACTION)) {
354 return CompactionDescriptor.parseFrom(kv.getValue());
355 }
356 return null;
357 }
358
359
360
361
362
363
364
365
366 public static WALEdit createBulkLoadEvent(HRegionInfo hri,
367 WALProtos.BulkLoadDescriptor bulkLoadDescriptor) {
368 KeyValue kv = new KeyValue(getRowForRegion(hri),
369 METAFAMILY,
370 BULK_LOAD,
371 EnvironmentEdgeManager.currentTime(),
372 bulkLoadDescriptor.toByteArray());
373 return new WALEdit().add(kv);
374 }
375
376
377
378
379
380
381 public static WALProtos.BulkLoadDescriptor getBulkLoadDescriptor(Cell cell) throws IOException {
382 if (CellUtil.matchingColumn(cell, METAFAMILY, BULK_LOAD)) {
383 return WALProtos.BulkLoadDescriptor.parseFrom(cell.getValue());
384 }
385 return null;
386 }
387 }