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