| /* |
| * Copyright 2009 The Apache Software Foundation |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.hadoop.hbase.regionserver; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.apache.hadoop.hbase.HBaseTestCase; |
| import org.apache.hadoop.hbase.KeyValue; |
| import org.apache.hadoop.hbase.util.Bytes; |
| |
| |
| public class TestKeyValueHeap extends HBaseTestCase { |
| private static final boolean PRINT = false; |
| |
| List<KeyValueScanner> scanners = new ArrayList<KeyValueScanner>(); |
| |
| private byte[] row1; |
| private byte[] fam1; |
| private byte[] col1; |
| private byte[] data; |
| |
| private byte[] row2; |
| private byte[] fam2; |
| private byte[] col2; |
| |
| private byte[] col3; |
| private byte[] col4; |
| private byte[] col5; |
| |
| public void setUp() throws Exception { |
| super.setUp(); |
| data = Bytes.toBytes("data"); |
| row1 = Bytes.toBytes("row1"); |
| fam1 = Bytes.toBytes("fam1"); |
| col1 = Bytes.toBytes("col1"); |
| row2 = Bytes.toBytes("row2"); |
| fam2 = Bytes.toBytes("fam2"); |
| col2 = Bytes.toBytes("col2"); |
| col3 = Bytes.toBytes("col3"); |
| col4 = Bytes.toBytes("col4"); |
| col5 = Bytes.toBytes("col5"); |
| } |
| |
| public void testSorted() throws IOException{ |
| //Cases that need to be checked are: |
| //1. The "smallest" KeyValue is in the same scanners as current |
| //2. Current scanner gets empty |
| |
| List<KeyValue> l1 = new ArrayList<KeyValue>(); |
| l1.add(new KeyValue(row1, fam1, col5, data)); |
| l1.add(new KeyValue(row2, fam1, col1, data)); |
| l1.add(new KeyValue(row2, fam1, col2, data)); |
| scanners.add(new Scanner(l1)); |
| |
| List<KeyValue> l2 = new ArrayList<KeyValue>(); |
| l2.add(new KeyValue(row1, fam1, col1, data)); |
| l2.add(new KeyValue(row1, fam1, col2, data)); |
| scanners.add(new Scanner(l2)); |
| |
| List<KeyValue> l3 = new ArrayList<KeyValue>(); |
| l3.add(new KeyValue(row1, fam1, col3, data)); |
| l3.add(new KeyValue(row1, fam1, col4, data)); |
| l3.add(new KeyValue(row1, fam2, col1, data)); |
| l3.add(new KeyValue(row1, fam2, col2, data)); |
| l3.add(new KeyValue(row2, fam1, col3, data)); |
| scanners.add(new Scanner(l3)); |
| |
| List<KeyValue> expected = new ArrayList<KeyValue>(); |
| expected.add(new KeyValue(row1, fam1, col1, data)); |
| expected.add(new KeyValue(row1, fam1, col2, data)); |
| expected.add(new KeyValue(row1, fam1, col3, data)); |
| expected.add(new KeyValue(row1, fam1, col4, data)); |
| expected.add(new KeyValue(row1, fam1, col5, data)); |
| expected.add(new KeyValue(row1, fam2, col1, data)); |
| expected.add(new KeyValue(row1, fam2, col2, data)); |
| expected.add(new KeyValue(row2, fam1, col1, data)); |
| expected.add(new KeyValue(row2, fam1, col2, data)); |
| expected.add(new KeyValue(row2, fam1, col3, data)); |
| |
| //Creating KeyValueHeap |
| KeyValueHeap kvh = |
| new KeyValueHeap(scanners, KeyValue.COMPARATOR); |
| |
| List<KeyValue> actual = new ArrayList<KeyValue>(); |
| while(kvh.peek() != null){ |
| actual.add(kvh.next()); |
| } |
| |
| assertEquals(expected.size(), actual.size()); |
| for(int i=0; i<expected.size(); i++){ |
| assertEquals(expected.get(i), actual.get(i)); |
| if(PRINT){ |
| System.out.println("expected " +expected.get(i)+ |
| "\nactual " +actual.get(i) +"\n"); |
| } |
| } |
| |
| //Check if result is sorted according to Comparator |
| for(int i=0; i<actual.size()-1; i++){ |
| int ret = KeyValue.COMPARATOR.compare(actual.get(i), actual.get(i+1)); |
| assertTrue(ret < 0); |
| } |
| |
| } |
| |
| public void testSeek() throws IOException { |
| //Cases: |
| //1. Seek KeyValue that is not in scanner |
| //2. Check that smallest that is returned from a seek is correct |
| |
| List<KeyValue> l1 = new ArrayList<KeyValue>(); |
| l1.add(new KeyValue(row1, fam1, col5, data)); |
| l1.add(new KeyValue(row2, fam1, col1, data)); |
| l1.add(new KeyValue(row2, fam1, col2, data)); |
| scanners.add(new Scanner(l1)); |
| |
| List<KeyValue> l2 = new ArrayList<KeyValue>(); |
| l2.add(new KeyValue(row1, fam1, col1, data)); |
| l2.add(new KeyValue(row1, fam1, col2, data)); |
| scanners.add(new Scanner(l2)); |
| |
| List<KeyValue> l3 = new ArrayList<KeyValue>(); |
| l3.add(new KeyValue(row1, fam1, col3, data)); |
| l3.add(new KeyValue(row1, fam1, col4, data)); |
| l3.add(new KeyValue(row1, fam2, col1, data)); |
| l3.add(new KeyValue(row1, fam2, col2, data)); |
| l3.add(new KeyValue(row2, fam1, col3, data)); |
| scanners.add(new Scanner(l3)); |
| |
| List<KeyValue> expected = new ArrayList<KeyValue>(); |
| expected.add(new KeyValue(row2, fam1, col1, data)); |
| |
| //Creating KeyValueHeap |
| KeyValueHeap kvh = |
| new KeyValueHeap(scanners, KeyValue.COMPARATOR); |
| |
| KeyValue seekKv = new KeyValue(row2, fam1, null, null); |
| kvh.seek(seekKv); |
| |
| List<KeyValue> actual = new ArrayList<KeyValue>(); |
| actual.add(kvh.peek()); |
| |
| assertEquals(expected.size(), actual.size()); |
| for(int i=0; i<expected.size(); i++){ |
| assertEquals(expected.get(i), actual.get(i)); |
| if(PRINT){ |
| System.out.println("expected " +expected.get(i)+ |
| "\nactual " +actual.get(i) +"\n"); |
| } |
| } |
| |
| } |
| |
| public void testScannerLeak() throws IOException { |
| // Test for unclosed scanners (HBASE-1927) |
| |
| List<KeyValue> l1 = new ArrayList<KeyValue>(); |
| l1.add(new KeyValue(row1, fam1, col5, data)); |
| l1.add(new KeyValue(row2, fam1, col1, data)); |
| l1.add(new KeyValue(row2, fam1, col2, data)); |
| scanners.add(new Scanner(l1)); |
| |
| List<KeyValue> l2 = new ArrayList<KeyValue>(); |
| l2.add(new KeyValue(row1, fam1, col1, data)); |
| l2.add(new KeyValue(row1, fam1, col2, data)); |
| scanners.add(new Scanner(l2)); |
| |
| List<KeyValue> l3 = new ArrayList<KeyValue>(); |
| l3.add(new KeyValue(row1, fam1, col3, data)); |
| l3.add(new KeyValue(row1, fam1, col4, data)); |
| l3.add(new KeyValue(row1, fam2, col1, data)); |
| l3.add(new KeyValue(row1, fam2, col2, data)); |
| l3.add(new KeyValue(row2, fam1, col3, data)); |
| scanners.add(new Scanner(l3)); |
| |
| List<KeyValue> l4 = new ArrayList<KeyValue>(); |
| scanners.add(new Scanner(l4)); |
| |
| //Creating KeyValueHeap |
| KeyValueHeap kvh = new KeyValueHeap(scanners, KeyValue.COMPARATOR); |
| |
| while(kvh.next() != null); |
| |
| for(KeyValueScanner scanner : scanners) { |
| assertTrue(((Scanner)scanner).isClosed()); |
| } |
| } |
| |
| private static class Scanner implements KeyValueScanner { |
| private Iterator<KeyValue> iter; |
| private KeyValue current; |
| private boolean closed = false; |
| |
| public Scanner(List<KeyValue> list) { |
| Collections.sort(list, KeyValue.COMPARATOR); |
| iter = list.iterator(); |
| if(iter.hasNext()){ |
| current = iter.next(); |
| } |
| } |
| |
| public KeyValue peek() { |
| return current; |
| } |
| |
| public KeyValue next() { |
| KeyValue oldCurrent = current; |
| if(iter.hasNext()){ |
| current = iter.next(); |
| } else { |
| current = null; |
| } |
| return oldCurrent; |
| } |
| |
| public void close(){ |
| closed = true; |
| } |
| |
| public boolean isClosed() { |
| return closed; |
| } |
| |
| public boolean seek(KeyValue seekKv) { |
| while(iter.hasNext()){ |
| KeyValue next = iter.next(); |
| int ret = KeyValue.COMPARATOR.compare(next, seekKv); |
| if(ret >= 0){ |
| current = next; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean reseek(KeyValue key) throws IOException { |
| return seek(key); |
| } |
| |
| @Override |
| public long getSequenceID() { |
| return 0; |
| } |
| } |
| |
| } |