1   /*
2    * Copyright 2009 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.regionserver;
22  
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.TreeSet;
27  import java.util.Arrays;
28  
29  import org.apache.hadoop.hbase.*;
30  import org.apache.hadoop.hbase.regionserver.ScanQueryMatcher.MatchCode;
31  import org.apache.hadoop.hbase.util.Bytes;
32  import org.junit.experimental.categories.Category;
33  
34  
35  @Category(SmallTests.class)
36  public class TestExplicitColumnTracker extends HBaseTestCase {
37    private boolean PRINT = false;
38  
39    private final byte[] col1 = Bytes.toBytes("col1");
40    private final byte[] col2 = Bytes.toBytes("col2");
41    private final byte[] col3 = Bytes.toBytes("col3");
42    private final byte[] col4 = Bytes.toBytes("col4");
43    private final byte[] col5 = Bytes.toBytes("col5");
44  
45    private void runTest(int maxVersions,
46                         TreeSet<byte[]> trackColumns,
47                         List<byte[]> scannerColumns,
48                         List<MatchCode> expected) throws IOException {
49      ColumnTracker exp = new ExplicitColumnTracker(
50        trackColumns, 0, maxVersions, Long.MIN_VALUE);
51  
52  
53      //Initialize result
54      List<ScanQueryMatcher.MatchCode> result = new ArrayList<ScanQueryMatcher.MatchCode>();
55  
56      long timestamp = 0;
57      //"Match"
58      for(byte [] col : scannerColumns){
59        result.add(ScanQueryMatcher.checkColumn(exp, col, 0, col.length, ++timestamp,
60            KeyValue.Type.Put.getCode(), false));
61      }
62  
63      assertEquals(expected.size(), result.size());
64      for(int i=0; i< expected.size(); i++){
65        assertEquals(expected.get(i), result.get(i));
66        if(PRINT){
67          System.out.println("Expected " +expected.get(i) + ", actual " +
68              result.get(i));
69        }
70      }
71    }
72  
73    public void testGet_SingleVersion() throws IOException{
74      if(PRINT){
75        System.out.println("SingleVersion");
76      }
77  
78      //Create tracker
79      TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
80      //Looking for every other
81      columns.add(col2);
82      columns.add(col4);
83      List<MatchCode> expected = new ArrayList<ScanQueryMatcher.MatchCode>();
84      expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);             // col1
85      expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL); // col2
86      expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);             // col3
87      expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW); // col4
88      expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);             // col5
89      int maxVersions = 1;
90  
91      //Create "Scanner"
92      List<byte[]> scanner = new ArrayList<byte[]>();
93      scanner.add(col1);
94      scanner.add(col2);
95      scanner.add(col3);
96      scanner.add(col4);
97      scanner.add(col5);
98  
99      runTest(maxVersions, columns, scanner, expected);
100   }
101 
102   public void testGet_MultiVersion() throws IOException{
103     if(PRINT){
104       System.out.println("\nMultiVersion");
105     }
106 
107     //Create tracker
108     TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
109     //Looking for every other
110     columns.add(col2);
111     columns.add(col4);
112 
113     List<ScanQueryMatcher.MatchCode> expected = new ArrayList<ScanQueryMatcher.MatchCode>();
114     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
115     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
116     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
117 
118     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);                   // col2; 1st version
119     expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL); // col2; 2nd version
120     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
121 
122     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
123     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
124     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
125 
126     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);                   // col4; 1st version
127     expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW); // col4; 2nd version
128     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
129 
130     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
131     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
132     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
133     int maxVersions = 2;
134 
135     //Create "Scanner"
136     List<byte[]> scanner = new ArrayList<byte[]>();
137     scanner.add(col1);
138     scanner.add(col1);
139     scanner.add(col1);
140     scanner.add(col2);
141     scanner.add(col2);
142     scanner.add(col2);
143     scanner.add(col3);
144     scanner.add(col3);
145     scanner.add(col3);
146     scanner.add(col4);
147     scanner.add(col4);
148     scanner.add(col4);
149     scanner.add(col5);
150     scanner.add(col5);
151     scanner.add(col5);
152 
153     //Initialize result
154     runTest(maxVersions, columns, scanner, expected);
155   }
156 
157 
158   /**
159    * hbase-2259
160    */
161   public void testStackOverflow() throws IOException{
162     int maxVersions = 1;
163     TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
164     for (int i = 0; i < 100000; i++) {
165       columns.add(Bytes.toBytes("col"+i));
166     }
167 
168     ColumnTracker explicit = new ExplicitColumnTracker(columns, 0, maxVersions,
169         Long.MIN_VALUE);
170     for (int i = 0; i < 100000; i+=2) {
171       byte [] col = Bytes.toBytes("col"+i);
172       ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(),
173           false);
174     }
175     explicit.reset();
176 
177     for (int i = 1; i < 100000; i+=2) {
178       byte [] col = Bytes.toBytes("col"+i);
179       ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(),
180           false);
181     }
182   }
183 
184   /**
185    * Regression test for HBASE-2545
186    */
187   public void testInfiniteLoop() throws IOException {
188     TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
189     columns.addAll(Arrays.asList(new byte[][] {
190       col2, col3, col5 }));
191     List<byte[]> scanner = Arrays.<byte[]>asList(
192       new byte[][] { col1, col4 });
193     List<ScanQueryMatcher.MatchCode> expected = Arrays.<ScanQueryMatcher.MatchCode>asList(
194       new ScanQueryMatcher.MatchCode[] {
195         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL,
196         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL });
197     runTest(1, columns, scanner, expected);
198   }
199 
200   @org.junit.Rule
201   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
202     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
203 }
204