1   /**
2    * Copyright 2007 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;
21  
22  import java.io.IOException;
23  import java.io.UnsupportedEncodingException;
24  import java.util.Random;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.client.Put;
29  import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
30  import org.apache.hadoop.hbase.regionserver.HRegion;
31  import org.apache.hadoop.hbase.util.Bytes;
32  
33  /** Abstract base class for merge tests */
34  public abstract class AbstractMergeTestBase extends HBaseClusterTestCase {
35    static final Log LOG =
36      LogFactory.getLog(AbstractMergeTestBase.class.getName());
37    static final byte [] COLUMN_NAME = Bytes.toBytes("contents");
38    protected final Random rand = new Random();
39    protected HTableDescriptor desc;
40    protected ImmutableBytesWritable value;
41    protected boolean startMiniHBase;
42  
43    public AbstractMergeTestBase() {
44      this(true);
45    }
46  
47    /** constructor
48     * @param startMiniHBase
49     */
50    public AbstractMergeTestBase(boolean startMiniHBase) {
51      super();
52  
53      this.startMiniHBase = startMiniHBase;
54  
55      // We will use the same value for the rows as that is not really important here
56  
57      String partialValue = String.valueOf(System.currentTimeMillis());
58      StringBuilder val = new StringBuilder();
59      while(val.length() < 1024) {
60        val.append(partialValue);
61      }
62  
63      try {
64        value = new ImmutableBytesWritable(
65            val.toString().getBytes(HConstants.UTF8_ENCODING));
66      } catch (UnsupportedEncodingException e) {
67        fail();
68      }
69      desc = new HTableDescriptor(Bytes.toBytes("test"));
70      desc.addFamily(new HColumnDescriptor(COLUMN_NAME));
71    }
72  
73    @Override
74    protected void hBaseClusterSetup() throws Exception {
75      if (startMiniHBase) {
76        super.hBaseClusterSetup();
77      }
78    }
79  
80    @Override
81    public void preHBaseClusterSetup() throws Exception {
82      conf.setLong("hbase.hregion.max.filesize", 64L * 1024L * 1024L);
83  
84      // We create three data regions: The first is too large to merge since it
85      // will be > 64 MB in size. The second two will be smaller and will be
86      // selected for merging.
87  
88      // To ensure that the first region is larger than 64MB we need to write at
89      // least 65536 rows. We will make certain by writing 70000
90  
91      byte [] row_70001 = Bytes.toBytes("row_70001");
92      byte [] row_80001 = Bytes.toBytes("row_80001");
93  
94      // XXX: Note that the number of rows we put in is different for each region
95      // because currently we don't have a good mechanism to handle merging two
96      // store files with the same sequence id. We can't just dumbly stick them
97      // in because it will screw up the order when the store files are loaded up.
98      // The sequence ids are used for arranging the store files, so if two files
99      // have the same id, one will overwrite the other one in our listing, which
100     // is very bad. See HBASE-1212 and HBASE-1274.
101     HRegion[] regions = {
102       createAregion(null, row_70001, 1, 70000),
103       createAregion(row_70001, row_80001, 70001, 10000),
104       createAregion(row_80001, null, 80001, 11000)
105     };
106 
107     // Now create the root and meta regions and insert the data regions
108     // created above into the meta
109 
110     createRootAndMetaRegions();
111 
112     for(int i = 0; i < regions.length; i++) {
113       HRegion.addRegionToMETA(meta, regions[i]);
114     }
115 
116     closeRootAndMeta();
117   }
118 
119   private HRegion createAregion(byte [] startKey, byte [] endKey, int firstRow,
120       int nrows) throws IOException {
121 
122     HRegion region = createNewHRegion(desc, startKey, endKey);
123 
124     System.out.println("created region " +
125         Bytes.toString(region.getRegionName()));
126 
127     HRegionIncommon r = new HRegionIncommon(region);
128     for(int i = firstRow; i < firstRow + nrows; i++) {
129       Put put = new Put(Bytes.toBytes("row_"
130           + String.format("%1$05d", i)));
131       put.add(COLUMN_NAME, null,  value.get());
132       region.put(put);
133       if(i % 10000 == 0) {
134         System.out.println("Flushing write #" + i);
135         r.flushcache();
136       }
137     }
138     region.close();
139     region.getLog().closeAndDelete();
140     region.getRegionInfo().setOffline(true);
141     return region;
142   }
143 }