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