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.regionserver;
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.fs.FileSystem;
29  import org.apache.hadoop.fs.Path;
30  import org.apache.hadoop.hbase.HBaseTestCase;
31  import org.apache.hadoop.hbase.HConstants;
32  import org.apache.hadoop.hbase.KeyValue;
33  import org.apache.hadoop.hbase.HRegionInfo;
34  import org.apache.hadoop.hbase.HTableDescriptor;
35  import org.apache.hadoop.hbase.client.Delete;
36  import org.apache.hadoop.hbase.client.Put;
37  import org.apache.hadoop.hbase.client.Result;
38  import org.apache.hadoop.hbase.client.Scan;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.apache.hadoop.hbase.util.Writables;
41  import org.apache.hadoop.hdfs.MiniDFSCluster;
42  
43  /**
44   * {@link TestGet} is a medley of tests of get all done up as a single test.
45   * This class
46   */
47  public class TestGetClosestAtOrBefore extends HBaseTestCase {
48    private static final Log LOG = LogFactory.getLog(TestGetClosestAtOrBefore.class);
49  
50    private static final byte[] T00 = Bytes.toBytes("000");
51    private static final byte[] T10 = Bytes.toBytes("010");
52    private static final byte[] T11 = Bytes.toBytes("011");
53    private static final byte[] T12 = Bytes.toBytes("012");
54    private static final byte[] T20 = Bytes.toBytes("020");
55    private static final byte[] T30 = Bytes.toBytes("030");
56    private static final byte[] T31 = Bytes.toBytes("031");
57    private static final byte[] T35 = Bytes.toBytes("035");
58    private static final byte[] T40 = Bytes.toBytes("040");
59  
60  
61  
62    public void testUsingMetaAndBinary() throws IOException {
63      FileSystem filesystem = FileSystem.get(conf);
64      Path rootdir = testDir;
65      // Up flush size else we bind up when we use default catalog flush of 16k.
66      HTableDescriptor.META_TABLEDESC.setMemStoreFlushSize(64 * 1024 * 1024);
67  
68      HRegion mr = HRegion.createHRegion(HRegionInfo.FIRST_META_REGIONINFO,
69        rootdir, this.conf, HTableDescriptor.META_TABLEDESC);
70      try {
71      // Write rows for three tables 'A', 'B', and 'C'.
72      for (char c = 'A'; c < 'D'; c++) {
73        HTableDescriptor htd = new HTableDescriptor("" + c);
74        final int last = 128;
75        final int interval = 2;
76        for (int i = 0; i <= last; i += interval) {
77          HRegionInfo hri = new HRegionInfo(htd.getName(),
78            i == 0? HConstants.EMPTY_BYTE_ARRAY: Bytes.toBytes((byte)i),
79            i == last? HConstants.EMPTY_BYTE_ARRAY: Bytes.toBytes((byte)i + interval));
80          Put put = new Put(hri.getRegionName());
81          put.setWriteToWAL(false);
82          put.add(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER,
83                  Writables.getBytes(hri));
84          mr.put(put, false);
85        }
86      }
87      InternalScanner s = mr.getScanner(new Scan());
88      try {
89        List<KeyValue> keys = new ArrayList<KeyValue>();
90        while(s.next(keys)) {
91          LOG.info(keys);
92          keys.clear();
93        }
94      } finally {
95        s.close();
96      }
97      findRow(mr, 'C', 44, 44);
98      findRow(mr, 'C', 45, 44);
99      findRow(mr, 'C', 46, 46);
100     findRow(mr, 'C', 43, 42);
101     mr.flushcache();
102     findRow(mr, 'C', 44, 44);
103     findRow(mr, 'C', 45, 44);
104     findRow(mr, 'C', 46, 46);
105     findRow(mr, 'C', 43, 42);
106     // Now delete 'C' and make sure I don't get entries from 'B'.
107     byte [] firstRowInC = HRegionInfo.createRegionName(Bytes.toBytes("" + 'C'),
108       HConstants.EMPTY_BYTE_ARRAY, HConstants.ZEROES, false);
109     Scan scan = new Scan(firstRowInC);
110     s = mr.getScanner(scan);
111     try {
112       List<KeyValue> keys = new ArrayList<KeyValue>();
113       while (s.next(keys)) {
114         mr.delete(new Delete(keys.get(0).getRow()), null, false);
115         keys.clear();
116       }
117     } finally {
118       s.close();
119     }
120     // Assert we get null back (pass -1).
121     findRow(mr, 'C', 44, -1);
122     findRow(mr, 'C', 45, -1);
123     findRow(mr, 'C', 46, -1);
124     findRow(mr, 'C', 43, -1);
125     mr.flushcache();
126     findRow(mr, 'C', 44, -1);
127     findRow(mr, 'C', 45, -1);
128     findRow(mr, 'C', 46, -1);
129     findRow(mr, 'C', 43, -1);
130     } finally {
131       if (mr != null) {
132         try {
133           mr.close();
134         } catch (Exception e) {
135           e.printStackTrace();
136         }
137         mr.getLog().closeAndDelete();
138       }
139     }
140   }
141 
142   /*
143    * @param mr
144    * @param table
145    * @param rowToFind
146    * @param answer Pass -1 if we're not to find anything.
147    * @return Row found.
148    * @throws IOException
149    */
150   private byte [] findRow(final HRegion mr, final char table,
151     final int rowToFind, final int answer)
152   throws IOException {
153     byte [] tableb = Bytes.toBytes("" + table);
154     // Find the row.
155     byte [] tofindBytes = Bytes.toBytes((short)rowToFind);
156     byte [] metaKey = HRegionInfo.createRegionName(tableb, tofindBytes,
157       HConstants.NINES, false);
158     LOG.info("find=" + new String(metaKey));
159     Result r = mr.getClosestRowBefore(metaKey);
160     if (answer == -1) {
161       assertNull(r);
162       return null;
163     }
164     assertTrue(Bytes.compareTo(Bytes.toBytes((short)answer),
165       extractRowFromMetaRow(r.getRow())) == 0);
166     return r.getRow();
167   }
168 
169   private byte [] extractRowFromMetaRow(final byte [] b) {
170     int firstDelimiter = KeyValue.getDelimiter(b, 0, b.length,
171       HRegionInfo.DELIMITER);
172     int lastDelimiter = KeyValue.getDelimiterInReverse(b, 0, b.length,
173       HRegionInfo.DELIMITER);
174     int length = lastDelimiter - firstDelimiter - 1;
175     byte [] row = new byte[length];
176     System.arraycopy(b, firstDelimiter + 1, row, 0, length);
177     return row;
178   }
179 
180   /**
181    * Test file of multiple deletes and with deletes as final key.
182    * @see <a href="https://issues.apache.org/jira/browse/HBASE-751">HBASE-751</a>
183    */
184   public void testGetClosestRowBefore3() throws IOException{
185     HRegion region = null;
186     byte [] c0 = COLUMNS[0];
187     byte [] c1 = COLUMNS[1];
188     try {
189       HTableDescriptor htd = createTableDescriptor(getName());
190       region = createNewHRegion(htd, null, null);
191 
192       Put p = new Put(T00);
193       p.add(c0, c0, T00);
194       region.put(p);
195 
196       p = new Put(T10);
197       p.add(c0, c0, T10);
198       region.put(p);
199 
200       p = new Put(T20);
201       p.add(c0, c0, T20);
202       region.put(p);
203 
204       Result r = region.getClosestRowBefore(T20, c0);
205       assertTrue(Bytes.equals(T20, r.getRow()));
206 
207       Delete d = new Delete(T20);
208       d.deleteColumn(c0, c0);
209       region.delete(d, null, false);
210 
211       r = region.getClosestRowBefore(T20, c0);
212       assertTrue(Bytes.equals(T10, r.getRow()));
213 
214       p = new Put(T30);
215       p.add(c0, c0, T30);
216       region.put(p);
217 
218       r = region.getClosestRowBefore(T30, c0);
219       assertTrue(Bytes.equals(T30, r.getRow()));
220 
221       d = new Delete(T30);
222       d.deleteColumn(c0, c0);
223       region.delete(d, null, false);
224 
225       r = region.getClosestRowBefore(T30, c0);
226       assertTrue(Bytes.equals(T10, r.getRow()));
227       r = region.getClosestRowBefore(T31, c0);
228       assertTrue(Bytes.equals(T10, r.getRow()));
229 
230       region.flushcache();
231 
232       // try finding "010" after flush
233       r = region.getClosestRowBefore(T30, c0);
234       assertTrue(Bytes.equals(T10, r.getRow()));
235       r = region.getClosestRowBefore(T31, c0);
236       assertTrue(Bytes.equals(T10, r.getRow()));
237 
238       // Put into a different column family.  Should make it so I still get t10
239       p = new Put(T20);
240       p.add(c1, c1, T20);
241       region.put(p);
242 
243       r = region.getClosestRowBefore(T30, c0);
244       assertTrue(Bytes.equals(T10, r.getRow()));
245       r = region.getClosestRowBefore(T31, c0);
246       assertTrue(Bytes.equals(T10, r.getRow()));
247 
248       region.flushcache();
249 
250       r = region.getClosestRowBefore(T30, c0);
251       assertTrue(Bytes.equals(T10, r.getRow()));
252       r = region.getClosestRowBefore(T31, c0);
253       assertTrue(Bytes.equals(T10, r.getRow()));
254 
255       // Now try combo of memcache and mapfiles.  Delete the t20 COLUMS[1]
256       // in memory; make sure we get back t10 again.
257       d = new Delete(T20);
258       d.deleteColumn(c1, c1);
259       region.delete(d, null, false);
260       r = region.getClosestRowBefore(T30, c0);
261       assertTrue(Bytes.equals(T10, r.getRow()));
262 
263       // Ask for a value off the end of the file.  Should return t10.
264       r = region.getClosestRowBefore(T31, c0);
265       assertTrue(Bytes.equals(T10, r.getRow()));
266       region.flushcache();
267       r = region.getClosestRowBefore(T31, c0);
268       assertTrue(Bytes.equals(T10, r.getRow()));
269 
270       // Ok.  Let the candidate come out of hfile but have delete of
271       // the candidate be in memory.
272       p = new Put(T11);
273       p.add(c0, c0, T11);
274       region.put(p);
275       d = new Delete(T10);
276       d.deleteColumn(c1, c1);
277       r = region.getClosestRowBefore(T12, c0);
278       assertTrue(Bytes.equals(T11, r.getRow()));
279     } finally {
280       if (region != null) {
281         try {
282           region.close();
283         } catch (Exception e) {
284           e.printStackTrace();
285         }
286         region.getLog().closeAndDelete();
287       }
288     }
289   }
290 
291   /** For HBASE-694 */
292   public void testGetClosestRowBefore2() throws IOException{
293     HRegion region = null;
294     byte [] c0 = COLUMNS[0];
295     try {
296       HTableDescriptor htd = createTableDescriptor(getName());
297       region = createNewHRegion(htd, null, null);
298 
299       Put p = new Put(T10);
300       p.add(c0, c0, T10);
301       region.put(p);
302 
303       p = new Put(T30);
304       p.add(c0, c0, T30);
305       region.put(p);
306 
307       p = new Put(T40);
308       p.add(c0, c0, T40);
309       region.put(p);
310 
311       // try finding "035"
312       Result r = region.getClosestRowBefore(T35, c0);
313       assertTrue(Bytes.equals(T30, r.getRow()));
314 
315       region.flushcache();
316 
317       // try finding "035"
318       r = region.getClosestRowBefore(T35, c0);
319       assertTrue(Bytes.equals(T30, r.getRow()));
320 
321       p = new Put(T20);
322       p.add(c0, c0, T20);
323       region.put(p);
324 
325       // try finding "035"
326       r = region.getClosestRowBefore(T35, c0);
327       assertTrue(Bytes.equals(T30, r.getRow()));
328 
329       region.flushcache();
330 
331       // try finding "035"
332       r = region.getClosestRowBefore(T35, c0);
333       assertTrue(Bytes.equals(T30, r.getRow()));
334     } finally {
335       if (region != null) {
336         try {
337           region.close();
338         } catch (Exception e) {
339           e.printStackTrace();
340         }
341         region.getLog().closeAndDelete();
342       }
343     }
344   }
345 }