1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002, 2014 Oracle and/or its affiliates.  All rights reserved.
5  *
6  */
7 
8 package com.sleepycat.je.rep.impl.node;
9 
10 import static org.junit.Assert.assertTrue;
11 import static org.junit.Assert.fail;
12 
13 import java.util.concurrent.TimeUnit;
14 
15 import org.junit.Before;
16 import org.junit.Test;
17 
18 import com.sleepycat.je.CommitToken;
19 import com.sleepycat.je.rep.GroupShutdownException;
20 import com.sleepycat.je.rep.NoConsistencyRequiredPolicy;
21 import com.sleepycat.je.rep.NodeType;
22 import com.sleepycat.je.rep.ReplicatedEnvironment;
23 import com.sleepycat.je.rep.impl.RepTestBase;
24 import com.sleepycat.je.rep.utilint.RepTestUtils;
25 import com.sleepycat.je.rep.utilint.RepTestUtils.RepEnvInfo;
26 
27 public class GroupShutdownTest extends RepTestBase {
28 
29     @Override
30     @Before
setUp()31     public void setUp()
32         throws Exception {
33 
34         super.setUp();
35 
36         /* Include a SECONDARY node. */
37         repEnvInfo = RepTestUtils.setupExtendEnvInfo(repEnvInfo, 1);
38         repEnvInfo[repEnvInfo.length-1].getRepConfig().setNodeType(
39             NodeType.SECONDARY);
40     }
41 
42     @Test
testShutdownExceptions()43     public void testShutdownExceptions() {
44         createGroup();
45         ReplicatedEnvironment mrep = repEnvInfo[0].getEnv();
46 
47         try {
48             repEnvInfo[1].getEnv().shutdownGroup(10000, TimeUnit.MILLISECONDS);
49             fail("expected exception");
50         } catch (IllegalStateException e) {
51             /* OK, shutdownGroup on Replica. */
52         }
53 
54         ReplicatedEnvironment mrep2 =
55             new ReplicatedEnvironment(repEnvInfo[0].getEnvHome(),
56                                       repEnvInfo[0].getRepConfig(),
57                                       repEnvInfo[0].getEnvConfig());
58 
59         try {
60             mrep.shutdownGroup(10000, TimeUnit.MILLISECONDS);
61             fail("expected exception");
62         } catch (IllegalStateException e) {
63             /* OK, multiple master handles. */
64             mrep2.close();
65         }
66         mrep.shutdownGroup(10000, TimeUnit.MILLISECONDS);
67         for (int i=1; i < repEnvInfo.length; i++) {
68             repEnvInfo[i].closeEnv();
69         }
70     }
71 
72     @Test
testShutdownTimeout()73     public void testShutdownTimeout()
74         throws InterruptedException {
75 
76         new ShutdownSupport() {
77             @Override
78             void checkException(GroupShutdownException e){}
79         }.shutdownBasic(500, 1);
80     }
81 
82     @Test
testShutdownBasic()83     public void testShutdownBasic()
84         throws InterruptedException {
85 
86         new ShutdownSupport() {
87             @Override
88             void checkException(GroupShutdownException e) {
89                 /*
90                  * It's possible, in rare circumstances, for the exception to
91                  * not contain the shutdown VLSN, that is, for it to be null,
92                  * because the VLSNIndex range was not yet initialized. Ignore
93                  * it in that circumstance.
94                  */
95                 assertTrue((e.getShutdownVLSN() == null) ||
96                            (ct.getVLSN() <=
97                             e.getShutdownVLSN().getSequence()));
98             }
99         }.shutdownBasic(10000, 0);
100     }
101 
102     abstract class ShutdownSupport {
103         CommitToken ct;
104 
checkException(GroupShutdownException e)105         abstract void checkException(GroupShutdownException e);
106 
shutdownBasic(long timeoutMs, int testDelayMs)107         public void shutdownBasic(long timeoutMs,
108                                   int testDelayMs)
109             throws InterruptedException {
110 
111             createGroup();
112             ReplicatedEnvironment mrep = repEnvInfo[0].getEnv();
113             leaveGroupAllButMaster();
114 
115             ct = populateDB(mrep, TEST_DB_NAME, 1000);
116             repEnvInfo[0].getRepNode().feederManager().
117                 setTestDelayMs(testDelayMs);
118             restartReplicasNoWait();
119 
120             mrep.shutdownGroup(timeoutMs, TimeUnit.MILLISECONDS);
121 
122             for (int i=1; i < repEnvInfo.length; i++) {
123                 RepEnvInfo repi = repEnvInfo[i];
124                 final int retries = 100;
125                 for (int j=0; j < retries; j++) {
126                     try {
127                         /* Provoke exception */
128                         repi.getEnv().getState();
129                         if ((j+1) == retries) {
130                             fail("expected exception from " +
131                                  repi.getRepNode().getNameIdPair());
132                         }
133                         /* Give the replica time to react */
134                         Thread.sleep(1000); /* a second between retries */
135                     } catch (GroupShutdownException e) {
136                         checkException(e);
137                         break;
138                     }
139                 }
140                 /* Close the handle. */
141                 repi.closeEnv();
142             }
143         }
144     }
145 
146     /**
147      * Start up replicas for existing master, but don't wait for any
148      * consistency to be reached.
149      */
restartReplicasNoWait()150     private void restartReplicasNoWait() {
151         for (int i=1; i < repEnvInfo.length; i++) {
152             RepEnvInfo ri = repEnvInfo[i];
153             ri.openEnv(new NoConsistencyRequiredPolicy());
154         }
155     }
156 }
157