Path: blob/master/test/jdk/java/rmi/dgc/retryDirtyCalls/RetryDirtyCalls.java
41153 views
/*1* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* @test24* @bug 426825825* @summary When a DGC dirty call fails, RMI's client-side DGC implementation26* should attempt to retry the same dirty call a few times, at least until the27* known lease for that endpoint has expired, instead of just giving up28* renewing that lease at all after the first failure.29* @author Peter Jones (inspired by Adrian Colley's test case in 4268258)30*31* @build RetryDirtyCalls RetryDirtyCalls_Stub32* @run main/othervm RetryDirtyCalls33*/3435import java.io.*;36import java.net.*;37import java.rmi.*;38import java.rmi.server.*;3940interface Self extends Remote {41Self getSelf() throws RemoteException;42}4344public class RetryDirtyCalls implements Self, Unreferenced {4546/** how long we wait before declaring that this test has passed */47private final static long TIMEOUT = 20000;4849/** true if this object's unreferenced method has been called */50private boolean unreferenced = false;5152/**53* Return this object. The need for this method is explained below.54*/55public Self getSelf() {56return this;57}5859public void unreferenced() {60synchronized (this) {61unreferenced = true;62notifyAll();63}64}6566public static void main(String[] args) {6768System.err.println("\nRegression test for bug 4268258\n");6970/*71* Set properties to tweak DGC behavior so that this test will execute72* quickly: set the granted lease duration to 10 seconds, the interval73* that leases are checked to 3 seconds.74*/75System.setProperty("java.rmi.dgc.leaseValue", "10000");76System.setProperty("sun.rmi.dgc.checkInterval", "3000");7778/*79* Make idle connections time out almost instantly (0.1 seconds) so80* that the DGC implementation will have to make a new connection for81* each dirty call, thus going through the socket factory, where we82* can easily cause the operation to fail.83*/84System.setProperty("sun.rmi.transport.connectionTimeout", "100");8586RetryDirtyCalls impl = new RetryDirtyCalls();8788try {89TestSF sf = new TestSF();90RMISocketFactory.setSocketFactory(sf);9192/*93* The stub returned by UnicastRemoteObject.exportObject() does94* not participate in DGC, but it does allow us to invoke a method95* on the remote object through RMI. Therefore, we invoke the96* getSelf() method through RMI, which returns an equivalent stub97* that does participate in DGC.98*/99Self stub = (Self) UnicastRemoteObject.exportObject(impl);100Self dgcStub = stub.getSelf();101stub = null; // in case 4114579 has been fixed102103/*104* Set the socket factory to cause 3 connections attempts in a row105* to fail before allowing a connection to succeed, expecting the106* client-side DGC implementation to make at least four attempts.107*/108final int FLAKE_FACTOR = 3;109sf.setFlakeFactor(FLAKE_FACTOR);110111long deadline = System.currentTimeMillis() + TIMEOUT;112boolean unreferenced;113114synchronized (impl) {115while (!(unreferenced = impl.unreferenced)) {116long timeToWait = deadline - System.currentTimeMillis();117if (timeToWait > 0) {118impl.wait(timeToWait);119} else {120break;121}122}123}124125if (unreferenced) {126throw new RuntimeException("remote object unreferenced");127}128129int createCount = sf.getCreateCount();130if (createCount == 0) {131throw new RuntimeException("test socket factory never used");132} else if (createCount < (FLAKE_FACTOR + 3)) {133/*134* The unreferenced method was not invoked for some reason,135* but the dirty calls were clearly not retried well enough.136*/137throw new RuntimeException(138"test failed because dirty calls not retried enough, " +139"but remote object not unreferenced");140}141142System.err.println(143"TEST PASSED: remote object not unreferenced");144145} catch (Exception e) {146e.printStackTrace();147throw new RuntimeException("TEST FAILED: " + e.toString());148} finally {149/*150* When all is said and done, try to unexport the remote object151* so that the VM has a chance to exit.152*/153try {154UnicastRemoteObject.unexportObject(impl, true);155} catch (Exception e) {156}157}158}159}160161class TestSF extends RMISocketFactory {162163private int flakeFactor = 0;164165private int flakeState = 0;166167private int createCount = 0;168169public synchronized void setFlakeFactor(int newFlakeFactor) {170flakeFactor = newFlakeFactor;171}172173public synchronized int getCreateCount() {174return createCount;175}176177public synchronized Socket createSocket(String host, int port)178throws IOException179{180createCount++;181182if (++flakeState > flakeFactor) {183flakeState = 0;184}185186if (flakeState == 0) {187return new Socket(host, port);188} else {189throw new IOException("random network failure");190}191}192193public ServerSocket createServerSocket(int port) throws IOException {194return new ServerSocket(port);195}196}197198199