1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.types;
19
20 import org.apache.hadoop.classification.InterfaceAudience;
21 import org.apache.hadoop.classification.InterfaceStability;
22 import org.apache.hadoop.hbase.util.Bytes;
23 import org.apache.hadoop.hbase.util.Order;
24 import org.apache.hadoop.hbase.util.PositionedByteRange;
25 import org.apache.hadoop.hbase.util.SimplePositionedByteRange;
26
27
28
29
30
31
32
33 @InterfaceAudience.Public
34 @InterfaceStability.Evolving
35 public class TerminatedWrapper<T> implements DataType<T> {
36
37 protected final DataType<T> wrapped;
38 protected final byte[] term;
39
40
41
42
43
44 public TerminatedWrapper(DataType<T> wrapped, byte[] term) {
45 if (null == term || term.length == 0)
46 throw new IllegalArgumentException("terminator must be non-null and non-empty.");
47 this.wrapped = wrapped;
48 wrapped.getOrder().apply(term);
49 this.term = term;
50 }
51
52
53
54
55
56
57
58 public TerminatedWrapper(DataType<T> wrapped, String term) {
59 this(wrapped, Bytes.toBytes(term));
60 }
61
62 @Override
63 public boolean isOrderPreserving() { return wrapped.isOrderPreserving(); }
64
65 @Override
66 public Order getOrder() { return wrapped.getOrder(); }
67
68 @Override
69 public boolean isNullable() { return wrapped.isNullable(); }
70
71 @Override
72 public boolean isSkippable() { return true; }
73
74 @Override
75 public int encodedLength(T val) {
76 return wrapped.encodedLength(val) + term.length;
77 }
78
79 @Override
80 public Class<T> encodedClass() { return wrapped.encodedClass(); }
81
82
83
84
85
86 protected int terminatorPosition(PositionedByteRange src) {
87 byte[] a = src.getBytes();
88 final int offset = src.getOffset();
89 int i;
90 SKIP: for (i = src.getPosition(); i < src.getLength(); i++) {
91 if (a[offset + i] != term[0]) continue;
92 int j;
93 for (j = 1; j < term.length && offset + j < src.getLength(); j++) {
94 if (a[offset + i + j] != term[j]) continue SKIP;
95 }
96 if (j == term.length) return i;
97 }
98 return -1;
99 }
100
101
102
103
104
105
106
107 @Override
108 public int skip(PositionedByteRange src) {
109 if (wrapped.isSkippable()) {
110 return wrapped.skip(src);
111 } else {
112
113 final int start = src.getPosition();
114 int skipped = terminatorPosition(src);
115 if (-1 == skipped) throw new IllegalArgumentException("Terminator sequence not found.");
116 skipped += term.length;
117 src.setPosition(skipped);
118 return skipped - start;
119 }
120 }
121
122 @Override
123 public T decode(PositionedByteRange src) {
124 if (wrapped.isSkippable()) {
125 return wrapped.decode(src);
126 } else {
127
128 int term = terminatorPosition(src);
129 if (-1 == term) throw new IllegalArgumentException("Terminator sequence not found.");
130 byte[] b = new byte[term - src.getPosition()];
131 src.get(b);
132
133 T ret = wrapped.decode(new SimplePositionedByteRange(b));
134 src.get(this.term);
135 return ret;
136 }
137 }
138
139
140
141
142
143
144 @Override
145 public int encode(PositionedByteRange dst, T val) {
146 final int start = dst.getPosition();
147 int written = wrapped.encode(dst, val);
148 PositionedByteRange b = dst.shallowCopy();
149 b.setLength(dst.getPosition());
150 b.setPosition(start);
151 if (-1 != terminatorPosition(b)) {
152 dst.setPosition(start);
153 throw new IllegalArgumentException("Encoded value contains terminator sequence.");
154 }
155 dst.put(term);
156 return written + term.length;
157 }
158 }