diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManager.java index 682c3484c04..6ee91cb0ff8 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManager.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; +import java.nio.channels.Channel; +import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.Date; @@ -233,7 +235,7 @@ public void startBackup() throws NodeManagerException { ActiveMQServerLogger.LOGGER.waitingToBecomeBackup(); try { backupLock = lock(FileLockNodeManager.BACKUP_LOCK_POS); - } catch (ActiveMQLockAcquisitionTimeoutException e) { + } catch (ClosedChannelException | ActiveMQLockAcquisitionTimeoutException e) { throw new NodeManagerException(e); } ActiveMQServerLogger.LOGGER.gotBackupLock(); @@ -267,7 +269,7 @@ public void activationComplete() { } } }; - } catch (ActiveMQLockAcquisitionTimeoutException e) { + } catch (ClosedChannelException | ActiveMQLockAcquisitionTimeoutException e) { throw new NodeManagerException(e); } } @@ -328,7 +330,7 @@ private void writeFileLockStatus(byte status) throws NodeManagerException { bb.put(status); bb.position(0); try { - if (!channel.isOpen()) { + if (channel == null || !channel.isOpen()) { setUpServerLockFile(); } FileLock lock = null; @@ -412,7 +414,7 @@ protected FileLock tryLock(final int lockPos) throws IOException { } } - protected FileLock lock(final int lockPosition) throws ActiveMQLockAcquisitionTimeoutException { + protected FileLock lock(final int lockPosition) throws ClosedChannelException, ActiveMQLockAcquisitionTimeoutException { long start = System.nanoTime(); boolean isRecurringFailure = false; @@ -437,6 +439,9 @@ protected FileLock lock(final int lockPosition) throws ActiveMQLockAcquisitionTi } else { return lock; } + } catch (ClosedChannelException e) { + // This is an unrecoverable error as there's no guarantee the channel will ever be opened again. + throw e; } catch (IOException e) { // IOException during trylock() may be a temporary issue, e.g. NFS volume not being accessible @@ -575,4 +580,8 @@ private boolean hasBeenModified(byte state) { return modified; } } + + protected Channel getChannel() { + return channel; + } } diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManagerTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManagerTest.java new file mode 100644 index 00000000000..c49cd6de6c0 --- /dev/null +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManagerTest.java @@ -0,0 +1,47 @@ +/* + * 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.activemq.artemis.core.server.impl; + +import java.io.File; +import java.nio.channels.ClosedChannelException; + +import org.apache.activemq.artemis.tests.extensions.TargetTempDirFactory; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.io.TempDir; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class FileLockNodeManagerTest { + + @TempDir(factory = TargetTempDirFactory.class) + public File temporaryFolder; + + @Test + @Timeout(3) + public void testChannelClosed() throws Exception { + FileLockNodeManager manager = new FileLockNodeManager(temporaryFolder, false); + + // calling this method sets up the internal FileChannel as it would be in normal usage + manager.pausePrimaryServer(); + + // now close the channel so we can ensure it throws + manager.getChannel().close(); + + assertThrows(ClosedChannelException.class, () -> manager.lock(0)); + } +}