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