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  
27  import org.apache.hadoop.hbase.HBaseTestCase;
28  import org.apache.hadoop.hbase.KeyValue;
29  import org.apache.hadoop.hbase.KeyValue.KVComparator;
30  import org.apache.hadoop.hbase.SmallTests;
31  import org.apache.hadoop.hbase.client.Get;
32  import org.apache.hadoop.hbase.client.Scan;
33  import org.apache.hadoop.hbase.regionserver.ScanQueryMatcher.MatchCode;
34  import org.apache.hadoop.hbase.util.Bytes;
35  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
36  import org.junit.experimental.categories.Category;
37  
38  @Category(SmallTests.class)
39  public class TestQueryMatcher extends HBaseTestCase {
40    private static final boolean PRINT = false;
41  
42    private byte[] row1;
43    private byte[] row2;
44    private byte[] fam1;
45    private byte[] fam2;
46    private byte[] col1;
47    private byte[] col2;
48    private byte[] col3;
49    private byte[] col4;
50    private byte[] col5;
51  
52    private byte[] data;
53  
54    private Get get;
55  
56    long ttl = Long.MAX_VALUE;
57    KVComparator rowComparator;
58    private Scan scan;
59  
60    public void setUp() throws Exception {
61      super.setUp();
62      row1 = Bytes.toBytes("row1");
63      row2 = Bytes.toBytes("row2");
64      fam1 = Bytes.toBytes("fam1");
65      fam2 = Bytes.toBytes("fam2");
66      col1 = Bytes.toBytes("col1");
67      col2 = Bytes.toBytes("col2");
68      col3 = Bytes.toBytes("col3");
69      col4 = Bytes.toBytes("col4");
70      col5 = Bytes.toBytes("col5");
71  
72      data = Bytes.toBytes("data");
73  
74      //Create Get
75      get = new Get(row1);
76      get.addFamily(fam1);
77      get.addColumn(fam2, col2);
78      get.addColumn(fam2, col4);
79      get.addColumn(fam2, col5);
80      this.scan = new Scan(get);
81  
82      rowComparator = KeyValue.COMPARATOR;
83  
84    }
85  
86    public void testMatch_ExplicitColumns()
87    throws IOException {
88      //Moving up from the Tracker by using Gets and List<KeyValue> instead
89      //of just byte []
90  
91      //Expected result
92      List<MatchCode> expected = new ArrayList<ScanQueryMatcher.MatchCode>();
93      expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
94      expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL);
95      expected.add(ScanQueryMatcher.MatchCode.SEEK_NEXT_COL);
96      expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL);
97      expected.add(ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW);
98      expected.add(ScanQueryMatcher.MatchCode.DONE);
99  
100     // 2,4,5
101     
102     ScanQueryMatcher qm = new ScanQueryMatcher(scan, new Store.ScanInfo(fam2,
103         0, 1, ttl, false, 0, rowComparator), get.getFamilyMap().get(fam2),
104         EnvironmentEdgeManager.currentTimeMillis() - ttl);
105 
106     List<KeyValue> memstore = new ArrayList<KeyValue>();
107     memstore.add(new KeyValue(row1, fam2, col1, 1, data));
108     memstore.add(new KeyValue(row1, fam2, col2, 1, data));
109     memstore.add(new KeyValue(row1, fam2, col3, 1, data));
110     memstore.add(new KeyValue(row1, fam2, col4, 1, data));
111     memstore.add(new KeyValue(row1, fam2, col5, 1, data));
112 
113     memstore.add(new KeyValue(row2, fam1, col1, data));
114 
115     List<ScanQueryMatcher.MatchCode> actual = new ArrayList<ScanQueryMatcher.MatchCode>();
116     KeyValue k = memstore.get(0);
117     qm.setRow(k.getBuffer(), k.getRowOffset(), k.getRowLength());
118 
119     for (KeyValue kv : memstore){
120       actual.add(qm.match(kv));
121     }
122 
123     assertEquals(expected.size(), actual.size());
124     for(int i=0; i< expected.size(); i++){
125       assertEquals(expected.get(i), actual.get(i));
126       if(PRINT){
127         System.out.println("expected "+expected.get(i)+
128             ", actual " +actual.get(i));
129       }
130     }
131   }
132 
133 
134   public void testMatch_Wildcard()
135   throws IOException {
136     //Moving up from the Tracker by using Gets and List<KeyValue> instead
137     //of just byte []
138 
139     //Expected result
140     List<MatchCode> expected = new ArrayList<ScanQueryMatcher.MatchCode>();
141     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);
142     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);
143     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);
144     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);
145     expected.add(ScanQueryMatcher.MatchCode.INCLUDE);
146     expected.add(ScanQueryMatcher.MatchCode.DONE);
147 
148     ScanQueryMatcher qm = new ScanQueryMatcher(scan, new Store.ScanInfo(fam2,
149         0, 1, ttl, false, 0, rowComparator), null,
150         EnvironmentEdgeManager.currentTimeMillis() - ttl);
151 
152     List<KeyValue> memstore = new ArrayList<KeyValue>();
153     memstore.add(new KeyValue(row1, fam2, col1, 1, data));
154     memstore.add(new KeyValue(row1, fam2, col2, 1, data));
155     memstore.add(new KeyValue(row1, fam2, col3, 1, data));
156     memstore.add(new KeyValue(row1, fam2, col4, 1, data));
157     memstore.add(new KeyValue(row1, fam2, col5, 1, data));
158     memstore.add(new KeyValue(row2, fam1, col1, 1, data));
159 
160     List<ScanQueryMatcher.MatchCode> actual = new ArrayList<ScanQueryMatcher.MatchCode>();
161 
162     KeyValue k = memstore.get(0);
163     qm.setRow(k.getBuffer(), k.getRowOffset(), k.getRowLength());
164 
165     for(KeyValue kv : memstore) {
166       actual.add(qm.match(kv));
167     }
168 
169     assertEquals(expected.size(), actual.size());
170     for(int i=0; i< expected.size(); i++){
171       assertEquals(expected.get(i), actual.get(i));
172       if(PRINT){
173         System.out.println("expected "+expected.get(i)+
174             ", actual " +actual.get(i));
175       }
176     }
177   }
178 
179 
180   /**
181    * Verify that {@link ScanQueryMatcher} only skips expired KeyValue
182    * instances and does not exit early from the row (skipping
183    * later non-expired KeyValues).  This version mimics a Get with
184    * explicitly specified column qualifiers.
185    *
186    * @throws IOException
187    */
188   public void testMatch_ExpiredExplicit()
189   throws IOException {
190 
191     long testTTL = 1000;
192     MatchCode [] expected = new MatchCode[] {
193         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL,
194         ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL,
195         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL,
196         ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL,
197         ScanQueryMatcher.MatchCode.SEEK_NEXT_ROW,
198         ScanQueryMatcher.MatchCode.DONE
199     };
200 
201     long now = EnvironmentEdgeManager.currentTimeMillis();
202     ScanQueryMatcher qm = new ScanQueryMatcher(scan, new Store.ScanInfo(fam2,
203         0, 1, testTTL, false, 0, rowComparator), get.getFamilyMap().get(fam2),
204         now - testTTL);
205 
206     KeyValue [] kvs = new KeyValue[] {
207         new KeyValue(row1, fam2, col1, now-100, data),
208         new KeyValue(row1, fam2, col2, now-50, data),
209         new KeyValue(row1, fam2, col3, now-5000, data),
210         new KeyValue(row1, fam2, col4, now-500, data),
211         new KeyValue(row1, fam2, col5, now-10000, data),
212         new KeyValue(row2, fam1, col1, now-10, data)
213     };
214 
215     KeyValue k = kvs[0];
216     qm.setRow(k.getBuffer(), k.getRowOffset(), k.getRowLength());
217 
218     List<MatchCode> actual = new ArrayList<MatchCode>(kvs.length);
219     for (KeyValue kv : kvs) {
220       actual.add( qm.match(kv) );
221     }
222 
223     assertEquals(expected.length, actual.size());
224     for (int i=0; i<expected.length; i++) {
225       if(PRINT){
226         System.out.println("expected "+expected[i]+
227             ", actual " +actual.get(i));
228       }
229       assertEquals(expected[i], actual.get(i));
230     }
231   }
232 
233 
234   /**
235    * Verify that {@link ScanQueryMatcher} only skips expired KeyValue
236    * instances and does not exit early from the row (skipping
237    * later non-expired KeyValues).  This version mimics a Get with
238    * wildcard-inferred column qualifiers.
239    *
240    * @throws IOException
241    */
242   public void testMatch_ExpiredWildcard()
243   throws IOException {
244 
245     long testTTL = 1000;
246     MatchCode [] expected = new MatchCode[] {
247         ScanQueryMatcher.MatchCode.INCLUDE,
248         ScanQueryMatcher.MatchCode.INCLUDE,
249         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL,
250         ScanQueryMatcher.MatchCode.INCLUDE,
251         ScanQueryMatcher.MatchCode.SEEK_NEXT_COL,
252         ScanQueryMatcher.MatchCode.DONE
253     };
254 
255     long now = EnvironmentEdgeManager.currentTimeMillis();
256     ScanQueryMatcher qm = new ScanQueryMatcher(scan, new Store.ScanInfo(fam2,
257         0, 1, testTTL, false, 0, rowComparator), null,
258         now - testTTL);
259 
260     KeyValue [] kvs = new KeyValue[] {
261         new KeyValue(row1, fam2, col1, now-100, data),
262         new KeyValue(row1, fam2, col2, now-50, data),
263         new KeyValue(row1, fam2, col3, now-5000, data),
264         new KeyValue(row1, fam2, col4, now-500, data),
265         new KeyValue(row1, fam2, col5, now-10000, data),
266         new KeyValue(row2, fam1, col1, now-10, data)
267     };
268     KeyValue k = kvs[0];
269     qm.setRow(k.getBuffer(), k.getRowOffset(), k.getRowLength());
270 
271     List<ScanQueryMatcher.MatchCode> actual =
272         new ArrayList<ScanQueryMatcher.MatchCode>(kvs.length);
273     for (KeyValue kv : kvs) {
274       actual.add( qm.match(kv) );
275     }
276 
277     assertEquals(expected.length, actual.size());
278     for (int i=0; i<expected.length; i++) {
279       if(PRINT){
280         System.out.println("expected "+expected[i]+
281             ", actual " +actual.get(i));
282       }
283       assertEquals(expected[i], actual.get(i));
284     }
285   }
286 
287   @org.junit.Rule
288   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
289     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
290 }
291