/** * Copyright 2016 LinkedIn Corp. All rights reserved. * * Licensed 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. */ package com.github.ambry.commons; import com.github.ambry.clustermap.ClusterMap; import com.github.ambry.clustermap.ReplicaEventType; import com.github.ambry.clustermap.ReplicaId; import com.github.ambry.network.ConnectionPoolTimeoutException; import com.github.ambry.network.NetworkClientErrorCode; import java.io.IOException; import java.net.SocketException; /** * ResponseHandler can be used by components whenever an operation encounters an error or an exception, to delegate * the responsibility of conveying appropriate replica related errors to the cluster map. * It can also be used to convey the information that a replica related operation was successful. * The cluster map uses this information to set soft states and dynamically handle failures. */ public class ResponseHandler { private ClusterMap clusterMap; /** * Construct a ResponseHandler instance. * @param clusterMap the {@link ClusterMap} associated with the cluster. */ public ResponseHandler(ClusterMap clusterMap) { this.clusterMap = clusterMap; } /** * Act on an event in the form of a {@link ServerErrorCode} on the given {@link ReplicaId} * @param replicaId the {@link ReplicaId} to which the request that received the error was made. * @param errorCode the {@link ServerErrorCode} received for the request. */ private void onServerEvent(ReplicaId replicaId, ServerErrorCode errorCode) { switch (errorCode) { case IO_Error: case Disk_Unavailable: clusterMap.onReplicaEvent(replicaId, ReplicaEventType.Disk_Error); break; case Partition_ReadOnly: clusterMap.onReplicaEvent(replicaId, ReplicaEventType.Partition_ReadOnly); //fall through default: clusterMap.onReplicaEvent(replicaId, ReplicaEventType.Disk_Ok); break; } // Regardless of what the error code is (or there is no error), it is a node response event. clusterMap.onReplicaEvent(replicaId, ReplicaEventType.Node_Response); } /** * Act on an event in the form of a {@link NetworkClientErrorCode} on the given {@link ReplicaId} * @param replicaId the {@link ReplicaId} to which the request that received the error was made. * @param errorCode the {@link NetworkClientErrorCode} received for the request. */ private void onNetworkEvent(ReplicaId replicaId, NetworkClientErrorCode errorCode) { switch (errorCode) { case NetworkError: clusterMap.onReplicaEvent(replicaId, ReplicaEventType.Node_Timeout); break; default: break; } } /** * Perform the action when a request to the given {@link ReplicaId} is met with an exception. * @param replicaId the {@link ReplicaId} to which the request that received the exception was made. * @param e the {@link Exception} received. */ private void onException(ReplicaId replicaId, Exception e) { if (e instanceof SocketException || e instanceof IOException || e instanceof ConnectionPoolTimeoutException) { clusterMap.onReplicaEvent(replicaId, ReplicaEventType.Node_Timeout); } } /** * Action to take when a request to the given {@link ReplicaId} results in an event. The event could come in the * form of an {@link Exception}, {@link NetworkClientErrorCode}, or a {@link ServerErrorCode} (possibly indicating * that there was no error). * @param replicaId the {@link ReplicaId} to which the request was sent. * @param event the type of the event. The event could be an {@link Exception}, {@link NetworkClientErrorCode} or a * {@link ServerErrorCode}. */ public void onEvent(ReplicaId replicaId, Object event) { if (event instanceof ServerErrorCode) { onServerEvent(replicaId, (ServerErrorCode) event); } else if (event instanceof Exception) { onException(replicaId, (Exception) event); } else if (event instanceof NetworkClientErrorCode) { onNetworkEvent(replicaId, (NetworkClientErrorCode) event); } } }