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  package org.apache.hadoop.hbase.io.hfile;
21  
22  import java.io.IOException;
23  
24  import org.apache.hadoop.fs.FSDataOutputStream;
25  import org.apache.hadoop.fs.Path;
26  import org.apache.hadoop.hbase.*;
27  import org.apache.hadoop.hbase.util.Bytes;
28  import org.junit.experimental.categories.Category;
29  
30  /**
31   * Test {@link HFileScanner#seekTo(byte[])} and its variants.
32   */
33  @Category(SmallTests.class)
34  public class TestSeekTo extends HBaseTestCase {
35  
36    static KeyValue toKV(String row) {
37      return new KeyValue(Bytes.toBytes(row), Bytes.toBytes("family"), Bytes
38          .toBytes("qualifier"), Bytes.toBytes("value"));
39    }
40  
41    static String toRowStr(KeyValue kv) {
42      return Bytes.toString(kv.getRow());
43    }
44  
45    Path makeNewFile() throws IOException {
46      Path ncTFile = new Path(this.testDir, "basic.hfile");
47      FSDataOutputStream fout = this.fs.create(ncTFile);
48      int blocksize = toKV("a").getLength() * 3;
49      HFile.Writer writer = HFile.getWriterFactoryNoCache(conf)
50          .withOutputStream(fout)
51          .withBlockSize(blocksize)
52          .create();
53      // 4 bytes * 3 * 2 for each key/value +
54      // 3 for keys, 15 for values = 42 (woot)
55      writer.append(toKV("c"));
56      writer.append(toKV("e"));
57      writer.append(toKV("g"));
58      // block transition
59      writer.append(toKV("i"));
60      writer.append(toKV("k"));
61      writer.close();
62      fout.close();
63      return ncTFile;
64    }
65  
66    public void testSeekBefore() throws Exception {
67      Path p = makeNewFile();
68      HFile.Reader reader = HFile.createReader(fs, p, new CacheConfig(conf));
69      reader.loadFileInfo();
70      HFileScanner scanner = reader.getScanner(false, true);
71      assertEquals(false, scanner.seekBefore(toKV("a").getKey()));
72  
73      assertEquals(false, scanner.seekBefore(toKV("c").getKey()));
74  
75      assertEquals(true, scanner.seekBefore(toKV("d").getKey()));
76      assertEquals("c", toRowStr(scanner.getKeyValue()));
77  
78      assertEquals(true, scanner.seekBefore(toKV("e").getKey()));
79      assertEquals("c", toRowStr(scanner.getKeyValue()));
80  
81      assertEquals(true, scanner.seekBefore(toKV("f").getKey()));
82      assertEquals("e", toRowStr(scanner.getKeyValue()));
83  
84      assertEquals(true, scanner.seekBefore(toKV("g").getKey()));
85      assertEquals("e", toRowStr(scanner.getKeyValue()));
86  
87      assertEquals(true, scanner.seekBefore(toKV("h").getKey()));
88      assertEquals("g", toRowStr(scanner.getKeyValue()));
89      assertEquals(true, scanner.seekBefore(toKV("i").getKey()));
90      assertEquals("g", toRowStr(scanner.getKeyValue()));
91      assertEquals(true, scanner.seekBefore(toKV("j").getKey()));
92      assertEquals("i", toRowStr(scanner.getKeyValue()));
93      assertEquals(true, scanner.seekBefore(toKV("k").getKey()));
94      assertEquals("i", toRowStr(scanner.getKeyValue()));
95      assertEquals(true, scanner.seekBefore(toKV("l").getKey()));
96      assertEquals("k", toRowStr(scanner.getKeyValue()));
97  
98      reader.close();
99    }
100 
101   public void testSeekBeforeWithReSeekTo() throws Exception {
102     Path p = makeNewFile();
103     HFile.Reader reader = HFile.createReader(fs, p, new CacheConfig(conf));
104     reader.loadFileInfo();
105     HFileScanner scanner = reader.getScanner(false, true);
106     assertEquals(false, scanner.seekBefore(toKV("a").getKey()));
107     assertEquals(false, scanner.seekBefore(toKV("b").getKey()));
108     assertEquals(false, scanner.seekBefore(toKV("c").getKey()));
109 
110     // seekBefore d, so the scanner points to c
111     assertEquals(true, scanner.seekBefore(toKV("d").getKey()));
112     assertEquals("c", toRowStr(scanner.getKeyValue()));
113     // reseekTo e and g
114     assertEquals(0, scanner.reseekTo(toKV("c").getKey()));
115     assertEquals("c", toRowStr(scanner.getKeyValue()));
116     assertEquals(0, scanner.reseekTo(toKV("g").getKey()));
117     assertEquals("g", toRowStr(scanner.getKeyValue()));
118 
119     // seekBefore e, so the scanner points to c
120     assertEquals(true, scanner.seekBefore(toKV("e").getKey()));
121     assertEquals("c", toRowStr(scanner.getKeyValue()));
122     // reseekTo e and g
123     assertEquals(0, scanner.reseekTo(toKV("e").getKey()));
124     assertEquals("e", toRowStr(scanner.getKeyValue()));
125     assertEquals(0, scanner.reseekTo(toKV("g").getKey()));
126     assertEquals("g", toRowStr(scanner.getKeyValue()));
127 
128     // seekBefore f, so the scanner points to e
129     assertEquals(true, scanner.seekBefore(toKV("f").getKey()));
130     assertEquals("e", toRowStr(scanner.getKeyValue()));
131     // reseekTo e and g
132     assertEquals(0, scanner.reseekTo(toKV("e").getKey()));
133     assertEquals("e", toRowStr(scanner.getKeyValue()));
134     assertEquals(0, scanner.reseekTo(toKV("g").getKey()));
135     assertEquals("g", toRowStr(scanner.getKeyValue()));
136 
137     // seekBefore g, so the scanner points to e
138     assertEquals(true, scanner.seekBefore(toKV("g").getKey()));
139     assertEquals("e", toRowStr(scanner.getKeyValue()));
140     // reseekTo e and g again
141     assertEquals(0, scanner.reseekTo(toKV("e").getKey()));
142     assertEquals("e", toRowStr(scanner.getKeyValue()));
143     assertEquals(0, scanner.reseekTo(toKV("g").getKey()));
144     assertEquals("g", toRowStr(scanner.getKeyValue()));
145 
146     // seekBefore h, so the scanner points to g
147     assertEquals(true, scanner.seekBefore(toKV("h").getKey()));
148     assertEquals("g", toRowStr(scanner.getKeyValue()));
149     // reseekTo g
150     assertEquals(0, scanner.reseekTo(toKV("g").getKey()));
151     assertEquals("g", toRowStr(scanner.getKeyValue()));
152 
153     // seekBefore i, so the scanner points to g
154     assertEquals(true, scanner.seekBefore(toKV("i").getKey()));
155     assertEquals("g", toRowStr(scanner.getKeyValue()));
156     // reseekTo g
157     assertEquals(0, scanner.reseekTo(toKV("g").getKey()));
158     assertEquals("g", toRowStr(scanner.getKeyValue()));
159 
160     // seekBefore j, so the scanner points to i
161     assertEquals(true, scanner.seekBefore(toKV("j").getKey()));
162     assertEquals("i", toRowStr(scanner.getKeyValue()));
163     // reseekTo i
164     assertEquals(0, scanner.reseekTo(toKV("i").getKey()));
165     assertEquals("i", toRowStr(scanner.getKeyValue()));
166 
167     // seekBefore k, so the scanner points to i
168     assertEquals(true, scanner.seekBefore(toKV("k").getKey()));
169     assertEquals("i", toRowStr(scanner.getKeyValue()));
170     // reseekTo i and k
171     assertEquals(0, scanner.reseekTo(toKV("i").getKey()));
172     assertEquals("i", toRowStr(scanner.getKeyValue()));
173     assertEquals(0, scanner.reseekTo(toKV("k").getKey()));
174     assertEquals("k", toRowStr(scanner.getKeyValue()));
175 
176     // seekBefore l, so the scanner points to k
177     assertEquals(true, scanner.seekBefore(toKV("l").getKey()));
178     assertEquals("k", toRowStr(scanner.getKeyValue()));
179     // reseekTo k
180     assertEquals(0, scanner.reseekTo(toKV("k").getKey()));
181     assertEquals("k", toRowStr(scanner.getKeyValue()));
182   }
183 
184   public void testSeekTo() throws Exception {
185     Path p = makeNewFile();
186     HFile.Reader reader = HFile.createReader(fs, p, new CacheConfig(conf));
187     reader.loadFileInfo();
188     assertEquals(2, reader.getDataBlockIndexReader().getRootBlockCount());
189     HFileScanner scanner = reader.getScanner(false, true);
190     // lies before the start of the file.
191     assertEquals(-1, scanner.seekTo(toKV("a").getKey()));
192 
193     assertEquals(1, scanner.seekTo(toKV("d").getKey()));
194     assertEquals("c", toRowStr(scanner.getKeyValue()));
195 
196     // Across a block boundary now.
197     assertEquals(1, scanner.seekTo(toKV("h").getKey()));
198     assertEquals("g", toRowStr(scanner.getKeyValue()));
199 
200     assertEquals(1, scanner.seekTo(toKV("l").getKey()));
201     assertEquals("k", toRowStr(scanner.getKeyValue()));
202 
203     reader.close();
204   }
205 
206   public void testBlockContainingKey() throws Exception {
207     Path p = makeNewFile();
208     HFile.Reader reader = HFile.createReader(fs, p, new CacheConfig(conf));
209     reader.loadFileInfo();
210     HFileBlockIndex.BlockIndexReader blockIndexReader = 
211       reader.getDataBlockIndexReader();
212     System.out.println(blockIndexReader.toString());
213     int klen = toKV("a").getKey().length;
214     // falls before the start of the file.
215     assertEquals(-1, blockIndexReader.rootBlockContainingKey(
216         toKV("a").getKey(), 0, klen));
217     assertEquals(0, blockIndexReader.rootBlockContainingKey(
218         toKV("c").getKey(), 0, klen));
219     assertEquals(0, blockIndexReader.rootBlockContainingKey(
220         toKV("d").getKey(), 0, klen));
221     assertEquals(0, blockIndexReader.rootBlockContainingKey(
222         toKV("e").getKey(), 0, klen));
223     assertEquals(0, blockIndexReader.rootBlockContainingKey(
224         toKV("g").getKey(), 0, klen));
225     assertEquals(0, blockIndexReader.rootBlockContainingKey(
226         toKV("h").getKey(), 0, klen));
227     assertEquals(1, blockIndexReader.rootBlockContainingKey(
228         toKV("i").getKey(), 0, klen));
229     assertEquals(1, blockIndexReader.rootBlockContainingKey(
230         toKV("j").getKey(), 0, klen));
231     assertEquals(1, blockIndexReader.rootBlockContainingKey(
232         toKV("k").getKey(), 0, klen));
233     assertEquals(1, blockIndexReader.rootBlockContainingKey(
234         toKV("l").getKey(), 0, klen));
235 
236     reader.close();
237  }
238 
239   @org.junit.Rule
240   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
241     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
242 }
243