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, int lookAhead) throws IOException {
49      ColumnTracker exp = new ExplicitColumnTracker(
50        trackColumns, 0, maxVersions, Long.MIN_VALUE, lookAhead);
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, 0);
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, 0);
155   }
156 
157   public void testGet_MultiVersionWithLookAhead() throws IOException{
158     if(PRINT){
159       System.out.println("\nMultiVersion");
160     }
161 
162     //Create tracker
163     TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
164     //Looking for every other
165     columns.add(col2);
166     columns.add(col4);
167 
168     List<ScanQueryMatcher.MatchCode> expected = new ArrayList<ScanQueryMatcher.MatchCode>();
169     expected.add(ScanQueryMatcher.MatchCode.SKIP);
170     expected.add(ScanQueryMatcher.MatchCode.SKIP);
171     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
172 
173     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);                   // col2; 1st version
174     expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL); // col2; 2nd version
175     expected.add(ScanQueryMatcher.MatchCode.SKIP);
176 
177     expected.add(ScanQueryMatcher.MatchCode.SKIP);
178     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
179     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
180 
181     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);                   // col4; 1st version
182     expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW); // col4; 2nd version
183     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
184 
185     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
186     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
187     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
188     int maxVersions = 2;
189 
190     //Create "Scanner"
191     List<byte[]> scanner = new ArrayList<byte[]>();
192     scanner.add(col1);
193     scanner.add(col1);
194     scanner.add(col1);
195     scanner.add(col2);
196     scanner.add(col2);
197     scanner.add(col2);
198     scanner.add(col3);
199     scanner.add(col3);
200     scanner.add(col3);
201     scanner.add(col4);
202     scanner.add(col4);
203     scanner.add(col4);
204     scanner.add(col5);
205     scanner.add(col5);
206     scanner.add(col5);
207 
208     //Initialize result
209     runTest(maxVersions, columns, scanner, expected, 2);
210   }
211 
212   /**
213    * hbase-2259
214    */
215   public void testStackOverflow() throws IOException{
216     int maxVersions = 1;
217     TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
218     for (int i = 0; i < 100000; i++) {
219       columns.add(Bytes.toBytes("col"+i));
220     }
221 
222     ColumnTracker explicit = new ExplicitColumnTracker(columns, 0, maxVersions,
223         Long.MIN_VALUE, 0);
224     for (int i = 0; i < 100000; i+=2) {
225       byte [] col = Bytes.toBytes("col"+i);
226       ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(),
227           false);
228     }
229     explicit.reset();
230 
231     for (int i = 1; i < 100000; i+=2) {
232       byte [] col = Bytes.toBytes("col"+i);
233       ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(),
234           false);
235     }
236   }
237 
238   /**
239    * Regression test for HBASE-2545
240    */
241   public void testInfiniteLoop() throws IOException {
242     TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
243     columns.addAll(Arrays.asList(new byte[][] {
244       col2, col3, col5 }));
245     List<byte[]> scanner = Arrays.<byte[]>asList(
246       new byte[][] { col1, col4 });
247     List<ScanQueryMatcher.MatchCode> expected = Arrays.<ScanQueryMatcher.MatchCode>asList(
248       new ScanQueryMatcher.MatchCode[] {
249         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL,
250         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL });
251     runTest(1, columns, scanner, expected, 0);
252   }
253 
254   @org.junit.Rule
255   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
256     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
257 }
258