All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.kv.impl.rep.admin.RepNodeAdminImpl Maven / Gradle / Ivy

Go to download

NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.

The newest version!
/*-
 * Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle NoSQL
 * Database made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle NoSQL Database for a copy of the license and
 * additional information.
 */

package oracle.kv.impl.rep.admin;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.rmi.RemoteException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import oracle.kv.KVSecurityException;
import oracle.kv.impl.admin.param.RepNodeParams;
import oracle.kv.impl.admin.param.StorageNodeParams;
import oracle.kv.impl.api.TopologyInfo;
import oracle.kv.impl.fault.ClientAccessException;
import oracle.kv.impl.fault.OperationFaultException;
import oracle.kv.impl.fault.ProcessExitCode;
import oracle.kv.impl.fault.ProcessFaultHandler;
import oracle.kv.impl.measurement.ServiceStatusChange;
import oracle.kv.impl.metadata.Metadata;
import oracle.kv.impl.metadata.Metadata.MetadataType;
import oracle.kv.impl.metadata.MetadataInfo;
import oracle.kv.impl.metadata.MetadataKey;
import oracle.kv.impl.mgmt.RepNodeStatusReceiver;
import oracle.kv.impl.param.LoadParameters;
import oracle.kv.impl.param.ParameterListener;
import oracle.kv.impl.param.ParameterMap;
import oracle.kv.impl.rep.NetworkRestoreStatus;
import oracle.kv.impl.rep.OperationsStatsTracker;
import oracle.kv.impl.rep.RepNode;
import oracle.kv.impl.rep.RepNode.ReplicationStateListener;
import oracle.kv.impl.rep.RepNodeService;
import oracle.kv.impl.rep.RepNodeStatus;
import oracle.kv.impl.rep.admin.ResourceInfo.UsageRecord;
import oracle.kv.impl.rep.migration.PartitionMigrationStatus;
import oracle.kv.impl.rep.monitor.StatsPacket;
import oracle.kv.impl.security.AccessChecker;
import oracle.kv.impl.security.AuthContext;
import oracle.kv.impl.security.ConfigurationException;
import oracle.kv.impl.security.ExecutionContext;
import oracle.kv.impl.security.KVStorePrivilege;
import oracle.kv.impl.security.KVStorePrivilegeLabel;
import oracle.kv.impl.security.OperationContext;
import oracle.kv.impl.security.SecureProxy;
import oracle.kv.impl.security.SessionAccessException;
import oracle.kv.impl.security.SystemPrivilege;
import oracle.kv.impl.security.annotations.PublicMethod;
import oracle.kv.impl.security.annotations.SecureAPI;
import oracle.kv.impl.security.annotations.SecureAutoMethod;
import oracle.kv.impl.security.annotations.SecureInternalMethod;
import oracle.kv.impl.security.annotations.SecureR2Method;
import oracle.kv.impl.security.util.KerberosPrincipals;
import oracle.kv.impl.test.RemoteTestInterface;
import oracle.kv.impl.topo.PartitionId;
import oracle.kv.impl.topo.RepGroupId;
import oracle.kv.impl.topo.RepNodeId;
import oracle.kv.impl.topo.Topology;
import oracle.kv.impl.util.ConfigurableService.ServiceStatus;
import oracle.kv.impl.util.PollCondition;
import oracle.kv.impl.util.SerialVersion;
import oracle.kv.impl.util.ServiceStatusTracker;
import oracle.kv.impl.util.registry.ClientSocketFactory;
import oracle.kv.impl.util.registry.RMISocketPolicy;
import oracle.kv.impl.util.registry.RMISocketPolicy.SocketFactoryPair;
import oracle.kv.impl.util.registry.RegistryUtils;
import oracle.kv.impl.util.registry.RegistryUtils.InterfaceType;
import oracle.kv.impl.util.registry.VersionedRemoteImpl;
import oracle.kv.impl.util.server.LoggerUtils;

import com.sleepycat.je.EnvironmentFailureException;
import com.sleepycat.je.EnvironmentStats;
import com.sleepycat.je.StatsConfig;
import com.sleepycat.je.rep.RepInternal;
import com.sleepycat.je.rep.ReplicaStateException;
import com.sleepycat.je.rep.ReplicatedEnvironment;
import com.sleepycat.je.rep.ReplicatedEnvironment.State;
import com.sleepycat.je.rep.ReplicatedEnvironmentStats;
import com.sleepycat.je.rep.StateChangeEvent;
import com.sleepycat.je.rep.UnknownMasterException;
import com.sleepycat.je.rep.impl.RepImpl;
import com.sleepycat.je.rep.vlsn.VLSNIndex;
import com.sleepycat.je.util.DbBackup;
import com.sleepycat.je.utilint.VLSN;

/**
 * The implementation of the RN administration protocol.
 */
@SecureAPI
public class RepNodeAdminImpl
    extends VersionedRemoteImpl implements RepNodeAdmin {

    /**
     *  The repNode being administered
     */
    private final RepNode repNode;
    private final RepNodeService repNodeService;

    /**
     * The fault handler associated with the service.
     */
    private final RepNodeAdminFaultHandler faultHandler;
    private final Logger logger;

    /**
     * The exportable/bindable version of this object
     */
    private RepNodeAdmin exportableRepNodeAdmin;

    private DbBackup dbBackup;

    /**
     * A remote reference to the status collector on the local StorageNode.
     */
    RepNodeStatusReceiver statusReceiver = null;

    /**
     * A conditional instance, created if the class can be found.
     */
    private RemoteTestInterface rti;
    private static final int REQUEST_QUIESCE_POLL_MS = 100;
    private static final int REQUEST_QUIESCE_MS = 10000;

    /* Set to true during shutdown when a shutdown request is in progress */
    private volatile boolean shutdownActive = false;

    private static final String TEST_INTERFACE_NAME=
        "oracle.kv.impl.rep.RepNodeTestInterface";

    public RepNodeAdminImpl(RepNodeService repNodeService, RepNode repNode) {

        this.repNodeService = repNodeService;
        this.repNode = repNode;
        rti = null;
        logger =
            LoggerUtils.getLogger(this.getClass(), repNodeService.getParams());

        faultHandler = new RepNodeAdminFaultHandler(repNodeService,
                                                    logger,
                                                    ProcessExitCode.RESTART);
    }

    private void assertRunning() {

        ServiceStatus status =
            repNodeService.getStatusTracker().getServiceStatus();
        if (status != ServiceStatus.RUNNING) {
            throw new IllegalRepNodeServiceStateException
                ("RepNode is not RUNNING, current status is " + status);
        }
    }

    /**
     * Create the test interface if it can be found.
     */
    private void startTestInterface() {
        try {
            Class cl = Class.forName(TEST_INTERFACE_NAME);
            Constructor c = cl.getConstructor(repNodeService.getClass());
            rti = (RemoteTestInterface) c.newInstance(repNodeService);
            rti.start(SerialVersion.CURRENT);
        } catch (Exception ignored) {
        }
    }

    @Override
    @SecureR2Method
    public void newParameters(short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public void newParameters(AuthContext authCtx, short serialVersion)
        throws RemoteException {
        faultHandler.execute(new ProcessFaultHandler.SimpleProcedure() {

            @Override
            public void execute() {

                /*
                 * Make sure that the service is running so that we know the
                 * environment has already been set.  Otherwise, we may have
                 * started initializing the environment, meaning that these new
                 * parameters would be missed.
                 */
                assertRunning();

                repNodeService.newParameters();
            }
        });
    }

    /* no R2-compatible version */
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public void newGlobalParameters(AuthContext authCtx, short serialVersion)
        throws RemoteException {
        faultHandler.execute(new ProcessFaultHandler.SimpleProcedure() {

            @Override
            public void execute() {
                repNodeService.newGlobalParameters();
            }
        });
    }

    @Override
    @SecureR2Method
    public Topology getTopology(short serialVersion) {
        throw invalidR2MethodException();
    }

    /*
     * Note that the topology related access and update operations, including
     * getTopology, getTopoSeqNum, getMetadata(Topology), updateTopology,
     * updateMetadata(Topology), require only USRVIEW as basic authentication
     * check rather than the SYSVIEW or SYSOPER in that of Admin. That's
     * because the RepNodeStateUpdateThread on the client will rely on these
     * operations to perform crossing-shard topology propagation, who not
     * always have the SYSXXX privileges. The merely basic check leaves a
     * security hole for attack from clients with masquerade topology updates.
     * This hole will addressed by using the signed topology updates as in
     * SR[#23709].
     */
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.USRVIEW })
    public Topology getTopology(AuthContext authCtx, short serialVersion) {
        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public Topology execute() {
                final ServiceStatus status =
                    repNodeService.getStatusTracker().getServiceStatus();

                return (status == ServiceStatus.RUNNING) ?
                       repNode.getTopology() : null ;
            }
        });
    }

    @Override
    @SecureR2Method
    public int getTopoSeqNum(short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.USRVIEW })
    public int getTopoSeqNum(AuthContext authCtx, short serialVersion)
        throws RemoteException {

        return faultHandler.
        execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public Integer execute() {
                final ServiceStatus status =
                    repNodeService.getStatusTracker().getServiceStatus();

                if (status != ServiceStatus.RUNNING) {
                    return 0;
                }

                final Topology topology = repNode.getTopology();
                return (topology != null) ?
                        topology.getSequenceNumber() :
                        Topology.EMPTY_SEQUENCE_NUMBER;
            }
        });
    }

    @Override
    @SecureR2Method
    public LoadParameters getParams(short serialVersion) {
        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public LoadParameters getParams(AuthContext authCtx, short serialVersion) {
        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public LoadParameters execute() {
                /* Service does not need to be in the running state. */
                return repNode.getAllParams();
            }
        });
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public void configure(final Set> metadataSet,
                          AuthContext authCtx,
                          short serialVersion) {
        faultHandler.execute(new ProcessFaultHandler.SimpleProcedure() {

            @Override
            public void execute() {
                /*
                 * Ensure RepNode update topology first in order to open
                 * database handles before update other types of metadata.
                 */
                for (Iterator> iter = metadataSet.iterator();
                     iter.hasNext();) {
                    Metadata md = iter.next();
                    if (md.getType().equals(MetadataType.TOPOLOGY)) {
                        repNode.updateMetadata(md);
                        iter.remove();
                        break;
                    }
                }

                for (Metadata md : metadataSet) {
                    repNode.updateMetadata(md);
                }
            }
        });
    }

    @Override
    @SecureR2Method
    public void configure(final Topology topology, short serialVersion)
        throws RemoteException {
        throw invalidR2MethodException();
    }

    @Override
    @Deprecated
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public void configure(final Topology topology,
                          AuthContext authCtx,
                          short serialVersion) {
        faultHandler.execute(new ProcessFaultHandler.SimpleProcedure() {

            @Override
            public void execute() {
                repNode.updateMetadata(topology);
            }
        });
    }

    @Override
    @SecureR2Method
    @Deprecated
    public void updateTopology(final Topology newTopology, short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    /**
     * Introduced in R3 to support the creation of SecureProxy for
     * #updateTopology(Topology, short)
     * @deprecated
     */
    @Deprecated
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.USRVIEW })
    public void updateTopology(final Topology newTopology,
                               AuthContext authCtx,
                               short serialVersion)
        throws RemoteException {

        updateMetadata(newTopology, authCtx, serialVersion);
    }

    @Deprecated
    @Override
    @SecureR2Method
    public int updateTopology(final TopologyInfo topoInfo,
                              final short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    /**
     * Introduced in R3 to support the creation of SecureProxy for
     * #updateTopology(TopologyInfo, short)
     * @deprecated
     */
    @Deprecated
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.USRVIEW })
    public int updateTopology(final TopologyInfo topoInfo,
                              final AuthContext authCtx,
                              short serialVersion)
        throws RemoteException {

        return updateMetadata(topoInfo, authCtx, serialVersion);
    }

    @Deprecated
    @Override
    @SecureR2Method
    public void shutdown(final boolean force, short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    /**
     * Shutdown the rep node service. Note that invoking shutdown will result
     * in a callback via the {@link #stop() method}, which will unregister the
     * admin from the registry. It should not impact this remote call which
     * is already in progress.
     */
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public void shutdown(final boolean force, AuthContext authCtx,
                         short serialVersion)
        throws RemoteException {

        faultHandler.execute(new ProcessFaultHandler.SimpleProcedure() {

            @Override
            public void execute() {
                logger.log(Level.INFO, "RepNodeAdmin shutdown({0})", force);
                shutdownActive = true;
                try {
                    repNodeService.stop(force);
                } finally {
                    shutdownActive = false;
                }
            }
        });
    }

    /**
     * Starts up the admin component, binding its stub in the registry, so that
     * it can start accepting remote admin requests.
     *
     * @throws RemoteException
     */
    public void startup()
        throws RemoteException {

        faultHandler.execute
        (new ProcessFaultHandler.Procedure() {

            @Override
            public void execute() throws RemoteException {
                final String kvsName = repNodeService.getParams().
                        getGlobalParams().getKVStoreName();
                final RepNodeParams rnp = repNodeService.getRepNodeParams();
                final StorageNodeParams snp =
                    repNodeService.getParams().getStorageNodeParams();

                final String csfName = ClientSocketFactory.
                        factoryName(kvsName,
                                    RepNodeId.getPrefix(),
                                    InterfaceType.ADMIN.interfaceName());

                RMISocketPolicy rmiPolicy = repNodeService.getParams().
                    getSecurityParams().getRMISocketPolicy();
                SocketFactoryPair sfp =
                    rnp.getAdminSFP(rmiPolicy,
                                    snp.getServicePortRange(),
                                    csfName);

                if (sfp.getServerFactory() != null) {
                    sfp.getServerFactory().setConnectionLogger(logger);
                }
                initExportableRepNodeAdmin();
                repNodeService.rebind(exportableRepNodeAdmin,
                                      InterfaceType.ADMIN,
                                      sfp.getClientFactory(),
                                      sfp.getServerFactory());

                logger.info("RepNodeAdmin registered");
                startTestInterface();
            }
        });
    }

    private void initExportableRepNodeAdmin() {
        try {
            exportableRepNodeAdmin =
                SecureProxy.create(
                    RepNodeAdminImpl.this,
                    repNodeService.getRepNodeSecurity().getAccessChecker(),
                    faultHandler);
            logger.info(
                "Successfully created secure proxy for the repnode admin");
        } catch (ConfigurationException ce) {
            logger.info("Unable to create proxy: " + ce + " : " +
                        ce.getMessage());
            throw new IllegalStateException("Unable to create proxy", ce);
        }
    }

    /**
     * Unbind the admin entry from the registry.
     *
     * If any exceptions are encountered, during the unbind, they are merely
     * logged and otherwise ignored, so that other components can continue
     * to be shut down.
     */
    public void stop() {
        try {
            repNodeService.unbind(exportableRepNodeAdmin,
                                  RegistryUtils.InterfaceType.ADMIN);
            logger.info("RepNodeAdmin stopping");
            if (rti != null) {
                rti.stop(SerialVersion.CURRENT);
            }

            /*
             * Wait for the admin requests to quiesce within the
             * requestQuiesceMs period now that new admin requests have been
             * blocked.
             */
            final boolean quiesced =
                new PollCondition(REQUEST_QUIESCE_POLL_MS,
                                  REQUEST_QUIESCE_MS) {

                @Override
                protected boolean condition() {
                    return faultHandler.getActiveRequests() ==
                           (shutdownActive ? 1 : 0);
                }

            }.await();

            if (!quiesced) {
                logger.info(faultHandler.getActiveRequests() +
                            " admin requests were active on close.");
            }
        } catch (RemoteException e) {
            logger.log(Level.INFO,
                       "Ignoring exception while stopping repNodeAdmin", e);
            return;
        }
    }

    @Override
    @SecureR2Method
    public RepNodeStatus ping(short serialVersion) {
        throw invalidR2MethodException();
    }

    @Override
    @PublicMethod
    public RepNodeStatus ping(AuthContext authCtx, short serialVersion) {

        return faultHandler.
        execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public RepNodeStatus execute() {
                ServiceStatus status =
                    repNodeService.getStatusTracker().getServiceStatus();
                State state = State.DETACHED;
                long currentVLSN = 0;
                ReplicatedEnvironmentStats repEnvStats = null;
                EnvironmentStats envStats = null;
                long availableLogSize = 0;
                long usedLogSize = 0;
                boolean envStatsAvailable = false;
                try {
                    ReplicatedEnvironment env = repNode.getEnv(1);
                    if (env != null) {
                        final RepImpl repImpl = RepInternal.getRepImpl(env);

                        /* May be null if env is invalidated */
                        final VLSNIndex vlsnIndex = (repImpl == null) ?
                                null :
                                RepInternal.getRepImpl(env).getVLSNIndex();
                        /* May be null if DETACHED. */
                        currentVLSN =  (vlsnIndex == null) ?
                                VLSN.NULL_VLSN.getSequence() :
                                vlsnIndex.getRange().getLast().getSequence();
                        try {
                            state = env.getState();
                        } catch (IllegalStateException iae) {
                            /* State cannot be queried if detached. */
                            state = State.DETACHED;
                        }
                        try {
                            repEnvStats = env.getRepStats(StatsConfig.DEFAULT);
                            /*
                             * Retrieving dynamic availableLogSize and
                             * totalLogSize for RepNode.
                             */
                            envStats = env.getStats(StatsConfig.DEFAULT);
                            if (envStats != null) {
                                availableLogSize =
                                    envStats.getAvailableLogSize();
                                usedLogSize = envStats.getTotalLogSize();
                                envStatsAvailable = true;
                            }
                        } catch (IllegalStateException iae) {
                            /* Can fail if environment has been closed */
                        }
                    }
                } catch (EnvironmentFailureException ignored) {

                    /*
                     * The environment could be invalid.
                     */
                }
                final String haHostPort =
                    repNode.getRepNodeParams().getJENodeHostPort();
                final String enabledRequestType =
                    repNode.getRepNodeParams().getEnabledRequestType().name();
                return new RepNodeStatus(status, state,
                                         currentVLSN, haHostPort,
                                         enabledRequestType,
                                         repNode.getMigrationStatus(),
                                         repEnvStats,
                                         availableLogSize, usedLogSize,
                                         envStatsAvailable,
                                         repNode.getNetworkRestoreStats(),
                                         repNode.getIsAuthoritativeMaster());
            }
        });
    }

    @Override
    @SecureR2Method
    public RepNodeInfo getInfo(short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public RepNodeInfo getInfo(AuthContext authCtx, short serialVersion)
        throws RemoteException {

        return faultHandler.
        execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public RepNodeInfo execute() {
                /* Service does not need to be in the running state. */
                return new RepNodeInfo(repNode);
            }
        });
    }

    @Override
    @SecureR2Method
    public String [] startBackup(short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public String [] startBackup(AuthContext authCtx, short serialVersion)
        throws RemoteException {

        return faultHandler.
        execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public String [] execute() {
                assertRunning();

                if (dbBackup != null) {
                    logger.warning("startBackup: dbBackup not null");
                    dbBackup.endBackup();
                }

                /*
                 * TODO: consider a checkpoint...
                 */
                ReplicatedEnvironment env = repNode.getEnv(1);
                if (env == null) {
                    throw new
                        OperationFaultException("Environment unavailable");
                }
                logger.info("startBackup: starting backup/snapshot");
                dbBackup = new DbBackup(env);
                dbBackup.startBackup();
                return dbBackup.getLogFilesInBackupSet();
            }
        });
    }

    @Override
    @SecureR2Method
    public long stopBackup(short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public long stopBackup(AuthContext authCtx, short serialVersion)
        throws RemoteException {

        return faultHandler.
        execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public Long execute() {
                assertRunning();
                logger.info("Ending backup/snapshot");
                long lastFile = -1;
                if (dbBackup != null) {
                    lastFile = dbBackup.getLastFileInBackupSet();
                    dbBackup.endBackup();
                    dbBackup = null;
                }
                return lastFile;
            }

        });
    }

    @Override
    @SecureR2Method
    public boolean updateMemberHAAddress(final String groupName,
                                         final String targetNodeName,
                                         final String targetHelperHosts,
                                         final String newNodeHostPort,
                                         short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public boolean updateMemberHAAddress(final String groupName,
                                         final String targetNodeName,
                                         final String targetHelperHosts,
                                         final String newNodeHostPort,
                                         AuthContext authCtx,
                                         short serialVersion)
        throws RemoteException {

        return faultHandler.execute
            (new ProcessFaultHandler.Operation() {

            @Override
            public Boolean execute() {
                assertRunning();
                try {
                    repNodeService.updateMemberHAAddress(groupName,
                                                         targetNodeName,
                                                         targetHelperHosts,
                                                         newNodeHostPort);
                    return true;
                } catch (UnknownMasterException | ReplicaStateException e) {
                    return false;
                }
            }
        });
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public boolean deleteMember(final String groupName,
                                final String targetNodeName,
                                final String targetHelperHosts,
                                AuthContext authCtx,
                                short serialVersion)
        throws RemoteException {

        return faultHandler.execute
            (new ProcessFaultHandler.Operation() {

            @Override
            public Boolean execute() {
                assertRunning();
                try {
                    repNodeService.deleteMember(groupName,
                                                targetNodeName,
                                                targetHelperHosts);
                    return true;
                } catch (UnknownMasterException | ReplicaStateException e){
                    return false;
                }
            }
        });
    }


    @Override
    @SecureR2Method
    public boolean initiateMasterTransfer(final RepNodeId replicaId,
                                          final int timeout,
                                          final TimeUnit timeUnit,
                                          final short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public boolean initiateMasterTransfer(final RepNodeId replicaId,
                                          final int timeout,
                                          final TimeUnit timeUnit,
                                          final AuthContext authCtx,
                                          final short serialVersion)
        throws RemoteException {

        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation() {

                @Override
                public Boolean execute() {
                    final ServiceStatus status = repNodeService.
                        getStatusTracker().getServiceStatus();

                    return (status != ServiceStatus.RUNNING) ?
                        false :
                        repNode.initiateMasterTransfer(replicaId,
                                                       timeout, timeUnit);
                }
            });
    }

    @Deprecated
    @Override
    @SecureR2Method
    public PartitionMigrationState
                    migratePartition(final PartitionId partitionId,
                                     final RepGroupId sourceRGId,
                                     short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Deprecated
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public PartitionMigrationState
                    migratePartition(final PartitionId partitionId,
                                     final RepGroupId sourceRGId,
                                     AuthContext authCtx,
                                     short serialVersion)
        throws RemoteException {

        return
            migratePartitionV2(partitionId, sourceRGId, authCtx, serialVersion).
                getPartitionMigrationState();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public MigrationState migratePartitionV2(final PartitionId partitionId,
                                             final RepGroupId sourceRGId,
                                             AuthContext authCtx,
                                             short serialVersion)
        throws RemoteException {

        return faultHandler.
        execute(
            new ProcessFaultHandler.SimpleOperation() {

            @Override
            public MigrationState execute() {
                assertRunning();
                return repNode.migratePartition(partitionId, sourceRGId);
            }
        });
    }

    @Deprecated
    @Override
    @SecureR2Method
    public PartitionMigrationState
                    getMigrationState(final PartitionId partitionId,
                                      short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Deprecated
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public PartitionMigrationState
                    getMigrationState(final PartitionId partitionId,
                                      AuthContext authCtx,
                                      short serialVersion)
        throws RemoteException {

        return getMigrationStateV2(partitionId, authCtx, serialVersion).
                getPartitionMigrationState();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public MigrationState getMigrationStateV2(final PartitionId partitionId,
                                              AuthContext authCtx,
                                              short serialVersion)
        throws RemoteException {

        return faultHandler.
        execute(
            new ProcessFaultHandler.SimpleOperation() {

            @Override
            public MigrationState execute() {
                try {
                    assertRunning();
                    return repNode.getMigrationState(partitionId);

                } catch (IllegalRepNodeServiceStateException irnsse) {
                    return new MigrationState(PartitionMigrationState.UNKNOWN,
                                              irnsse);
                }
            }
        });
    }

    @Deprecated
    @Override
    @SecureR2Method
    public PartitionMigrationState canCancel(final PartitionId partitionId,
                                             short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Deprecated
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public PartitionMigrationState canCancel(final PartitionId partitionId,
                                             AuthContext authCtx,
                                             short serialVersion)
        throws RemoteException {
        return canCancelV2(partitionId, authCtx, serialVersion).
                getPartitionMigrationState();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public MigrationState canCancelV2(final PartitionId partitionId,
                                      AuthContext authCtx,
                                      short serialVersion)
        throws RemoteException {

        return faultHandler.
        execute(
            new ProcessFaultHandler.SimpleOperation() {

            @Override
            public MigrationState execute() {
                try {
                    assertRunning();
                    return repNode.canCancel(partitionId);
                } catch (IllegalRepNodeServiceStateException irnsse) {
                    return new MigrationState(PartitionMigrationState.UNKNOWN,
                                              irnsse);
                }
            }
        });
    }

    @Override
    @SecureR2Method
    public boolean canceled(final PartitionId partitionId,
                            final RepGroupId targetRGId,
                            short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public boolean canceled(final PartitionId partitionId,
                            final RepGroupId targetRGId,
                            AuthContext authCtx,
                            short serialVersion)
        throws RemoteException {

        return faultHandler.
        execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public Boolean execute() {
                final ServiceStatus status = repNodeService.
                        getStatusTracker().getServiceStatus();

                return (status != ServiceStatus.RUNNING) ?
                        false : repNode.canceled(partitionId, targetRGId);
            }
        });
    }

    @Override
    @SecureR2Method
    public PartitionMigrationStatus
                    getMigrationStatus(final PartitionId partitionId,
                                       short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public PartitionMigrationStatus
                    getMigrationStatus(final PartitionId partitionId,
                                       AuthContext authCtx,
                                       short serialVersion)
        throws RemoteException {

        return faultHandler.
        execute(
           new ProcessFaultHandler.SimpleOperation() {

            @Override
            public PartitionMigrationStatus execute() {
                assertRunning();
                return repNode.getMigrationStatus(partitionId);
            }
        });
    }

    @Override
    @SecureR2Method
    public void installStatusReceiver(final RepNodeStatusReceiver receiver,
                                      short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public void installStatusReceiver(final RepNodeStatusReceiver receiver,
                                      AuthContext authCtx,
                                      short serialVersion)
        throws RemoteException {

        statusReceiver = receiver;

        faultHandler.execute
            (new ProcessFaultHandler.Procedure() {

            @Override
            public void execute() throws RemoteException {
                ServiceStatusTracker rnStatusTracker =
                    repNodeService.getStatusTracker();
                rnStatusTracker.addListener(new StatusListener(), receiver);

                OperationsStatsTracker opStatsTracker =
                    repNodeService.getOpStatsTracker();
                opStatsTracker.addListener(new OpStatsListener());

                repNodeService.addParameterListener
                    (new ParameterChangeListener());
                repNodeService.setReplicationStateListener
                    (new RnStateListener());
            }
        });
    }

    @Override
    @SecureR2Method
    public boolean awaitConsistency(final long targetTime,
                                    final int timeout,
                                    final TimeUnit timeoutUnit,
                                    short serialVersion)
        throws RemoteException {

        throw invalidR2MethodException();
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public boolean awaitConsistency(final long targetTime, /* unused */
                                    final int timeout,
                                    final TimeUnit timeoutUnit,
                                    AuthContext authCtx,
                                    short serialVersion)
        throws RemoteException {

        return faultHandler.execute
            (new ProcessFaultHandler.SimpleOperation() {

            @Override
            public Boolean execute() {
                return repNode.awaitConsistency(timeout, timeoutUnit);
            }
        });
    }

    @Override
    @SecureR2Method
    public int getMetadataSeqNum(final MetadataType type, short serialVersion) {

        throw invalidR2MethodException();
    }

    @Override
    /*
     * TOPOLOGY requires USRVIEW, TABLE requires DBVIEW, and others require
     * INTLOPER.
     */
    @SecureInternalMethod
    public int getMetadataSeqNum(final MetadataType type,
                                 final AuthContext authCtx,
                                 short serialVersion) {

        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public Integer execute() {
                /* Check access rights */
                checkAccessPermission(new MetadataAccessContext(type));

                final ServiceStatus status =
                    repNodeService.getStatusTracker().getServiceStatus();

                if (status != ServiceStatus.RUNNING) {
                    return Metadata.EMPTY_SEQUENCE_NUMBER;
                }

                return repNode.getMetadataSeqNum(type);
            }
        });
    }

    @Override
    @SecureR2Method
    public Metadata getMetadata(final MetadataType type,
                                   short serialVersion) {
        throw invalidR2MethodException();
    }

    @Override
    /*
     * TOPOLOGY requires USRVIEW, TABLE requires DBVIEW, and others require
     * INTLOPER.
     */
    @SecureInternalMethod
    public Metadata getMetadata(final MetadataType type,
                                   final AuthContext authCtx,
                                   short serialVersion) {

        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation>() {

            @Override
            public Metadata execute() {
                /* Check access rights */
                checkAccessPermission(new MetadataAccessContext(type));

                final ServiceStatus status =
                    repNodeService.getStatusTracker().getServiceStatus();

                return (status == ServiceStatus.RUNNING) ?
                       repNode.getMetadata(type) : null ;
            }
        });
    }

    @Override
    @SecureR2Method
    public MetadataInfo getMetadata(final MetadataType type,
                                    final int seqNum,
                                    short serialVersion) {
        throw invalidR2MethodException();
    }

    @Override
    /*
     * TOPOLOGY requires USRVIEW, TABLE requires DBVIEW, and others require
     * INTLOPER.
     */
    @SecureInternalMethod
    public MetadataInfo getMetadata(final MetadataType type,
                                    final int seqNum,
                                    final AuthContext authCtx,
                                    short serialVersion) {

        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public MetadataInfo execute() {
                /* Check access rights */
                checkAccessPermission(new MetadataAccessContext(type));

                final ServiceStatus status =
                    repNodeService.getStatusTracker().getServiceStatus();

                return (status == ServiceStatus.RUNNING) ?
                       repNode.getMetadata(type, seqNum) : null ;
            }
        });
    }

    @Override
    @SecureR2Method
    public MetadataInfo getMetadata(final MetadataType type,
                                    final MetadataKey key,
                                    final int seqNum,
                                    short serialVersion) {

        throw invalidR2MethodException();
    }

    @Override
    /*
     * TOPOLOGY requires USRVIEW, TABLE requires DBVIEW, and others require
     * INTLOPER.
     */
    @SecureInternalMethod
    public MetadataInfo getMetadata(final MetadataType type,
                                    final MetadataKey key,
                                    final int seqNum,
                                    final AuthContext authCtx,
                                    short serialVersion) {

        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public MetadataInfo execute() {
                /* Check access rights */
                checkAccessPermission(new MetadataAccessContext(type));

                final ServiceStatus status =
                    repNodeService.getStatusTracker().getServiceStatus();

                return (status == ServiceStatus.RUNNING) ?
                       repNode.getMetadata(type, key, seqNum) : null ;
            }
        });
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.DBVIEW })
    public MetadataInfo getTableById(final long tableId,
                                     final AuthContext authCtx,
                                     short serialVersion) {
        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation() {
            @Override
            public MetadataInfo execute() {
                final ServiceStatus status =
                    repNodeService.getStatusTracker().getServiceStatus();
                return (status == ServiceStatus.RUNNING) ?
                       repNode.getTable(tableId) : null;
            }
         });
    }
    
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.DBVIEW })
    public MetadataInfo getTable(final String namespace,
                                 final String tableName,
                                 final int cost,
                                 AuthContext authCtx, short serialVersion) {
        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation() {
            @Override
            public MetadataInfo execute() {
                final ServiceStatus status =
                    repNodeService.getStatusTracker().getServiceStatus();
                return (status == ServiceStatus.RUNNING) ?
                       repNode.getTable(namespace, tableName, cost) : null;
            }
         });
    }

    @Override
    @SecureR2Method
    public void updateMetadata(final Metadata newMetadata,
                               short serialVersion) {

        throw invalidR2MethodException();
    }

    @Override
    @SecureInternalMethod
    public void updateMetadata(final Metadata newMetadata,
                               AuthContext authCtx,
                               short serialVersion) {

        faultHandler.execute(new ProcessFaultHandler.SimpleProcedure() {

            @Override
            public void execute() {
                assertRunning();

                /* Check access rights */
                checkAccessPermission(
                    new MetadataUpdateContext(newMetadata.getType()));
                if (!repNode.updateMetadata(newMetadata)) {
                    throw new
                       OperationFaultException("Update " +
                                               newMetadata.getType() +
                                               " metadata seq# " +
                                               newMetadata.getSequenceNumber() +
                                               " failed");
                }
            }
        });
    }

    @Override
    @SecureR2Method
    public int updateMetadata(final MetadataInfo metadataInfo,
                              short serialVersion) {

        throw invalidR2MethodException();
    }

    @Override
    @SecureInternalMethod
    public int updateMetadata(final MetadataInfo metadataInfo,
                              AuthContext authCtx,
                              short serialVersion) {

        return faultHandler.
            execute(new ProcessFaultHandler.SimpleOperation() {

            @Override
            public Integer execute() {
                assertRunning();

                /* Check access rights */
                checkAccessPermission(
                    new MetadataUpdateContext(metadataInfo.getType()));
                return repNode.updateMetadata(metadataInfo);
            }
        });
    }

    /* pre-4.4 */
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public boolean addIndexComplete(final String indexId,
                                    final String tableName,
                                    AuthContext authCtx,
                                    short serialVersion) {
        return addIndexComplete(null,
                                indexId,
                                tableName,
                                authCtx,
                                serialVersion);
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public boolean addIndexComplete(final String namespace,
                                    final String indexId,
                                    final String tableName,
                                    AuthContext authCtx,
                                    short serialVersion) {
        return faultHandler.execute
            (new ProcessFaultHandler.SimpleOperation() {
            @Override
            public Boolean execute() {
                return repNode.addIndexComplete(namespace, indexId, tableName);
            }
        });
    }

    /* pre-4.4 */
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public boolean removeTableDataComplete(final String tableName,
                                           AuthContext authCtx,
                                           short serialVersion) {
        return removeTableDataComplete(null,
                                       tableName,
                                       authCtx,
                                       serialVersion);
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER })
    public boolean removeTableDataComplete(final String namespace,
                                           final String tableName,
                                           AuthContext authCtx,
                                           short serialVersion) {
        return faultHandler.execute
            (new ProcessFaultHandler.SimpleOperation() {
            @Override
            public Boolean execute() {
                return repNode.removeTableDataComplete(namespace, tableName);
            }
        });
    }

    @Override
    /*
     * Require USERVIEW for Kerberos principals information so that all clients
     * are able to access. Kerberos principals information must be widely
     * available, since clients need to know all RNs' Kerberos information for
     * its attempts to obtian a new Kerbeors TGS token.
     */
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.USRVIEW })
    public KerberosPrincipals getKerberosPrincipals(AuthContext authCtx,
                                                    short serialVersion) {

        return faultHandler.execute(new ProcessFaultHandler.
            SimpleOperation() {
                @Override
                public KerberosPrincipals execute() {
                    return repNode.getKerberosPrincipals();
                }
        });
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER})
    public boolean startNetworkRestore(final RepNodeId sourceNode,
                                       final boolean retainOriginalLogFile,
                                       final long minVLSN,
                                       AuthContext authCtx,
                                       short serialVersion) {

        return faultHandler.execute
            (new ProcessFaultHandler.SimpleOperation() {

            @Override
            public Boolean execute() {
                return repNode.startAsyncNetworkRestore(sourceNode,
                                                        retainOriginalLogFile,
                                                        minVLSN);
            }
        });
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.INTLOPER})
    public NetworkRestoreStatus getNetworkRestoreStatus(AuthContext authCtx,
                                                        short serialVersion) {
        return faultHandler.execute(new ProcessFaultHandler.
            SimpleOperation() {
                @Override
                public NetworkRestoreStatus execute() {
                    return repNode.getAsyncNetworkRestoreStatus();
                }
        });
    }

    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.SYSVIEW })
    public ResourceInfo exchangeResourceInfo(
                                    final long sinceMillis,
                                    final Collection usageRecords,
                                    AuthContext authCtx,
                                    short serialVersion) {
        return faultHandler.
        execute(
            new ProcessFaultHandler.SimpleOperation() {

            @Override
            public ResourceInfo execute() {
                try {
                    assertRunning();
                    return repNode.exchangeResourceInfo(sinceMillis,
                                                        usageRecords);
                } catch (IllegalRepNodeServiceStateException irnsse) {
                    return null;
                }
            }
        });
    }

    /**
     * Verify that the caller of an operation has sufficient
     * authorization to access it.
     *
     * @param opCtx operation context
     * @throws SessionAccessException if there is an internal security error
     * @throws KVSecurityException if the a security exception is generated by
     * the requesting client
     */
    private void checkAccessPermission(OperationContext opCtx)
        throws SessionAccessException, KVSecurityException {

        final AccessChecker accessChecker =
            repNodeService.getRepNodeSecurity().getAccessChecker();

        if (accessChecker != null) {
            try {
                accessChecker.checkAccess(ExecutionContext.getCurrent(),
                                          opCtx);
            } catch (KVSecurityException kvse) {
                throw new ClientAccessException(kvse);
            }
        }
    }

    /**
     * Provides an implementation of OperationContext for access checking when
     * Metadata is requested.
     */
    private static class MetadataAccessContext implements OperationContext {
        private final MetadataType mdType;

        private MetadataAccessContext(MetadataType type) {
            this.mdType = type;
        }

        @Override
        public String describe() {
            return "Metadata request for type: " + mdType;
        }

        @Override
        public List getRequiredPrivileges() {
            switch(mdType) {
            case TABLE:
                return SystemPrivilege.dbviewPrivList;
            case TOPOLOGY:
                return SystemPrivilege.usrviewPrivList;
            default:
                return SystemPrivilege.internalPrivList;
            }
        }
    }


    /**
     * Provides an implementation of OperationContext for access checking when
     * Metadata is updated.
     */
    private static class MetadataUpdateContext implements OperationContext {
        private final MetadataType mdType;

        private MetadataUpdateContext(MetadataType type) {
            this.mdType = type;
        }

        @Override
        public String describe() {
            return "Metadata update for type: " + mdType;
        }

        @Override
        public List getRequiredPrivileges() {
            switch(mdType) {
            case TOPOLOGY:
                return SystemPrivilege.usrviewPrivList;
            default:
                return SystemPrivilege.internalPrivList;
            }
        }
    }

    /**
     * The status listener for updating the status receiver.
     */
    private class StatusListener implements ServiceStatusTracker.Listener {
        @Override
        public void update(ServiceStatusChange prevStatus,
                           ServiceStatusChange newStatus) {

            try {
                RepNodeAdminImpl.this.statusReceiver.updateNodeStatus(
                    newStatus);
            } catch (RemoteException re) {
                /* If we fail to deliver, who can we tell about it? */
                logger.log(Level.INFO,
                           "Failure to deliver status update to SNA: " +
                           re.getMessage());
                return;
            }
        }
    }

    /**
     * The perf stats listener for updating the status receiver.
     */
    private class OpStatsListener implements OperationsStatsTracker.Listener {
        @Override
        public void receiveStats(StatsPacket packet) {
            try {
                RepNodeAdminImpl.this.statusReceiver.receiveStats(packet);
            } catch (RemoteException re) {
                /* If we fail to deliver, who can we tell about it? */
                logger.log(Level.INFO,
                           "Failure to deliver perf stats to MgmtAgent: " +
                           re.getMessage());
                return;
            }
        }
    }

    /**
     * The parameter listener for updating the status receiver.
     */
    private class ParameterChangeListener implements ParameterListener {

        @Override
        public void newParameters(ParameterMap oldMap, ParameterMap newMap) {
            try {
                RepNodeAdminImpl.this.statusReceiver.receiveNewParams(newMap);
            } catch (RemoteException re) {
                /* If we fail to deliver, who can we tell about it? */
                logger.log(Level.INFO,
                           "Failure to deliver parameter change to MgmtAgent: " +
                           re.getMessage());
                return;
            }
        }
    }

    /**
     * The RN replication state listener for updating the replication state
     * receiver.
     */
    private class RnStateListener implements ReplicationStateListener {
        @Override
        public void doNotify(final StateChangeEvent sce) {
            new Thread() {
                @Override
                public void run() {
                    try {
                        RepNodeAdminImpl.this.statusReceiver.
                            updateReplicationState(sce);
                    } catch (RemoteException re) {
                        /* If we fail to deliver, who can we tell about it? */
                        logger.log(Level.INFO,
                                   "Failure to deliver replication state change"
                                   + " to MgmtAgent: " + re.getMessage());
                        return;
                    }
                }
            }.start();
        }
    }

    /**
     * Verify data for this repnode.
     */
    @Override
    @SecureAutoMethod(privileges = { KVStorePrivilegeLabel.SYSOPER })
    public void verifyData(final boolean verifyBtree,
                           final boolean verifyLog,
                           final boolean verifyIndex,
                           final boolean verifyRecord,
                           final long btreeDelay,
                           final long logDelay,
                           AuthContext authCtx,
                           short serialVersion)
        throws RemoteException, IOException {
        faultHandler.execute(new ProcessFaultHandler.Procedure() {

            @Override
            public void execute() throws IOException {
                assertRunning();
                repNode.verifyData(verifyBtree, verifyLog, verifyIndex,
                                   verifyRecord, btreeDelay, logDelay);

            }

        });

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy