jdk/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java
author xdono
Wed, 02 Jul 2008 12:55:45 -0700
changeset 715 f16baef3a20e
parent 309 bda219d843f6
child 5506 202f599c92aa
permissions -rw-r--r--
6719955: Update copyright year Summary: Update copyright year for files that have been modified in 2008 Reviewed-by: ohair, tbell

/*
 * Copyright 1998-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

/* @test
 * @bug 4116437
 * @summary Distributed Garbage Collector Memory Leak
 *
 * @author Laird Dornin
 *
 * @library ../../testlibrary
 * @build CheckLeaseLeak CheckLeaseLeak_Stub LeaseLeakClient LeaseLeak
 * @run main/othervm/timeout=240 CheckLeaseLeak
 *
 */

/**
 * A bug in sun.rmi.transport.DGCImp.checkLeases() results in memory
 * leak of LeaseInfo objects.
 *
 * In order to verify that this problem no longer exists, we create a
 * remote object and a serveral clients in different VMs. The clients
 * call a remote method on an exported object. This will cause the rmi
 * runtime to create several references (all with different vmids) to
 * the remote object.  Each vmid needs a seperate LeaseInfo object in
 * the object table target DGCImpl.leaseTable.  If the leak is fixed,
 * the leaseTable field will contain no objects.  We use reflection to
 * find the number of objects contained in this table.
 */

import java.rmi.*;
import java.rmi.server.*;
import sun.rmi.transport.*;
import sun.rmi.*;
import java.util.Map;
import java.io.*;
import java.lang.reflect.*;
import java.rmi.registry.*;

public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak {

    public CheckLeaseLeak() throws RemoteException { }
    public void ping () throws RemoteException { }

    /**
     * Id to fake the DGC_ID, so we can later get a reference to the
     * DGCImpl in the object table.
     */
    private final static int DGC_ID = 2;

    private final static int ITERATIONS = 10;
    private final static int numberPingCalls = 0;
    private final static int CHECK_INTERVAL = 400;
    private final static int LEASE_VALUE = 20;

    public static void main (String[] args) {
        CheckLeaseLeak leakServer = null;
        int numLeft =0;

        /*
         * we want DGC to collect leases *quickly*
         * decrease the lease check interval
         */
        TestLibrary.setInteger("sun.rmi.dgc.checkInterval",
                               CHECK_INTERVAL);
        TestLibrary.setInteger("java.rmi.dgc.leaseValue",
                               LEASE_VALUE);

        try {
            Registry registry =
                java.rmi.registry.LocateRegistry.
                    createRegistry(TestLibrary.REGISTRY_PORT);

            leakServer = new CheckLeaseLeak();
            registry.rebind("/LeaseLeak", leakServer);

            /* create a bunch of clients in a *different* vm */
            for (int i = 0 ; i < ITERATIONS ; i ++ ) {
                System.err.println("Created client: " + i);

                JavaVM jvm = new JavaVM("LeaseLeakClient",
                                        " -Djava.security.policy=" +
                                        TestParams.defaultPolicy, "");
                jvm.start();

                if (jvm.getVM().waitFor() == 1 ) {
                    TestLibrary.bomb("Client process failed");
                }
            }
            numLeft = getDGCLeaseTableSize();
            Thread.sleep(3000);

        } catch(Exception e) {
            TestLibrary.bomb("CheckLeaseLeak Error: ", e);
        } finally {
            if (leakServer != null) {
                TestLibrary.unexport(leakServer);
                leakServer = null;
            }
        }

        /* numLeft should be 2 - if 11 there is a problem. */
        if (numLeft > 2) {
            TestLibrary.bomb("Too many objects in DGCImpl.leaseTable: "+
                            numLeft);
        } else {
            System.err.println("Check leaseInfo leak passed with " +
                               numLeft
                                   + " object(s) in the leaseTable");
        }
    }

    /**
     * Obtain a reference to the main DGCImpl via reflection.  Extract
     * the DGCImpl using the ObjectTable and the well known ID of the
     * DGCImpl.
     */
    private static int getDGCLeaseTableSize () {
        int numLeaseInfosLeft = 0;

        /**
         * Will eventually be set to point at the leaseTable inside
         * DGCImpl.
         */
        Map leaseTable = null;
        final Remote[] dgcImpl = new Remote[1];
        Field f;

        try {
            f = (Field) java.security.AccessController.doPrivileged
                (new java.security.PrivilegedExceptionAction() {
                    public Object run() throws Exception {

                        ObjID dgcID = new ObjID(DGC_ID);

                        /*
                         * Construct an ObjectEndpoint containing DGC's
                         * ObjID.
                         */
                        Class oeClass =
                            Class.forName("sun.rmi.transport.ObjectEndpoint");
                        Class[] constrParams =
                            new Class[]{ ObjID.class, Transport.class };
                        Constructor oeConstructor =
                            oeClass.getDeclaredConstructor(constrParams);
                        oeConstructor.setAccessible(true);
                        Object oe =
                            oeConstructor.newInstance(
                                new Object[]{ dgcID, null });

                        /*
                         * Get Target that contains DGCImpl in ObjectTable
                         */
                        Class objTableClass =
                            Class.forName("sun.rmi.transport.ObjectTable");
                        Class getTargetParams[] = new Class[] { oeClass };
                        Method objTableGetTarget =
                            objTableClass.getDeclaredMethod("getTarget",
                                                            getTargetParams);
                        objTableGetTarget.setAccessible(true);
                        Target dgcTarget = (Target)
                            objTableGetTarget.invoke(null, new Object[]{ oe });

                        /* get the DGCImpl from its Target */
                        Method targetGetImpl =
                            dgcTarget.getClass().getDeclaredMethod
                            ("getImpl", null);
                        targetGetImpl.setAccessible(true);
                        dgcImpl[0] =
                            (Remote) targetGetImpl.invoke(dgcTarget, null);

                        /* Get the lease table from the DGCImpl. */
                        Field reflectedLeaseTable =
                            dgcImpl[0].getClass().getDeclaredField
                            ("leaseTable");
                        reflectedLeaseTable.setAccessible(true);

                        return reflectedLeaseTable;
                    }
            });

            /**
             * This is the leaseTable that will fill up with LeaseInfo
             * objects if the LeaseInfo memory leak is not fixed.
             */
            leaseTable = (Map) f.get(dgcImpl[0]);

            numLeaseInfosLeft = leaseTable.size();

        } catch(Exception e) {
            if (e instanceof java.security.PrivilegedActionException)
                e = ((java.security.PrivilegedActionException) e).
                    getException();
            TestLibrary.bomb(e);
        }

        return numLeaseInfosLeft;
    }
}