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