| /* |
| * 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.spi; |
| |
| import java.net.SocketException; |
| import java.net.SocketTimeoutException; |
| import org.apache.ignite.internal.util.typedef.X; |
| import org.apache.ignite.internal.util.typedef.internal.U; |
| |
| /** |
| * Object that incorporates logic that determines a timeout value for the next network related operation and checks |
| * whether a failure detection timeout is reached or not. |
| * |
| * A new instance of the class should be created for every complex network based operations that usually consists of |
| * request and response parts. |
| * |
| */ |
| public class IgniteSpiOperationTimeoutHelper { |
| /** Flag whether to use timeout. */ |
| private final boolean timeoutEnabled; |
| |
| /** Time in nanos which cannot be reached for current operation. */ |
| private final long timeoutThreshold; |
| |
| /** |
| * Constructor. |
| * |
| * @param adapter SPI adapter. |
| * @param srvOp {@code True} if communicates with server node. |
| */ |
| public IgniteSpiOperationTimeoutHelper(IgniteSpiAdapter adapter, boolean srvOp) { |
| this(adapter, srvOp, -1, -1); |
| } |
| |
| /** |
| * Creates timeout helper based on time of last related operation. |
| * |
| * @param adapter SPI adapter. |
| * @param srvOp {@code True} if communicates with server node. |
| * @param lastRelatedOperationTime Time of last related operation in nanos. Ignored if negative, 0 or |
| * {@code adapter.failureDetectionTimeoutEnabled()} is false. |
| * @param absoluteThreshold Absolute time threshold (nanos) which must not be reached. Ignored if negative or 0. |
| */ |
| public IgniteSpiOperationTimeoutHelper(IgniteSpiAdapter adapter, boolean srvOp, long lastRelatedOperationTime, |
| long absoluteThreshold) { |
| timeoutEnabled = adapter.failureDetectionTimeoutEnabled(); |
| |
| if (timeoutEnabled) { |
| long timeout = (lastRelatedOperationTime > 0 ? lastRelatedOperationTime : System.nanoTime()) + |
| U.millisToNanos(srvOp ? adapter.failureDetectionTimeout() : adapter.clientFailureDetectionTimeout()); |
| |
| if (absoluteThreshold > 0 && timeout > absoluteThreshold) |
| timeout = absoluteThreshold; |
| |
| timeoutThreshold = timeout; |
| } |
| else { |
| // Save absolute threshold if it is set. |
| timeoutThreshold = absoluteThreshold > 0 ? absoluteThreshold : 0; |
| } |
| } |
| |
| /** |
| * Returns a timeout value to use for the next network operation. |
| * |
| * If failure detection timeout is enabled then the returned value is a portion of time left since the last time |
| * this method is called. If the timeout is disabled then {@code dfltTimeout} is returned. |
| * |
| * @param dfltTimeout Timeout to use if failure detection timeout is disabled. |
| * @return Timeout in milliseconds. |
| * @throws IgniteSpiOperationTimeoutException If failure detection timeout is reached for an operation that uses |
| * this {@code IgniteSpiOperationTimeoutController}. |
| */ |
| public long nextTimeoutChunk(long dfltTimeout) throws IgniteSpiOperationTimeoutException { |
| long now = System.nanoTime(); |
| |
| long left; |
| |
| if (timeoutEnabled) |
| left = timeoutThreshold - now; |
| else { |
| left = U.millisToNanos(dfltTimeout); |
| |
| if (timeoutThreshold > 0 && now + left >= timeoutThreshold) |
| left = timeoutThreshold - now; |
| } |
| |
| if (left <= 0) |
| throw new IgniteSpiOperationTimeoutException("Network operation timed out."); |
| |
| return U.nanosToMillis(left); |
| } |
| |
| /** |
| * Checks whether the given {@link Exception} is a timeout. |
| * |
| * @param e Exception to check. |
| * @return {@code True} if given exception is a timeout. {@code False} otherwise. |
| */ |
| public boolean checkFailureTimeoutReached(Exception e) { |
| return X.hasCause(e, IgniteSpiOperationTimeoutException.class, SocketTimeoutException.class, SocketException.class); |
| } |
| } |