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 @VisibleForTesting
93 public static final byte [] METAROW = Bytes.toBytes("METAROW");
94 @VisibleForTesting
95 public static final byte[] COMPACTION = Bytes.toBytes("HBASE::COMPACTION");
96 @VisibleForTesting
97 public static final byte [] FLUSH = Bytes.toBytes("HBASE::FLUSH");
98 @VisibleForTesting
99 public static final byte [] REGION_EVENT = Bytes.toBytes("HBASE::REGION_EVENT");
100 @VisibleForTesting
101 public static final byte [] BULK_LOAD = Bytes.toBytes("HBASE::BULK_LOAD");
102
103 private final int VERSION_2 = -1;
104 private final boolean isReplay;
105
106 private ArrayList<Cell> cells = new ArrayList<Cell>(1);
107
108 public static final WALEdit EMPTY_WALEDIT = new WALEdit();
109
110
111
112
113
114 @Deprecated
115 private NavigableMap<byte[], Integer> scopes;
116
117 private CompressionContext compressionContext;
118
119 public WALEdit() {
120 this(false);
121 }
122
123 public WALEdit(boolean isReplay) {
124 this.isReplay = isReplay;
125 }
126
127
128
129
130
131 public static boolean isMetaEditFamily(final byte [] f) {
132 return Bytes.equals(METAFAMILY, f);
133 }
134
135 public static boolean isMetaEditFamily(Cell cell) {
136 return CellUtil.matchingFamily(cell, METAFAMILY);
137 }
138
139 public boolean isMetaEdit() {
140 for (Cell cell: cells) {
141 if (!isMetaEditFamily(cell)) {
142 return false;
143 }
144 }
145 return true;
146 }
147
148
149
150
151
152 public boolean isReplay() {
153 return this.isReplay;
154 }
155
156 public void setCompressionContext(final CompressionContext compressionContext) {
157 this.compressionContext = compressionContext;
158 }
159
160 public WALEdit add(Cell cell) {
161 this.cells.add(cell);
162 return this;
163 }
164
165 public boolean isEmpty() {
166 return cells.isEmpty();
167 }
168
169 public int size() {
170 return cells.size();
171 }
172
173 public ArrayList<Cell> getCells() {
174 return cells;
175 }
176
177
178
179
180
181
182
183
184 @InterfaceAudience.Private
185 public void setCells(ArrayList<Cell> cells) {
186 this.cells = cells;
187 }
188
189 public NavigableMap<byte[], Integer> getAndRemoveScopes() {
190 NavigableMap<byte[], Integer> result = scopes;
191 scopes = null;
192 return result;
193 }
194
195 @Override
196 public void readFields(DataInput in) throws IOException {
197 cells.clear();
198 if (scopes != null) {
199 scopes.clear();
200 }
201 int versionOrLength = in.readInt();
202
203 if (versionOrLength == VERSION_2) {
204
205 int numEdits = in.readInt();
206 for (int idx = 0; idx < numEdits; idx++) {
207 if (compressionContext != null) {
208 this.add(KeyValueCompression.readKV(in, compressionContext));
209 } else {
210 this.add(KeyValue.create(in));
211 }
212 }
213 int numFamilies = in.readInt();
214 if (numFamilies > 0) {
215 if (scopes == null) {
216 scopes = new TreeMap<byte[], Integer>(Bytes.BYTES_COMPARATOR);
217 }
218 for (int i = 0; i < numFamilies; i++) {
219 byte[] fam = Bytes.readByteArray(in);
220 int scope = in.readInt();
221 scopes.put(fam, scope);
222 }
223 }
224 } else {
225
226
227 this.add(KeyValue.create(versionOrLength, in));
228 }
229 }
230
231 @Override
232 public void write(DataOutput out) throws IOException {
233 LOG.warn("WALEdit is being serialized to writable - only expected in test code");
234 out.writeInt(VERSION_2);
235 out.writeInt(cells.size());
236
237 for (Cell cell : cells) {
238
239 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
240 if (compressionContext != null) {
241 KeyValueCompression.writeKV(out, kv, compressionContext);
242 } else{
243 KeyValue.write(kv, out);
244 }
245 }
246 if (scopes == null) {
247 out.writeInt(0);
248 } else {
249 out.writeInt(scopes.size());
250 for (byte[] key : scopes.keySet()) {
251 Bytes.writeByteArray(out, key);
252 out.writeInt(scopes.get(key));
253 }
254 }
255 }
256
257
258
259
260
261
262
263 public int readFromCells(Codec.Decoder cellDecoder, int expectedCount) throws IOException {
264 cells.clear();
265 cells.ensureCapacity(expectedCount);
266 while (cells.size() < expectedCount && cellDecoder.advance()) {
267 cells.add(cellDecoder.current());
268 }
269 return cells.size();
270 }
271
272 @Override
273 public long heapSize() {
274 long ret = ClassSize.ARRAYLIST;
275 for (Cell cell : cells) {
276 ret += CellUtil.estimatedHeapSizeOf(cell);
277 }
278 if (scopes != null) {
279 ret += ClassSize.TREEMAP;
280 ret += ClassSize.align(scopes.size() * ClassSize.MAP_ENTRY);
281
282 }
283 return ret;
284 }
285
286 @Override
287 public String toString() {
288 StringBuilder sb = new StringBuilder();
289
290 sb.append("[#edits: " + cells.size() + " = <");
291 for (Cell cell : cells) {
292 sb.append(cell);
293 sb.append("; ");
294 }
295 if (scopes != null) {
296 sb.append(" scopes: " + scopes.toString());
297 }
298 sb.append(">]");
299 return sb.toString();
300 }
301
302 public static WALEdit createFlushWALEdit(HRegionInfo hri, FlushDescriptor f) {
303 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, FLUSH,
304 EnvironmentEdgeManager.currentTime(), f.toByteArray());
305 return new WALEdit().add(kv);
306 }
307
308 public static FlushDescriptor getFlushDescriptor(Cell cell) throws IOException {
309 if (CellUtil.matchingColumn(cell, METAFAMILY, FLUSH)) {
310 return FlushDescriptor.parseFrom(cell.getValue());
311 }
312 return null;
313 }
314
315 public static WALEdit createRegionEventWALEdit(HRegionInfo hri,
316 RegionEventDescriptor regionEventDesc) {
317 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, REGION_EVENT,
318 EnvironmentEdgeManager.currentTime(), regionEventDesc.toByteArray());
319 return new WALEdit().add(kv);
320 }
321
322 public static RegionEventDescriptor getRegionEventDescriptor(Cell cell) throws IOException {
323 if (CellUtil.matchingColumn(cell, METAFAMILY, REGION_EVENT)) {
324 return RegionEventDescriptor.parseFrom(cell.getValue());
325 }
326 return null;
327 }
328
329
330
331
332
333
334 public static WALEdit createCompaction(final HRegionInfo hri, final CompactionDescriptor c) {
335 byte [] pbbytes = c.toByteArray();
336 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, COMPACTION,
337 EnvironmentEdgeManager.currentTime(), pbbytes);
338 return new WALEdit().add(kv);
339 }
340
341 public static byte[] getRowForRegion(HRegionInfo hri) {
342 byte[] startKey = hri.getStartKey();
343 if (startKey.length == 0) {
344
345
346 return new byte[] {0};
347 }
348 return startKey;
349 }
350
351
352
353
354
355
356 public static CompactionDescriptor getCompaction(Cell kv) throws IOException {
357 if (isCompactionMarker(kv)) {
358 return CompactionDescriptor.parseFrom(CellUtil.cloneValue(kv));
359 }
360 return null;
361 }
362
363
364
365
366
367
368 public static boolean isCompactionMarker(Cell cell) {
369 return CellUtil.matchingColumn(cell, METAFAMILY, COMPACTION);
370 }
371
372
373
374
375
376
377
378
379 public static WALEdit createBulkLoadEvent(HRegionInfo hri,
380 WALProtos.BulkLoadDescriptor bulkLoadDescriptor) {
381 KeyValue kv = new KeyValue(getRowForRegion(hri),
382 METAFAMILY,
383 BULK_LOAD,
384 EnvironmentEdgeManager.currentTime(),
385 bulkLoadDescriptor.toByteArray());
386 return new WALEdit().add(kv);
387 }
388
389
390
391
392
393
394 public static WALProtos.BulkLoadDescriptor getBulkLoadDescriptor(Cell cell) throws IOException {
395 if (CellUtil.matchingColumn(cell, METAFAMILY, BULK_LOAD)) {
396 return WALProtos.BulkLoadDescriptor.parseFrom(cell.getValue());
397 }
398 return null;
399 }
400 }