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