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.CompactionDescriptor;
40 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.FlushDescriptor;
41 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.RegionEventDescriptor;
42 import org.apache.hadoop.hbase.util.Bytes;
43 import org.apache.hadoop.hbase.util.ClassSize;
44 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
45 import org.apache.hadoop.io.Writable;
46
47
48
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 @InterfaceAudience.LimitedPrivate({ HBaseInterfaceAudience.REPLICATION,
83 HBaseInterfaceAudience.COPROC })
84 public class WALEdit implements Writable, HeapSize {
85 public static final Log LOG = LogFactory.getLog(WALEdit.class);
86
87
88 public static final byte [] METAFAMILY = Bytes.toBytes("METAFAMILY");
89 static final byte [] METAROW = Bytes.toBytes("METAROW");
90 static final byte[] COMPACTION = Bytes.toBytes("HBASE::COMPACTION");
91 static final byte [] FLUSH = Bytes.toBytes("HBASE::FLUSH");
92 static final byte [] REGION_EVENT = Bytes.toBytes("HBASE::REGION_EVENT");
93
94 private final int VERSION_2 = -1;
95 private final boolean isReplay;
96
97 private final ArrayList<Cell> cells = new ArrayList<Cell>(1);
98
99 public static final WALEdit EMPTY_WALEDIT = new WALEdit();
100
101
102 @Deprecated
103 private NavigableMap<byte[], Integer> scopes;
104
105 private CompressionContext compressionContext;
106
107 public WALEdit() {
108 this(false);
109 }
110
111 public WALEdit(boolean isReplay) {
112 this.isReplay = isReplay;
113 }
114
115
116
117
118
119 public static boolean isMetaEditFamily(final byte [] f) {
120 return Bytes.equals(METAFAMILY, f);
121 }
122
123 public static boolean isMetaEditFamily(Cell cell) {
124 return CellUtil.matchingFamily(cell, METAFAMILY);
125 }
126
127
128
129
130
131 public boolean isReplay() {
132 return this.isReplay;
133 }
134
135 public void setCompressionContext(final CompressionContext compressionContext) {
136 this.compressionContext = compressionContext;
137 }
138
139 public WALEdit add(Cell cell) {
140 this.cells.add(cell);
141 return this;
142 }
143
144 public boolean isEmpty() {
145 return cells.isEmpty();
146 }
147
148 public int size() {
149 return cells.size();
150 }
151
152 public ArrayList<Cell> getCells() {
153 return cells;
154 }
155
156 public NavigableMap<byte[], Integer> getAndRemoveScopes() {
157 NavigableMap<byte[], Integer> result = scopes;
158 scopes = null;
159 return result;
160 }
161
162 @Override
163 public void readFields(DataInput in) throws IOException {
164 cells.clear();
165 if (scopes != null) {
166 scopes.clear();
167 }
168 int versionOrLength = in.readInt();
169
170 if (versionOrLength == VERSION_2) {
171
172 int numEdits = in.readInt();
173 for (int idx = 0; idx < numEdits; idx++) {
174 if (compressionContext != null) {
175 this.add(KeyValueCompression.readKV(in, compressionContext));
176 } else {
177 this.add(KeyValue.create(in));
178 }
179 }
180 int numFamilies = in.readInt();
181 if (numFamilies > 0) {
182 if (scopes == null) {
183 scopes = new TreeMap<byte[], Integer>(Bytes.BYTES_COMPARATOR);
184 }
185 for (int i = 0; i < numFamilies; i++) {
186 byte[] fam = Bytes.readByteArray(in);
187 int scope = in.readInt();
188 scopes.put(fam, scope);
189 }
190 }
191 } else {
192
193
194 this.add(KeyValue.create(versionOrLength, in));
195 }
196 }
197
198 @Override
199 public void write(DataOutput out) throws IOException {
200 LOG.warn("WALEdit is being serialized to writable - only expected in test code");
201 out.writeInt(VERSION_2);
202 out.writeInt(cells.size());
203
204 for (Cell cell : cells) {
205
206 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
207 if (compressionContext != null) {
208 KeyValueCompression.writeKV(out, kv, compressionContext);
209 } else{
210 KeyValue.write(kv, out);
211 }
212 }
213 if (scopes == null) {
214 out.writeInt(0);
215 } else {
216 out.writeInt(scopes.size());
217 for (byte[] key : scopes.keySet()) {
218 Bytes.writeByteArray(out, key);
219 out.writeInt(scopes.get(key));
220 }
221 }
222 }
223
224
225
226
227
228
229
230 public int readFromCells(Codec.Decoder cellDecoder, int expectedCount) throws IOException {
231 cells.clear();
232 cells.ensureCapacity(expectedCount);
233 while (cells.size() < expectedCount && cellDecoder.advance()) {
234 cells.add(cellDecoder.current());
235 }
236 return cells.size();
237 }
238
239 @Override
240 public long heapSize() {
241 long ret = ClassSize.ARRAYLIST;
242 for (Cell cell : cells) {
243 ret += CellUtil.estimatedHeapSizeOf(cell);
244 }
245 if (scopes != null) {
246 ret += ClassSize.TREEMAP;
247 ret += ClassSize.align(scopes.size() * ClassSize.MAP_ENTRY);
248
249 }
250 return ret;
251 }
252
253 @Override
254 public String toString() {
255 StringBuilder sb = new StringBuilder();
256
257 sb.append("[#edits: " + cells.size() + " = <");
258 for (Cell cell : cells) {
259 sb.append(cell);
260 sb.append("; ");
261 }
262 if (scopes != null) {
263 sb.append(" scopes: " + scopes.toString());
264 }
265 sb.append(">]");
266 return sb.toString();
267 }
268
269 public static WALEdit createFlushWALEdit(HRegionInfo hri, FlushDescriptor f) {
270 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, FLUSH,
271 EnvironmentEdgeManager.currentTime(), f.toByteArray());
272 return new WALEdit().add(kv);
273 }
274
275 public static FlushDescriptor getFlushDescriptor(Cell cell) throws IOException {
276 if (CellUtil.matchingColumn(cell, METAFAMILY, FLUSH)) {
277 return FlushDescriptor.parseFrom(cell.getValue());
278 }
279 return null;
280 }
281
282 public static WALEdit createRegionEventWALEdit(HRegionInfo hri,
283 RegionEventDescriptor regionEventDesc) {
284 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, REGION_EVENT,
285 EnvironmentEdgeManager.currentTime(), regionEventDesc.toByteArray());
286 return new WALEdit().add(kv);
287 }
288
289 public static RegionEventDescriptor getRegionEventDescriptor(Cell cell) throws IOException {
290 if (CellUtil.matchingColumn(cell, METAFAMILY, REGION_EVENT)) {
291 return RegionEventDescriptor.parseFrom(cell.getValue());
292 }
293 return null;
294 }
295
296
297
298
299
300
301 public static WALEdit createCompaction(final HRegionInfo hri, final CompactionDescriptor c) {
302 byte [] pbbytes = c.toByteArray();
303 KeyValue kv = new KeyValue(getRowForRegion(hri), METAFAMILY, COMPACTION,
304 EnvironmentEdgeManager.currentTime(), pbbytes);
305 return new WALEdit().add(kv);
306 }
307
308 private static byte[] getRowForRegion(HRegionInfo hri) {
309 byte[] startKey = hri.getStartKey();
310 if (startKey.length == 0) {
311
312
313 return new byte[] {0};
314 }
315 return startKey;
316 }
317
318
319
320
321
322
323 public static CompactionDescriptor getCompaction(Cell kv) throws IOException {
324 if (CellUtil.matchingColumn(kv, METAFAMILY, COMPACTION)) {
325 return CompactionDescriptor.parseFrom(kv.getValue());
326 }
327 return null;
328 }
329 }