View Javadoc

1   /**
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements. See the NOTICE file distributed with this
6    * work for additional information regarding copyright ownership. The ASF
7    * licenses this file to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16   * License for the specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.hadoop.hbase.regionserver;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.util.List;
25  import java.util.Random;
26  
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.KeyValue;
29  import org.apache.hadoop.hbase.testclassification.SmallTests;
30  import org.apache.hadoop.hbase.util.ByteRange;
31  import org.apache.hadoop.hbase.util.Bytes;
32  import org.junit.AfterClass;
33  import org.junit.Before;
34  import org.junit.BeforeClass;
35  import org.junit.Test;
36  import org.junit.experimental.categories.Category;
37  
38  /**
39   * Test the {@link MemStoreChunkPool} class
40   */
41  @Category(SmallTests.class)
42  public class TestMemStoreChunkPool {
43    private final static Configuration conf = new Configuration();
44    private static MemStoreChunkPool chunkPool;
45    private static boolean chunkPoolDisabledBeforeTest;
46  
47    @BeforeClass
48    public static void setUpBeforeClass() throws Exception {
49      conf.setBoolean(DefaultMemStore.USEMSLAB_KEY, true);
50      conf.setFloat(MemStoreChunkPool.CHUNK_POOL_MAXSIZE_KEY, 0.2f);
51      chunkPoolDisabledBeforeTest = MemStoreChunkPool.chunkPoolDisabled;
52      MemStoreChunkPool.chunkPoolDisabled = false;
53      chunkPool = MemStoreChunkPool.getPool(conf);
54      assertTrue(chunkPool != null);
55    }
56  
57    @AfterClass
58    public static void tearDownAfterClass() throws Exception {
59      MemStoreChunkPool.chunkPoolDisabled = chunkPoolDisabledBeforeTest;
60    }
61  
62    @Before
63    public void tearDown() throws Exception {
64      chunkPool.clearChunks();
65    }
66  
67    @Test
68    public void testReusingChunks() {
69      Random rand = new Random();
70      MemStoreLAB mslab = new HeapMemStoreLAB(conf);
71      int expectedOff = 0;
72      byte[] lastBuffer = null;
73      // Randomly allocate some bytes
74      for (int i = 0; i < 100; i++) {
75        int size = rand.nextInt(1000);
76        ByteRange alloc = mslab.allocateBytes(size);
77  
78        if (alloc.getBytes() != lastBuffer) {
79          expectedOff = 0;
80          lastBuffer = alloc.getBytes();
81        }
82        assertEquals(expectedOff, alloc.getOffset());
83        assertTrue("Allocation overruns buffer", alloc.getOffset()
84            + size <= alloc.getBytes().length);
85        expectedOff += size;
86      }
87      // chunks will be put back to pool after close
88      mslab.close();
89      int chunkCount = chunkPool.getPoolSize();
90      assertTrue(chunkCount > 0);
91      // reconstruct mslab
92      mslab = new HeapMemStoreLAB(conf);
93      // chunk should be got from the pool, so we can reuse it.
94      mslab.allocateBytes(1000);
95      assertEquals(chunkCount - 1, chunkPool.getPoolSize());
96    }
97  
98    @Test
99    public void testPuttingBackChunksAfterFlushing() throws UnexpectedStateException {
100     byte[] row = Bytes.toBytes("testrow");
101     byte[] fam = Bytes.toBytes("testfamily");
102     byte[] qf1 = Bytes.toBytes("testqualifier1");
103     byte[] qf2 = Bytes.toBytes("testqualifier2");
104     byte[] qf3 = Bytes.toBytes("testqualifier3");
105     byte[] qf4 = Bytes.toBytes("testqualifier4");
106     byte[] qf5 = Bytes.toBytes("testqualifier5");
107     byte[] val = Bytes.toBytes("testval");
108 
109     DefaultMemStore memstore = new DefaultMemStore();
110 
111     // Setting up memstore
112     memstore.add(new KeyValue(row, fam, qf1, val));
113     memstore.add(new KeyValue(row, fam, qf2, val));
114     memstore.add(new KeyValue(row, fam, qf3, val));
115 
116     // Creating a snapshot
117     MemStoreSnapshot snapshot = memstore.snapshot();
118     assertEquals(3, memstore.snapshot.size());
119 
120     // Adding value to "new" memstore
121     assertEquals(0, memstore.cellSet.size());
122     memstore.add(new KeyValue(row, fam, qf4, val));
123     memstore.add(new KeyValue(row, fam, qf5, val));
124     assertEquals(2, memstore.cellSet.size());
125     memstore.clearSnapshot(snapshot.getId());
126 
127     int chunkCount = chunkPool.getPoolSize();
128     assertTrue(chunkCount > 0);
129 
130   }
131 
132   @Test
133   public void testPuttingBackChunksWithOpeningScanner()
134       throws UnexpectedStateException {
135     byte[] row = Bytes.toBytes("testrow");
136     byte[] fam = Bytes.toBytes("testfamily");
137     byte[] qf1 = Bytes.toBytes("testqualifier1");
138     byte[] qf2 = Bytes.toBytes("testqualifier2");
139     byte[] qf3 = Bytes.toBytes("testqualifier3");
140     byte[] qf4 = Bytes.toBytes("testqualifier4");
141     byte[] qf5 = Bytes.toBytes("testqualifier5");
142     byte[] qf6 = Bytes.toBytes("testqualifier6");
143     byte[] qf7 = Bytes.toBytes("testqualifier7");
144     byte[] val = Bytes.toBytes("testval");
145 
146     DefaultMemStore memstore = new DefaultMemStore();
147 
148     // Setting up memstore
149     memstore.add(new KeyValue(row, fam, qf1, val));
150     memstore.add(new KeyValue(row, fam, qf2, val));
151     memstore.add(new KeyValue(row, fam, qf3, val));
152 
153     // Creating a snapshot
154     MemStoreSnapshot snapshot = memstore.snapshot();
155     assertEquals(3, memstore.snapshot.size());
156 
157     // Adding value to "new" memstore
158     assertEquals(0, memstore.cellSet.size());
159     memstore.add(new KeyValue(row, fam, qf4, val));
160     memstore.add(new KeyValue(row, fam, qf5, val));
161     assertEquals(2, memstore.cellSet.size());
162 
163     // opening scanner before clear the snapshot
164     List<KeyValueScanner> scanners = memstore.getScanners(0);
165     // Shouldn't putting back the chunks to pool,since some scanners are opening
166     // based on their data
167     memstore.clearSnapshot(snapshot.getId());
168 
169     assertTrue(chunkPool.getPoolSize() == 0);
170 
171     // Chunks will be put back to pool after close scanners;
172     for (KeyValueScanner scanner : scanners) {
173       scanner.close();
174     }
175     assertTrue(chunkPool.getPoolSize() > 0);
176 
177     // clear chunks
178     chunkPool.clearChunks();
179 
180     // Creating another snapshot
181     snapshot = memstore.snapshot();
182     // Adding more value
183     memstore.add(new KeyValue(row, fam, qf6, val));
184     memstore.add(new KeyValue(row, fam, qf7, val));
185     // opening scanners
186     scanners = memstore.getScanners(0);
187     // close scanners before clear the snapshot
188     for (KeyValueScanner scanner : scanners) {
189       scanner.close();
190     }
191     // Since no opening scanner, the chunks of snapshot should be put back to
192     // pool
193     memstore.clearSnapshot(snapshot.getId());
194     assertTrue(chunkPool.getPoolSize() > 0);
195   }
196 
197 }