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;
19  
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertNotNull;
24  import static org.junit.Assert.assertTrue;
25  
26  import java.io.IOException;
27  import java.util.Map;
28  import java.util.NavigableMap;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.HBaseTestCase.FlushCache;
34  import org.apache.hadoop.hbase.HBaseTestCase.HTableIncommon;
35  import org.apache.hadoop.hbase.HBaseTestCase.Incommon;
36  import org.apache.hadoop.hbase.client.Get;
37  import org.apache.hadoop.hbase.client.HBaseAdmin;
38  import org.apache.hadoop.hbase.client.HTable;
39  import org.apache.hadoop.hbase.client.Put;
40  import org.apache.hadoop.hbase.client.Result;
41  import org.apache.hadoop.hbase.client.ResultScanner;
42  import org.apache.hadoop.hbase.client.Scan;
43  import org.apache.hadoop.hbase.testclassification.MediumTests;
44  import org.apache.hadoop.hbase.util.Bytes;
45  import org.junit.After;
46  import org.junit.AfterClass;
47  import org.junit.Before;
48  import org.junit.BeforeClass;
49  import org.junit.Test;
50  import org.junit.experimental.categories.Category;
51  
52  /**
53   * Port of old TestScanMultipleVersions, TestTimestamp and TestGetRowVersions
54   * from old testing framework to {@link HBaseTestingUtility}.
55   */
56  @Category(MediumTests.class)
57  public class TestMultiVersions {
58    private static final Log LOG = LogFactory.getLog(TestMultiVersions.class);
59    private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
60    private HBaseAdmin admin;
61    
62    private static final int NUM_SLAVES = 3;
63  
64    @BeforeClass
65    public static void setUpBeforeClass() throws Exception {
66      UTIL.startMiniCluster(NUM_SLAVES);
67    }
68  
69    @AfterClass
70    public static void tearDownAfterClass() throws Exception {
71      UTIL.shutdownMiniCluster();
72    }
73  
74    @Before
75    public void before()
76    throws MasterNotRunningException, ZooKeeperConnectionException, IOException {
77      this.admin = new HBaseAdmin(UTIL.getConfiguration());
78    }
79  
80    @After
81    public void after() throws IOException {
82      this.admin.close();
83    }
84  
85    /**
86    * Tests user specifiable time stamps putting, getting and scanning.  Also
87     * tests same in presence of deletes.  Test cores are written so can be
88     * run against an HRegion and against an HTable: i.e. both local and remote.
89     * 
90     * <p>Port of old TestTimestamp test to here so can better utilize the spun
91     * up cluster running more than a single test per spin up.  Keep old tests'
92     * crazyness.
93     */
94    @Test
95    public void testTimestamps() throws Exception {
96      HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("testTimestamps"));
97      HColumnDescriptor hcd = new HColumnDescriptor(TimestampTestBase.FAMILY_NAME);
98      hcd.setMaxVersions(3);
99      desc.addFamily(hcd);
100     this.admin.createTable(desc);
101     HTable table = new HTable(UTIL.getConfiguration(), desc.getTableName());
102     // TODO: Remove these deprecated classes or pull them in here if this is
103     // only test using them.
104     Incommon incommon = new HTableIncommon(table);
105     TimestampTestBase.doTestDelete(incommon, new FlushCache() {
106       public void flushcache() throws IOException {
107         UTIL.getHBaseCluster().flushcache();
108       }
109      });
110 
111     // Perhaps drop and readd the table between tests so the former does
112     // not pollute this latter?  Or put into separate tests.
113     TimestampTestBase.doTestTimestampScanning(incommon, new FlushCache() {
114       public void flushcache() throws IOException {
115         UTIL.getMiniHBaseCluster().flushcache();
116       }
117     });
118 
119     table.close();
120   }
121 
122   /**
123    * Verifies versions across a cluster restart.
124    * Port of old TestGetRowVersions test to here so can better utilize the spun
125    * up cluster running more than a single test per spin up.  Keep old tests'
126    * crazyness.
127    */
128   @Test
129   public void testGetRowVersions() throws Exception {
130     final String tableName = "testGetRowVersions";
131     final byte [] contents = Bytes.toBytes("contents");
132     final byte [] row = Bytes.toBytes("row");
133     final byte [] value1 = Bytes.toBytes("value1");
134     final byte [] value2 = Bytes.toBytes("value2");
135     final long timestamp1 = 100L;
136     final long timestamp2 = 200L;
137     final HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
138     HColumnDescriptor hcd = new HColumnDescriptor(contents);
139     hcd.setMaxVersions(3);
140     desc.addFamily(hcd);
141     this.admin.createTable(desc);
142     Put put = new Put(row, timestamp1);
143     put.add(contents, contents, value1);
144     HTable table = new HTable(UTIL.getConfiguration(), tableName);
145     table.put(put);
146     // Shut down and restart the HBase cluster
147     table.close();
148     UTIL.shutdownMiniHBaseCluster();
149     LOG.debug("HBase cluster shut down -- restarting");
150     UTIL.startMiniHBaseCluster(1, NUM_SLAVES);
151     // Make a new connection.  Use new Configuration instance because old one
152     // is tied to an HConnection that has since gone stale.
153     table = new HTable(new Configuration(UTIL.getConfiguration()), tableName);
154     // Overwrite previous value
155     put = new Put(row, timestamp2);
156     put.add(contents, contents, value2);
157     table.put(put);
158     // Now verify that getRow(row, column, latest) works
159     Get get = new Get(row);
160     // Should get one version by default
161     Result r = table.get(get);
162     assertNotNull(r);
163     assertFalse(r.isEmpty());
164     assertTrue(r.size() == 1);
165     byte [] value = r.getValue(contents, contents);
166     assertTrue(value.length != 0);
167     assertTrue(Bytes.equals(value, value2));
168     // Now check getRow with multiple versions
169     get = new Get(row);
170     get.setMaxVersions();
171     r = table.get(get);
172     assertTrue(r.size() == 2);
173     value = r.getValue(contents, contents);
174     assertTrue(value.length != 0);
175     assertTrue(Bytes.equals(value, value2));
176     NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map =
177       r.getMap();
178     NavigableMap<byte[], NavigableMap<Long, byte[]>> familyMap =
179       map.get(contents);
180     NavigableMap<Long, byte[]> versionMap = familyMap.get(contents);
181     assertTrue(versionMap.size() == 2);
182     assertTrue(Bytes.equals(value1, versionMap.get(timestamp1)));
183     assertTrue(Bytes.equals(value2, versionMap.get(timestamp2)));
184     table.close();
185   }
186 
187   /**
188    * Port of old TestScanMultipleVersions test here so can better utilize the
189    * spun up cluster running more than just a single test.  Keep old tests
190    * crazyness.
191    * 
192    * <p>Tests five cases of scans and timestamps.
193    * @throws Exception
194    */
195   @Test
196   public void testScanMultipleVersions() throws Exception {
197     final byte [] tableName = Bytes.toBytes("testScanMultipleVersions");
198     final HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
199     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
200     final byte [][] rows = new byte[][] {
201       Bytes.toBytes("row_0200"),
202       Bytes.toBytes("row_0800")
203     };
204     final byte [][] splitRows = new byte[][] {Bytes.toBytes("row_0500")};
205     final long [] timestamp = new long[] {100L, 1000L};
206     this.admin.createTable(desc, splitRows);
207     HTable table = new HTable(UTIL.getConfiguration(), tableName);
208     // Assert we got the region layout wanted.
209     NavigableMap<HRegionInfo, ServerName> locations = table.getRegionLocations();
210     assertEquals(2, locations.size());
211     int index = 0;
212     for (Map.Entry<HRegionInfo, ServerName> e: locations.entrySet()) {
213       HRegionInfo hri = e.getKey();
214       if (index == 0) {
215         assertTrue(Bytes.equals(HConstants.EMPTY_START_ROW, hri.getStartKey()));
216         assertTrue(Bytes.equals(hri.getEndKey(), splitRows[0]));
217       } else if (index == 1) {
218         assertTrue(Bytes.equals(splitRows[0], hri.getStartKey()));
219         assertTrue(Bytes.equals(hri.getEndKey(), HConstants.EMPTY_END_ROW));
220       }
221       index++;
222     }
223     // Insert data
224     for (int i = 0; i < locations.size(); i++) {
225       for (int j = 0; j < timestamp.length; j++) {
226         Put put = new Put(rows[i], timestamp[j]);
227         put.add(HConstants.CATALOG_FAMILY, null, timestamp[j],
228             Bytes.toBytes(timestamp[j]));
229         table.put(put);
230       }
231     }
232     // There are 5 cases we have to test. Each is described below.
233     for (int i = 0; i < rows.length; i++) {
234       for (int j = 0; j < timestamp.length; j++) {
235         Get get = new Get(rows[i]);
236         get.addFamily(HConstants.CATALOG_FAMILY);
237         get.setTimeStamp(timestamp[j]);
238         Result result = table.get(get);
239         int cellCount = 0;
240         for(@SuppressWarnings("unused")Cell kv : result.listCells()) {
241           cellCount++;
242         }
243         assertTrue(cellCount == 1);
244       }
245       table.close();
246     }
247 
248     // Case 1: scan with LATEST_TIMESTAMP. Should get two rows
249     int count = 0;
250     Scan scan = new Scan();
251     scan.addFamily(HConstants.CATALOG_FAMILY);
252     ResultScanner s = table.getScanner(scan);
253     try {
254       for (Result rr = null; (rr = s.next()) != null;) {
255         System.out.println(rr.toString());
256         count += 1;
257       }
258       assertEquals("Number of rows should be 2", 2, count);
259     } finally {
260       s.close();
261     }
262 
263     // Case 2: Scan with a timestamp greater than most recent timestamp
264     // (in this case > 1000 and < LATEST_TIMESTAMP. Should get 2 rows.
265 
266     count = 0;
267     scan = new Scan();
268     scan.setTimeRange(1000L, Long.MAX_VALUE);
269     scan.addFamily(HConstants.CATALOG_FAMILY);
270 
271     s = table.getScanner(scan);
272     try {
273       while (s.next() != null) {
274         count += 1;
275       }
276       assertEquals("Number of rows should be 2", 2, count);
277     } finally {
278       s.close();
279     }
280 
281     // Case 3: scan with timestamp equal to most recent timestamp
282     // (in this case == 1000. Should get 2 rows.
283 
284     count = 0;
285     scan = new Scan();
286     scan.setTimeStamp(1000L);
287     scan.addFamily(HConstants.CATALOG_FAMILY);
288 
289     s = table.getScanner(scan);
290     try {
291       while (s.next() != null) {
292         count += 1;
293       }
294       assertEquals("Number of rows should be 2", 2, count);
295     } finally {
296       s.close();
297     }
298 
299     // Case 4: scan with timestamp greater than first timestamp but less than
300     // second timestamp (100 < timestamp < 1000). Should get 2 rows.
301 
302     count = 0;
303     scan = new Scan();
304     scan.setTimeRange(100L, 1000L);
305     scan.addFamily(HConstants.CATALOG_FAMILY);
306 
307     s = table.getScanner(scan);
308     try {
309       while (s.next() != null) {
310         count += 1;
311       }
312       assertEquals("Number of rows should be 2", 2, count);
313     } finally {
314       s.close();
315     }
316 
317     // Case 5: scan with timestamp equal to first timestamp (100)
318     // Should get 2 rows.
319 
320     count = 0;
321     scan = new Scan();
322     scan.setTimeStamp(100L);
323     scan.addFamily(HConstants.CATALOG_FAMILY);
324 
325     s = table.getScanner(scan);
326     try {
327       while (s.next() != null) {
328         count += 1;
329       }
330       assertEquals("Number of rows should be 2", 2, count);
331     } finally {
332       s.close();
333     }
334   }
335 
336 }
337