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