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 PendingMessageCursor currentCursor; 040 041 /** 042 * Construct 043 * @param broker 044 * @param queue 045 */ 046 public StoreQueueCursor(Broker broker,Queue queue) { 047 super((queue != null ? queue.isPrioritizedMessages():false)); 048 this.broker=broker; 049 this.queue = queue; 050 this.persistent = new QueueStorePrefetch(queue, broker); 051 currentCursor = persistent; 052 } 053 054 @Override 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 @Override 078 public synchronized void stop() throws Exception { 079 started = false; 080 if (nonPersistent != null) { 081 nonPersistent.destroy(); 082 } 083 persistent.stop(); 084 persistent.gc(); 085 super.stop(); 086 pendingCount = 0; 087 } 088 089 @Override 090 public synchronized boolean tryAddMessageLast(MessageReference node, long maxWait) throws Exception { 091 boolean result = true; 092 if (node != null) { 093 Message msg = node.getMessage(); 094 if (started) { 095 pendingCount++; 096 if (!msg.isPersistent()) { 097 result = nonPersistent.tryAddMessageLast(node, maxWait); 098 } 099 } 100 if (msg.isPersistent()) { 101 result = persistent.addMessageLast(node); 102 } 103 } 104 return result; 105 } 106 107 @Override 108 public synchronized void addMessageFirst(MessageReference node) throws Exception { 109 if (node != null) { 110 Message msg = node.getMessage(); 111 if (started) { 112 pendingCount++; 113 if (!msg.isPersistent()) { 114 nonPersistent.addMessageFirst(node); 115 } 116 } 117 if (msg.isPersistent()) { 118 persistent.addMessageFirst(node); 119 } 120 } 121 } 122 123 @Override 124 public synchronized void clear() { 125 pendingCount = 0; 126 } 127 128 @Override 129 public synchronized boolean hasNext() { 130 try { 131 getNextCursor(); 132 } catch (Exception e) { 133 LOG.error("Failed to get current cursor ", e); 134 throw new RuntimeException(e); 135 } 136 return currentCursor != null ? currentCursor.hasNext() : false; 137 } 138 139 @Override 140 public synchronized MessageReference next() { 141 MessageReference result = currentCursor != null ? currentCursor.next() : null; 142 return result; 143 } 144 145 @Override 146 public synchronized void remove() { 147 if (currentCursor != null) { 148 currentCursor.remove(); 149 } 150 pendingCount--; 151 } 152 153 @Override 154 public synchronized void remove(MessageReference node) { 155 if (!node.isPersistent()) { 156 nonPersistent.remove(node); 157 } else { 158 persistent.remove(node); 159 } 160 pendingCount--; 161 } 162 163 @Override 164 public synchronized void reset() { 165 nonPersistent.reset(); 166 persistent.reset(); 167 pendingCount = persistent.size() + nonPersistent.size(); 168 } 169 170 @Override 171 public void release() { 172 nonPersistent.release(); 173 persistent.release(); 174 } 175 176 177 @Override 178 public synchronized int size() { 179 if (pendingCount < 0) { 180 pendingCount = persistent.size() + nonPersistent.size(); 181 } 182 return pendingCount; 183 } 184 185 @Override 186 public synchronized long messageSize() { 187 return persistent.messageSize() + nonPersistent.messageSize(); 188 } 189 190 @Override 191 public synchronized boolean isEmpty() { 192 // if negative, more messages arrived in store since last reset so non empty 193 return pendingCount == 0; 194 } 195 196 /** 197 * Informs the Broker if the subscription needs to intervention to recover 198 * it's state e.g. DurableTopicSubscriber may do 199 * 200 * @see org.apache.activemq.broker.region.cursors.PendingMessageCursor 201 * @return true if recovery required 202 */ 203 @Override 204 public boolean isRecoveryRequired() { 205 return false; 206 } 207 208 /** 209 * @return the nonPersistent Cursor 210 */ 211 public PendingMessageCursor getNonPersistent() { 212 return this.nonPersistent; 213 } 214 215 /** 216 * @param nonPersistent cursor to set 217 */ 218 public void setNonPersistent(PendingMessageCursor nonPersistent) { 219 this.nonPersistent = nonPersistent; 220 } 221 222 /** 223 * @return the persistent Cursor 224 */ 225 public PendingMessageCursor getPersistent() { return this.persistent; } 226 227 @Override 228 public void setMaxBatchSize(int maxBatchSize) { 229 persistent.setMaxBatchSize(maxBatchSize); 230 if (nonPersistent != null) { 231 nonPersistent.setMaxBatchSize(maxBatchSize); 232 } 233 super.setMaxBatchSize(maxBatchSize); 234 } 235 236 237 @Override 238 public void setMaxProducersToAudit(int maxProducersToAudit) { 239 super.setMaxProducersToAudit(maxProducersToAudit); 240 if (persistent != null) { 241 persistent.setMaxProducersToAudit(maxProducersToAudit); 242 } 243 if (nonPersistent != null) { 244 nonPersistent.setMaxProducersToAudit(maxProducersToAudit); 245 } 246 } 247 248 @Override 249 public void setMaxAuditDepth(int maxAuditDepth) { 250 super.setMaxAuditDepth(maxAuditDepth); 251 if (persistent != null) { 252 persistent.setMaxAuditDepth(maxAuditDepth); 253 } 254 if (nonPersistent != null) { 255 nonPersistent.setMaxAuditDepth(maxAuditDepth); 256 } 257 } 258 259 @Override 260 public void setEnableAudit(boolean enableAudit) { 261 super.setEnableAudit(enableAudit); 262 if (persistent != null) { 263 persistent.setEnableAudit(enableAudit); 264 } 265 if (nonPersistent != null) { 266 nonPersistent.setEnableAudit(enableAudit); 267 } 268 } 269 270 @Override 271 public void rollback(MessageId id) { 272 nonPersistent.rollback(id); 273 persistent.rollback(id); 274 } 275 276 @Override 277 public void setUseCache(boolean useCache) { 278 super.setUseCache(useCache); 279 if (persistent != null) { 280 persistent.setUseCache(useCache); 281 } 282 if (nonPersistent != null) { 283 nonPersistent.setUseCache(useCache); 284 } 285 } 286 287 @Override 288 public void setMemoryUsageHighWaterMark(int memoryUsageHighWaterMark) { 289 super.setMemoryUsageHighWaterMark(memoryUsageHighWaterMark); 290 if (persistent != null) { 291 persistent.setMemoryUsageHighWaterMark(memoryUsageHighWaterMark); 292 } 293 if (nonPersistent != null) { 294 nonPersistent.setMemoryUsageHighWaterMark(memoryUsageHighWaterMark); 295 } 296 } 297 298 299 300 @Override 301 public synchronized void gc() { 302 if (persistent != null) { 303 persistent.gc(); 304 } 305 if (nonPersistent != null) { 306 nonPersistent.gc(); 307 } 308 pendingCount = persistent.size() + nonPersistent.size(); 309 } 310 311 @Override 312 public void setSystemUsage(SystemUsage usageManager) { 313 super.setSystemUsage(usageManager); 314 if (persistent != null) { 315 persistent.setSystemUsage(usageManager); 316 } 317 if (nonPersistent != null) { 318 nonPersistent.setSystemUsage(usageManager); 319 } 320 } 321 322 protected synchronized PendingMessageCursor getNextCursor() throws Exception { 323 if (currentCursor == null || !currentCursor.hasMessagesBufferedToDeliver()) { 324 currentCursor = currentCursor == persistent ? nonPersistent : persistent; 325 // sanity check 326 if (currentCursor.isEmpty()) { 327 currentCursor = currentCursor == persistent ? nonPersistent : persistent; 328 } 329 } 330 return currentCursor; 331 } 332 333 @Override 334 public boolean isCacheEnabled() { 335 boolean cacheEnabled = isUseCache(); 336 if (cacheEnabled) { 337 if (persistent != null) { 338 cacheEnabled &= persistent.isCacheEnabled(); 339 } 340 if (nonPersistent != null) { 341 cacheEnabled &= nonPersistent.isCacheEnabled(); 342 } 343 setCacheEnabled(cacheEnabled); 344 } 345 return cacheEnabled; 346 } 347 348 @Override 349 public void rebase() { 350 persistent.rebase(); 351 reset(); 352 } 353 354}