View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.mapreduce;
19  
20  import java.io.IOException;
21  import java.util.Arrays;
22  import java.util.List;
23  
24  import org.apache.hadoop.conf.Configuration;
25  import org.apache.hadoop.hbase.HBaseConfiguration;
26  import org.apache.hadoop.hbase.HBaseTestingUtility;
27  import org.apache.hadoop.hbase.client.Delete;
28  import org.apache.hadoop.hbase.client.Mutation;
29  import org.apache.hadoop.hbase.client.Put;
30  import org.apache.hadoop.hbase.client.Result;
31  import org.apache.hadoop.hbase.client.ResultScanner;
32  import org.apache.hadoop.hbase.client.Row;
33  import org.apache.hadoop.hbase.client.Scan;
34  import org.apache.hadoop.hbase.testclassification.MediumTests;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.hbase.util.TestTableName;
37  
38  import org.junit.AfterClass;
39  import org.junit.Assert;
40  import org.junit.BeforeClass;
41  import org.junit.Rule;
42  import org.junit.Test;
43  import org.junit.experimental.categories.Category;
44  import org.junit.rules.ExpectedException;
45  
46  @Category(MediumTests.class)
47  public class TestBufferedHTable {
48  
49    public static final Configuration CONF = HBaseConfiguration.create();
50    public static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(CONF);
51  
52    private static final byte[] CF = Bytes.toBytes("cf");
53    private static final byte[] QUAL = Bytes.toBytes("qual");
54    private static final byte[] VAL = Bytes.toBytes("val");
55    private static final byte[] ROW1 = Bytes.toBytes("row1");
56    private static final byte[] ROW2 = Bytes.toBytes("row2");
57    private static final byte[] ROW3 = Bytes.toBytes("row3");
58    private static final byte[] ROW4 = Bytes.toBytes("row4");
59  
60    @Rule
61    public TestTableName name = new TestTableName();
62  
63    @Rule
64    public ExpectedException thrown = ExpectedException.none();
65  
66    @BeforeClass
67    public static void startMiniCluster() throws Exception {
68      TEST_UTIL.startMiniCluster();
69    }
70  
71    @AfterClass
72    public static void shutdownMiniCluster() throws Exception {
73      TEST_UTIL.shutdownMiniCluster();
74    }
75  
76    /**
77     * Verifies Puts/Deletes are buffered together and automatically flushed when write buffer
78     * size limit is reached.
79     */
80    @Test
81    public void testMutationBuffering() throws IOException {
82      TEST_UTIL.createTable(name.getTableName(), CF);
83      BufferedHTable table = null;
84      ResultScanner scanner = null;
85      try {
86        table = createBufferedHTable();
87        // verify that mutations are buffered, and ordered correctly
88        Put put1 = createPut(ROW1);
89        table.put(put1);
90        Delete delete2 = new Delete(ROW2);
91        table.delete(delete2);
92        Put put2 = createPut(ROW2);
93        Put put3 = createPut(ROW3);
94        table.put(Arrays.asList(put2, put3));
95        Delete delete1 = new Delete(ROW1);
96        Delete delete3 = new Delete(ROW3);
97        table.delete(Arrays.asList(delete1, delete3));
98        List<Row> buffer = table.getWriteBuffer();
99        List<Mutation> expected = Arrays.asList(put1, delete2, put2, put3, delete1, delete3);
100       Assert.assertEquals(expected.size(), buffer.size());
101       for (int i = 0; i < buffer.size(); i++) {
102         Assert.assertEquals(expected.get(i), buffer.get(i));
103       }
104       // add another mutation and resize the buffer
105       table.put(createPut(ROW4));
106       table.setWriteBufferSize(0L);
107       // verify that mutations are flushed
108       Assert.assertEquals(0, buffer.size());
109       Assert.assertEquals(0, table.getCurrentWriteBufferSize());
110       // only the last row should be visible
111       scanner = table.getScanner(new Scan());
112       for (Result result : scanner) {
113         Assert.assertArrayEquals(ROW4, result.getRow());
114       }
115       scanner.close();
116       // verify that delete mutations are auto-flushed when buffer limit is reached (last row
117       // should no longer be visible)
118       table.delete(new Delete(ROW4));
119       scanner = table.getScanner(new Scan());
120       Assert.assertNull(scanner.next());
121     } finally {
122       if (scanner != null) scanner.close();
123       if (table != null) table.close();
124     }
125   }
126 
127   /**
128    * Verifies that Deletes are rejected after BufferedHTable is closed.
129    */
130   @Test
131   public void testDeletesAfterCloseNotAllowed() throws IOException {
132     TEST_UTIL.createTable(name.getTableName(), CF);
133     BufferedHTable table = null;
134     try {
135       table = createBufferedHTable();
136       table.close();
137       thrown.expect(IllegalStateException.class);
138       table.delete(new Delete(ROW1));
139     } finally {
140       if (table != null) table.close();
141     }
142   }
143 
144   private BufferedHTable createBufferedHTable() throws IOException {
145     BufferedHTable table = new BufferedHTable(CONF, name.getTableName().getName());
146     // disabling auto-flush is required for buffering
147     table.setAutoFlush(false, false);
148     return table;
149   }
150 
151   private Put createPut(byte[] row) throws IOException {
152     Put put = new Put(row);
153     put.add(CF, QUAL, VAL);
154     return put;
155   }
156 }