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.cursors; 018 019import org.apache.activemq.broker.Broker; 020import org.apache.activemq.broker.region.MessageReference; 021import org.apache.activemq.broker.region.Queue; 022import org.apache.activemq.command.Message; 023import org.apache.activemq.command.MessageId; 024import org.apache.activemq.usage.SystemUsage; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028/** 029 * Store based Cursor for Queues 030 */ 031public class StoreQueueCursor extends AbstractPendingMessageCursor { 032 033 private static final Logger LOG = LoggerFactory.getLogger(StoreQueueCursor.class); 034 private final Broker broker; 035 private int pendingCount; 036 private final Queue queue; 037 private PendingMessageCursor nonPersistent; 038 private final QueueStorePrefetch persistent; 039 private boolean started; 040 private PendingMessageCursor currentCursor; 041 042 /** 043 * Construct 044 * @param broker 045 * @param queue 046 */ 047 public StoreQueueCursor(Broker broker,Queue queue) { 048 super((queue != null ? queue.isPrioritizedMessages():false)); 049 this.broker=broker; 050 this.queue = queue; 051 this.persistent = new QueueStorePrefetch(queue, broker); 052 currentCursor = persistent; 053 } 054 055 public synchronized void start() throws Exception { 056 started = true; 057 super.start(); 058 if (nonPersistent == null) { 059 if (broker.getBrokerService().isPersistent()) { 060 nonPersistent = new FilePendingMessageCursor(broker,queue.getName(),this.prioritizedMessages); 061 }else { 062 nonPersistent = new VMPendingMessageCursor(this.prioritizedMessages); 063 } 064 nonPersistent.setMaxBatchSize(getMaxBatchSize()); 065 nonPersistent.setSystemUsage(systemUsage); 066 nonPersistent.setEnableAudit(isEnableAudit()); 067 nonPersistent.setMaxAuditDepth(getMaxAuditDepth()); 068 nonPersistent.setMaxProducersToAudit(getMaxProducersToAudit()); 069 } 070 nonPersistent.setMessageAudit(getMessageAudit()); 071 nonPersistent.start(); 072 persistent.setMessageAudit(getMessageAudit()); 073 persistent.start(); 074 pendingCount = persistent.size() + nonPersistent.size(); 075 } 076 077 public synchronized void stop() throws Exception { 078 started = false; 079 if (nonPersistent != null) { 080 nonPersistent.destroy(); 081 } 082 persistent.stop(); 083 persistent.gc(); 084 super.stop(); 085 pendingCount = 0; 086 } 087 088 public synchronized boolean addMessageLast(MessageReference node) throws Exception { 089 boolean result = true; 090 if (node != null) { 091 Message msg = node.getMessage(); 092 if (started) { 093 pendingCount++; 094 if (!msg.isPersistent()) { 095 nonPersistent.addMessageLast(node); 096 } 097 } 098 if (msg.isPersistent()) { 099 result = persistent.addMessageLast(node); 100 } 101 } 102 return result; 103 } 104 105 public synchronized void addMessageFirst(MessageReference node) throws Exception { 106 if (node != null) { 107 Message msg = node.getMessage(); 108 if (started) { 109 pendingCount++; 110 if (!msg.isPersistent()) { 111 nonPersistent.addMessageFirst(node); 112 } 113 } 114 if (msg.isPersistent()) { 115 persistent.addMessageFirst(node); 116 } 117 } 118 } 119 120 public synchronized void clear() { 121 pendingCount = 0; 122 } 123 124 public synchronized boolean hasNext() { 125 try { 126 getNextCursor(); 127 } catch (Exception e) { 128 LOG.error("Failed to get current cursor ", e); 129 throw new RuntimeException(e); 130 } 131 return currentCursor != null ? currentCursor.hasNext() : false; 132 } 133 134 public synchronized MessageReference next() { 135 MessageReference result = currentCursor != null ? currentCursor.next() : null; 136 return result; 137 } 138 139 public synchronized void remove() { 140 if (currentCursor != null) { 141 currentCursor.remove(); 142 } 143 pendingCount--; 144 } 145 146 public synchronized void remove(MessageReference node) { 147 if (!node.isPersistent()) { 148 nonPersistent.remove(node); 149 } else { 150 persistent.remove(node); 151 } 152 pendingCount--; 153 } 154 155 public synchronized void reset() { 156 nonPersistent.reset(); 157 persistent.reset(); 158 pendingCount = persistent.size() + nonPersistent.size(); 159 } 160 161 public void release() { 162 nonPersistent.release(); 163 persistent.release(); 164 } 165 166 167 public synchronized int size() { 168 if (pendingCount < 0) { 169 pendingCount = persistent.size() + nonPersistent.size(); 170 } 171 return pendingCount; 172 } 173 174 public synchronized boolean isEmpty() { 175 // if negative, more messages arrived in store since last reset so non empty 176 return pendingCount == 0; 177 } 178 179 /** 180 * Informs the Broker if the subscription needs to intervention to recover 181 * it's state e.g. DurableTopicSubscriber may do 182 * 183 * @see org.apache.activemq.broker.region.cursors.PendingMessageCursor 184 * @return true if recovery required 185 */ 186 public boolean isRecoveryRequired() { 187 return false; 188 } 189 190 /** 191 * @return the nonPersistent Cursor 192 */ 193 public PendingMessageCursor getNonPersistent() { 194 return this.nonPersistent; 195 } 196 197 /** 198 * @param nonPersistent cursor to set 199 */ 200 public void setNonPersistent(PendingMessageCursor nonPersistent) { 201 this.nonPersistent = nonPersistent; 202 } 203 204 public void setMaxBatchSize(int maxBatchSize) { 205 persistent.setMaxBatchSize(maxBatchSize); 206 if (nonPersistent != null) { 207 nonPersistent.setMaxBatchSize(maxBatchSize); 208 } 209 super.setMaxBatchSize(maxBatchSize); 210 } 211 212 213 public void setMaxProducersToAudit(int maxProducersToAudit) { 214 super.setMaxProducersToAudit(maxProducersToAudit); 215 if (persistent != null) { 216 persistent.setMaxProducersToAudit(maxProducersToAudit); 217 } 218 if (nonPersistent != null) { 219 nonPersistent.setMaxProducersToAudit(maxProducersToAudit); 220 } 221 } 222 223 public void setMaxAuditDepth(int maxAuditDepth) { 224 super.setMaxAuditDepth(maxAuditDepth); 225 if (persistent != null) { 226 persistent.setMaxAuditDepth(maxAuditDepth); 227 } 228 if (nonPersistent != null) { 229 nonPersistent.setMaxAuditDepth(maxAuditDepth); 230 } 231 } 232 233 public void setEnableAudit(boolean enableAudit) { 234 super.setEnableAudit(enableAudit); 235 if (persistent != null) { 236 persistent.setEnableAudit(enableAudit); 237 } 238 if (nonPersistent != null) { 239 nonPersistent.setEnableAudit(enableAudit); 240 } 241 } 242 243 @Override 244 public void rollback(MessageId id) { 245 nonPersistent.rollback(id); 246 persistent.rollback(id); 247 } 248 249 @Override 250 public void setUseCache(boolean useCache) { 251 super.setUseCache(useCache); 252 if (persistent != null) { 253 persistent.setUseCache(useCache); 254 } 255 if (nonPersistent != null) { 256 nonPersistent.setUseCache(useCache); 257 } 258 } 259 260 @Override 261 public void setMemoryUsageHighWaterMark(int memoryUsageHighWaterMark) { 262 super.setMemoryUsageHighWaterMark(memoryUsageHighWaterMark); 263 if (persistent != null) { 264 persistent.setMemoryUsageHighWaterMark(memoryUsageHighWaterMark); 265 } 266 if (nonPersistent != null) { 267 nonPersistent.setMemoryUsageHighWaterMark(memoryUsageHighWaterMark); 268 } 269 } 270 271 272 273 public synchronized void gc() { 274 if (persistent != null) { 275 persistent.gc(); 276 } 277 if (nonPersistent != null) { 278 nonPersistent.gc(); 279 } 280 pendingCount = persistent.size() + nonPersistent.size(); 281 } 282 283 public void setSystemUsage(SystemUsage usageManager) { 284 super.setSystemUsage(usageManager); 285 if (persistent != null) { 286 persistent.setSystemUsage(usageManager); 287 } 288 if (nonPersistent != null) { 289 nonPersistent.setSystemUsage(usageManager); 290 } 291 } 292 293 protected synchronized PendingMessageCursor getNextCursor() throws Exception { 294 if (currentCursor == null || !currentCursor.hasMessagesBufferedToDeliver()) { 295 currentCursor = currentCursor == persistent ? nonPersistent : persistent; 296 // sanity check 297 if (currentCursor.isEmpty()) { 298 currentCursor = currentCursor == persistent ? nonPersistent : persistent; 299 } 300 } 301 return currentCursor; 302 } 303 304 @Override 305 public boolean isCacheEnabled() { 306 boolean cacheEnabled = isUseCache(); 307 if (cacheEnabled) { 308 if (persistent != null) { 309 cacheEnabled &= persistent.isCacheEnabled(); 310 } 311 if (nonPersistent != null) { 312 cacheEnabled &= nonPersistent.isCacheEnabled(); 313 } 314 setCacheEnabled(cacheEnabled); 315 } 316 return cacheEnabled; 317 } 318 319 @Override 320 public void rebase() { 321 persistent.rebase(); 322 reset(); 323 } 324 325}