eclipse-ee4j / openmq

OpenMQ
https://projects.eclipse.org/projects/ee4j.openmq/
Other
52 stars 34 forks source link

imqcmd failed when the command repeats many times at 2-minute intervals #374

Closed glassfishrobot closed 2 years ago

glassfishrobot commented 8 years ago

When the imqcmd command repeats many times at 2-minute intervals, the command failed and output the following message to console.

Error while connecting to the broker on host 'localhost' and port '37676'. com.sun.messaging.jms.JMSSecurityException: [C4076]: Client does not have permission to create producer on destination: __JMQAdmin user=admin, broker=localhost:37676(47987) Please check your security configurations. Querying the destination failed.

The following message appeared on the broker log when this happened.

[B2083]: Unable to create destination _JMQAdmin [Queue], auto-creation is forbidden

Using Open MQ version is 4.5.

glassfishrobot commented 6 years ago
glassfishrobot commented 8 years ago

@glassfishrobot Commented Reported by tsyama

glassfishrobot commented 8 years ago

@glassfishrobot Commented tsyama said: "JMQAdmin" is the Physical Destination that the broker create automatically when the imqcmd are executed. Connecting with the broker, the imqcmd requests the broker to (1) and (2) processing. (1) Create "JMQAdmin" (2) Add producer on "JMQAdmin" It seems that the avobe failure occurs when "JMQAdmin" is deleted between (1) and (2).

Receiving the request of (1), the broker confirms if the connection is AdminConnection, adds DestType.DEST_ADMIN, DestType.DEST_LOCAL and DestType.DEST_AUTO to the original type of destination only in the case of AdminConnection.

On the other hand, receiving the request of (2), the broker doesn't confirm if the connection is AdminConnection, the destination type is not change.

If "JMQAdmin" is deleted between (1) and (2), the broker is going to create "JMQAdmin" at (2). But the imqcmd command ends in failure because the broker throws BrokerException when "com.sun.messaging.jmq.jmsserver.core.Destination" is instantiated.

if (!DestType.isAdmin(type) && !canAutoCreate(DestType.isQueue(type),type) && !BrokerMonitor.isInternal(destination)) {
    throw new BrokerException(
            Globals.getBrokerResources().getKString(
            BrokerResources.W_DST_NO_AUTOCREATE,
             getName()),
            BrokerResources.W_DST_NO_AUTOCREATE,
            (Throwable) null,
            Status.FORBIDDEN);

When this happend, the property "imq.autocreate.queue" is false.

This failure might be fixed by confirming if the connection is AdminConnection and adding DestType.DEST_ADMIN, DestType.DEST_LOCAL and DestType.DEST_AUTO to the destination type when the broker receives the request of (2).

But this fix cause another problem with the multiple executions of the imqcmd. The following error message appeared when a lot of imqcmd commands are executed at the same time.

3 09, 2016 10:23:14 AM com.sun.messaging.jmq.jmsclient.ExceptionHandler logCaughtException WARNING: [I500]: Caught JVM Exception: com.sun.messaging.jms.JMSException: [ADD_PRODUCER_REPLY(19)] [C4036]: A broker error occurred. :[409] [B4063]: Can not create Destination JMQAdmin [Queue] - the destination already exists user=admin, broker=localhost:37676(47987) Error while connecting to the broker on host 'localhost' and port '37676'. com.sun.messaging.jms.JMSException: [ADD_PRODUCER_REPLY(19)] [C4036]: A broker error occurred. :[409] [B4063]: Can not create Destination JMQAdmin [Queue] - the destination already exists user=admin, broker=localhost:37676(47987) Please verify that there is a broker running on the specified host and port or use the '-b' option to specify the correct broker host and port.

Querying the destination failed.

The broker logged the following message at this time.

[B4063]: Can not create Destination __JMQAdmin [Queue] - the destination already exists

It may happens when creating the destination object conflicts at (2). One imqcmd process creates "JMQAdmin" and puts it into the list of destinations managed by a broker, and the other one put "JMQAdmin" which created at the same time into the list, the broker throws the BrokerException through the following part.

synchronized (destinationList) {
          Destination newd = (Destination)destinationList.get(duid);
          if (newd != null) { // updating existing
              throw new BrokerException("Destination already exists");
          }

I think it only have to change BrokerException to ConflictException to fix it. ConflictException will be caught by invoker method immediately, "__JMQAdmin" are taken out from the list at the time, and then, the broker carrys on the processing. As a result, multiple executions of the imqcmd would not be failure.

Please refer to the following diff about a suggested fix.


--- com/sun/messaging/jmq/jmsserver/core/Destination.java   Tue Jan 18 11:15:55 2011
+++ com/sun/messaging/jmq/jmsserver/core/Destination.java   Fri May 20 18:52:30 2016
@@ -5523,7 +5523,10 @@
               synchronized (destinationList) {
     Destination newd = (Destination)destinationList.get(duid);
     if (newd != null) { // updating existing -        throw new BrokerException("Destination already exists");
+        throw new ConflictException(
+               Globals.getBrokerResources().getKString(
+    BrokerResources.X_DESTINATION_EXISTS,
+    duid));
     }

     if (!autocreated)
@@ -5535,6 +5538,8 @@
     destinationList.put(duid, d);

}
+            } catch (ConflictException ex) {
+throw ex;
             } catch (BrokerException ex) {
     // may happen with timing of two brokers in an
     // HA cluster
--- com/sun/messaging/jmq/jmsserver/data/handlers/ProducerHandler.java  Fri Sep 10 07:20:39 2010
+++ com/sun/messaging/jmq/jmsserver/data/handlers/ProducerHandler.java  Fri May 20 18:53:03 2016
@@ -113,6 +113,11 @@
 assert dest != null : " bad protocol ";
 assert type != null : " bad protocol ";

+if (con.isAdminConnection()) {
+   type |= DestType.DEST_ADMIN | DestType.DEST_LOCAL 
+         | DestType.DEST_AUTO;
+}
+
 if (!con.isAdminConnection() && MemoryGlobals.MEM_DISALLOW_PRODUCERS) {
     status = Status.ERROR;
     reason = "Low memory";
glassfishrobot commented 8 years ago

@glassfishrobot Commented tsyama said: OpenMQ 5.1 becomes this error, too.

I propose an another idea that is better than before.

JMQAdmin had been deleted by the timer task to delete JMQAdmin automatically. The imqcmd command internally create the producer to __JMQAdmin, and the timer task is scheduled by this producer when the producer is closed and disconnect from the broker.

It's not necessary to delete JMQAdmin because imqcmd command surely use it when the command works. Therefore, I think that I should correct logic so as not to schedule the timer task to delete JMQAdmin automatically at the end of the work of the imqcmd command. The imqbridgemgr command also similarly schedules the timer task to delete __JMQBridgeAdmin automatically. I think that this is also unnecessary.

There is no connection from Consumer though in JMQAdmin and JMQBridgeAdmin, there is a connection from producer. Therefore, I think that only the correction of logic concerning scheduling the timer task by the disconnection from producer is necessary. If the imqcmd command is not executed after the broker starts, JMQAdmin is unnecessary. Therefore, I think that the broker need not generate JMQAdmin at the time of starup.

I propose the following correction methods for the reasons mentioned above.

--- mq-broker/broker-core/src/main/java/com/sun/messaging/jmq/jmsserver/core/Destination.java   
+++ mq-broker/broker-core/src/main/java/com/sun/messaging/jmq/jmsserver/core/Destination.java   
@@ -3712,6 +3712,7 @@
         producerFlow.removeProducer(p);
         producerFlow.checkResumeFlow(p, false);

+        if (!(MessageType.JMQ_ADMIN_DEST.equals(getDestinationName()) || MessageType.JMQ_BRIDGE_ADMIN_DEST.equals(getDestinationName()))) {
         synchronized (this) {
             if (shouldDestroy()) {
 if (destReaper != null) {
@@ -3728,6 +3729,7 @@
 }
             }
         }
+        }
     }

     /*
glassfishrobot commented 8 years ago

@glassfishrobot Commented tsyama said: Do you have any opinions about the above proposal ?

glassfishrobot commented 8 years ago

@glassfishrobot Commented tsyama said: If the timer task is not scheduled and JMQAdmin is not deleted by the task, there is no need to re-create JMQAdmin when the imqcmd command works after auto-creating __JMQAdmin at first. By doing so, unnecessary processing can be omitted.

What do you think about the above proposal ?

glassfishrobot commented 7 years ago

@glassfishrobot Commented This issue was imported from java.net JIRA MQ-374

pzygielo commented 2 years ago

I cannot reproduce this. Please comment with reproduction steps or open PR with the fix for this to reopen.