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.HBaseTestCase;
30  import org.apache.hadoop.hbase.regionserver.ScanQueryMatcher.MatchCode;
31  import org.apache.hadoop.hbase.util.Bytes;
32  
33  
34  public class TestExplicitColumnTracker extends HBaseTestCase {
35    private boolean PRINT = false;
36  
37    private final byte[] col1 = Bytes.toBytes("col1");
38    private final byte[] col2 = Bytes.toBytes("col2");
39    private final byte[] col3 = Bytes.toBytes("col3");
40    private final byte[] col4 = Bytes.toBytes("col4");
41    private final byte[] col5 = Bytes.toBytes("col5");
42  
43    private void runTest(int maxVersions,
44                         TreeSet<byte[]> trackColumns,
45                         List<byte[]> scannerColumns,
46                         List<MatchCode> expected) throws IOException {
47      ColumnTracker exp = new ExplicitColumnTracker(
48        trackColumns, 0, maxVersions, Long.MAX_VALUE);
49  
50  
51      //Initialize result
52      List<ScanQueryMatcher.MatchCode> result = new ArrayList<ScanQueryMatcher.MatchCode>();
53  
54      long timestamp = 0;
55      //"Match"
56      for(byte [] col : scannerColumns){
57        result.add(exp.checkColumn(col, 0, col.length, ++timestamp, false));
58      }
59  
60      assertEquals(expected.size(), result.size());
61      for(int i=0; i< expected.size(); i++){
62        assertEquals(expected.get(i), result.get(i));
63        if(PRINT){
64          System.out.println("Expected " +expected.get(i) + ", actual " +
65              result.get(i));
66        }
67      }
68    }
69  
70    public void testGet_SingleVersion() throws IOException{
71      if(PRINT){
72        System.out.println("SingleVersion");
73      }
74  
75      //Create tracker
76      TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
77      //Looking for every other
78      columns.add(col2);
79      columns.add(col4);
80      List<MatchCode> expected = new ArrayList<ScanQueryMatcher.MatchCode>();
81      expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);             // col1
82      expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL); // col2
83      expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);             // col3
84      expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW); // col4
85      expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);             // col5
86      int maxVersions = 1;
87  
88      //Create "Scanner"
89      List<byte[]> scanner = new ArrayList<byte[]>();
90      scanner.add(col1);
91      scanner.add(col2);
92      scanner.add(col3);
93      scanner.add(col4);
94      scanner.add(col5);
95  
96      runTest(maxVersions, columns, scanner, expected);
97    }
98  
99    public void testGet_MultiVersion() throws IOException{
100     if(PRINT){
101       System.out.println("\nMultiVersion");
102     }
103 
104     //Create tracker
105     TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
106     //Looking for every other
107     columns.add(col2);
108     columns.add(col4);
109 
110     List<ScanQueryMatcher.MatchCode> expected = new ArrayList<ScanQueryMatcher.MatchCode>();
111     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
112     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
113     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
114 
115     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);                   // col2; 1st version
116     expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL); // col2; 2nd version
117     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
118 
119     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
120     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
121     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
122 
123     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);                   // col4; 1st version
124     expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW); // col4; 2nd version
125     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
126 
127     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
128     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
129     expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW);
130     int maxVersions = 2;
131 
132     //Create "Scanner"
133     List<byte[]> scanner = new ArrayList<byte[]>();
134     scanner.add(col1);
135     scanner.add(col1);
136     scanner.add(col1);
137     scanner.add(col2);
138     scanner.add(col2);
139     scanner.add(col2);
140     scanner.add(col3);
141     scanner.add(col3);
142     scanner.add(col3);
143     scanner.add(col4);
144     scanner.add(col4);
145     scanner.add(col4);
146     scanner.add(col5);
147     scanner.add(col5);
148     scanner.add(col5);
149 
150     //Initialize result
151     runTest(maxVersions, columns, scanner, expected);
152   }
153 
154 
155   /**
156    * hbase-2259
157    */
158   public void testStackOverflow() throws IOException{
159     int maxVersions = 1;
160     TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
161     for (int i = 0; i < 100000; i++) {
162       columns.add(Bytes.toBytes("col"+i));
163     }
164 
165     ColumnTracker explicit = new ExplicitColumnTracker(columns, 0, maxVersions,
166         Long.MAX_VALUE);
167     for (int i = 0; i < 100000; i+=2) {
168       byte [] col = Bytes.toBytes("col"+i);
169       explicit.checkColumn(col, 0, col.length, 1, false);
170     }
171     explicit.update();
172 
173     for (int i = 1; i < 100000; i+=2) {
174       byte [] col = Bytes.toBytes("col"+i);
175       explicit.checkColumn(col, 0, col.length, 1, false);
176     }
177   }
178 
179   /**
180    * Regression test for HBASE-2545
181    */
182   public void testInfiniteLoop() throws IOException {
183     TreeSet<byte[]> columns = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
184     columns.addAll(Arrays.asList(new byte[][] {
185       col2, col3, col5 }));
186     List<byte[]> scanner = Arrays.<byte[]>asList(
187       new byte[][] { col1, col4 });
188     List<ScanQueryMatcher.MatchCode> expected = Arrays.<ScanQueryMatcher.MatchCode>asList(
189       new ScanQueryMatcher.MatchCode[] {
190         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL,
191         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL });
192     runTest(1, columns, scanner, expected);
193   }
194 }