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.exceptions.UnexpectedStateException;
30  import org.apache.hadoop.hbase.testclassification.SmallTests;
31  import org.apache.hadoop.hbase.util.ByteRange;
32  import org.apache.hadoop.hbase.util.Bytes;
33  import org.junit.After;
34  import org.junit.AfterClass;
35  import org.junit.BeforeClass;
36  import org.junit.Test;
37  import org.junit.experimental.categories.Category;
38  
39  /**
40   * Test the {@link MemStoreChunkPool} class
41   */
42  @Category(SmallTests.class)
43  public class TestMemStoreChunkPool {
44    private final static Configuration conf = new Configuration();
45    private static MemStoreChunkPool chunkPool;
46    private static boolean chunkPoolDisabledBeforeTest;
47  
48    @BeforeClass
49    public static void setUpBeforeClass() throws Exception {
50      conf.setBoolean(DefaultMemStore.USEMSLAB_KEY, true);
51      conf.setFloat(MemStoreChunkPool.CHUNK_POOL_MAXSIZE_KEY, 0.2f);
52      chunkPoolDisabledBeforeTest = MemStoreChunkPool.chunkPoolDisabled;
53      MemStoreChunkPool.chunkPoolDisabled = false;
54      chunkPool = MemStoreChunkPool.getPool(conf);
55      assertTrue(chunkPool != null);
56    }
57  
58    @AfterClass
59    public static void tearDownAfterClass() throws Exception {
60      MemStoreChunkPool.chunkPoolDisabled = chunkPoolDisabledBeforeTest;
61    }
62  
63    @After
64    public void tearDown() throws Exception {
65      chunkPool.clearChunks();
66    }
67  
68    @Test
69    public void testReusingChunks() {
70      Random rand = new Random();
71      MemStoreLAB mslab = new HeapMemStoreLAB(conf);
72      int expectedOff = 0;
73      byte[] lastBuffer = null;
74      // Randomly allocate some bytes
75      for (int i = 0; i < 100; i++) {
76        int size = rand.nextInt(1000);
77        ByteRange alloc = mslab.allocateBytes(size);
78  
79        if (alloc.getBytes() != lastBuffer) {
80          expectedOff = 0;
81          lastBuffer = alloc.getBytes();
82        }
83        assertEquals(expectedOff, alloc.getOffset());
84        assertTrue("Allocation overruns buffer", alloc.getOffset()
85            + size <= alloc.getBytes().length);
86        expectedOff += size;
87      }
88      // chunks will be put back to pool after close
89      mslab.close();
90      int chunkCount = chunkPool.getPoolSize();
91      assertTrue(chunkCount > 0);
92      // reconstruct mslab
93      mslab = new HeapMemStoreLAB(conf);
94      // chunk should be got from the pool, so we can reuse it.
95      mslab.allocateBytes(1000);
96      assertEquals(chunkCount - 1, chunkPool.getPoolSize());
97    }
98  
99    @Test
100   public void testPuttingBackChunksAfterFlushing() throws UnexpectedStateException {
101     byte[] row = Bytes.toBytes("testrow");
102     byte[] fam = Bytes.toBytes("testfamily");
103     byte[] qf1 = Bytes.toBytes("testqualifier1");
104     byte[] qf2 = Bytes.toBytes("testqualifier2");
105     byte[] qf3 = Bytes.toBytes("testqualifier3");
106     byte[] qf4 = Bytes.toBytes("testqualifier4");
107     byte[] qf5 = Bytes.toBytes("testqualifier5");
108     byte[] val = Bytes.toBytes("testval");
109 
110     DefaultMemStore memstore = new DefaultMemStore();
111 
112     // Setting up memstore
113     memstore.add(new KeyValue(row, fam, qf1, val));
114     memstore.add(new KeyValue(row, fam, qf2, val));
115     memstore.add(new KeyValue(row, fam, qf3, val));
116 
117     // Creating a snapshot
118     MemStoreSnapshot snapshot = memstore.snapshot();
119     assertEquals(3, memstore.snapshotSection.getCellSkipListSet().sizeForTests());
120 
121     // Adding value to "new" memstore
122     assertEquals(0, memstore.activeSection.getCellSkipListSet().sizeForTests());
123     memstore.add(new KeyValue(row, fam, qf4, val));
124     memstore.add(new KeyValue(row, fam, qf5, val));
125     assertEquals(2, memstore.activeSection.getCellSkipListSet().sizeForTests());
126     memstore.clearSnapshot(snapshot.getId());
127 
128     int chunkCount = chunkPool.getPoolSize();
129     assertTrue(chunkCount > 0);
130 
131   }
132 
133   @Test
134   public void testPuttingBackChunksWithOpeningScanner()
135       throws UnexpectedStateException {
136     byte[] row = Bytes.toBytes("testrow");
137     byte[] fam = Bytes.toBytes("testfamily");
138     byte[] qf1 = Bytes.toBytes("testqualifier1");
139     byte[] qf2 = Bytes.toBytes("testqualifier2");
140     byte[] qf3 = Bytes.toBytes("testqualifier3");
141     byte[] qf4 = Bytes.toBytes("testqualifier4");
142     byte[] qf5 = Bytes.toBytes("testqualifier5");
143     byte[] qf6 = Bytes.toBytes("testqualifier6");
144     byte[] qf7 = Bytes.toBytes("testqualifier7");
145     byte[] val = Bytes.toBytes("testval");
146 
147     DefaultMemStore memstore = new DefaultMemStore();
148 
149     // Setting up memstore
150     memstore.add(new KeyValue(row, fam, qf1, val));
151     memstore.add(new KeyValue(row, fam, qf2, val));
152     memstore.add(new KeyValue(row, fam, qf3, val));
153 
154     // Creating a snapshot
155     MemStoreSnapshot snapshot = memstore.snapshot();
156     assertEquals(3, memstore.snapshotSection.getCellSkipListSet().sizeForTests());
157 
158     // Adding value to "new" memstore
159     assertEquals(0, memstore.activeSection.getCellSkipListSet().sizeForTests());
160     memstore.add(new KeyValue(row, fam, qf4, val));
161     memstore.add(new KeyValue(row, fam, qf5, val));
162     assertEquals(2, memstore.activeSection.getCellSkipListSet().sizeForTests());
163 
164     // opening scanner before clear the snapshot
165     List<KeyValueScanner> scanners = memstore.getScanners(0);
166     // Shouldn't putting back the chunks to pool,since some scanners are opening
167     // based on their data
168     memstore.clearSnapshot(snapshot.getId());
169 
170     assertTrue(chunkPool.getPoolSize() == 0);
171 
172     // Chunks will be put back to pool after close scanners;
173     for (KeyValueScanner scanner : scanners) {
174       scanner.close();
175     }
176     assertTrue(chunkPool.getPoolSize() > 0);
177 
178     // clear chunks
179     chunkPool.clearChunks();
180 
181     // Creating another snapshot
182     snapshot = memstore.snapshot();
183     // Adding more value
184     memstore.add(new KeyValue(row, fam, qf6, val));
185     memstore.add(new KeyValue(row, fam, qf7, val));
186     // opening scanners
187     scanners = memstore.getScanners(0);
188     // close scanners before clear the snapshot
189     for (KeyValueScanner scanner : scanners) {
190       scanner.close();
191     }
192     // Since no opening scanner, the chunks of snapshot should be put back to
193     // pool
194     memstore.clearSnapshot(snapshot.getId());
195     assertTrue(chunkPool.getPoolSize() > 0);
196   }
197 
198 }