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}