/* * 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.igfs; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.configuration.FileSystemConfiguration; import org.apache.ignite.igfs.IgfsIpcEndpointConfiguration; import org.apache.ignite.internal.util.ipc.IpcEndpointBindException; import org.apache.ignite.internal.util.ipc.IpcServerEndpoint; import org.apache.ignite.internal.util.typedef.C1; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.internal.util.worker.GridWorker; import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.thread.IgniteThread; import static org.apache.ignite.igfs.IgfsIpcEndpointType.TCP; /** * IGFS server manager. */ public class IgfsServerManager extends IgfsManager { /** IPC server rebind interval. */ private static final long REBIND_INTERVAL = 3000; /** Collection of servers to maintain. */ private Collection<IgfsServer> srvrs; /** Server port binders. */ private BindWorker bindWorker; /** Kernal start latch. */ private CountDownLatch kernalStartLatch = new CountDownLatch(1); /** {@inheritDoc} */ @Override protected void start0() throws IgniteCheckedException { FileSystemConfiguration igfsCfg = igfsCtx.configuration(); if (igfsCfg.isIpcEndpointEnabled()) { IgfsIpcEndpointConfiguration ipcCfg = igfsCfg.getIpcEndpointConfiguration(); if (ipcCfg == null) ipcCfg = new IgfsIpcEndpointConfiguration(); bind(ipcCfg, /*management*/false); } if (igfsCfg.getManagementPort() >= 0) { IgfsIpcEndpointConfiguration mgmtIpcCfg = new IgfsIpcEndpointConfiguration(); mgmtIpcCfg.setType(TCP); mgmtIpcCfg.setPort(igfsCfg.getManagementPort()); bind(mgmtIpcCfg, /*management*/true); } if (bindWorker != null) new IgniteThread(bindWorker).start(); } /** * Tries to start server endpoint with specified configuration. If failed, will print warning and start a thread * that will try to periodically start this endpoint. * * @param endpointCfg Endpoint configuration to start. * @param mgmt {@code True} if endpoint is management. * @throws IgniteCheckedException If failed. */ private void bind(final IgfsIpcEndpointConfiguration endpointCfg, final boolean mgmt) throws IgniteCheckedException { if (srvrs == null) srvrs = new ConcurrentLinkedQueue<>(); IgfsServer ipcSrv = new IgfsServer(igfsCtx, endpointCfg, mgmt); try { ipcSrv.start(); srvrs.add(ipcSrv); } catch (IpcEndpointBindException ignored) { int port = ipcSrv.getIpcServerEndpoint().getPort(); String portMsg = port != -1 ? " Failed to bind to port (is port already in use?): " + port : ""; U.warn(log, "Failed to start IGFS " + (mgmt ? "management " : "") + "endpoint " + "(will retry every " + (REBIND_INTERVAL / 1000) + "s)." + portMsg); if (bindWorker == null) bindWorker = new BindWorker(); bindWorker.addConfiguration(endpointCfg, mgmt); } } /** * @return Collection of active endpoints. */ public Collection<IpcServerEndpoint> endpoints() { return F.viewReadOnly(srvrs, new C1<IgfsServer, IpcServerEndpoint>() { @Override public IpcServerEndpoint apply(IgfsServer e) { return e.getIpcServerEndpoint(); } }); } /** {@inheritDoc} */ @Override protected void onKernalStart0() throws IgniteCheckedException { if (!F.isEmpty(srvrs)) { for (IgfsServer srv : srvrs) srv.onKernalStart(); } kernalStartLatch.countDown(); } /** {@inheritDoc} */ @Override protected void stop0(boolean cancel) { // Safety. kernalStartLatch.countDown(); if (bindWorker != null) { bindWorker.cancel(); U.join(bindWorker, log); } if (!F.isEmpty(srvrs)) { for (IgfsServer srv : srvrs) srv.stop(cancel); } } /** * Bind worker. */ @SuppressWarnings("BusyWait") private class BindWorker extends GridWorker { /** Configurations to bind. */ private Collection<IgniteBiTuple<IgfsIpcEndpointConfiguration, Boolean>> bindCfgs = new LinkedList<>(); /** * Constructor. */ private BindWorker() { super(igfsCtx.kernalContext().igniteInstanceName(), "bind-worker", igfsCtx.kernalContext().log(IgfsServerManager.class)); } /** * Adds configuration to bind on. Should not be called after thread start. * * @param cfg Configuration. * @param mgmt Management flag. */ public void addConfiguration(IgfsIpcEndpointConfiguration cfg, boolean mgmt) { bindCfgs.add(F.t(cfg, mgmt)); } /** {@inheritDoc} */ @Override protected void body() throws InterruptedException { kernalStartLatch.await(); while (!isCancelled()) { Thread.sleep(REBIND_INTERVAL); Iterator<IgniteBiTuple<IgfsIpcEndpointConfiguration, Boolean>> it = bindCfgs.iterator(); while (it.hasNext()) { IgniteBiTuple<IgfsIpcEndpointConfiguration, Boolean> cfg = it.next(); IgfsServer ipcSrv = new IgfsServer(igfsCtx, cfg.get1(), cfg.get2()); try { ipcSrv.start(); ipcSrv.onKernalStart(); srvrs.add(ipcSrv); it.remove(); } catch (IgniteCheckedException e) { if (log.isDebugEnabled()) log.debug("Failed to bind IGFS endpoint [cfg=" + cfg + ", err=" + e.getMessage() + ']'); } } if (bindCfgs.isEmpty()) break; } } } }