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.regionserver;
19  
20  import junit.framework.TestCase;
21  import org.apache.hadoop.hbase.testclassification.SmallTests;
22  import org.junit.experimental.categories.Category;
23  
24  import java.util.Random;
25  import java.util.concurrent.atomic.AtomicBoolean;
26  import java.util.concurrent.atomic.AtomicLong;
27  
28  /**
29   * This is a hammer test that verifies MultiVersionConcurrencyControl in a
30   * multiple writer single reader scenario.
31   */
32  @Category(SmallTests.class)
33  public class TestMultiVersionConcurrencyControl extends TestCase {
34    static class Writer implements Runnable {
35      final AtomicBoolean finished;
36      final MultiVersionConcurrencyControl mvcc;
37      final AtomicBoolean status;
38  
39      Writer(AtomicBoolean finished, MultiVersionConcurrencyControl mvcc, AtomicBoolean status) {
40        this.finished = finished;
41        this.mvcc = mvcc;
42        this.status = status;
43      }
44  
45      private Random rnd = new Random();
46      public boolean failed = false;
47  
48      public void run() {
49        while (!finished.get()) {
50          MultiVersionConcurrencyControl.WriteEntry e =
51              mvcc.begin();
52          // System.out.println("Begin write: " + e.getWriteNumber());
53          // 10 usec - 500usec (including 0)
54          int sleepTime = rnd.nextInt(500);
55          // 500 * 1000 = 500,000ns = 500 usec
56          // 1 * 100 = 100ns = 1usec
57          try {
58            if (sleepTime > 0) Thread.sleep(0, sleepTime * 1000);
59          } catch (InterruptedException e1) {
60          }
61          try {
62            mvcc.completeAndWait(e);
63          } catch (RuntimeException ex) {
64            // got failure
65            System.out.println(ex.toString());
66            ex.printStackTrace();
67            status.set(false);
68            return;
69            // Report failure if possible.
70          }
71        }
72      }
73    }
74  
75    public void testParallelism() throws Exception {
76      final MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl();
77  
78      final AtomicBoolean finished = new AtomicBoolean(false);
79  
80      // fail flag for the reader thread
81      final AtomicBoolean readerFailed = new AtomicBoolean(false);
82      final AtomicLong failedAt = new AtomicLong();
83      Runnable reader = new Runnable() {
84        public void run() {
85          long prev = mvcc.getReadPoint();
86          while (!finished.get()) {
87            long newPrev = mvcc.getReadPoint();
88            if (newPrev < prev) {
89              // serious problem.
90              System.out.println("Reader got out of order, prev: " + prev + " next was: " + newPrev);
91              readerFailed.set(true);
92              // might as well give up
93              failedAt.set(newPrev);
94              return;
95            }
96          }
97        }
98      };
99  
100     // writer thread parallelism.
101     int n = 20;
102     Thread[] writers = new Thread[n];
103     AtomicBoolean[] statuses = new AtomicBoolean[n];
104     Thread readThread = new Thread(reader);
105 
106     for (int i = 0; i < n; ++i) {
107       statuses[i] = new AtomicBoolean(true);
108       writers[i] = new Thread(new Writer(finished, mvcc, statuses[i]));
109       writers[i].start();
110     }
111     readThread.start();
112 
113     try {
114       Thread.sleep(10 * 1000);
115     } catch (InterruptedException ex) {
116     }
117 
118     finished.set(true);
119 
120     readThread.join();
121     for (int i = 0; i < n; ++i) {
122       writers[i].join();
123     }
124 
125     // check failure.
126     assertFalse(readerFailed.get());
127     for (int i = 0; i < n; ++i) {
128       assertTrue(statuses[i].get());
129     }
130   }
131 }