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.client;
21
22 import static org.junit.Assert.*;
23
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.hadoop.hbase.HBaseTestingUtility;
32 import org.apache.hadoop.hbase.KeyValue;
33 import org.apache.hadoop.hbase.filter.Filter;
34 import org.apache.hadoop.hbase.filter.TimestampsFilter;
35 import org.apache.hadoop.hbase.util.Bytes;
36 import org.junit.After;
37 import org.junit.AfterClass;
38 import org.junit.Before;
39 import org.junit.BeforeClass;
40 import org.junit.Test;
41
42
43
44
45
46
47 public class TestTimestampsFilter {
48 final Log LOG = LogFactory.getLog(getClass());
49 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
50
51
52
53
54 @BeforeClass
55 public static void setUpBeforeClass() throws Exception {
56 TEST_UTIL.startMiniCluster(3);
57 }
58
59
60
61
62 @AfterClass
63 public static void tearDownAfterClass() throws Exception {
64 TEST_UTIL.shutdownMiniCluster();
65 }
66
67
68
69
70 @Before
71 public void setUp() throws Exception {
72
73 }
74
75
76
77
78 @After
79 public void tearDown() throws Exception {
80
81 }
82
83
84
85
86
87
88
89
90
91 @Test
92 public void testTimestampsFilter() throws Exception {
93 byte [] TABLE = Bytes.toBytes("testTimestampsFilter");
94 byte [] FAMILY = Bytes.toBytes("event_log");
95 byte [][] FAMILIES = new byte[][] { FAMILY };
96 KeyValue kvs[];
97
98
99 HTable ht = TEST_UTIL.createTable(TABLE, FAMILIES, Integer.MAX_VALUE);
100
101 for (int rowIdx = 0; rowIdx < 5; rowIdx++) {
102 for (int colIdx = 0; colIdx < 5; colIdx++) {
103
104 putNVersions(ht, FAMILY, rowIdx, colIdx, 201, 300);
105
106 putNVersions(ht, FAMILY, rowIdx, colIdx, 1, 100);
107 }
108 }
109
110
111 verifyInsertedValues(ht, FAMILY);
112
113 flush();
114
115
116 verifyInsertedValues(ht, FAMILY);
117
118
119
120 for (int rowIdx = 0; rowIdx < 5; rowIdx++) {
121 for (int colIdx = 0; colIdx < 5; colIdx++) {
122 putNVersions(ht, FAMILY, rowIdx, colIdx, 301, 400);
123 putNVersions(ht, FAMILY, rowIdx, colIdx, 101, 200);
124 }
125 }
126
127 for (int rowIdx = 0; rowIdx < 5; rowIdx++) {
128 for (int colIdx = 0; colIdx < 5; colIdx++) {
129 kvs = getNVersions(ht, FAMILY, rowIdx, colIdx,
130 Arrays.asList(505L, 5L, 105L, 305L, 205L));
131 assertEquals(4, kvs.length);
132 checkOneCell(kvs[0], FAMILY, rowIdx, colIdx, 305);
133 checkOneCell(kvs[1], FAMILY, rowIdx, colIdx, 205);
134 checkOneCell(kvs[2], FAMILY, rowIdx, colIdx, 105);
135 checkOneCell(kvs[3], FAMILY, rowIdx, colIdx, 5);
136 }
137 }
138
139
140
141 kvs = getNVersions(ht, FAMILY, 2, 2, new ArrayList<Long>());
142 assertEquals(0, kvs.length);
143
144
145
146
147
148 Result[] results = scanNVersions(ht, FAMILY, 0, 4,
149 Arrays.asList(6L, 106L, 306L));
150 assertEquals("# of rows returned from scan", 5, results.length);
151 for (int rowIdx = 0; rowIdx < 5; rowIdx++) {
152 kvs = results[rowIdx].raw();
153
154
155 assertEquals("Number of KeyValues in result for row:" + rowIdx,
156 3*5, kvs.length);
157 for (int colIdx = 0; colIdx < 5; colIdx++) {
158 int offset = colIdx * 3;
159 checkOneCell(kvs[offset + 0], FAMILY, rowIdx, colIdx, 306);
160 checkOneCell(kvs[offset + 1], FAMILY, rowIdx, colIdx, 106);
161 checkOneCell(kvs[offset + 2], FAMILY, rowIdx, colIdx, 6);
162 }
163 }
164 }
165
166
167
168
169
170
171 @Test
172 public void testWithVersionDeletes() throws Exception {
173
174
175 testWithVersionDeletes(false);
176
177
178 testWithVersionDeletes(true);
179 }
180
181 private void testWithVersionDeletes(boolean flushTables) throws IOException {
182 byte [] TABLE = Bytes.toBytes("testWithVersionDeletes_" +
183 (flushTables ? "flush" : "noflush"));
184 byte [] FAMILY = Bytes.toBytes("event_log");
185 byte [][] FAMILIES = new byte[][] { FAMILY };
186
187
188 HTable ht = TEST_UTIL.createTable(TABLE, FAMILIES, Integer.MAX_VALUE);
189
190
191 putNVersions(ht, FAMILY, 0, 0, 1, 5);
192
193
194 deleteOneVersion(ht, FAMILY, 0, 0, 4);
195
196 if (flushTables) {
197 flush();
198 }
199
200
201
202 KeyValue kvs[] = getNVersions(ht, FAMILY, 0, 0, Arrays.asList(2L, 3L, 4L, 5L));
203 assertEquals(3, kvs.length);
204 checkOneCell(kvs[0], FAMILY, 0, 0, 5);
205 checkOneCell(kvs[1], FAMILY, 0, 0, 3);
206 checkOneCell(kvs[2], FAMILY, 0, 0, 2);
207 }
208
209 private void verifyInsertedValues(HTable ht, byte[] cf) throws IOException {
210 for (int rowIdx = 0; rowIdx < 5; rowIdx++) {
211 for (int colIdx = 0; colIdx < 5; colIdx++) {
212
213 KeyValue[] kvs = getNVersions(ht, cf, rowIdx, colIdx,
214 Arrays.asList(5L, 300L, 6L, 80L));
215 assertEquals(4, kvs.length);
216 checkOneCell(kvs[0], cf, rowIdx, colIdx, 300);
217 checkOneCell(kvs[1], cf, rowIdx, colIdx, 80);
218 checkOneCell(kvs[2], cf, rowIdx, colIdx, 6);
219 checkOneCell(kvs[3], cf, rowIdx, colIdx, 5);
220
221
222 kvs = getNVersions(ht, cf, rowIdx, colIdx,
223 Arrays.asList(101L, 102L));
224 assertEquals(0, kvs.length);
225
226
227 kvs = getNVersions(ht, cf, rowIdx, colIdx,
228 Arrays.asList(1L, 300L, 105L, 70L, 115L));
229 assertEquals(3, kvs.length);
230 checkOneCell(kvs[0], cf, rowIdx, colIdx, 300);
231 checkOneCell(kvs[1], cf, rowIdx, colIdx, 70);
232 checkOneCell(kvs[2], cf, rowIdx, colIdx, 1);
233 }
234 }
235 }
236
237
238 private void flush() throws IOException {
239 TEST_UTIL.flush();
240 try {
241 Thread.sleep(3000);
242 } catch (InterruptedException i) {
243
244 }
245 }
246
247
248
249
250
251 private void checkOneCell(KeyValue kv, byte[] cf,
252 int rowIdx, int colIdx, long ts) {
253
254 String ctx = "rowIdx=" + rowIdx + "; colIdx=" + colIdx + "; ts=" + ts;
255
256 assertEquals("Row mismatch which checking: " + ctx,
257 "row:"+ rowIdx, Bytes.toString(kv.getRow()));
258
259 assertEquals("ColumnFamily mismatch while checking: " + ctx,
260 Bytes.toString(cf), Bytes.toString(kv.getFamily()));
261
262 assertEquals("Column qualifier mismatch while checking: " + ctx,
263 "column:" + colIdx,
264 Bytes.toString(kv.getQualifier()));
265
266 assertEquals("Timestamp mismatch while checking: " + ctx,
267 ts, kv.getTimestamp());
268
269 assertEquals("Value mismatch while checking: " + ctx,
270 "value-version-" + ts, Bytes.toString(kv.getValue()));
271 }
272
273
274
275
276
277
278 private KeyValue[] getNVersions(HTable ht, byte[] cf, int rowIdx,
279 int colIdx, List<Long> versions)
280 throws IOException {
281 byte row[] = Bytes.toBytes("row:" + rowIdx);
282 byte column[] = Bytes.toBytes("column:" + colIdx);
283 Filter filter = new TimestampsFilter(versions);
284 Get get = new Get(row);
285 get.addColumn(cf, column);
286 get.setFilter(filter);
287 get.setMaxVersions();
288 Result result = ht.get(get);
289
290 return result.raw();
291 }
292
293
294
295
296
297 private Result[] scanNVersions(HTable ht, byte[] cf, int startRowIdx,
298 int endRowIdx, List<Long> versions)
299 throws IOException {
300 byte startRow[] = Bytes.toBytes("row:" + startRowIdx);
301 byte endRow[] = Bytes.toBytes("row:" + endRowIdx + 1);
302 Filter filter = new TimestampsFilter(versions);
303 Scan scan = new Scan(startRow, endRow);
304 scan.setFilter(filter);
305 scan.setMaxVersions();
306 ResultScanner scanner = ht.getScanner(scan);
307 return scanner.next(endRowIdx - startRowIdx + 1);
308 }
309
310
311
312
313
314 private void putNVersions(HTable ht, byte[] cf, int rowIdx, int colIdx,
315 long versionStart, long versionEnd)
316 throws IOException {
317 byte row[] = Bytes.toBytes("row:" + rowIdx);
318 byte column[] = Bytes.toBytes("column:" + colIdx);
319 Put put = new Put(row);
320
321 for (long idx = versionStart; idx <= versionEnd; idx++) {
322 put.add(cf, column, idx, Bytes.toBytes("value-version-" + idx));
323 }
324
325 ht.put(put);
326 }
327
328
329
330
331
332 private void deleteOneVersion(HTable ht, byte[] cf, int rowIdx,
333 int colIdx, long version)
334 throws IOException {
335 byte row[] = Bytes.toBytes("row:" + rowIdx);
336 byte column[] = Bytes.toBytes("column:" + colIdx);
337 Delete del = new Delete(row);
338 del.deleteColumn(cf, column, version);
339 ht.delete(del);
340 }
341 }
342