/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ignite.internal.processors.cluster; import java.io.Serializable; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Timer; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.IgniteProperties; import org.apache.ignite.internal.cluster.IgniteClusterImpl; import org.apache.ignite.internal.processors.GridProcessorAdapter; import org.apache.ignite.internal.util.GridTimerTask; import org.apache.ignite.internal.util.future.IgniteFinishedFutureImpl; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.lang.IgniteFuture; import org.apache.ignite.spi.discovery.DiscoveryDataBag; import org.apache.ignite.spi.discovery.DiscoveryDataBag.GridDiscoveryData; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER; import static org.apache.ignite.internal.GridComponent.DiscoveryDataExchangeType.CLUSTER_PROC; import static org.apache.ignite.internal.IgniteVersionUtils.VER_STR; /** * */ public class ClusterProcessor extends GridProcessorAdapter { /** */ private static final String ATTR_UPDATE_NOTIFIER_STATUS = "UPDATE_NOTIFIER_STATUS"; /** Periodic version check delay. */ private static final long PERIODIC_VER_CHECK_DELAY = 1000 * 60 * 60; // Every hour. /** Periodic version check delay. */ private static final long PERIODIC_VER_CHECK_CONN_TIMEOUT = 10 * 1000; // 10 seconds. /** */ private IgniteClusterImpl cluster; /** */ private final AtomicBoolean notifyEnabled = new AtomicBoolean(); /** */ @GridToStringExclude private Timer updateNtfTimer; /** Version checker. */ @GridToStringExclude private GridUpdateNotifier verChecker; /** * @param ctx Kernal context. */ public ClusterProcessor(GridKernalContext ctx) { super(ctx); notifyEnabled.set(IgniteSystemProperties.getBoolean(IGNITE_UPDATE_NOTIFIER, Boolean.parseBoolean(IgniteProperties.get("ignite.update.notifier.enabled.by.default")))); cluster = new IgniteClusterImpl(ctx); } /** * @return Cluster. */ public IgniteClusterImpl get() { return cluster; } /** * @return Client reconnect future. */ public IgniteFuture<?> clientReconnectFuture() { IgniteFuture<?> fut = cluster.clientReconnectFuture(); return fut != null ? fut : new IgniteFinishedFutureImpl<>(); } /** {@inheritDoc} */ @Nullable @Override public DiscoveryDataExchangeType discoveryDataType() { return CLUSTER_PROC; } /** {@inheritDoc} */ @Override public void collectJoiningNodeData(DiscoveryDataBag dataBag) { dataBag.addJoiningNodeData(CLUSTER_PROC.ordinal(), getDiscoveryData()); } /** {@inheritDoc} */ @Override public void collectGridNodeData(DiscoveryDataBag dataBag) { dataBag.addNodeSpecificData(CLUSTER_PROC.ordinal(), getDiscoveryData()); } /** * @return Discovery data. */ private Serializable getDiscoveryData() { HashMap<String, Object> map = new HashMap<>(); map.put(ATTR_UPDATE_NOTIFIER_STATUS, notifyEnabled.get()); return map; } /** {@inheritDoc} */ @Override public void onGridDataReceived(GridDiscoveryData data) { Map<UUID, Serializable> nodeSpecData = data.nodeSpecificData(); if (nodeSpecData != null) { Boolean lstFlag = findLastFlag(nodeSpecData.values()); if (lstFlag != null) notifyEnabled.set(lstFlag); } } /** * @param vals collection to seek through. */ private Boolean findLastFlag(Collection<Serializable> vals) { Boolean flag = null; for (Serializable ser : vals) { if (ser != null) { Map<String, Object> map = (Map<String, Object>) ser; if (map.containsKey(ATTR_UPDATE_NOTIFIER_STATUS)) flag = (Boolean) map.get(ATTR_UPDATE_NOTIFIER_STATUS); } } return flag; } /** {@inheritDoc} */ @Override public void onKernalStart(boolean activeOnStart) throws IgniteCheckedException { if (notifyEnabled.get()) { try { verChecker = new GridUpdateNotifier(ctx.igniteInstanceName(), VER_STR, ctx.gateway(), ctx.plugins().allProviders(), false); updateNtfTimer = new Timer("ignite-update-notifier-timer", true); // Setup periodic version check. updateNtfTimer.scheduleAtFixedRate( new UpdateNotifierTimerTask((IgniteKernal)ctx.grid(), verChecker, notifyEnabled), 0, PERIODIC_VER_CHECK_DELAY); } catch (IgniteCheckedException e) { if (log.isDebugEnabled()) log.debug("Failed to create GridUpdateNotifier: " + e); } } } /** {@inheritDoc} */ @Override public void stop(boolean cancel) throws IgniteCheckedException { // Cancel update notification timer. if (updateNtfTimer != null) updateNtfTimer.cancel(); if (verChecker != null) verChecker.stop(); } /** * Disables update notifier. */ public void disableUpdateNotifier() { notifyEnabled.set(false); } /** * @return Update notifier status. */ public boolean updateNotifierEnabled() { return notifyEnabled.get(); } /** * @return Latest version string. */ public String latestVersion() { return verChecker != null ? verChecker.latestVersion() : null; } /** * Update notifier timer task. */ private static class UpdateNotifierTimerTask extends GridTimerTask { /** Reference to kernal. */ private final WeakReference<IgniteKernal> kernalRef; /** Logger. */ private final IgniteLogger log; /** Version checker. */ private final GridUpdateNotifier verChecker; /** Whether this is the first run. */ private boolean first = true; /** */ private final AtomicBoolean notifyEnabled; /** * Constructor. * * @param kernal Kernal. * @param verChecker Version checker. */ private UpdateNotifierTimerTask(IgniteKernal kernal, GridUpdateNotifier verChecker, AtomicBoolean notifyEnabled) { kernalRef = new WeakReference<>(kernal); log = kernal.context().log(UpdateNotifierTimerTask.class); this.verChecker = verChecker; this.notifyEnabled = notifyEnabled; } /** {@inheritDoc} */ @Override public void safeRun() throws InterruptedException { if (!notifyEnabled.get()) return; if (!first) { IgniteKernal kernal = kernalRef.get(); if (kernal != null) verChecker.topologySize(kernal.cluster().nodes().size()); } verChecker.checkForNewVersion(log); // Just wait for 10 secs. Thread.sleep(PERIODIC_VER_CHECK_CONN_TIMEOUT); // Just wait another 60 secs in order to get // version info even on slow connection. for (int i = 0; i < 60 && verChecker.latestVersion() == null; i++) Thread.sleep(1000); // Report status if one is available. // No-op if status is NOT available. verChecker.reportStatus(log); if (first) { first = false; verChecker.reportOnlyNew(true); } } } }