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 static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.NavigableSet;
31 import java.util.Random;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.hadoop.conf.Configuration;
36 import org.apache.hadoop.fs.FileSystem;
37 import org.apache.hadoop.fs.Path;
38 import org.apache.hadoop.hbase.Cell;
39 import org.apache.hadoop.hbase.HBaseConfiguration;
40 import org.apache.hadoop.hbase.HBaseTestingUtility;
41 import org.apache.hadoop.hbase.HConstants;
42 import org.apache.hadoop.hbase.KeyValue;
43 import org.apache.hadoop.hbase.MediumTests;
44 import org.apache.hadoop.hbase.client.Durability;
45 import org.apache.hadoop.hbase.client.Put;
46 import org.apache.hadoop.hbase.client.Result;
47 import org.apache.hadoop.hbase.client.Scan;
48 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
49 import org.apache.hadoop.hbase.filter.Filter;
50 import org.apache.hadoop.hbase.filter.FilterList;
51 import org.apache.hadoop.hbase.filter.FilterList.Operator;
52 import org.apache.hadoop.hbase.filter.PageFilter;
53 import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
54 import org.apache.hadoop.hbase.io.hfile.CacheConfig;
55 import org.apache.hadoop.hbase.io.hfile.HFileContext;
56 import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder;
57 import org.apache.hadoop.hbase.util.Bytes;
58 import org.apache.hadoop.hbase.util.Pair;
59 import org.junit.Test;
60 import org.junit.experimental.categories.Category;
61
62 import com.google.common.collect.Lists;
63
64
65
66 @Category(MediumTests.class)
67 public class TestReversibleScanners {
68 private static final Log LOG = LogFactory.getLog(TestReversibleScanners.class);
69 HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
70
71 private static byte[] FAMILYNAME = Bytes.toBytes("testCf");
72 private static long TS = System.currentTimeMillis();
73 private static int MAXMVCC = 7;
74 private static byte[] ROW = Bytes.toBytes("testRow");
75 private static final int ROWSIZE = 200;
76 private static byte[][] ROWS = makeN(ROW, ROWSIZE);
77 private static byte[] QUAL = Bytes.toBytes("testQual");
78 private static final int QUALSIZE = 5;
79 private static byte[][] QUALS = makeN(QUAL, QUALSIZE);
80 private static byte[] VALUE = Bytes.toBytes("testValue");
81 private static final int VALUESIZE = 3;
82 private static byte[][] VALUES = makeN(VALUE, VALUESIZE);
83
84 @Test
85 public void testReversibleStoreFileScanner() throws IOException {
86 FileSystem fs = TEST_UTIL.getTestFileSystem();
87 Path hfilePath = new Path(new Path(
88 TEST_UTIL.getDataTestDir("testReversibleStoreFileScanner"),
89 "regionname"), "familyname");
90 CacheConfig cacheConf = new CacheConfig(TEST_UTIL.getConfiguration());
91 HFileContextBuilder hcBuilder = new HFileContextBuilder();
92 hcBuilder.withBlockSize(2 * 1024);
93 HFileContext hFileContext = hcBuilder.build();
94 StoreFile.Writer writer = new StoreFile.WriterBuilder(
95 TEST_UTIL.getConfiguration(), cacheConf, fs).withOutputDir(
96 hfilePath).withFileContext(hFileContext).build();
97 writeStoreFile(writer);
98
99 StoreFile sf = new StoreFile(fs, writer.getPath(),
100 TEST_UTIL.getConfiguration(), cacheConf, BloomType.NONE);
101
102 List<StoreFileScanner> scanners = StoreFileScanner
103 .getScannersForStoreFiles(Collections.singletonList(sf), false, true,
104 false, Long.MAX_VALUE);
105 StoreFileScanner scanner = scanners.get(0);
106 seekTestOfReversibleKeyValueScanner(scanner);
107 for (int readPoint = 0; readPoint < MAXMVCC; readPoint++) {
108 LOG.info("Setting read point to " + readPoint);
109 scanners = StoreFileScanner.getScannersForStoreFiles(
110 Collections.singletonList(sf), false, true, false, readPoint);
111 seekTestOfReversibleKeyValueScannerWithMVCC(scanners.get(0), readPoint);
112 }
113 }
114
115 @Test
116 public void testReversibleMemstoreScanner() throws IOException {
117 MemStore memstore = new MemStore();
118 writeMemstore(memstore);
119 List<KeyValueScanner> scanners = memstore.getScanners(Long.MAX_VALUE);
120 seekTestOfReversibleKeyValueScanner(scanners.get(0));
121 for (int readPoint = 0; readPoint < MAXMVCC; readPoint++) {
122 LOG.info("Setting read point to " + readPoint);
123 scanners = memstore.getScanners(readPoint);
124 seekTestOfReversibleKeyValueScannerWithMVCC(scanners.get(0), readPoint);
125 }
126
127 }
128
129 @Test
130 public void testReversibleKeyValueHeap() throws IOException {
131
132 FileSystem fs = TEST_UTIL.getTestFileSystem();
133 Path hfilePath = new Path(new Path(
134 TEST_UTIL.getDataTestDir("testReversibleKeyValueHeap"), "regionname"),
135 "familyname");
136 CacheConfig cacheConf = new CacheConfig(TEST_UTIL.getConfiguration());
137 HFileContextBuilder hcBuilder = new HFileContextBuilder();
138 hcBuilder.withBlockSize(2 * 1024);
139 HFileContext hFileContext = hcBuilder.build();
140 StoreFile.Writer writer1 = new StoreFile.WriterBuilder(
141 TEST_UTIL.getConfiguration(), cacheConf, fs).withOutputDir(
142 hfilePath).withFileContext(hFileContext).build();
143 StoreFile.Writer writer2 = new StoreFile.WriterBuilder(
144 TEST_UTIL.getConfiguration(), cacheConf, fs).withOutputDir(
145 hfilePath).withFileContext(hFileContext).build();
146
147 MemStore memstore = new MemStore();
148 writeMemstoreAndStoreFiles(memstore, new StoreFile.Writer[] { writer1,
149 writer2 });
150
151 StoreFile sf1 = new StoreFile(fs, writer1.getPath(),
152 TEST_UTIL.getConfiguration(), cacheConf, BloomType.NONE);
153
154 StoreFile sf2 = new StoreFile(fs, writer2.getPath(),
155 TEST_UTIL.getConfiguration(), cacheConf, BloomType.NONE);
156
157
158
159 int startRowNum = ROWSIZE / 2;
160 ReversedKeyValueHeap kvHeap = getReversibleKeyValueHeap(memstore, sf1, sf2,
161 ROWS[startRowNum], MAXMVCC);
162 internalTestSeekAndNextForReversibleKeyValueHeap(kvHeap, startRowNum);
163
164 startRowNum = ROWSIZE - 1;
165 kvHeap = getReversibleKeyValueHeap(memstore, sf1, sf2,
166 HConstants.EMPTY_START_ROW, MAXMVCC);
167 internalTestSeekAndNextForReversibleKeyValueHeap(kvHeap, startRowNum);
168
169
170
171
172 for (int readPoint = 0; readPoint < MAXMVCC; readPoint++) {
173 LOG.info("Setting read point to " + readPoint);
174 startRowNum = ROWSIZE - 1;
175 kvHeap = getReversibleKeyValueHeap(memstore, sf1, sf2,
176 HConstants.EMPTY_START_ROW, readPoint);
177 for (int i = startRowNum; i >= 0; i--) {
178 if (i - 2 < 0) break;
179 i = i - 2;
180 kvHeap.seekToPreviousRow(KeyValue.createFirstOnRow(ROWS[i + 1]));
181 Pair<Integer, Integer> nextReadableNum = getNextReadableNumWithBackwardScan(
182 i, 0, readPoint);
183 if (nextReadableNum == null) break;
184 KeyValue expecedKey = makeKV(nextReadableNum.getFirst(),
185 nextReadableNum.getSecond());
186 assertEquals(expecedKey, kvHeap.peek());
187 i = nextReadableNum.getFirst();
188 int qualNum = nextReadableNum.getSecond();
189 if (qualNum + 1 < QUALSIZE) {
190 kvHeap.backwardSeek(makeKV(i, qualNum + 1));
191 nextReadableNum = getNextReadableNumWithBackwardScan(i, qualNum + 1,
192 readPoint);
193 if (nextReadableNum == null) break;
194 expecedKey = makeKV(nextReadableNum.getFirst(),
195 nextReadableNum.getSecond());
196 assertEquals(expecedKey, kvHeap.peek());
197 i = nextReadableNum.getFirst();
198 qualNum = nextReadableNum.getSecond();
199 }
200
201 kvHeap.next();
202
203 if (qualNum + 1 >= QUALSIZE) {
204 nextReadableNum = getNextReadableNumWithBackwardScan(i - 1, 0,
205 readPoint);
206 } else {
207 nextReadableNum = getNextReadableNumWithBackwardScan(i, qualNum + 1,
208 readPoint);
209 }
210 if (nextReadableNum == null) break;
211 expecedKey = makeKV(nextReadableNum.getFirst(),
212 nextReadableNum.getSecond());
213 assertEquals(expecedKey, kvHeap.peek());
214 i = nextReadableNum.getFirst();
215 }
216 }
217 }
218
219 @Test
220 public void testReversibleStoreScanner() throws IOException {
221
222 FileSystem fs = TEST_UTIL.getTestFileSystem();
223 Path hfilePath = new Path(new Path(
224 TEST_UTIL.getDataTestDir("testReversibleStoreScanner"), "regionname"),
225 "familyname");
226 CacheConfig cacheConf = new CacheConfig(TEST_UTIL.getConfiguration());
227 HFileContextBuilder hcBuilder = new HFileContextBuilder();
228 hcBuilder.withBlockSize(2 * 1024);
229 HFileContext hFileContext = hcBuilder.build();
230 StoreFile.Writer writer1 = new StoreFile.WriterBuilder(
231 TEST_UTIL.getConfiguration(), cacheConf, fs).withOutputDir(
232 hfilePath).withFileContext(hFileContext).build();
233 StoreFile.Writer writer2 = new StoreFile.WriterBuilder(
234 TEST_UTIL.getConfiguration(), cacheConf, fs).withOutputDir(
235 hfilePath).withFileContext(hFileContext).build();
236
237 MemStore memstore = new MemStore();
238 writeMemstoreAndStoreFiles(memstore, new StoreFile.Writer[] { writer1,
239 writer2 });
240
241 StoreFile sf1 = new StoreFile(fs, writer1.getPath(),
242 TEST_UTIL.getConfiguration(), cacheConf, BloomType.NONE);
243
244 StoreFile sf2 = new StoreFile(fs, writer2.getPath(),
245 TEST_UTIL.getConfiguration(), cacheConf, BloomType.NONE);
246
247 ScanType scanType = ScanType.USER_SCAN;
248 ScanInfo scanInfo = new ScanInfo(FAMILYNAME, 0, Integer.MAX_VALUE,
249 Long.MAX_VALUE, false, 0, KeyValue.COMPARATOR);
250
251
252 Scan scan = new Scan();
253 scan.setReversed(true);
254 StoreScanner storeScanner = getReversibleStoreScanner(memstore, sf1, sf2,
255 scan, scanType, scanInfo, MAXMVCC);
256 verifyCountAndOrder(storeScanner, QUALSIZE * ROWSIZE, ROWSIZE, false);
257
258
259 int startRowNum = ROWSIZE / 2;
260 byte[] startRow = ROWS[startRowNum];
261 scan.setStartRow(startRow);
262 storeScanner = getReversibleStoreScanner(memstore, sf1, sf2, scan,
263 scanType, scanInfo, MAXMVCC);
264 verifyCountAndOrder(storeScanner, QUALSIZE * (startRowNum + 1),
265 startRowNum + 1, false);
266
267
268
269 assertTrue(QUALSIZE > 2);
270 scan.addColumn(FAMILYNAME, QUALS[0]);
271 scan.addColumn(FAMILYNAME, QUALS[2]);
272 storeScanner = getReversibleStoreScanner(memstore, sf1, sf2, scan,
273 scanType, scanInfo, MAXMVCC);
274 verifyCountAndOrder(storeScanner, 2 * (startRowNum + 1), startRowNum + 1,
275 false);
276
277
278 for (int readPoint = 0; readPoint < MAXMVCC; readPoint++) {
279 LOG.info("Setting read point to " + readPoint);
280 storeScanner = getReversibleStoreScanner(memstore, sf1, sf2, scan,
281 scanType, scanInfo, readPoint);
282 int expectedRowCount = 0;
283 int expectedKVCount = 0;
284 for (int i = startRowNum; i >= 0; i--) {
285 int kvCount = 0;
286 if (makeMVCC(i, 0) <= readPoint) {
287 kvCount++;
288 }
289 if (makeMVCC(i, 2) <= readPoint) {
290 kvCount++;
291 }
292 if (kvCount > 0) {
293 expectedRowCount++;
294 expectedKVCount += kvCount;
295 }
296 }
297 verifyCountAndOrder(storeScanner, expectedKVCount, expectedRowCount,
298 false);
299 }
300 }
301
302 @Test
303 public void testReversibleRegionScanner() throws IOException {
304 byte[] tableName = Bytes.toBytes("testtable");
305 byte[] FAMILYNAME2 = Bytes.toBytes("testCf2");
306 Configuration conf = HBaseConfiguration.create();
307 HRegion region = TEST_UTIL.createLocalHRegion(tableName, null, null,
308 "testReversibleRegionScanner", conf, false, Durability.SYNC_WAL, null,
309 FAMILYNAME, FAMILYNAME2);
310 loadDataToRegion(region, FAMILYNAME2);
311
312
313 Scan scan = new Scan();
314 InternalScanner scanner = region.getScanner(scan);
315 verifyCountAndOrder(scanner, ROWSIZE * QUALSIZE * 2, ROWSIZE, true);
316
317
318 scan.setReversed(true);
319 scanner = region.getScanner(scan);
320 verifyCountAndOrder(scanner, ROWSIZE * QUALSIZE * 2, ROWSIZE, false);
321
322
323 scan = new Scan();
324 scan.setReversed(true);
325 scan.addFamily(FAMILYNAME);
326 scanner = region.getScanner(scan);
327 verifyCountAndOrder(scanner, ROWSIZE * QUALSIZE, ROWSIZE, false);
328
329
330 byte[][] specifiedQualifiers = { QUALS[1], QUALS[2] };
331 for (byte[] specifiedQualifier : specifiedQualifiers)
332 scan.addColumn(FAMILYNAME, specifiedQualifier);
333 scanner = region.getScanner(scan);
334 verifyCountAndOrder(scanner, ROWSIZE * 2, ROWSIZE, false);
335
336
337 for (byte[] specifiedQualifier : specifiedQualifiers)
338 scan.addColumn(FAMILYNAME2, specifiedQualifier);
339 scanner = region.getScanner(scan);
340 verifyCountAndOrder(scanner, ROWSIZE * 2 * 2, ROWSIZE, false);
341
342
343 int startRowNum = ROWSIZE * 3 / 4;
344 scan.setStartRow(ROWS[startRowNum]);
345 scanner = region.getScanner(scan);
346 verifyCountAndOrder(scanner, (startRowNum + 1) * 2 * 2, (startRowNum + 1),
347 false);
348
349
350 int stopRowNum = ROWSIZE / 4;
351 scan.setStartRow(HConstants.EMPTY_BYTE_ARRAY);
352 scan.setStopRow(ROWS[stopRowNum]);
353 scanner = region.getScanner(scan);
354 verifyCountAndOrder(scanner, (ROWSIZE - stopRowNum - 1) * 2 * 2, (ROWSIZE
355 - stopRowNum - 1), false);
356
357
358 scan.setStartRow(ROWS[startRowNum]);
359 scanner = region.getScanner(scan);
360 verifyCountAndOrder(scanner, (startRowNum - stopRowNum) * 2 * 2,
361 (startRowNum - stopRowNum), false);
362
363
364 int valueNum = startRowNum % VALUESIZE;
365 Filter filter = new SingleColumnValueFilter(FAMILYNAME,
366 specifiedQualifiers[0], CompareOp.EQUAL, VALUES[valueNum]);
367 scan.setFilter(filter);
368 scanner = region.getScanner(scan);
369 int unfilteredRowNum = (startRowNum - stopRowNum) / VALUESIZE
370 + (stopRowNum / VALUESIZE == valueNum ? 0 : 1);
371 verifyCountAndOrder(scanner, unfilteredRowNum * 2 * 2, unfilteredRowNum,
372 false);
373
374
375 int pageSize = 10;
376 filter = new PageFilter(pageSize);
377 scan.setFilter(filter);
378 scanner = region.getScanner(scan);
379 int expectedRowNum = pageSize;
380 verifyCountAndOrder(scanner, expectedRowNum * 2 * 2, expectedRowNum, false);
381
382
383 SingleColumnValueFilter scvFilter1 = new SingleColumnValueFilter(
384 FAMILYNAME, specifiedQualifiers[0], CompareOp.EQUAL, VALUES[0]);
385 SingleColumnValueFilter scvFilter2 = new SingleColumnValueFilter(
386 FAMILYNAME, specifiedQualifiers[0], CompareOp.EQUAL, VALUES[1]);
387 expectedRowNum = 0;
388 for (int i = startRowNum; i > stopRowNum; i--) {
389 if (i % VALUESIZE == 0 || i % VALUESIZE == 1) {
390 expectedRowNum++;
391 }
392 }
393 filter = new FilterList(Operator.MUST_PASS_ONE, scvFilter1, scvFilter2);
394 scan.setFilter(filter);
395 scanner = region.getScanner(scan);
396 verifyCountAndOrder(scanner, expectedRowNum * 2 * 2, expectedRowNum, false);
397
398
399 filter = new FilterList(Operator.MUST_PASS_ALL, scvFilter1, scvFilter2);
400 expectedRowNum = 0;
401 scan.setFilter(filter);
402 scanner = region.getScanner(scan);
403 verifyCountAndOrder(scanner, expectedRowNum * 2 * 2, expectedRowNum, false);
404 }
405
406 private StoreScanner getReversibleStoreScanner(MemStore memstore,
407 StoreFile sf1, StoreFile sf2, Scan scan, ScanType scanType,
408 ScanInfo scanInfo, int readPoint) throws IOException {
409 List<KeyValueScanner> scanners = getScanners(memstore, sf1, sf2, null,
410 false, readPoint);
411 NavigableSet<byte[]> columns = null;
412 for (Map.Entry<byte[], NavigableSet<byte[]>> entry : scan.getFamilyMap()
413 .entrySet()) {
414
415 columns = entry.getValue();
416 }
417 StoreScanner storeScanner = new ReversedStoreScanner(scan, scanInfo,
418 scanType, columns, scanners);
419 return storeScanner;
420 }
421
422 private void verifyCountAndOrder(InternalScanner scanner,
423 int expectedKVCount, int expectedRowCount, boolean forward)
424 throws IOException {
425 List<Cell> kvList = new ArrayList<Cell>();
426 Result lastResult = null;
427 int rowCount = 0;
428 int kvCount = 0;
429 try {
430 while (scanner.next(kvList)) {
431 if (kvList.isEmpty()) continue;
432 rowCount++;
433 kvCount += kvList.size();
434 if (lastResult != null) {
435 Result curResult = Result.create(kvList);
436 assertEquals("LastResult:" + lastResult + "CurResult:" + curResult,
437 forward,
438 Bytes.compareTo(curResult.getRow(), lastResult.getRow()) > 0);
439 }
440 lastResult = Result.create(kvList);
441 kvList.clear();
442 }
443 } finally {
444 scanner.close();
445 }
446 if (!kvList.isEmpty()) {
447 rowCount++;
448 kvCount += kvList.size();
449 kvList.clear();
450 }
451 assertEquals(expectedKVCount, kvCount);
452 assertEquals(expectedRowCount, rowCount);
453 }
454
455 private void internalTestSeekAndNextForReversibleKeyValueHeap(
456 ReversedKeyValueHeap kvHeap, int startRowNum) throws IOException {
457
458 for (int i = startRowNum; i >= 0; i--) {
459 if (i % 2 == 1 && i - 2 >= 0) {
460 i = i - 2;
461 kvHeap.seekToPreviousRow(KeyValue.createFirstOnRow(ROWS[i + 1]));
462 }
463 for (int j = 0; j < QUALSIZE; j++) {
464 if (j % 2 == 1 && (j + 1) < QUALSIZE) {
465 j = j + 1;
466 kvHeap.backwardSeek(makeKV(i, j));
467 }
468 assertEquals(makeKV(i, j), kvHeap.peek());
469 kvHeap.next();
470 }
471 }
472 assertEquals(null, kvHeap.peek());
473 }
474
475 private ReversedKeyValueHeap getReversibleKeyValueHeap(MemStore memstore,
476 StoreFile sf1, StoreFile sf2, byte[] startRow, int readPoint)
477 throws IOException {
478 List<KeyValueScanner> scanners = getScanners(memstore, sf1, sf2, startRow,
479 true, readPoint);
480 ReversedKeyValueHeap kvHeap = new ReversedKeyValueHeap(scanners,
481 KeyValue.COMPARATOR);
482 return kvHeap;
483 }
484
485 private List<KeyValueScanner> getScanners(MemStore memstore, StoreFile sf1,
486 StoreFile sf2, byte[] startRow, boolean doSeek, int readPoint)
487 throws IOException {
488 List<StoreFileScanner> fileScanners = StoreFileScanner
489 .getScannersForStoreFiles(Lists.newArrayList(sf1, sf2), false, true,
490 false, readPoint);
491 List<KeyValueScanner> memScanners = memstore.getScanners(readPoint);
492 List<KeyValueScanner> scanners = new ArrayList<KeyValueScanner>(
493 fileScanners.size() + 1);
494 scanners.addAll(fileScanners);
495 scanners.addAll(memScanners);
496
497 if (doSeek) {
498 if (Bytes.equals(HConstants.EMPTY_START_ROW, startRow)) {
499 for (KeyValueScanner scanner : scanners) {
500 scanner.seekToLastRow();
501 }
502 } else {
503 KeyValue startKey = KeyValue.createFirstOnRow(startRow);
504 for (KeyValueScanner scanner : scanners) {
505 scanner.backwardSeek(startKey);
506 }
507 }
508 }
509 return scanners;
510 }
511
512 private void seekTestOfReversibleKeyValueScanner(KeyValueScanner scanner)
513 throws IOException {
514
515
516
517
518 assertTrue(scanner.seekToLastRow());
519 assertEquals(makeKV(ROWSIZE - 1, 0), scanner.peek());
520
521
522
523 KeyValue seekKey = makeKV(ROWSIZE - 2, QUALSIZE - 2);
524 assertTrue(scanner.backwardSeek(seekKey));
525 assertEquals(seekKey, scanner.peek());
526
527
528 int seekRowNum = ROWSIZE - 2;
529 assertTrue(scanner.backwardSeek(KeyValue.createLastOnRow(ROWS[seekRowNum])));
530 KeyValue expectedKey = makeKV(seekRowNum - 1, 0);
531 assertEquals(expectedKey, scanner.peek());
532
533
534 assertFalse(scanner.backwardSeek(KeyValue.createLastOnRow(ROWS[0])));
535 assertEquals(null, scanner.peek());
536
537
538 seekRowNum = ROWSIZE - 4;
539 assertTrue(scanner.seekToPreviousRow(KeyValue
540 .createFirstOnRow(ROWS[seekRowNum])));
541 expectedKey = makeKV(seekRowNum - 1, 0);
542 assertEquals(expectedKey, scanner.peek());
543
544
545 assertFalse(scanner.seekToPreviousRow(makeKV(0, 0)));
546 assertEquals(null, scanner.peek());
547
548 }
549
550 private void seekTestOfReversibleKeyValueScannerWithMVCC(
551 KeyValueScanner scanner, int readPoint) throws IOException {
552
553
554
555
556 KeyValue expectedKey = getNextReadableKeyValueWithBackwardScan(
557 ROWSIZE - 1, 0, readPoint);
558 assertEquals(expectedKey != null, scanner.seekToLastRow());
559 assertEquals(expectedKey, scanner.peek());
560
561
562
563 expectedKey = getNextReadableKeyValueWithBackwardScan(ROWSIZE - 2,
564 QUALSIZE - 2, readPoint);
565 assertEquals(expectedKey != null, scanner.backwardSeek(expectedKey));
566 assertEquals(expectedKey, scanner.peek());
567
568
569 int seekRowNum = ROWSIZE - 3;
570 KeyValue seekKey = KeyValue.createLastOnRow(ROWS[seekRowNum]);
571 expectedKey = getNextReadableKeyValueWithBackwardScan(seekRowNum - 1, 0,
572 readPoint);
573 assertEquals(expectedKey != null, scanner.backwardSeek(seekKey));
574 assertEquals(expectedKey, scanner.peek());
575
576
577 seekRowNum = ROWSIZE - 4;
578 expectedKey = getNextReadableKeyValueWithBackwardScan(seekRowNum - 1, 0,
579 readPoint);
580 assertEquals(expectedKey != null, scanner.seekToPreviousRow(KeyValue
581 .createFirstOnRow(ROWS[seekRowNum])));
582 assertEquals(expectedKey, scanner.peek());
583 }
584
585 private KeyValue getNextReadableKeyValueWithBackwardScan(int startRowNum,
586 int startQualNum, int readPoint) {
587 Pair<Integer, Integer> nextReadableNum = getNextReadableNumWithBackwardScan(
588 startRowNum, startQualNum, readPoint);
589 if (nextReadableNum == null)
590 return null;
591 return makeKV(nextReadableNum.getFirst(), nextReadableNum.getSecond());
592 }
593
594 private Pair<Integer, Integer> getNextReadableNumWithBackwardScan(
595 int startRowNum, int startQualNum, int readPoint) {
596 Pair<Integer, Integer> nextReadableNum = null;
597 boolean findExpected = false;
598 for (int i = startRowNum; i >= 0; i--) {
599 for (int j = (i == startRowNum ? startQualNum : 0); j < QUALSIZE; j++) {
600 if (makeMVCC(i, j) <= readPoint) {
601 nextReadableNum = new Pair<Integer, Integer>(i, j);
602 findExpected = true;
603 break;
604 }
605 }
606 if (findExpected)
607 break;
608 }
609 return nextReadableNum;
610 }
611
612 private static void loadDataToRegion(HRegion region, byte[] additionalFamily)
613 throws IOException {
614 for (int i = 0; i < ROWSIZE; i++) {
615 Put put = new Put(ROWS[i]);
616 for (int j = 0; j < QUALSIZE; j++) {
617 put.add(makeKV(i, j));
618
619 put.add(makeKV(i, j, additionalFamily));
620 }
621 region.put(put);
622 if (i == ROWSIZE / 3 || i == ROWSIZE * 2 / 3) {
623 region.flushcache();
624 }
625 }
626 }
627
628 private static void writeMemstoreAndStoreFiles(MemStore memstore,
629 final StoreFile.Writer[] writers) throws IOException {
630 Random rand = new Random();
631 try {
632 for (int i = 0; i < ROWSIZE; i++) {
633 for (int j = 0; j < QUALSIZE; j++) {
634 if (i % 2 == 0) {
635 memstore.add(makeKV(i, j));
636 } else {
637 writers[(i + j) % writers.length].append(makeKV(i, j));
638 }
639 }
640 }
641 } finally {
642 for (int i = 0; i < writers.length; i++) {
643 writers[i].close();
644 }
645 }
646 }
647
648 private static void writeStoreFile(final StoreFile.Writer writer)
649 throws IOException {
650 try {
651 for (int i = 0; i < ROWSIZE; i++) {
652 for (int j = 0; j < QUALSIZE; j++) {
653 writer.append(makeKV(i, j));
654 }
655 }
656 } finally {
657 writer.close();
658 }
659 }
660
661 private static void writeMemstore(MemStore memstore) throws IOException {
662
663 for (int i = 0; i < ROWSIZE; i++) {
664 for (int j = 0; j < QUALSIZE; j++) {
665 if ((i + j) % 2 == 0) {
666 memstore.add(makeKV(i, j));
667 }
668 }
669 }
670 memstore.snapshot();
671
672 for (int i = 0; i < ROWSIZE; i++) {
673 for (int j = 0; j < QUALSIZE; j++) {
674 if ((i + j) % 2 == 1) {
675 memstore.add(makeKV(i, j));
676 }
677 }
678 }
679 }
680
681 private static KeyValue makeKV(int rowNum, int cqNum) {
682 return makeKV(rowNum, cqNum, FAMILYNAME);
683 }
684
685 private static KeyValue makeKV(int rowNum, int cqNum, byte[] familyName) {
686 KeyValue kv = new KeyValue(ROWS[rowNum], familyName, QUALS[cqNum], TS,
687 VALUES[rowNum % VALUESIZE]);
688 kv.setMvccVersion(makeMVCC(rowNum, cqNum));
689 return kv;
690 }
691
692 private static long makeMVCC(int rowNum, int cqNum) {
693 return (rowNum + cqNum) % (MAXMVCC + 1);
694 }
695
696 private static byte[][] makeN(byte[] base, int n) {
697 byte[][] ret = new byte[n][];
698 for (int i = 0; i < n; i++) {
699 ret[i] = Bytes.add(base, Bytes.toBytes(String.format("%04d", i)));
700 }
701 return ret;
702 }
703 }