ARTEMIS-187 Hold lock between server running and data tools to avoid data damaged
This commit is contained in:
parent
dab882030c
commit
511bfc7e15
|
@ -63,7 +63,11 @@ public class Artemis {
|
|||
System.err.println(configException.getMessage());
|
||||
System.out.println();
|
||||
System.out.println("Configuration should be specified as 'scheme:location'. Default configuration is 'xml:${ARTEMIS_INSTANCE}/etc/bootstrap.xml'");
|
||||
return null;
|
||||
return configException;
|
||||
}
|
||||
catch (CLIException cliException) {
|
||||
System.err.println(cliException.getMessage());
|
||||
return cliException;
|
||||
}
|
||||
catch (RuntimeException re) {
|
||||
System.err.println(re.getMessage());
|
||||
|
@ -72,7 +76,7 @@ public class Artemis {
|
|||
Cli<Action> parser = builder(null).build();
|
||||
|
||||
parser.parse("help").execute(ActionContext.system());
|
||||
return null;
|
||||
return re;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* 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.cli;
|
||||
|
||||
public class CLIException extends Exception {
|
||||
|
||||
public CLIException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,8 @@ package org.apache.activemq.artemis.cli.commands;
|
|||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.FileLock;
|
||||
|
||||
import io.airlift.airline.Arguments;
|
||||
import io.airlift.airline.Help;
|
||||
|
@ -26,6 +28,7 @@ import io.airlift.airline.Option;
|
|||
import io.airlift.airline.model.CommandGroupMetadata;
|
||||
import io.airlift.airline.model.CommandMetadata;
|
||||
import io.airlift.airline.model.GlobalMetadata;
|
||||
import org.apache.activemq.artemis.cli.CLIException;
|
||||
import org.apache.activemq.artemis.core.config.FileDeploymentManager;
|
||||
import org.apache.activemq.artemis.core.config.impl.FileConfiguration;
|
||||
import org.apache.activemq.artemis.dto.BrokerDTO;
|
||||
|
@ -72,6 +75,35 @@ public abstract class Configurable extends ActionAbstract {
|
|||
}
|
||||
}
|
||||
|
||||
// There should be one lock per VM
|
||||
// These will be locked as long as the VM is running
|
||||
private static RandomAccessFile serverLockFile = null;
|
||||
private static FileLock serverLockLock = null;
|
||||
|
||||
protected static void lock(File journalPlace) throws Exception {
|
||||
journalPlace.mkdirs();
|
||||
File fileLock = new File(journalPlace, "srv.lock");
|
||||
RandomAccessFile file = new RandomAccessFile(fileLock, "rw");
|
||||
serverLockLock = file.getChannel().tryLock();
|
||||
if (serverLockLock == null) {
|
||||
throw new CLIException("Error: There is another process using the journal at " + journalPlace + ". Cannot start the process!");
|
||||
}
|
||||
}
|
||||
|
||||
public static void unlock() {
|
||||
try {
|
||||
if (serverLockFile != null) {
|
||||
serverLockFile.close();
|
||||
}
|
||||
|
||||
if (serverLockLock != null) {
|
||||
serverLockLock.close();
|
||||
}
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
protected FileConfiguration getFileConfiguration() throws Exception {
|
||||
if (fileConfiguration == null) {
|
||||
if (getBrokerInstance() == null) {
|
||||
|
|
|
@ -64,6 +64,10 @@ public class Run extends Configurable {
|
|||
public Object execute(ActionContext context) throws Exception {
|
||||
super.execute(context);
|
||||
|
||||
FileConfiguration fileConfiguration = getFileConfiguration();
|
||||
|
||||
lock(fileConfiguration.getJournalLocation());
|
||||
|
||||
Artemis.printBanner();
|
||||
|
||||
createDirectories(getFileConfiguration());
|
||||
|
@ -89,7 +93,6 @@ public class Run extends Configurable {
|
|||
component.start();
|
||||
components.add(component);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,15 +19,14 @@ package org.apache.activemq.artemis.cli.commands.tools;
|
|||
import java.io.File;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.activemq.artemis.cli.commands.Action;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.io.IOCriticalErrorListener;
|
||||
import org.apache.activemq.artemis.core.journal.impl.JournalImpl;
|
||||
import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory;
|
||||
import org.apache.activemq.artemis.core.journal.impl.JournalImpl;
|
||||
|
||||
@Command(name = "compact", description = "Compacts the journal of a non running server")
|
||||
public final class CompactJournal extends DataAbstract implements Action {
|
||||
public final class CompactJournal extends LockAbstract {
|
||||
|
||||
@Override
|
||||
public Object execute(ActionContext context) throws Exception {
|
||||
|
@ -35,7 +34,10 @@ public final class CompactJournal extends DataAbstract implements Action {
|
|||
try {
|
||||
Configuration configuration = getFileConfiguration();
|
||||
compactJournal(new File(getJournal()), "activemq-data", "amq", configuration.getJournalMinFiles(), configuration.getJournalFileSize(), null);
|
||||
System.out.println("Compactation succeeded for " + getJournal());
|
||||
compactJournal(new File(getBinding()), "activemq-bindings", "bindings", 2, 1048576, null);
|
||||
System.out.println("Compactation succeeded for " + getBinding());
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
treatError(e, "data", "compact");
|
||||
|
|
|
@ -29,17 +29,15 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.activemq.artemis.cli.commands.Action;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
import org.apache.activemq.artemis.cli.commands.Configurable;
|
||||
import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory;
|
||||
import org.apache.activemq.artemis.core.journal.RecordInfo;
|
||||
import org.apache.activemq.artemis.core.journal.impl.JournalImpl;
|
||||
import org.apache.activemq.artemis.core.journal.impl.JournalRecord;
|
||||
import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory;
|
||||
import org.apache.activemq.artemis.utils.Base64;
|
||||
|
||||
@Command(name = "decode", description = "Decode a journal's internal format into a new journal set of files")
|
||||
public class DecodeJournal extends Configurable implements Action {
|
||||
public class DecodeJournal extends LockAbstract {
|
||||
|
||||
@Option(name = "--directory", description = "The journal folder (default journal folder from broker.xml)")
|
||||
public String directory;
|
||||
|
|
|
@ -24,19 +24,17 @@ import java.util.List;
|
|||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.activemq.artemis.cli.commands.Action;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
import org.apache.activemq.artemis.cli.commands.Configurable;
|
||||
import org.apache.activemq.artemis.core.journal.RecordInfo;
|
||||
import org.apache.activemq.artemis.core.io.SequentialFileFactory;
|
||||
import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory;
|
||||
import org.apache.activemq.artemis.core.journal.RecordInfo;
|
||||
import org.apache.activemq.artemis.core.journal.impl.JournalFile;
|
||||
import org.apache.activemq.artemis.core.journal.impl.JournalImpl;
|
||||
import org.apache.activemq.artemis.core.journal.impl.JournalReaderCallback;
|
||||
import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory;
|
||||
import org.apache.activemq.artemis.utils.Base64;
|
||||
|
||||
@Command(name = "encode", description = "Encode a set of journal files into an internal encoded data format")
|
||||
public class EncodeJournal extends Configurable implements Action {
|
||||
public class EncodeJournal extends LockAbstract {
|
||||
|
||||
@Option(name = "--directory", description = "The journal folder (default the journal folder from broker.xml)")
|
||||
public String directory;
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* 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.cli.commands.tools;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.activemq.artemis.cli.commands.Action;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
|
||||
public abstract class LockAbstract extends DataAbstract implements Action {
|
||||
@Override
|
||||
public Object execute(ActionContext context) throws Exception {
|
||||
super.execute(context);
|
||||
lock(new File(getJournal()));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -32,7 +32,6 @@ import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
|||
import org.apache.activemq.artemis.api.core.ActiveMQBuffers;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.cli.Artemis;
|
||||
import org.apache.activemq.artemis.cli.commands.Action;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
import org.apache.activemq.artemis.core.journal.RecordInfo;
|
||||
import org.apache.activemq.artemis.core.paging.PagedMessage;
|
||||
|
@ -57,7 +56,7 @@ import org.apache.activemq.artemis.core.settings.impl.HierarchicalObjectReposito
|
|||
import org.apache.activemq.artemis.utils.ExecutorFactory;
|
||||
|
||||
@Command(name = "print", description = "Print data records information (WARNING: don't use while a production server is running)")
|
||||
public class PrintData extends DataAbstract implements Action {
|
||||
public class PrintData extends LockAbstract {
|
||||
|
||||
@Override
|
||||
public Object execute(ActionContext context) throws Exception {
|
||||
|
|
|
@ -45,17 +45,16 @@ import org.apache.activemq.artemis.api.core.Message;
|
|||
import org.apache.activemq.artemis.api.core.Pair;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
|
||||
import org.apache.activemq.artemis.cli.commands.Action;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
|
||||
import org.apache.activemq.artemis.core.io.SequentialFileFactory;
|
||||
import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory;
|
||||
import org.apache.activemq.artemis.core.journal.Journal;
|
||||
import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo;
|
||||
import org.apache.activemq.artemis.core.journal.RecordInfo;
|
||||
import org.apache.activemq.artemis.core.io.SequentialFileFactory;
|
||||
import org.apache.activemq.artemis.core.journal.TransactionFailureCallback;
|
||||
import org.apache.activemq.artemis.core.journal.impl.JournalImpl;
|
||||
import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory;
|
||||
import org.apache.activemq.artemis.core.message.BodyEncoder;
|
||||
import org.apache.activemq.artemis.core.paging.PagedMessage;
|
||||
import org.apache.activemq.artemis.core.paging.PagingManager;
|
||||
|
@ -92,7 +91,7 @@ import org.apache.activemq.artemis.utils.Base64;
|
|||
import org.apache.activemq.artemis.utils.ExecutorFactory;
|
||||
|
||||
@Command(name = "exp", description = "Export all message-data using an XML that could be interpreted by any system.")
|
||||
public final class XmlDataExporter extends DataAbstract implements Action {
|
||||
public final class XmlDataExporter extends LockAbstract {
|
||||
|
||||
private static final Long LARGE_MESSAGE_CHUNK_SIZE = 1000L;
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ public interface ActiveMQBootstrapLogger extends BasicLogger {
|
|||
@Message(id = 101003, value = "Halting ActiveMQ Artemis Server after user request", format = Message.Format.MESSAGE_FORMAT)
|
||||
void serverKilled();
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@LogMessage(level = Logger.Level.DEBUG)
|
||||
@Message(id = 101005, value = "Using broker configuration: {0}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void usingBrokerConfig(String location);
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.activemq.artemis.api.core.client.ClientSession;
|
|||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.cli.Artemis;
|
||||
import org.apache.activemq.artemis.cli.commands.Configurable;
|
||||
import org.apache.activemq.artemis.cli.commands.Run;
|
||||
import org.apache.activemq.artemis.cli.commands.util.SyncCalculation;
|
||||
import org.apache.activemq.artemis.core.client.impl.ServerLocatorImpl;
|
||||
|
@ -58,6 +59,7 @@ public class ArtemisTest {
|
|||
public void cleanup() {
|
||||
System.clearProperty("artemis.instance");
|
||||
Run.setEmbedded(false);
|
||||
Configurable.unlock();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.apache.activemq.artemis.maven;
|
||||
|
||||
import org.apache.activemq.artemis.cli.commands.Configurable;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
|
@ -32,6 +33,10 @@ public abstract class ArtemisAbstractPlugin extends AbstractMojo {
|
|||
}
|
||||
else {
|
||||
doExecute();
|
||||
// We could execute the maven plugins over and over on examples
|
||||
// For that reason we just unlock the server here
|
||||
// Notice this has no implementations if you are using spawn
|
||||
Configurable.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ public class RemotingServiceImpl implements RemotingService, ConnectionLifeCycle
|
|||
ProtocolManager protocolManager = protocolMap.get(protocol);
|
||||
|
||||
if (protocolManager == null) {
|
||||
throw ActiveMQMessageBundle.BUNDLE.noProtocolManagerFound(protocol);
|
||||
ActiveMQServerLogger.LOGGER.noProtocolManagerFound(protocol, info.toString());
|
||||
}
|
||||
else {
|
||||
supportedProtocols.put(protocol, protocolManager);
|
||||
|
@ -237,7 +237,7 @@ public class RemotingServiceImpl implements RemotingService, ConnectionLifeCycle
|
|||
ProtocolManager protocolManager = protocolMap.get(actualProtocol);
|
||||
|
||||
if (protocolManager == null) {
|
||||
throw ActiveMQMessageBundle.BUNDLE.noProtocolManagerFound(actualProtocol);
|
||||
ActiveMQServerLogger.LOGGER.noProtocolManagerFound(actualProtocol, info.toString());
|
||||
}
|
||||
else {
|
||||
supportedProtocols.put(actualProtocol, protocolManager);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.core.server;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQAddressFullException;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQClusterSecurityException;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQConnectionTimedOutException;
|
||||
|
@ -36,12 +38,10 @@ import org.apache.activemq.artemis.api.core.SimpleString;
|
|||
import org.apache.activemq.artemis.core.postoffice.Binding;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.ReplicationSyncFileMessage;
|
||||
import org.apache.activemq.artemis.core.security.CheckType;
|
||||
import org.jboss.logging.Messages;
|
||||
import org.jboss.logging.annotations.Cause;
|
||||
import org.jboss.logging.annotations.Message;
|
||||
import org.jboss.logging.annotations.MessageBundle;
|
||||
import org.jboss.logging.Messages;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Logger Code 11
|
||||
|
@ -314,10 +314,6 @@ public interface ActiveMQMessageBundle {
|
|||
@Message(id = 119083, value = "Queue {0} has a different filter than requested", format = Message.Format.MESSAGE_FORMAT)
|
||||
ActiveMQInvalidTransientQueueUseException queueSubscriptionBelongsToDifferentFilter(SimpleString queueName);
|
||||
|
||||
@Message(id = 119085, value = "Classpath lacks a protocol-manager for protocol {0}",
|
||||
format = Message.Format.MESSAGE_FORMAT)
|
||||
ActiveMQException noProtocolManagerFound(String protocol);
|
||||
|
||||
// this code has to match with version 2.3.x as it's used on integration tests at Wildfly and JBoss EAP
|
||||
@Message(id = 119099, value = "Unable to authenticate cluster user: {0}",
|
||||
format = Message.Format.MESSAGE_FORMAT)
|
||||
|
|
|
@ -43,9 +43,9 @@ import io.netty.channel.Channel;
|
|||
import org.apache.activemq.artemis.api.core.ActiveMQExceptionType;
|
||||
import org.apache.activemq.artemis.api.core.Pair;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.core.io.IOCallback;
|
||||
import org.apache.activemq.artemis.core.client.impl.ServerLocatorInternal;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.io.IOCallback;
|
||||
import org.apache.activemq.artemis.core.io.SequentialFile;
|
||||
import org.apache.activemq.artemis.core.journal.impl.JournalFile;
|
||||
import org.apache.activemq.artemis.core.paging.cursor.PagePosition;
|
||||
|
@ -61,9 +61,9 @@ import org.apache.activemq.artemis.core.server.impl.ServerSessionImpl;
|
|||
import org.apache.activemq.artemis.core.server.management.Notification;
|
||||
import org.apache.activemq.artemis.utils.FutureLatch;
|
||||
import org.jboss.logging.BasicLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.logging.annotations.Cause;
|
||||
import org.jboss.logging.annotations.LogMessage;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.logging.annotations.Message;
|
||||
import org.jboss.logging.annotations.MessageLogger;
|
||||
import org.w3c.dom.Node;
|
||||
|
@ -1181,6 +1181,11 @@ public interface ActiveMQServerLogger extends BasicLogger {
|
|||
format = Message.Format.MESSAGE_FORMAT)
|
||||
void connectionTTLEqualsCheckPeriod(String connectionName, String ttl, String checkPeriod);
|
||||
|
||||
@LogMessage(level = Logger.Level.WARN)
|
||||
@Message(id = 222203, value = "Classpath lacks a protocol-manager for protocol {0}, Protocol being ignored on acceptor {1}",
|
||||
format = Message.Format.MESSAGE_FORMAT)
|
||||
void noProtocolManagerFound(String protocol, String host);
|
||||
|
||||
@LogMessage(level = Logger.Level.ERROR)
|
||||
@Message(id = 224000, value = "Failure in initialisation", format = Message.Format.MESSAGE_FORMAT)
|
||||
void initializationError(@Cause Throwable e);
|
||||
|
|
Loading…
Reference in New Issue