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.NavigableSet;
23
24 import org.apache.hadoop.hbase.HConstants;
25 import org.apache.hadoop.hbase.KeyValue;
26 import org.apache.hadoop.hbase.regionserver.ScanQueryMatcher.MatchCode;
27 import org.apache.hadoop.hbase.util.Bytes;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class ExplicitColumnTracker implements ColumnTracker {
53
54 private final int maxVersions;
55 private final int minVersions;
56
57
58
59 private final int lookAhead;
60
61
62
63
64
65
66 private final ColumnCount[] columns;
67 private int index;
68 private ColumnCount column;
69
70
71 private long latestTSOfCurrentColumn;
72 private long oldestStamp;
73 private int skipCount;
74
75
76
77
78
79
80
81
82
83
84
85 public ExplicitColumnTracker(NavigableSet<byte[]> columns, int minVersions,
86 int maxVersions, long oldestUnexpiredTS, int lookAhead) {
87 this.maxVersions = maxVersions;
88 this.minVersions = minVersions;
89 this.lookAhead = lookAhead;
90 this.oldestStamp = oldestUnexpiredTS;
91 this.columns = new ColumnCount[columns.size()];
92 int i=0;
93 for(byte [] column : columns) {
94 this.columns[i++] = new ColumnCount(column);
95 }
96 reset();
97 }
98
99
100
101
102 public boolean done() {
103 return this.index >= columns.length;
104 }
105
106 public ColumnCount getColumnHint() {
107 return this.column;
108 }
109
110
111
112
113 @Override
114 public ScanQueryMatcher.MatchCode checkColumn(byte [] bytes, int offset,
115 int length, byte type) {
116
117
118 assert !KeyValue.isDelete(type);
119 do {
120
121 if(done()) {
122 return ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW;
123 }
124
125
126 if(this.column == null) {
127 return ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW;
128 }
129
130
131 int ret = Bytes.compareTo(column.getBuffer(), column.getOffset(),
132 column.getLength(), bytes, offset, length);
133
134
135
136 if(ret == 0) {
137 return ScanQueryMatcher.MatchCode.INCLUDE;
138 }
139
140 resetTS();
141
142 if (ret > 0) {
143
144
145 return this.skipCount++ < this.lookAhead ? ScanQueryMatcher.MatchCode.SKIP
146 : ScanQueryMatcher.MatchCode.SEEK_NEXT_COL;
147 }
148
149
150
151
152
153 if (ret <= -1) {
154 ++this.index;
155 this.skipCount = 0;
156 if (done()) {
157
158 return ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW;
159 }
160
161 this.column = this.columns[this.index];
162 }
163 } while(true);
164 }
165
166 @Override
167 public ScanQueryMatcher.MatchCode checkVersions(byte[] bytes, int offset, int length,
168 long timestamp, byte type, boolean ignoreCount) {
169 assert !KeyValue.isDelete(type);
170 if (ignoreCount) return ScanQueryMatcher.MatchCode.INCLUDE;
171
172 if (sameAsPreviousTS(timestamp)) {
173
174 return ScanQueryMatcher.MatchCode.SKIP;
175 }
176 int count = this.column.increment();
177 if (count >= maxVersions || (count >= minVersions && isExpired(timestamp))) {
178
179 ++this.index;
180 this.skipCount = 0;
181 resetTS();
182 if (done()) {
183
184 this.column = null;
185 return ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW;
186 }
187
188
189 this.column = this.columns[this.index];
190 return ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL;
191 }
192 setTS(timestamp);
193 return ScanQueryMatcher.MatchCode.INCLUDE;
194 }
195
196
197 public void reset() {
198 this.index = 0;
199 this.skipCount = 0;
200 this.column = this.columns[this.index];
201 for(ColumnCount col : this.columns) {
202 col.setCount(0);
203 }
204 resetTS();
205 }
206
207 private void resetTS() {
208 latestTSOfCurrentColumn = HConstants.LATEST_TIMESTAMP;
209 }
210
211 private void setTS(long timestamp) {
212 latestTSOfCurrentColumn = timestamp;
213 }
214
215 private boolean sameAsPreviousTS(long timestamp) {
216 return timestamp == latestTSOfCurrentColumn;
217 }
218
219 private boolean isExpired(long timestamp) {
220 return timestamp < oldestStamp;
221 }
222
223
224
225
226
227
228
229
230
231
232 public void doneWithColumn(byte [] bytes, int offset, int length) {
233 while (this.column != null) {
234 int compare = Bytes.compareTo(column.getBuffer(), column.getOffset(),
235 column.getLength(), bytes, offset, length);
236 resetTS();
237 if (compare <= 0) {
238 ++this.index;
239 this.skipCount = 0;
240 if (done()) {
241
242 this.column = null;
243 } else {
244 this.column = this.columns[this.index];
245 }
246 if (compare <= -1)
247 continue;
248 }
249 return;
250 }
251 }
252
253 public MatchCode getNextRowOrNextColumn(byte[] bytes, int offset,
254 int qualLength) {
255 doneWithColumn(bytes, offset,qualLength);
256
257 if (getColumnHint() == null) {
258 return MatchCode.SEEK_NEXT_ROW;
259 } else {
260 return MatchCode.SEEK_NEXT_COL;
261 }
262 }
263
264 public boolean isDone(long timestamp) {
265 return minVersions <= 0 && isExpired(timestamp);
266 }
267 }