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