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.broker.region; 018 019import java.io.IOException; 020import java.util.List; 021import java.util.concurrent.atomic.AtomicBoolean; 022 023import javax.jms.ResourceAllocationException; 024 025import org.apache.activemq.advisory.AdvisorySupport; 026import org.apache.activemq.broker.Broker; 027import org.apache.activemq.broker.BrokerService; 028import org.apache.activemq.broker.ConnectionContext; 029import org.apache.activemq.broker.ProducerBrokerExchange; 030import org.apache.activemq.broker.region.policy.DeadLetterStrategy; 031import org.apache.activemq.broker.region.policy.SlowConsumerStrategy; 032import org.apache.activemq.command.ActiveMQDestination; 033import org.apache.activemq.command.ActiveMQTopic; 034import org.apache.activemq.command.Message; 035import org.apache.activemq.command.MessageAck; 036import org.apache.activemq.command.MessageDispatchNotification; 037import org.apache.activemq.command.ProducerInfo; 038import org.apache.activemq.filter.NonCachedMessageEvaluationContext; 039import org.apache.activemq.security.SecurityContext; 040import org.apache.activemq.state.ProducerState; 041import org.apache.activemq.store.MessageStore; 042import org.apache.activemq.thread.Scheduler; 043import org.apache.activemq.usage.MemoryUsage; 044import org.apache.activemq.usage.SystemUsage; 045import org.apache.activemq.usage.TempUsage; 046import org.apache.activemq.usage.Usage; 047import org.slf4j.Logger; 048 049/** 050 * 051 */ 052public abstract class BaseDestination implements Destination { 053 /** 054 * The maximum number of messages to page in to the destination from 055 * persistent storage 056 */ 057 public static final int MAX_PAGE_SIZE = 200; 058 public static final int MAX_BROWSE_PAGE_SIZE = MAX_PAGE_SIZE * 2; 059 public static final long EXPIRE_MESSAGE_PERIOD = 30 * 1000; 060 public static final long DEFAULT_INACTIVE_TIMEOUT_BEFORE_GC = 60 * 1000; 061 public static final int MAX_PRODUCERS_TO_AUDIT = 64; 062 public static final int MAX_AUDIT_DEPTH = 10000; 063 public static final String DUPLICATE_FROM_STORE_MSG_PREFIX = "duplicate from store for "; 064 065 protected final AtomicBoolean started = new AtomicBoolean(); 066 protected final ActiveMQDestination destination; 067 protected final Broker broker; 068 protected final MessageStore store; 069 protected SystemUsage systemUsage; 070 protected MemoryUsage memoryUsage; 071 private boolean producerFlowControl = true; 072 private boolean alwaysRetroactive = false; 073 protected long lastBlockedProducerWarnTime = 0l; 074 protected long blockedProducerWarningInterval = DEFAULT_BLOCKED_PRODUCER_WARNING_INTERVAL; 075 076 private int maxProducersToAudit = 1024; 077 private int maxAuditDepth = 2048; 078 private boolean enableAudit = true; 079 private int maxPageSize = MAX_PAGE_SIZE; 080 private int maxBrowsePageSize = MAX_BROWSE_PAGE_SIZE; 081 private boolean useCache = true; 082 private int minimumMessageSize = 1024; 083 private boolean lazyDispatch = false; 084 private boolean advisoryForSlowConsumers; 085 private boolean advisoryForFastProducers; 086 private boolean advisoryForDiscardingMessages; 087 private boolean advisoryWhenFull; 088 private boolean advisoryForDelivery; 089 private boolean advisoryForConsumed; 090 private boolean sendAdvisoryIfNoConsumers; 091 private boolean sendDuplicateFromStoreToDLQ = true; 092 private boolean includeBodyForAdvisory; 093 protected final DestinationStatistics destinationStatistics = new DestinationStatistics(); 094 protected final BrokerService brokerService; 095 protected final Broker regionBroker; 096 protected DeadLetterStrategy deadLetterStrategy = DEFAULT_DEAD_LETTER_STRATEGY; 097 protected long expireMessagesPeriod = EXPIRE_MESSAGE_PERIOD; 098 private int maxExpirePageSize = MAX_BROWSE_PAGE_SIZE; 099 protected int cursorMemoryHighWaterMark = 70; 100 protected int storeUsageHighWaterMark = 100; 101 private SlowConsumerStrategy slowConsumerStrategy; 102 private boolean prioritizedMessages; 103 private long inactiveTimeoutBeforeGC = DEFAULT_INACTIVE_TIMEOUT_BEFORE_GC; 104 private boolean gcIfInactive; 105 private boolean gcWithNetworkConsumers; 106 private long lastActiveTime=0l; 107 private boolean reduceMemoryFootprint = false; 108 protected final Scheduler scheduler; 109 private boolean disposed = false; 110 private boolean doOptimzeMessageStorage = true; 111 /* 112 * percentage of in-flight messages above which optimize message store is disabled 113 */ 114 private int optimizeMessageStoreInFlightLimit = 10; 115 private boolean persistJMSRedelivered; 116 117 /** 118 * @param brokerService 119 * @param store 120 * @param destination 121 * @param parentStats 122 * @throws Exception 123 */ 124 public BaseDestination(BrokerService brokerService, MessageStore store, ActiveMQDestination destination, DestinationStatistics parentStats) throws Exception { 125 this.brokerService = brokerService; 126 this.broker = brokerService.getBroker(); 127 this.store = store; 128 this.destination = destination; 129 // let's copy the enabled property from the parent DestinationStatistics 130 this.destinationStatistics.setEnabled(parentStats.isEnabled()); 131 this.destinationStatistics.setParent(parentStats); 132 this.systemUsage = new SystemUsage(brokerService.getProducerSystemUsage(), destination.toString()); 133 this.memoryUsage = this.systemUsage.getMemoryUsage(); 134 this.memoryUsage.setUsagePortion(1.0f); 135 this.regionBroker = brokerService.getRegionBroker(); 136 this.scheduler = brokerService.getBroker().getScheduler(); 137 } 138 139 /** 140 * initialize the destination 141 * 142 * @throws Exception 143 */ 144 public void initialize() throws Exception { 145 // Let the store know what usage manager we are using so that he can 146 // flush messages to disk when usage gets high. 147 if (store != null) { 148 store.setMemoryUsage(this.memoryUsage); 149 } 150 } 151 152 /** 153 * @return the producerFlowControl 154 */ 155 @Override 156 public boolean isProducerFlowControl() { 157 return producerFlowControl; 158 } 159 160 /** 161 * @param producerFlowControl the producerFlowControl to set 162 */ 163 @Override 164 public void setProducerFlowControl(boolean producerFlowControl) { 165 this.producerFlowControl = producerFlowControl; 166 } 167 168 @Override 169 public boolean isAlwaysRetroactive() { 170 return alwaysRetroactive; 171 } 172 173 @Override 174 public void setAlwaysRetroactive(boolean alwaysRetroactive) { 175 this.alwaysRetroactive = alwaysRetroactive; 176 } 177 178 /** 179 * Set's the interval at which warnings about producers being blocked by 180 * resource usage will be triggered. Values of 0 or less will disable 181 * warnings 182 * 183 * @param blockedProducerWarningInterval the interval at which warning about 184 * blocked producers will be triggered. 185 */ 186 @Override 187 public void setBlockedProducerWarningInterval(long blockedProducerWarningInterval) { 188 this.blockedProducerWarningInterval = blockedProducerWarningInterval; 189 } 190 191 /** 192 * 193 * @return the interval at which warning about blocked producers will be 194 * triggered. 195 */ 196 @Override 197 public long getBlockedProducerWarningInterval() { 198 return blockedProducerWarningInterval; 199 } 200 201 /** 202 * @return the maxProducersToAudit 203 */ 204 @Override 205 public int getMaxProducersToAudit() { 206 return maxProducersToAudit; 207 } 208 209 /** 210 * @param maxProducersToAudit the maxProducersToAudit to set 211 */ 212 @Override 213 public void setMaxProducersToAudit(int maxProducersToAudit) { 214 this.maxProducersToAudit = maxProducersToAudit; 215 } 216 217 /** 218 * @return the maxAuditDepth 219 */ 220 @Override 221 public int getMaxAuditDepth() { 222 return maxAuditDepth; 223 } 224 225 /** 226 * @param maxAuditDepth the maxAuditDepth to set 227 */ 228 @Override 229 public void setMaxAuditDepth(int maxAuditDepth) { 230 this.maxAuditDepth = maxAuditDepth; 231 } 232 233 /** 234 * @return the enableAudit 235 */ 236 @Override 237 public boolean isEnableAudit() { 238 return enableAudit; 239 } 240 241 /** 242 * @param enableAudit the enableAudit to set 243 */ 244 @Override 245 public void setEnableAudit(boolean enableAudit) { 246 this.enableAudit = enableAudit; 247 } 248 249 @Override 250 public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception { 251 destinationStatistics.getProducers().increment(); 252 this.lastActiveTime=0l; 253 } 254 255 @Override 256 public void removeProducer(ConnectionContext context, ProducerInfo info) throws Exception { 257 destinationStatistics.getProducers().decrement(); 258 } 259 260 @Override 261 public void addSubscription(ConnectionContext context, Subscription sub) throws Exception{ 262 destinationStatistics.getConsumers().increment(); 263 this.lastActiveTime=0l; 264 } 265 266 @Override 267 public void removeSubscription(ConnectionContext context, Subscription sub, long lastDeliveredSequenceId) throws Exception{ 268 destinationStatistics.getConsumers().decrement(); 269 this.lastActiveTime=0l; 270 } 271 272 273 @Override 274 public final MemoryUsage getMemoryUsage() { 275 return memoryUsage; 276 } 277 278 @Override 279 public void setMemoryUsage(MemoryUsage memoryUsage) { 280 this.memoryUsage = memoryUsage; 281 } 282 283 @Override 284 public TempUsage getTempUsage() { 285 return systemUsage.getTempUsage(); 286 } 287 288 @Override 289 public DestinationStatistics getDestinationStatistics() { 290 return destinationStatistics; 291 } 292 293 @Override 294 public ActiveMQDestination getActiveMQDestination() { 295 return destination; 296 } 297 298 @Override 299 public final String getName() { 300 return getActiveMQDestination().getPhysicalName(); 301 } 302 303 @Override 304 public final MessageStore getMessageStore() { 305 return store; 306 } 307 308 @Override 309 public boolean isActive() { 310 boolean isActive = destinationStatistics.getConsumers().getCount() > 0 || 311 destinationStatistics.getProducers().getCount() > 0; 312 if (isActive && isGcWithNetworkConsumers() && destinationStatistics.getConsumers().getCount() > 0) { 313 isActive = hasRegularConsumers(getConsumers()); 314 } 315 return isActive; 316 } 317 318 @Override 319 public int getMaxPageSize() { 320 return maxPageSize; 321 } 322 323 @Override 324 public void setMaxPageSize(int maxPageSize) { 325 this.maxPageSize = maxPageSize; 326 } 327 328 @Override 329 public int getMaxBrowsePageSize() { 330 return this.maxBrowsePageSize; 331 } 332 333 @Override 334 public void setMaxBrowsePageSize(int maxPageSize) { 335 this.maxBrowsePageSize = maxPageSize; 336 } 337 338 public int getMaxExpirePageSize() { 339 return this.maxExpirePageSize; 340 } 341 342 public void setMaxExpirePageSize(int maxPageSize) { 343 this.maxExpirePageSize = maxPageSize; 344 } 345 346 public void setExpireMessagesPeriod(long expireMessagesPeriod) { 347 this.expireMessagesPeriod = expireMessagesPeriod; 348 } 349 350 public long getExpireMessagesPeriod() { 351 return expireMessagesPeriod; 352 } 353 354 @Override 355 public boolean isUseCache() { 356 return useCache; 357 } 358 359 @Override 360 public void setUseCache(boolean useCache) { 361 this.useCache = useCache; 362 } 363 364 @Override 365 public int getMinimumMessageSize() { 366 return minimumMessageSize; 367 } 368 369 @Override 370 public void setMinimumMessageSize(int minimumMessageSize) { 371 this.minimumMessageSize = minimumMessageSize; 372 } 373 374 @Override 375 public boolean isLazyDispatch() { 376 return lazyDispatch; 377 } 378 379 @Override 380 public void setLazyDispatch(boolean lazyDispatch) { 381 this.lazyDispatch = lazyDispatch; 382 } 383 384 protected long getDestinationSequenceId() { 385 return regionBroker.getBrokerSequenceId(); 386 } 387 388 /** 389 * @return the advisoryForSlowConsumers 390 */ 391 public boolean isAdvisoryForSlowConsumers() { 392 return advisoryForSlowConsumers; 393 } 394 395 /** 396 * @param advisoryForSlowConsumers the advisoryForSlowConsumers to set 397 */ 398 public void setAdvisoryForSlowConsumers(boolean advisoryForSlowConsumers) { 399 this.advisoryForSlowConsumers = advisoryForSlowConsumers; 400 } 401 402 /** 403 * @return the advisoryForDiscardingMessages 404 */ 405 public boolean isAdvisoryForDiscardingMessages() { 406 return advisoryForDiscardingMessages; 407 } 408 409 /** 410 * @param advisoryForDiscardingMessages the advisoryForDiscardingMessages to 411 * set 412 */ 413 public void setAdvisoryForDiscardingMessages(boolean advisoryForDiscardingMessages) { 414 this.advisoryForDiscardingMessages = advisoryForDiscardingMessages; 415 } 416 417 /** 418 * @return the advisoryWhenFull 419 */ 420 public boolean isAdvisoryWhenFull() { 421 return advisoryWhenFull; 422 } 423 424 /** 425 * @param advisoryWhenFull the advisoryWhenFull to set 426 */ 427 public void setAdvisoryWhenFull(boolean advisoryWhenFull) { 428 this.advisoryWhenFull = advisoryWhenFull; 429 } 430 431 /** 432 * @return the advisoryForDelivery 433 */ 434 public boolean isAdvisoryForDelivery() { 435 return advisoryForDelivery; 436 } 437 438 /** 439 * @param advisoryForDelivery the advisoryForDelivery to set 440 */ 441 public void setAdvisoryForDelivery(boolean advisoryForDelivery) { 442 this.advisoryForDelivery = advisoryForDelivery; 443 } 444 445 /** 446 * @return the advisoryForConsumed 447 */ 448 public boolean isAdvisoryForConsumed() { 449 return advisoryForConsumed; 450 } 451 452 /** 453 * @param advisoryForConsumed the advisoryForConsumed to set 454 */ 455 public void setAdvisoryForConsumed(boolean advisoryForConsumed) { 456 this.advisoryForConsumed = advisoryForConsumed; 457 } 458 459 /** 460 * @return the advisdoryForFastProducers 461 */ 462 public boolean isAdvisoryForFastProducers() { 463 return advisoryForFastProducers; 464 } 465 466 /** 467 * @param advisoryForFastProducers the advisdoryForFastProducers to set 468 */ 469 public void setAdvisoryForFastProducers(boolean advisoryForFastProducers) { 470 this.advisoryForFastProducers = advisoryForFastProducers; 471 } 472 473 public boolean isSendAdvisoryIfNoConsumers() { 474 return sendAdvisoryIfNoConsumers; 475 } 476 477 public void setSendAdvisoryIfNoConsumers(boolean sendAdvisoryIfNoConsumers) { 478 this.sendAdvisoryIfNoConsumers = sendAdvisoryIfNoConsumers; 479 } 480 481 public boolean isSendDuplicateFromStoreToDLQ() { 482 return this.sendDuplicateFromStoreToDLQ; 483 } 484 485 public void setSendDuplicateFromStoreToDLQ(boolean sendDuplicateFromStoreToDLQ) { 486 this.sendDuplicateFromStoreToDLQ = sendDuplicateFromStoreToDLQ; 487 } 488 489 public boolean isIncludeBodyForAdvisory() { 490 return includeBodyForAdvisory; 491 } 492 493 public void setIncludeBodyForAdvisory(boolean includeBodyForAdvisory) { 494 this.includeBodyForAdvisory = includeBodyForAdvisory; 495 } 496 497 /** 498 * @return the dead letter strategy 499 */ 500 @Override 501 public DeadLetterStrategy getDeadLetterStrategy() { 502 return deadLetterStrategy; 503 } 504 505 /** 506 * set the dead letter strategy 507 * 508 * @param deadLetterStrategy 509 */ 510 public void setDeadLetterStrategy(DeadLetterStrategy deadLetterStrategy) { 511 this.deadLetterStrategy = deadLetterStrategy; 512 } 513 514 @Override 515 public int getCursorMemoryHighWaterMark() { 516 return this.cursorMemoryHighWaterMark; 517 } 518 519 @Override 520 public void setCursorMemoryHighWaterMark(int cursorMemoryHighWaterMark) { 521 this.cursorMemoryHighWaterMark = cursorMemoryHighWaterMark; 522 } 523 524 /** 525 * called when message is consumed 526 * 527 * @param context 528 * @param messageReference 529 */ 530 @Override 531 public void messageConsumed(ConnectionContext context, MessageReference messageReference) { 532 if (advisoryForConsumed) { 533 broker.messageConsumed(context, messageReference); 534 } 535 } 536 537 /** 538 * Called when message is delivered to the broker 539 * 540 * @param context 541 * @param messageReference 542 */ 543 @Override 544 public void messageDelivered(ConnectionContext context, MessageReference messageReference) { 545 this.lastActiveTime = 0L; 546 if (advisoryForDelivery) { 547 broker.messageDelivered(context, messageReference); 548 } 549 } 550 551 /** 552 * Called when a message is discarded - e.g. running low on memory This will 553 * happen only if the policy is enabled - e.g. non durable topics 554 * 555 * @param context 556 * @param messageReference 557 */ 558 @Override 559 public void messageDiscarded(ConnectionContext context, Subscription sub, MessageReference messageReference) { 560 if (advisoryForDiscardingMessages) { 561 broker.messageDiscarded(context, sub, messageReference); 562 } 563 } 564 565 /** 566 * Called when there is a slow consumer 567 * 568 * @param context 569 * @param subs 570 */ 571 @Override 572 public void slowConsumer(ConnectionContext context, Subscription subs) { 573 if (advisoryForSlowConsumers) { 574 broker.slowConsumer(context, this, subs); 575 } 576 if (slowConsumerStrategy != null) { 577 slowConsumerStrategy.slowConsumer(context, subs); 578 } 579 } 580 581 /** 582 * Called to notify a producer is too fast 583 * 584 * @param context 585 * @param producerInfo 586 */ 587 @Override 588 public void fastProducer(ConnectionContext context, ProducerInfo producerInfo) { 589 if (advisoryForFastProducers) { 590 broker.fastProducer(context, producerInfo, getActiveMQDestination()); 591 } 592 } 593 594 /** 595 * Called when a Usage reaches a limit 596 * 597 * @param context 598 * @param usage 599 */ 600 @Override 601 public void isFull(ConnectionContext context, Usage<?> usage) { 602 if (advisoryWhenFull) { 603 broker.isFull(context, this, usage); 604 } 605 } 606 607 @Override 608 public void dispose(ConnectionContext context) throws IOException { 609 if (this.store != null) { 610 this.store.removeAllMessages(context); 611 this.store.dispose(context); 612 } 613 this.destinationStatistics.setParent(null); 614 this.memoryUsage.stop(); 615 this.disposed = true; 616 } 617 618 @Override 619 public boolean isDisposed() { 620 return this.disposed; 621 } 622 623 /** 624 * Provides a hook to allow messages with no consumer to be processed in 625 * some way - such as to send to a dead letter queue or something.. 626 */ 627 protected void onMessageWithNoConsumers(ConnectionContext context, Message msg) throws Exception { 628 if (!msg.isPersistent()) { 629 if (isSendAdvisoryIfNoConsumers()) { 630 // allow messages with no consumers to be dispatched to a dead 631 // letter queue 632 if (destination.isQueue() || !AdvisorySupport.isAdvisoryTopic(destination)) { 633 634 Message message = msg.copy(); 635 // The original destination and transaction id do not get 636 // filled when the message is first sent, 637 // it is only populated if the message is routed to another 638 // destination like the DLQ 639 if (message.getOriginalDestination() != null) { 640 message.setOriginalDestination(message.getDestination()); 641 } 642 if (message.getOriginalTransactionId() != null) { 643 message.setOriginalTransactionId(message.getTransactionId()); 644 } 645 646 ActiveMQTopic advisoryTopic; 647 if (destination.isQueue()) { 648 advisoryTopic = AdvisorySupport.getNoQueueConsumersAdvisoryTopic(destination); 649 } else { 650 advisoryTopic = AdvisorySupport.getNoTopicConsumersAdvisoryTopic(destination); 651 } 652 message.setDestination(advisoryTopic); 653 message.setTransactionId(null); 654 655 // Disable flow control for this since since we don't want 656 // to block. 657 boolean originalFlowControl = context.isProducerFlowControl(); 658 try { 659 context.setProducerFlowControl(false); 660 ProducerBrokerExchange producerExchange = new ProducerBrokerExchange(); 661 producerExchange.setMutable(false); 662 producerExchange.setConnectionContext(context); 663 producerExchange.setProducerState(new ProducerState(new ProducerInfo())); 664 context.getBroker().send(producerExchange, message); 665 } finally { 666 context.setProducerFlowControl(originalFlowControl); 667 } 668 669 } 670 } 671 } 672 } 673 674 @Override 675 public void processDispatchNotification(MessageDispatchNotification messageDispatchNotification) throws Exception { 676 } 677 678 public final int getStoreUsageHighWaterMark() { 679 return this.storeUsageHighWaterMark; 680 } 681 682 public void setStoreUsageHighWaterMark(int storeUsageHighWaterMark) { 683 this.storeUsageHighWaterMark = storeUsageHighWaterMark; 684 } 685 686 protected final void waitForSpace(ConnectionContext context,ProducerBrokerExchange producerBrokerExchange, Usage<?> usage, String warning) throws IOException, InterruptedException, ResourceAllocationException { 687 waitForSpace(context, producerBrokerExchange, usage, 100, warning); 688 } 689 690 protected final void waitForSpace(ConnectionContext context, ProducerBrokerExchange producerBrokerExchange, Usage<?> usage, int highWaterMark, String warning) throws IOException, InterruptedException, ResourceAllocationException { 691 if (!context.isNetworkConnection() && systemUsage.isSendFailIfNoSpace()) { 692 if (isFlowControlLogRequired()) { 693 getLog().info("sendFailIfNoSpace, forcing exception on send, usage: {}: {}", usage, warning); 694 } else { 695 getLog().debug("sendFailIfNoSpace, forcing exception on send, usage: {}: {}", usage, warning); 696 } 697 throw new ResourceAllocationException(warning); 698 } 699 if (!context.isNetworkConnection() && systemUsage.getSendFailIfNoSpaceAfterTimeout() != 0) { 700 if (!usage.waitForSpace(systemUsage.getSendFailIfNoSpaceAfterTimeout(), highWaterMark)) { 701 if (isFlowControlLogRequired()) { 702 getLog().info("sendFailIfNoSpaceAfterTimeout expired, forcing exception on send, usage: {}: {}", usage, warning); 703 } else { 704 getLog().debug("sendFailIfNoSpaceAfterTimeout expired, forcing exception on send, usage: {}: {}", usage, warning); 705 } 706 throw new ResourceAllocationException(warning); 707 } 708 } else { 709 long start = System.currentTimeMillis(); 710 producerBrokerExchange.blockingOnFlowControl(true); 711 destinationStatistics.getBlockedSends().increment(); 712 while (!usage.waitForSpace(1000, highWaterMark)) { 713 if (context.getStopping().get()) { 714 throw new IOException("Connection closed, send aborted."); 715 } 716 717 if (isFlowControlLogRequired()) { 718 getLog().warn("{}: {} (blocking for: {}s)", new Object[]{ usage, warning, new Long(((System.currentTimeMillis() - start) / 1000))}); 719 } else { 720 getLog().debug("{}: {} (blocking for: {}s)", new Object[]{ usage, warning, new Long(((System.currentTimeMillis() - start) / 1000))}); 721 } 722 } 723 long finish = System.currentTimeMillis(); 724 long totalTimeBlocked = finish - start; 725 destinationStatistics.getBlockedTime().addTime(totalTimeBlocked); 726 producerBrokerExchange.incrementTimeBlocked(this,totalTimeBlocked); 727 producerBrokerExchange.blockingOnFlowControl(false); 728 } 729 } 730 731 protected boolean isFlowControlLogRequired() { 732 boolean answer = false; 733 if (blockedProducerWarningInterval > 0) { 734 long now = System.currentTimeMillis(); 735 if (lastBlockedProducerWarnTime + blockedProducerWarningInterval <= now) { 736 lastBlockedProducerWarnTime = now; 737 answer = true; 738 } 739 } 740 return answer; 741 } 742 743 protected abstract Logger getLog(); 744 745 public void setSlowConsumerStrategy(SlowConsumerStrategy slowConsumerStrategy) { 746 this.slowConsumerStrategy = slowConsumerStrategy; 747 } 748 749 @Override 750 public SlowConsumerStrategy getSlowConsumerStrategy() { 751 return this.slowConsumerStrategy; 752 } 753 754 755 @Override 756 public boolean isPrioritizedMessages() { 757 return this.prioritizedMessages; 758 } 759 760 public void setPrioritizedMessages(boolean prioritizedMessages) { 761 this.prioritizedMessages = prioritizedMessages; 762 if (store != null) { 763 store.setPrioritizedMessages(prioritizedMessages); 764 } 765 } 766 767 /** 768 * @return the inactiveTimeoutBeforeGC 769 */ 770 @Override 771 public long getInactiveTimeoutBeforeGC() { 772 return this.inactiveTimeoutBeforeGC; 773 } 774 775 /** 776 * @param inactiveTimeoutBeforeGC the inactiveTimeoutBeforeGC to set 777 */ 778 public void setInactiveTimeoutBeforeGC(long inactiveTimeoutBeforeGC) { 779 this.inactiveTimeoutBeforeGC = inactiveTimeoutBeforeGC; 780 } 781 782 /** 783 * @return the gcIfInactive 784 */ 785 public boolean isGcIfInactive() { 786 return this.gcIfInactive; 787 } 788 789 /** 790 * @param gcIfInactive the gcIfInactive to set 791 */ 792 public void setGcIfInactive(boolean gcIfInactive) { 793 this.gcIfInactive = gcIfInactive; 794 } 795 796 /** 797 * Indicate if it is ok to gc destinations that have only network consumers 798 * @param gcWithNetworkConsumers 799 */ 800 public void setGcWithNetworkConsumers(boolean gcWithNetworkConsumers) { 801 this.gcWithNetworkConsumers = gcWithNetworkConsumers; 802 } 803 804 public boolean isGcWithNetworkConsumers() { 805 return gcWithNetworkConsumers; 806 } 807 808 @Override 809 public void markForGC(long timeStamp) { 810 if (isGcIfInactive() && this.lastActiveTime == 0 && isActive() == false 811 && destinationStatistics.messages.getCount() == 0 && getInactiveTimeoutBeforeGC() > 0l) { 812 this.lastActiveTime = timeStamp; 813 } 814 } 815 816 @Override 817 public boolean canGC() { 818 boolean result = false; 819 final long currentLastActiveTime = this.lastActiveTime; 820 if (isGcIfInactive() && currentLastActiveTime != 0l && destinationStatistics.messages.getCount() == 0L ) { 821 if ((System.currentTimeMillis() - currentLastActiveTime) >= getInactiveTimeoutBeforeGC()) { 822 result = true; 823 } 824 } 825 return result; 826 } 827 828 public void setReduceMemoryFootprint(boolean reduceMemoryFootprint) { 829 this.reduceMemoryFootprint = reduceMemoryFootprint; 830 } 831 832 public boolean isReduceMemoryFootprint() { 833 return this.reduceMemoryFootprint; 834 } 835 836 @Override 837 public boolean isDoOptimzeMessageStorage() { 838 return doOptimzeMessageStorage; 839 } 840 841 @Override 842 public void setDoOptimzeMessageStorage(boolean doOptimzeMessageStorage) { 843 this.doOptimzeMessageStorage = doOptimzeMessageStorage; 844 } 845 846 public int getOptimizeMessageStoreInFlightLimit() { 847 return optimizeMessageStoreInFlightLimit; 848 } 849 850 public void setOptimizeMessageStoreInFlightLimit(int optimizeMessageStoreInFlightLimit) { 851 this.optimizeMessageStoreInFlightLimit = optimizeMessageStoreInFlightLimit; 852 } 853 854 855 @Override 856 public abstract List<Subscription> getConsumers(); 857 858 protected boolean hasRegularConsumers(List<Subscription> consumers) { 859 boolean hasRegularConsumers = false; 860 for (Subscription subscription: consumers) { 861 if (!subscription.getConsumerInfo().isNetworkSubscription()) { 862 hasRegularConsumers = true; 863 break; 864 } 865 } 866 return hasRegularConsumers; 867 } 868 869 public ConnectionContext createConnectionContext() { 870 ConnectionContext answer = new ConnectionContext(); 871 answer.setBroker(this.broker); 872 answer.getMessageEvaluationContext().setDestination(getActiveMQDestination()); 873 answer.setSecurityContext(SecurityContext.BROKER_SECURITY_CONTEXT); 874 return answer; 875 } 876 877 protected MessageAck convertToNonRangedAck(MessageAck ack, MessageReference node) { 878 // the original ack may be a ranged ack, but we are trying to delete 879 // a specific 880 // message store here so we need to convert to a non ranged ack. 881 if (ack.getMessageCount() > 0) { 882 // Dup the ack 883 MessageAck a = new MessageAck(); 884 ack.copy(a); 885 ack = a; 886 // Convert to non-ranged. 887 ack.setMessageCount(1); 888 } 889 // always use node messageId so we can access entry/data Location 890 ack.setFirstMessageId(node.getMessageId()); 891 ack.setLastMessageId(node.getMessageId()); 892 return ack; 893 } 894 895 protected boolean isDLQ() { 896 return destination.isDLQ(); 897 } 898 899 @Override 900 public void duplicateFromStore(Message message, Subscription subscription) { 901 destinationStatistics.getDuplicateFromStore().increment(); 902 ConnectionContext connectionContext = createConnectionContext(); 903 getLog().warn("{}{}, redirecting {} for dlq processing", DUPLICATE_FROM_STORE_MSG_PREFIX, destination, message.getMessageId()); 904 Throwable cause = new Throwable(DUPLICATE_FROM_STORE_MSG_PREFIX + destination); 905 message.setRegionDestination(this); 906 if(this.isSendDuplicateFromStoreToDLQ()) { 907 broker.getRoot().sendToDeadLetterQueue(connectionContext, message, null, cause); 908 } 909 MessageAck messageAck = new MessageAck(message, MessageAck.POISON_ACK_TYPE, 1); 910 messageAck.setPoisonCause(cause); 911 try { 912 acknowledge(connectionContext, subscription, messageAck, message); 913 } catch (IOException e) { 914 getLog().error("Failed to acknowledge duplicate message {} from {} with {}", message.getMessageId(), destination, messageAck); 915 } 916 } 917 918 public void setPersistJMSRedelivered(boolean persistJMSRedelivered) { 919 this.persistJMSRedelivered = persistJMSRedelivered; 920 } 921 922 public boolean isPersistJMSRedelivered() { 923 return persistJMSRedelivered; 924 } 925 926 public SystemUsage getSystemUsage() { 927 return systemUsage; 928 } 929}