001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.util; 018 019import java.io.IOException; 020import java.sql.SQLException; 021import java.util.Map; 022import java.util.concurrent.TimeUnit; 023import java.util.concurrent.atomic.AtomicBoolean; 024 025import org.apache.activemq.broker.BrokerService; 026import org.apache.activemq.broker.SuppressReplyException; 027import org.apache.activemq.broker.region.Destination; 028import org.apache.activemq.broker.region.Queue; 029import org.apache.activemq.broker.region.RegionBroker; 030import org.apache.activemq.command.ActiveMQDestination; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034/** 035 * @org.apache.xbean.XBean 036 */ 037 public class DefaultIOExceptionHandler implements IOExceptionHandler { 038 039 private static final Logger LOG = LoggerFactory 040 .getLogger(DefaultIOExceptionHandler.class); 041 protected BrokerService broker; 042 private boolean ignoreAllErrors = false; 043 private boolean ignoreNoSpaceErrors = true; 044 private boolean ignoreSQLExceptions = true; 045 private boolean stopStartConnectors = false; 046 private String noSpaceMessage = "space"; 047 private String sqlExceptionMessage = ""; // match all 048 private long resumeCheckSleepPeriod = 5*1000; 049 private AtomicBoolean handlingException = new AtomicBoolean(false); 050 051 public void handle(IOException exception) { 052 if (ignoreAllErrors) { 053 LOG.info("Ignoring IO exception, " + exception, exception); 054 return; 055 } 056 057 if (ignoreNoSpaceErrors) { 058 Throwable cause = exception; 059 while (cause != null && cause instanceof IOException) { 060 String message = cause.getMessage(); 061 if (message != null && message.contains(noSpaceMessage)) { 062 LOG.info("Ignoring no space left exception, " + exception, exception); 063 return; 064 } 065 cause = cause.getCause(); 066 } 067 } 068 069 if (ignoreSQLExceptions) { 070 Throwable cause = exception; 071 while (cause != null) { 072 String message = cause.getMessage(); 073 if (cause instanceof SQLException && message.contains(sqlExceptionMessage)) { 074 LOG.info("Ignoring SQLException, " + exception, cause); 075 return; 076 } 077 cause = cause.getCause(); 078 } 079 } 080 081 if (stopStartConnectors) { 082 if (handlingException.compareAndSet(false, true)) { 083 LOG.info("Initiating stop/restart of transports on " + broker + " due to IO exception, " + exception, exception); 084 085 new Thread("IOExceptionHandler: stop transports") { 086 public void run() { 087 try { 088 ServiceStopper stopper = new ServiceStopper(); 089 broker.stopAllConnectors(stopper); 090 LOG.info("Successfully stopped transports on " + broker); 091 } catch (Exception e) { 092 LOG.warn("Failure occurred while stopping broker connectors", e); 093 } finally { 094 // resume again 095 new Thread("IOExceptionHandler: restart transports") { 096 public void run() { 097 try { 098 while (hasLockOwnership() && isPersistenceAdapterDown()) { 099 LOG.info("waiting for broker persistence adapter checkpoint to succeed before restarting transports"); 100 TimeUnit.MILLISECONDS.sleep(resumeCheckSleepPeriod); 101 } 102 if (hasLockOwnership()) { 103 Map<ActiveMQDestination, Destination> destinations = ((RegionBroker)broker.getRegionBroker()).getDestinationMap(); 104 for (Destination destination : destinations.values()) { 105 106 if (destination instanceof Queue) { 107 Queue queue = (Queue)destination; 108 if (queue.isResetNeeded()) { 109 queue.clearPendingMessages(); 110 } 111 } 112 } 113 broker.startAllConnectors(); 114 LOG.info("Successfully restarted transports on " + broker); 115 } 116 } catch (Exception e) { 117 LOG.warn("Stopping " + broker + " due to failure restarting transports", e); 118 stopBroker(e); 119 } finally { 120 handlingException.compareAndSet(true, false); 121 } 122 } 123 124 private boolean isPersistenceAdapterDown() { 125 boolean checkpointSuccess = false; 126 try { 127 broker.getPersistenceAdapter().checkpoint(true); 128 checkpointSuccess = true; 129 } catch (Throwable ignored) { 130 } 131 return !checkpointSuccess; 132 } 133 }.start(); 134 135 136 } 137 } 138 }.start(); 139 } 140 141 throw new SuppressReplyException("Stop/RestartTransportsInitiated", exception); 142 } 143 144 if (handlingException.compareAndSet(false, true)) { 145 stopBroker(exception); 146 } 147 148 // we don't want to propagate the exception back to the client 149 // They will see a delay till they see a disconnect via socket.close 150 // at which point failover: can kick in. 151 throw new SuppressReplyException("ShutdownBrokerInitiated", exception); 152 } 153 154 private void stopBroker(Exception exception) { 155 LOG.info("Stopping " + broker + " due to exception, " + exception, exception); 156 new Thread("IOExceptionHandler: stopping " + broker) { 157 public void run() { 158 try { 159 if( broker.isRestartAllowed() ) { 160 broker.requestRestart(); 161 } 162 broker.stop(); 163 } catch (Exception e) { 164 LOG.warn("Failure occurred while stopping broker", e); 165 } 166 } 167 }.start(); 168 } 169 170 protected boolean hasLockOwnership() throws IOException { 171 return true; 172 } 173 174 public void setBrokerService(BrokerService broker) { 175 this.broker = broker; 176 } 177 178 public boolean isIgnoreAllErrors() { 179 return ignoreAllErrors; 180 } 181 182 public void setIgnoreAllErrors(boolean ignoreAllErrors) { 183 this.ignoreAllErrors = ignoreAllErrors; 184 } 185 186 public boolean isIgnoreNoSpaceErrors() { 187 return ignoreNoSpaceErrors; 188 } 189 190 public void setIgnoreNoSpaceErrors(boolean ignoreNoSpaceErrors) { 191 this.ignoreNoSpaceErrors = ignoreNoSpaceErrors; 192 } 193 194 public String getNoSpaceMessage() { 195 return noSpaceMessage; 196 } 197 198 public void setNoSpaceMessage(String noSpaceMessage) { 199 this.noSpaceMessage = noSpaceMessage; 200 } 201 202 public boolean isIgnoreSQLExceptions() { 203 return ignoreSQLExceptions; 204 } 205 206 public void setIgnoreSQLExceptions(boolean ignoreSQLExceptions) { 207 this.ignoreSQLExceptions = ignoreSQLExceptions; 208 } 209 210 public String getSqlExceptionMessage() { 211 return sqlExceptionMessage; 212 } 213 214 public void setSqlExceptionMessage(String sqlExceptionMessage) { 215 this.sqlExceptionMessage = sqlExceptionMessage; 216 } 217 218 public boolean isStopStartConnectors() { 219 return stopStartConnectors; 220 } 221 222 public void setStopStartConnectors(boolean stopStartConnectors) { 223 this.stopStartConnectors = stopStartConnectors; 224 } 225 226 public long getResumeCheckSleepPeriod() { 227 return resumeCheckSleepPeriod; 228 } 229 230 public void setResumeCheckSleepPeriod(long resumeCheckSleepPeriod) { 231 this.resumeCheckSleepPeriod = resumeCheckSleepPeriod; 232 } 233}