File: RetryDirtyCalls.java

package info (click to toggle)
openjdk-11 11.0.4%2B11-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 757,028 kB
  • sloc: java: 5,016,041; xml: 1,191,974; cpp: 934,731; ansic: 555,697; sh: 24,299; objc: 12,703; python: 3,602; asm: 3,415; makefile: 2,772; awk: 351; sed: 172; perl: 114; jsp: 24; csh: 3
file content (197 lines) | stat: -rw-r--r-- 6,811 bytes parent folder | download | duplicates (16)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/* @test
 * @bug 4268258
 * @summary When a DGC dirty call fails, RMI's client-side DGC implementation
 * should attempt to retry the same dirty call a few times, at least until the
 * known lease for that endpoint has expired, instead of just giving up
 * renewing that lease at all after the first failure.
 * @author Peter Jones (inspired by Adrian Colley's test case in 4268258)
 *
 * @build RetryDirtyCalls RetryDirtyCalls_Stub
 * @run main/othervm RetryDirtyCalls
 */

import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.server.*;

interface Self extends Remote {
    Self getSelf() throws RemoteException;
}

public class RetryDirtyCalls implements Self, Unreferenced {

    /** how long we wait before declaring that this test has passed */
    private final static long TIMEOUT = 20000;

    /** true if this object's unreferenced method has been called */
    private boolean unreferenced = false;

    /**
     * Return this object.  The need for this method is explained below.
     */
    public Self getSelf() {
        return this;
    }

    public void unreferenced() {
        synchronized (this) {
            unreferenced = true;
            notifyAll();
        }
    }

    public static void main(String[] args) {

        System.err.println("\nRegression test for bug 4268258\n");

        /*
         * Set properties to tweak DGC behavior so that this test will execute
         * quickly: set the granted lease duration to 10 seconds, the interval
         * that leases are checked to 3 seconds.
         */
        System.setProperty("java.rmi.dgc.leaseValue", "10000");
        System.setProperty("sun.rmi.dgc.checkInterval", "3000");

        /*
         * Make idle connections time out almost instantly (0.1 seconds) so
         * that the DGC implementation will have to make a new connection for
         * each dirty call, thus going through the socket factory, where we
         * can easily cause the operation to fail.
         */
        System.setProperty("sun.rmi.transport.connectionTimeout", "100");

        RetryDirtyCalls impl = new RetryDirtyCalls();

        try {
            TestSF sf = new TestSF();
            RMISocketFactory.setSocketFactory(sf);

            /*
             * The stub returned by UnicastRemoteObject.exportObject() does
             * not participate in DGC, but it does allow us to invoke a method
             * on the remote object through RMI.  Therefore, we invoke the
             * getSelf() method through RMI, which returns an equivalent stub
             * that does participate in DGC.
             */
            Self stub = (Self) UnicastRemoteObject.exportObject(impl);
            Self dgcStub = stub.getSelf();
            stub = null;                // in case 4114579 has been fixed

            /*
             * Set the socket factory to cause 3 connections attempts in a row
             * to fail before allowing a connection to succeed, expecting the
             * client-side DGC implementation to make at least four attempts.
             */
            final int FLAKE_FACTOR = 3;
            sf.setFlakeFactor(FLAKE_FACTOR);

            long deadline = System.currentTimeMillis() + TIMEOUT;
            boolean unreferenced;

            synchronized (impl) {
                while (!(unreferenced = impl.unreferenced)) {
                    long timeToWait = deadline - System.currentTimeMillis();
                    if (timeToWait > 0) {
                        impl.wait(timeToWait);
                    } else {
                        break;
                    }
                }
            }

            if (unreferenced) {
                throw new RuntimeException("remote object unreferenced");
            }

            int createCount = sf.getCreateCount();
            if (createCount == 0) {
                throw new RuntimeException("test socket factory never used");
            } else if (createCount < (FLAKE_FACTOR + 3)) {
                /*
                 * The unreferenced method was not invoked for some reason,
                 * but the dirty calls were clearly not retried well enough.
                 */
                throw new RuntimeException(
                    "test failed because dirty calls not retried enough, " +
                    "but remote object not unreferenced");
            }

            System.err.println(
                "TEST PASSED: remote object not unreferenced");

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("TEST FAILED: " + e.toString());
        } finally {
            /*
             * When all is said and done, try to unexport the remote object
             * so that the VM has a chance to exit.
             */
            try {
                UnicastRemoteObject.unexportObject(impl, true);
            } catch (Exception e) {
            }
        }
    }
}

class TestSF extends RMISocketFactory {

    private int flakeFactor = 0;

    private int flakeState = 0;

    private int createCount = 0;

    public synchronized void setFlakeFactor(int newFlakeFactor) {
        flakeFactor = newFlakeFactor;
    }

    public synchronized int getCreateCount() {
        return createCount;
    }

    public synchronized Socket createSocket(String host, int port)
        throws IOException
    {
        createCount++;

        if (++flakeState > flakeFactor) {
            flakeState = 0;
        }

        if (flakeState == 0) {
            return new Socket(host, port);
        } else {
            throw new IOException("random network failure");
        }
    }

    public ServerSocket createServerSocket(int port) throws IOException {
        return new ServerSocket(port);
    }
}