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.store.journal; 018 019import java.io.File; 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.HashSet; 023import java.util.Iterator; 024import java.util.Set; 025import java.util.concurrent.Callable; 026import java.util.concurrent.ConcurrentHashMap; 027import java.util.concurrent.CountDownLatch; 028import java.util.concurrent.FutureTask; 029import java.util.concurrent.LinkedBlockingQueue; 030import java.util.concurrent.ThreadFactory; 031import java.util.concurrent.ThreadPoolExecutor; 032import java.util.concurrent.TimeUnit; 033import java.util.concurrent.atomic.AtomicBoolean; 034 035import org.apache.activeio.journal.InvalidRecordLocationException; 036import org.apache.activeio.journal.Journal; 037import org.apache.activeio.journal.JournalEventListener; 038import org.apache.activeio.journal.RecordLocation; 039import org.apache.activeio.packet.ByteArrayPacket; 040import org.apache.activeio.packet.Packet; 041import org.apache.activemq.broker.BrokerService; 042import org.apache.activemq.broker.BrokerServiceAware; 043import org.apache.activemq.broker.ConnectionContext; 044import org.apache.activemq.broker.scheduler.JobSchedulerStore; 045import org.apache.activemq.command.ActiveMQDestination; 046import org.apache.activemq.command.ActiveMQQueue; 047import org.apache.activemq.command.ActiveMQTopic; 048import org.apache.activemq.command.DataStructure; 049import org.apache.activemq.command.JournalQueueAck; 050import org.apache.activemq.command.JournalTopicAck; 051import org.apache.activemq.command.JournalTrace; 052import org.apache.activemq.command.JournalTransaction; 053import org.apache.activemq.command.Message; 054import org.apache.activemq.command.MessageAck; 055import org.apache.activemq.command.ProducerId; 056import org.apache.activemq.filter.NonCachedMessageEvaluationContext; 057import org.apache.activemq.openwire.OpenWireFormat; 058import org.apache.activemq.store.MessageStore; 059import org.apache.activemq.store.PersistenceAdapter; 060import org.apache.activemq.store.TopicMessageStore; 061import org.apache.activemq.store.TransactionStore; 062import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; 063import org.apache.activemq.store.journal.JournalTransactionStore.Tx; 064import org.apache.activemq.store.journal.JournalTransactionStore.TxOperation; 065import org.apache.activemq.thread.Scheduler; 066import org.apache.activemq.thread.Task; 067import org.apache.activemq.thread.TaskRunner; 068import org.apache.activemq.thread.TaskRunnerFactory; 069import org.apache.activemq.usage.SystemUsage; 070import org.apache.activemq.usage.Usage; 071import org.apache.activemq.usage.UsageListener; 072import org.apache.activemq.util.ByteSequence; 073import org.apache.activemq.util.IOExceptionSupport; 074import org.apache.activemq.util.ThreadPoolUtils; 075import org.apache.activemq.wireformat.WireFormat; 076import org.slf4j.Logger; 077import org.slf4j.LoggerFactory; 078 079/** 080 * An implementation of {@link PersistenceAdapter} designed for use with a 081 * {@link Journal} and then check pointing asynchronously on a timeout with some 082 * other long term persistent storage. 083 * 084 * @org.apache.xbean.XBean 085 * 086 */ 087public class JournalPersistenceAdapter implements PersistenceAdapter, JournalEventListener, UsageListener, BrokerServiceAware { 088 089 private BrokerService brokerService; 090 091 protected Scheduler scheduler; 092 private static final Logger LOG = LoggerFactory.getLogger(JournalPersistenceAdapter.class); 093 094 private Journal journal; 095 private PersistenceAdapter longTermPersistence; 096 097 private final WireFormat wireFormat = new OpenWireFormat(); 098 099 private final ConcurrentHashMap<ActiveMQQueue, JournalMessageStore> queues = new ConcurrentHashMap<ActiveMQQueue, JournalMessageStore>(); 100 private final ConcurrentHashMap<ActiveMQTopic, JournalTopicMessageStore> topics = new ConcurrentHashMap<ActiveMQTopic, JournalTopicMessageStore>(); 101 102 private SystemUsage usageManager; 103 private long checkpointInterval = 1000 * 60 * 5; 104 private long lastCheckpointRequest = System.currentTimeMillis(); 105 private long lastCleanup = System.currentTimeMillis(); 106 private int maxCheckpointWorkers = 10; 107 private int maxCheckpointMessageAddSize = 1024 * 1024; 108 109 private final JournalTransactionStore transactionStore = new JournalTransactionStore(this); 110 private ThreadPoolExecutor checkpointExecutor; 111 112 private TaskRunner checkpointTask; 113 private CountDownLatch nextCheckpointCountDownLatch = new CountDownLatch(1); 114 private boolean fullCheckPoint; 115 116 private final AtomicBoolean started = new AtomicBoolean(false); 117 118 private final Runnable periodicCheckpointTask = createPeriodicCheckpointTask(); 119 120 private TaskRunnerFactory taskRunnerFactory; 121 private File directory; 122 123 public JournalPersistenceAdapter() { 124 } 125 126 public JournalPersistenceAdapter(Journal journal, PersistenceAdapter longTermPersistence, TaskRunnerFactory taskRunnerFactory) throws IOException { 127 setJournal(journal); 128 setTaskRunnerFactory(taskRunnerFactory); 129 setPersistenceAdapter(longTermPersistence); 130 } 131 132 public void setTaskRunnerFactory(TaskRunnerFactory taskRunnerFactory) { 133 this.taskRunnerFactory = taskRunnerFactory; 134 } 135 136 public void setJournal(Journal journal) { 137 this.journal = journal; 138 journal.setJournalEventListener(this); 139 } 140 141 public void setPersistenceAdapter(PersistenceAdapter longTermPersistence) { 142 this.longTermPersistence = longTermPersistence; 143 } 144 145 final Runnable createPeriodicCheckpointTask() { 146 return new Runnable() { 147 @Override 148 public void run() { 149 long lastTime = 0; 150 synchronized (this) { 151 lastTime = lastCheckpointRequest; 152 } 153 if (System.currentTimeMillis() > lastTime + checkpointInterval) { 154 checkpoint(false, true); 155 } 156 } 157 }; 158 } 159 160 /** 161 * @param usageManager The UsageManager that is controlling the 162 * destination's memory usage. 163 */ 164 @Override 165 public void setUsageManager(SystemUsage usageManager) { 166 this.usageManager = usageManager; 167 longTermPersistence.setUsageManager(usageManager); 168 } 169 170 @Override 171 public Set<ActiveMQDestination> getDestinations() { 172 Set<ActiveMQDestination> destinations = new HashSet<ActiveMQDestination>(longTermPersistence.getDestinations()); 173 destinations.addAll(queues.keySet()); 174 destinations.addAll(topics.keySet()); 175 return destinations; 176 } 177 178 private MessageStore createMessageStore(ActiveMQDestination destination) throws IOException { 179 if (destination.isQueue()) { 180 return createQueueMessageStore((ActiveMQQueue)destination); 181 } else { 182 return createTopicMessageStore((ActiveMQTopic)destination); 183 } 184 } 185 186 @Override 187 public MessageStore createQueueMessageStore(ActiveMQQueue destination) throws IOException { 188 JournalMessageStore store = queues.get(destination); 189 if (store == null) { 190 MessageStore checkpointStore = longTermPersistence.createQueueMessageStore(destination); 191 store = new JournalMessageStore(this, checkpointStore, destination); 192 queues.put(destination, store); 193 } 194 return store; 195 } 196 197 @Override 198 public TopicMessageStore createTopicMessageStore(ActiveMQTopic destinationName) throws IOException { 199 JournalTopicMessageStore store = topics.get(destinationName); 200 if (store == null) { 201 TopicMessageStore checkpointStore = longTermPersistence.createTopicMessageStore(destinationName); 202 store = new JournalTopicMessageStore(this, checkpointStore, destinationName); 203 topics.put(destinationName, store); 204 } 205 return store; 206 } 207 208 /** 209 * Cleanup method to remove any state associated with the given destination 210 * 211 * @param destination Destination to forget 212 */ 213 @Override 214 public void removeQueueMessageStore(ActiveMQQueue destination) { 215 queues.remove(destination); 216 } 217 218 /** 219 * Cleanup method to remove any state associated with the given destination 220 * 221 * @param destination Destination to forget 222 */ 223 @Override 224 public void removeTopicMessageStore(ActiveMQTopic destination) { 225 topics.remove(destination); 226 } 227 228 @Override 229 public TransactionStore createTransactionStore() throws IOException { 230 return transactionStore; 231 } 232 233 @Override 234 public long getLastMessageBrokerSequenceId() throws IOException { 235 return longTermPersistence.getLastMessageBrokerSequenceId(); 236 } 237 238 @Override 239 public void beginTransaction(ConnectionContext context) throws IOException { 240 longTermPersistence.beginTransaction(context); 241 } 242 243 @Override 244 public void commitTransaction(ConnectionContext context) throws IOException { 245 longTermPersistence.commitTransaction(context); 246 } 247 248 @Override 249 public void rollbackTransaction(ConnectionContext context) throws IOException { 250 longTermPersistence.rollbackTransaction(context); 251 } 252 253 @Override 254 public synchronized void start() throws Exception { 255 if (!started.compareAndSet(false, true)) { 256 return; 257 } 258 259 if( brokerService!=null ) { 260 wireFormat.setVersion(brokerService.getStoreOpenWireVersion()); 261 } 262 263 checkpointTask = taskRunnerFactory.createTaskRunner(new Task() { 264 @Override 265 public boolean iterate() { 266 return doCheckpoint(); 267 } 268 }, "ActiveMQ Journal Checkpoint Worker"); 269 270 checkpointExecutor = new ThreadPoolExecutor(maxCheckpointWorkers, maxCheckpointWorkers, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() { 271 @Override 272 public Thread newThread(Runnable runable) { 273 Thread t = new Thread(runable, "Journal checkpoint worker"); 274 t.setPriority(7); 275 return t; 276 } 277 }); 278 // checkpointExecutor.allowCoreThreadTimeOut(true); 279 280 this.usageManager.getMemoryUsage().addUsageListener(this); 281 282 if (longTermPersistence instanceof JDBCPersistenceAdapter) { 283 // Disabled periodic clean up as it deadlocks with the checkpoint 284 // operations. 285 ((JDBCPersistenceAdapter)longTermPersistence).setCleanupPeriod(0); 286 } 287 288 longTermPersistence.start(); 289 createTransactionStore(); 290 recover(); 291 292 // Do a checkpoint periodically. 293 this.scheduler = new Scheduler("Journal Scheduler"); 294 this.scheduler.start(); 295 this.scheduler.executePeriodically(periodicCheckpointTask, checkpointInterval / 10); 296 297 } 298 299 @Override 300 public void stop() throws Exception { 301 302 this.usageManager.getMemoryUsage().removeUsageListener(this); 303 if (!started.compareAndSet(true, false)) { 304 return; 305 } 306 307 this.scheduler.cancel(periodicCheckpointTask); 308 this.scheduler.stop(); 309 310 // Take one final checkpoint and stop checkpoint processing. 311 checkpoint(true, true); 312 checkpointTask.shutdown(); 313 ThreadPoolUtils.shutdown(checkpointExecutor); 314 checkpointExecutor = null; 315 316 queues.clear(); 317 topics.clear(); 318 319 IOException firstException = null; 320 try { 321 journal.close(); 322 } catch (Exception e) { 323 firstException = IOExceptionSupport.create("Failed to close journals: " + e, e); 324 } 325 longTermPersistence.stop(); 326 327 if (firstException != null) { 328 throw firstException; 329 } 330 } 331 332 // Properties 333 // ------------------------------------------------------------------------- 334 public PersistenceAdapter getLongTermPersistence() { 335 return longTermPersistence; 336 } 337 338 /** 339 * @return Returns the wireFormat. 340 */ 341 public WireFormat getWireFormat() { 342 return wireFormat; 343 } 344 345 // Implementation methods 346 // ------------------------------------------------------------------------- 347 348 /** 349 * The Journal give us a call back so that we can move old data out of the 350 * journal. Taking a checkpoint does this for us. 351 * 352 * @see org.apache.activemq.journal.JournalEventListener#overflowNotification(org.apache.activemq.journal.RecordLocation) 353 */ 354 @Override 355 public void overflowNotification(RecordLocation safeLocation) { 356 checkpoint(false, true); 357 } 358 359 /** 360 * When we checkpoint we move all the journalled data to long term storage. 361 * 362 */ 363 public void checkpoint(boolean sync, boolean fullCheckpoint) { 364 try { 365 if (journal == null) { 366 throw new IllegalStateException("Journal is closed."); 367 } 368 369 long now = System.currentTimeMillis(); 370 CountDownLatch latch = null; 371 synchronized (this) { 372 latch = nextCheckpointCountDownLatch; 373 lastCheckpointRequest = now; 374 if (fullCheckpoint) { 375 this.fullCheckPoint = true; 376 } 377 } 378 379 checkpointTask.wakeup(); 380 381 if (sync) { 382 LOG.debug("Waking for checkpoint to complete."); 383 latch.await(); 384 } 385 } catch (InterruptedException e) { 386 Thread.currentThread().interrupt(); 387 LOG.warn("Request to start checkpoint failed: " + e, e); 388 } 389 } 390 391 @Override 392 public void checkpoint(boolean sync) { 393 checkpoint(sync, sync); 394 } 395 396 /** 397 * This does the actual checkpoint. 398 * 399 * @return 400 */ 401 public boolean doCheckpoint() { 402 CountDownLatch latch = null; 403 boolean fullCheckpoint; 404 synchronized (this) { 405 latch = nextCheckpointCountDownLatch; 406 nextCheckpointCountDownLatch = new CountDownLatch(1); 407 fullCheckpoint = this.fullCheckPoint; 408 this.fullCheckPoint = false; 409 } 410 try { 411 412 LOG.debug("Checkpoint started."); 413 RecordLocation newMark = null; 414 415 ArrayList<FutureTask<RecordLocation>> futureTasks = new ArrayList<FutureTask<RecordLocation>>(queues.size() + topics.size()); 416 417 // 418 // We do many partial checkpoints (fullCheckpoint==false) to move 419 // topic messages 420 // to long term store as soon as possible. 421 // 422 // We want to avoid doing that for queue messages since removes the 423 // come in the same 424 // checkpoint cycle will nullify the previous message add. 425 // Therefore, we only 426 // checkpoint queues on the fullCheckpoint cycles. 427 // 428 if (fullCheckpoint) { 429 Iterator<JournalMessageStore> iterator = queues.values().iterator(); 430 while (iterator.hasNext()) { 431 try { 432 final JournalMessageStore ms = iterator.next(); 433 FutureTask<RecordLocation> task = new FutureTask<RecordLocation>(new Callable<RecordLocation>() { 434 @Override 435 public RecordLocation call() throws Exception { 436 return ms.checkpoint(); 437 } 438 }); 439 futureTasks.add(task); 440 checkpointExecutor.execute(task); 441 } catch (Exception e) { 442 LOG.error("Failed to checkpoint a message store: " + e, e); 443 } 444 } 445 } 446 447 Iterator<JournalTopicMessageStore> iterator = topics.values().iterator(); 448 while (iterator.hasNext()) { 449 try { 450 final JournalTopicMessageStore ms = iterator.next(); 451 FutureTask<RecordLocation> task = new FutureTask<RecordLocation>(new Callable<RecordLocation>() { 452 @Override 453 public RecordLocation call() throws Exception { 454 return ms.checkpoint(); 455 } 456 }); 457 futureTasks.add(task); 458 checkpointExecutor.execute(task); 459 } catch (Exception e) { 460 LOG.error("Failed to checkpoint a message store: " + e, e); 461 } 462 } 463 464 try { 465 for (Iterator<FutureTask<RecordLocation>> iter = futureTasks.iterator(); iter.hasNext();) { 466 FutureTask<RecordLocation> ft = iter.next(); 467 RecordLocation mark = ft.get(); 468 // We only set a newMark on full checkpoints. 469 if (fullCheckpoint) { 470 if (mark != null && (newMark == null || newMark.compareTo(mark) < 0)) { 471 newMark = mark; 472 } 473 } 474 } 475 } catch (Throwable e) { 476 LOG.error("Failed to checkpoint a message store: " + e, e); 477 } 478 479 if (fullCheckpoint) { 480 try { 481 if (newMark != null) { 482 LOG.debug("Marking journal at: " + newMark); 483 journal.setMark(newMark, true); 484 } 485 } catch (Exception e) { 486 LOG.error("Failed to mark the Journal: " + e, e); 487 } 488 489 if (longTermPersistence instanceof JDBCPersistenceAdapter) { 490 // We may be check pointing more often than the 491 // checkpointInterval if under high use 492 // But we don't want to clean up the db that often. 493 long now = System.currentTimeMillis(); 494 if (now > lastCleanup + checkpointInterval) { 495 lastCleanup = now; 496 ((JDBCPersistenceAdapter)longTermPersistence).cleanup(); 497 } 498 } 499 } 500 501 LOG.debug("Checkpoint done."); 502 } finally { 503 latch.countDown(); 504 } 505 synchronized (this) { 506 return this.fullCheckPoint; 507 } 508 509 } 510 511 /** 512 * @param location 513 * @return 514 * @throws IOException 515 */ 516 public DataStructure readCommand(RecordLocation location) throws IOException { 517 try { 518 Packet packet = journal.read(location); 519 return (DataStructure)wireFormat.unmarshal(toByteSequence(packet)); 520 } catch (InvalidRecordLocationException e) { 521 throw createReadException(location, e); 522 } catch (IOException e) { 523 throw createReadException(location, e); 524 } 525 } 526 527 /** 528 * Move all the messages that were in the journal into long term storage. We 529 * just replay and do a checkpoint. 530 * 531 * @throws IOException 532 * @throws IOException 533 * @throws InvalidRecordLocationException 534 * @throws IllegalStateException 535 */ 536 private void recover() throws IllegalStateException, InvalidRecordLocationException, IOException, IOException { 537 538 RecordLocation pos = null; 539 int transactionCounter = 0; 540 541 LOG.info("Journal Recovery Started from: " + journal); 542 ConnectionContext context = new ConnectionContext(new NonCachedMessageEvaluationContext()); 543 544 // While we have records in the journal. 545 while ((pos = journal.getNextRecordLocation(pos)) != null) { 546 Packet data = journal.read(pos); 547 DataStructure c = (DataStructure)wireFormat.unmarshal(toByteSequence(data)); 548 549 if (c instanceof Message) { 550 Message message = (Message)c; 551 JournalMessageStore store = (JournalMessageStore)createMessageStore(message.getDestination()); 552 if (message.isInTransaction()) { 553 transactionStore.addMessage(store, message, pos); 554 } else { 555 store.replayAddMessage(context, message); 556 transactionCounter++; 557 } 558 } else { 559 switch (c.getDataStructureType()) { 560 case JournalQueueAck.DATA_STRUCTURE_TYPE: { 561 JournalQueueAck command = (JournalQueueAck)c; 562 JournalMessageStore store = (JournalMessageStore)createMessageStore(command.getDestination()); 563 if (command.getMessageAck().isInTransaction()) { 564 transactionStore.removeMessage(store, command.getMessageAck(), pos); 565 } else { 566 store.replayRemoveMessage(context, command.getMessageAck()); 567 transactionCounter++; 568 } 569 } 570 break; 571 case JournalTopicAck.DATA_STRUCTURE_TYPE: { 572 JournalTopicAck command = (JournalTopicAck)c; 573 JournalTopicMessageStore store = (JournalTopicMessageStore)createMessageStore(command.getDestination()); 574 if (command.getTransactionId() != null) { 575 transactionStore.acknowledge(store, command, pos); 576 } else { 577 store.replayAcknowledge(context, command.getClientId(), command.getSubscritionName(), command.getMessageId()); 578 transactionCounter++; 579 } 580 } 581 break; 582 case JournalTransaction.DATA_STRUCTURE_TYPE: { 583 JournalTransaction command = (JournalTransaction)c; 584 try { 585 // Try to replay the packet. 586 switch (command.getType()) { 587 case JournalTransaction.XA_PREPARE: 588 transactionStore.replayPrepare(command.getTransactionId()); 589 break; 590 case JournalTransaction.XA_COMMIT: 591 case JournalTransaction.LOCAL_COMMIT: 592 Tx tx = transactionStore.replayCommit(command.getTransactionId(), command.getWasPrepared()); 593 if (tx == null) { 594 break; // We may be trying to replay a commit 595 } 596 // that 597 // was already committed. 598 599 // Replay the committed operations. 600 tx.getOperations(); 601 for (Iterator iter = tx.getOperations().iterator(); iter.hasNext();) { 602 TxOperation op = (TxOperation)iter.next(); 603 if (op.operationType == TxOperation.ADD_OPERATION_TYPE) { 604 op.store.replayAddMessage(context, (Message)op.data); 605 } 606 if (op.operationType == TxOperation.REMOVE_OPERATION_TYPE) { 607 op.store.replayRemoveMessage(context, (MessageAck)op.data); 608 } 609 if (op.operationType == TxOperation.ACK_OPERATION_TYPE) { 610 JournalTopicAck ack = (JournalTopicAck)op.data; 611 ((JournalTopicMessageStore)op.store).replayAcknowledge(context, ack.getClientId(), ack.getSubscritionName(), ack.getMessageId()); 612 } 613 } 614 transactionCounter++; 615 break; 616 case JournalTransaction.LOCAL_ROLLBACK: 617 case JournalTransaction.XA_ROLLBACK: 618 transactionStore.replayRollback(command.getTransactionId()); 619 break; 620 default: 621 throw new IOException("Invalid journal command type: " + command.getType()); 622 } 623 } catch (IOException e) { 624 LOG.error("Recovery Failure: Could not replay: " + c + ", reason: " + e, e); 625 } 626 } 627 break; 628 case JournalTrace.DATA_STRUCTURE_TYPE: 629 JournalTrace trace = (JournalTrace)c; 630 LOG.debug("TRACE Entry: " + trace.getMessage()); 631 break; 632 default: 633 LOG.error("Unknown type of record in transaction log which will be discarded: " + c); 634 } 635 } 636 } 637 638 RecordLocation location = writeTraceMessage("RECOVERED", true); 639 journal.setMark(location, true); 640 641 LOG.info("Journal Recovered: " + transactionCounter + " message(s) in transactions recovered."); 642 } 643 644 private IOException createReadException(RecordLocation location, Exception e) { 645 return IOExceptionSupport.create("Failed to read to journal for: " + location + ". Reason: " + e, e); 646 } 647 648 protected IOException createWriteException(DataStructure packet, Exception e) { 649 return IOExceptionSupport.create("Failed to write to journal for: " + packet + ". Reason: " + e, e); 650 } 651 652 protected IOException createWriteException(String command, Exception e) { 653 return IOExceptionSupport.create("Failed to write to journal for command: " + command + ". Reason: " + e, e); 654 } 655 656 protected IOException createRecoveryFailedException(Exception e) { 657 return IOExceptionSupport.create("Failed to recover from journal. Reason: " + e, e); 658 } 659 660 /** 661 * @param command 662 * @param sync 663 * @return 664 * @throws IOException 665 */ 666 public RecordLocation writeCommand(DataStructure command, boolean sync) throws IOException { 667 if (started.get()) { 668 try { 669 return journal.write(toPacket(wireFormat.marshal(command)), sync); 670 } catch (IOException ioe) { 671 LOG.error("Cannot write to the journal", ioe); 672 brokerService.handleIOException(ioe); 673 throw ioe; 674 } 675 } 676 throw new IOException("closed"); 677 } 678 679 private RecordLocation writeTraceMessage(String message, boolean sync) throws IOException { 680 JournalTrace trace = new JournalTrace(); 681 trace.setMessage(message); 682 return writeCommand(trace, sync); 683 } 684 685 @Override 686 public void onUsageChanged(Usage usage, int oldPercentUsage, int newPercentUsage) { 687 newPercentUsage = (newPercentUsage / 10) * 10; 688 oldPercentUsage = (oldPercentUsage / 10) * 10; 689 if (newPercentUsage >= 70 && oldPercentUsage < newPercentUsage) { 690 boolean sync = newPercentUsage >= 90; 691 checkpoint(sync, true); 692 } 693 } 694 695 public JournalTransactionStore getTransactionStore() { 696 return transactionStore; 697 } 698 699 @Override 700 public void deleteAllMessages() throws IOException { 701 try { 702 JournalTrace trace = new JournalTrace(); 703 trace.setMessage("DELETED"); 704 RecordLocation location = journal.write(toPacket(wireFormat.marshal(trace)), false); 705 journal.setMark(location, true); 706 LOG.info("Journal deleted: "); 707 } catch (IOException e) { 708 throw e; 709 } catch (Throwable e) { 710 throw IOExceptionSupport.create(e); 711 } 712 longTermPersistence.deleteAllMessages(); 713 } 714 715 public SystemUsage getUsageManager() { 716 return usageManager; 717 } 718 719 public int getMaxCheckpointMessageAddSize() { 720 return maxCheckpointMessageAddSize; 721 } 722 723 public void setMaxCheckpointMessageAddSize(int maxCheckpointMessageAddSize) { 724 this.maxCheckpointMessageAddSize = maxCheckpointMessageAddSize; 725 } 726 727 public int getMaxCheckpointWorkers() { 728 return maxCheckpointWorkers; 729 } 730 731 public void setMaxCheckpointWorkers(int maxCheckpointWorkers) { 732 this.maxCheckpointWorkers = maxCheckpointWorkers; 733 } 734 735 public long getCheckpointInterval() { 736 return checkpointInterval; 737 } 738 739 public void setCheckpointInterval(long checkpointInterval) { 740 this.checkpointInterval = checkpointInterval; 741 } 742 743 public boolean isUseExternalMessageReferences() { 744 return false; 745 } 746 747 public void setUseExternalMessageReferences(boolean enable) { 748 if (enable) { 749 throw new IllegalArgumentException("The journal does not support message references."); 750 } 751 } 752 753 public Packet toPacket(ByteSequence sequence) { 754 return new ByteArrayPacket(new org.apache.activeio.packet.ByteSequence(sequence.data, sequence.offset, sequence.length)); 755 } 756 757 public ByteSequence toByteSequence(Packet packet) { 758 org.apache.activeio.packet.ByteSequence sequence = packet.asByteSequence(); 759 return new ByteSequence(sequence.getData(), sequence.getOffset(), sequence.getLength()); 760 } 761 762 @Override 763 public void setBrokerName(String brokerName) { 764 longTermPersistence.setBrokerName(brokerName); 765 } 766 767 @Override 768 public String toString() { 769 return "JournalPersistenceAdapter(" + longTermPersistence + ")"; 770 } 771 772 @Override 773 public void setDirectory(File dir) { 774 this.directory=dir; 775 } 776 777 @Override 778 public File getDirectory(){ 779 return directory; 780 } 781 782 @Override 783 public long size(){ 784 return 0; 785 } 786 787 @Override 788 public void setBrokerService(BrokerService brokerService) { 789 this.brokerService = brokerService; 790 PersistenceAdapter pa = getLongTermPersistence(); 791 if( pa instanceof BrokerServiceAware ) { 792 ((BrokerServiceAware)pa).setBrokerService(brokerService); 793 } 794 } 795 796 @Override 797 public long getLastProducerSequenceId(ProducerId id) { 798 return -1; 799 } 800 801 @Override 802 public JobSchedulerStore createJobSchedulerStore() throws IOException, UnsupportedOperationException { 803 return longTermPersistence.createJobSchedulerStore(); 804 } 805 806}