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;
20
21 import java.util.NavigableMap;
22 import java.util.NavigableSet;
23 import java.util.TreeMap;
24 import java.util.TreeSet;
25
26 import org.apache.hadoop.classification.InterfaceAudience;
27 import org.apache.hadoop.hbase.HConstants;
28 import org.apache.hadoop.hbase.KeyValue;
29 import org.apache.hadoop.hbase.KeyValue.KVComparator;
30 import org.apache.hadoop.hbase.util.Bytes;
31
32
33
34
35
36
37
38 @InterfaceAudience.Private
39 class GetClosestRowBeforeTracker {
40 private final KeyValue targetkey;
41
42 private final long oldestts;
43 private KeyValue candidate = null;
44 private final KVComparator kvcomparator;
45
46 private final boolean metaregion;
47
48 private final int rowoffset;
49 private final int tablenamePlusDelimiterLength;
50
51
52 private final NavigableMap<KeyValue, NavigableSet<KeyValue>> deletes;
53
54
55
56
57
58
59
60
61 GetClosestRowBeforeTracker(final KVComparator c, final KeyValue kv,
62 final long ttl, final boolean metaregion) {
63 super();
64 this.metaregion = metaregion;
65 this.targetkey = kv;
66
67
68 this.rowoffset = kv.getRowOffset();
69 int l = -1;
70 if (metaregion) {
71 l = KeyValue.getDelimiter(kv.getBuffer(), rowoffset, kv.getRowLength(),
72 HConstants.DELIMITER) - this.rowoffset;
73 }
74 this.tablenamePlusDelimiterLength = metaregion? l + 1: -1;
75 this.oldestts = System.currentTimeMillis() - ttl;
76 this.kvcomparator = c;
77 KeyValue.RowOnlyComparator rc = new KeyValue.RowOnlyComparator(this.kvcomparator);
78 this.deletes = new TreeMap<KeyValue, NavigableSet<KeyValue>>(rc);
79 }
80
81
82
83
84
85 boolean isExpired(final KeyValue kv) {
86 return HStore.isExpired(kv, this.oldestts);
87 }
88
89
90
91
92
93 private void addDelete(final KeyValue kv) {
94 NavigableSet<KeyValue> rowdeletes = this.deletes.get(kv);
95 if (rowdeletes == null) {
96 rowdeletes = new TreeSet<KeyValue>(this.kvcomparator);
97 this.deletes.put(kv, rowdeletes);
98 }
99 rowdeletes.add(kv);
100 }
101
102
103
104
105
106 private boolean addCandidate(final KeyValue kv) {
107 if (!isDeleted(kv) && isBetterCandidate(kv)) {
108 this.candidate = kv;
109 return true;
110 }
111 return false;
112 }
113
114 boolean isBetterCandidate(final KeyValue contender) {
115 return this.candidate == null ||
116 (this.kvcomparator.compareRows(this.candidate, contender) < 0 &&
117 this.kvcomparator.compareRows(contender, this.targetkey) <= 0);
118 }
119
120
121
122
123
124
125
126 private boolean isDeleted(final KeyValue kv) {
127 if (this.deletes.isEmpty()) return false;
128 NavigableSet<KeyValue> rowdeletes = this.deletes.get(kv);
129 if (rowdeletes == null || rowdeletes.isEmpty()) return false;
130 return isDeleted(kv, rowdeletes);
131 }
132
133
134
135
136
137
138
139
140 public boolean isDeleted(final KeyValue kv, final NavigableSet<KeyValue> ds) {
141 if (deletes == null || deletes.isEmpty()) return false;
142 for (KeyValue d: ds) {
143 long kvts = kv.getTimestamp();
144 long dts = d.getTimestamp();
145 if (d.isDeleteFamily()) {
146 if (kvts <= dts) return true;
147 continue;
148 }
149
150 int ret = Bytes.compareTo(kv.getBuffer(), kv.getQualifierOffset(),
151 kv.getQualifierLength(),
152 d.getBuffer(), d.getQualifierOffset(), d.getQualifierLength());
153 if (ret <= -1) {
154
155 continue;
156 } else if (ret >= 1) {
157
158 break;
159 }
160
161 if (kvts > dts) return false;
162
163
164 switch (KeyValue.Type.codeToType(d.getType())) {
165 case Delete: return kvts == dts;
166 case DeleteColumn: return true;
167 default: continue;
168 }
169 }
170 return false;
171 }
172
173
174
175
176
177
178
179
180
181 boolean handleDeletes(final KeyValue kv) {
182 addDelete(kv);
183 boolean deleted = false;
184 if (!hasCandidate()) return deleted;
185 if (isDeleted(this.candidate)) {
186 this.candidate = null;
187 deleted = true;
188 }
189 return deleted;
190 }
191
192
193
194
195
196
197 boolean handle(final KeyValue kv) {
198 if (kv.isDelete()) {
199 handleDeletes(kv);
200 return false;
201 }
202 return addCandidate(kv);
203 }
204
205
206
207
208 public boolean hasCandidate() {
209 return this.candidate != null;
210 }
211
212
213
214
215 public KeyValue getCandidate() {
216 return this.candidate;
217 }
218
219 public KeyValue getTargetKey() {
220 return this.targetkey;
221 }
222
223
224
225
226
227
228 boolean isTooFar(final KeyValue kv, final KeyValue firstOnRow) {
229 return this.kvcomparator.compareRows(kv, firstOnRow) > 0;
230 }
231
232 boolean isTargetTable(final KeyValue kv) {
233 if (!metaregion) return true;
234
235
236 return Bytes.compareTo(this.targetkey.getBuffer(), this.rowoffset,
237 this.tablenamePlusDelimiterLength,
238 kv.getBuffer(), kv.getRowOffset(), this.tablenamePlusDelimiterLength) == 0;
239 }
240 }