/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.artemis.core.persistence; import javax.transaction.xa.Xid; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import org.apache.activemq.artemis.api.core.Message; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.JournalLoadInformation; import org.apache.activemq.artemis.core.paging.PageTransactionInfo; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.PagingManager; import org.apache.activemq.artemis.core.paging.PagingStore; import org.apache.activemq.artemis.core.paging.cursor.PagePosition; import org.apache.activemq.artemis.core.persistence.config.PersistedAddressSetting; import org.apache.activemq.artemis.core.persistence.config.PersistedRoles; import org.apache.activemq.artemis.core.persistence.impl.PageCountPending; import org.apache.activemq.artemis.core.postoffice.Binding; import org.apache.activemq.artemis.core.postoffice.PostOffice; import org.apache.activemq.artemis.core.replication.ReplicationManager; import org.apache.activemq.artemis.core.server.ActiveMQComponent; import org.apache.activemq.artemis.core.server.LargeServerMessage; import org.apache.activemq.artemis.core.server.MessageReference; import org.apache.activemq.artemis.core.server.RouteContextList; import org.apache.activemq.artemis.core.server.files.FileStoreMonitor; import org.apache.activemq.artemis.core.server.group.impl.GroupBinding; import org.apache.activemq.artemis.core.server.impl.AddressInfo; import org.apache.activemq.artemis.core.server.impl.JournalLoader; import org.apache.activemq.artemis.core.transaction.ResourceManager; import org.apache.activemq.artemis.core.transaction.Transaction; import org.apache.activemq.artemis.utils.IDGenerator; /** * A StorageManager * * Note about IDGEnerator * * I've changed StorageManager to extend IDGenerator, because in some places * all we needed from the StorageManager was the idGeneration. * I couldn't just get the IDGenerator from the inner part because the NullPersistent has its own sequence. * So the best was to add the interface and adjust the callers for the method */ public interface StorageManager extends IDGenerator, ActiveMQComponent { void criticalError(Throwable error); /** * Get the context associated with the thread for later reuse */ OperationContext getContext(); void lineUpContext(); /** * It just creates an OperationContext without associating it */ OperationContext newContext(Executor executor); OperationContext newSingleThreadContext(); /** * Set the context back to the thread */ void setContext(OperationContext context); /** * * @param ioCriticalError is the server being stopped due to an IO critical error. * @param sendFailover this is to send the replication stopping in case of replication. * @throws Exception */ void stop(boolean ioCriticalError, boolean sendFailover) throws Exception; // Message related operations void pageClosed(SimpleString storeName, int pageNumber); void pageDeleted(SimpleString storeName, int pageNumber); void pageWrite(PagedMessage message, int pageNumber); void afterCompleteOperations(IOCallback run); /** * This is similar to afterComplete, however this only cares about the journal part. */ void afterStoreOperations(IOCallback run); /** * Block until the operations are done. * Warning: Don't use it inside an ordered executor, otherwise the system may lock up * in case of the pools are full * * @throws Exception */ boolean waitOnOperations(long timeout) throws Exception; /** * Block until the operations are done. * Warning: Don't use it inside an ordered executor, otherwise the system may lock up * in case of the pools are full * * @throws Exception */ void waitOnOperations() throws Exception; /** * We need a safeguard in place to avoid too much concurrent IO happening on Paging, otherwise * the system may become unresponsive if too many destinations are reading all the same time. * This is called before we read, so we can limit concurrent reads * * @throws Exception */ void beforePageRead() throws Exception; /** * We need a safeguard in place to avoid too much concurrent IO happening on Paging, otherwise * the system may become unresponsive if too many destinations are reading all the same time. * This is called after we read, so we can limit concurrent reads * * @throws Exception */ void afterPageRead() throws Exception; /** * AIO has an optimized buffer which has a method to release it * instead of the way NIO will release data based on GC. * These methods will use that buffer if the inner method supports it */ ByteBuffer allocateDirectBuffer(int size); /** * AIO has an optimized buffer which has a method to release it * instead of the way NIO will release data based on GC. * These methods will use that buffer if the inner method supports it */ void freeDirectBuffer(ByteBuffer buffer); void clearContext(); /** * Confirms that a large message was finished */ void confirmPendingLargeMessageTX(Transaction transaction, long messageID, long recordID) throws Exception; /** * Confirms that a large message was finished */ void confirmPendingLargeMessage(long recordID) throws Exception; void storeMessage(Message message) throws Exception; void storeReference(long queueID, long messageID, boolean last) throws Exception; void deleteMessage(long messageID) throws Exception; void storeAcknowledge(long queueID, long messageID) throws Exception; void storeCursorAcknowledge(long queueID, PagePosition position) throws Exception; void updateDeliveryCount(MessageReference ref) throws Exception; void updateScheduledDeliveryTime(MessageReference ref) throws Exception; void storeDuplicateID(SimpleString address, byte[] duplID, long recordID) throws Exception; void deleteDuplicateID(long recordID) throws Exception; void storeMessageTransactional(long txID, Message message) throws Exception; void storeReferenceTransactional(long txID, long queueID, long messageID) throws Exception; void storeAcknowledgeTransactional(long txID, long queueID, long messageID) throws Exception; void storeCursorAcknowledgeTransactional(long txID, long queueID, PagePosition position) throws Exception; void deleteCursorAcknowledgeTransactional(long txID, long ackID) throws Exception; void deleteCursorAcknowledge(long ackID) throws Exception; void storePageCompleteTransactional(long txID, long queueID, PagePosition position) throws Exception; void deletePageComplete(long ackID) throws Exception; void updateScheduledDeliveryTimeTransactional(long txID, MessageReference ref) throws Exception; void storeDuplicateIDTransactional(long txID, SimpleString address, byte[] duplID, long recordID) throws Exception; void updateDuplicateIDTransactional(long txID, SimpleString address, byte[] duplID, long recordID) throws Exception; void deleteDuplicateIDTransactional(long txID, long recordID) throws Exception; LargeServerMessage createLargeMessage(); /** * Creates a new LargeMessage with the given id. * * @param id * @param message This is a temporary message that holds the parsed properties. The remoting * layer can't create a ServerMessage directly, then this will be replaced. * @return a large message object * @throws Exception */ LargeServerMessage createLargeMessage(long id, Message message) throws Exception; enum LargeMessageExtension { DURABLE(".msg"), TEMPORARY(".tmp"), SYNC(".sync"); final String extension; LargeMessageExtension(String extension) { this.extension = extension; } public String getExtension() { return extension; } } /** * Instantiates a SequentialFile to be used for storing a {@link LargeServerMessage}. * * @param messageID the id of the message * @param extension the extension to add to the file * @return */ SequentialFile createFileForLargeMessage(final long messageID, LargeMessageExtension extension); void prepare(long txID, Xid xid) throws Exception; void commit(long txID) throws Exception; void commit(long txID, boolean lineUpContext) throws Exception; void rollback(long txID) throws Exception; void rollbackBindings(long txID) throws Exception; void commitBindings(long txID) throws Exception; void storePageTransaction(long txID, PageTransactionInfo pageTransaction) throws Exception; void updatePageTransaction(long txID, PageTransactionInfo pageTransaction, int depage) throws Exception; void deletePageTransactional(long recordID) throws Exception; JournalLoadInformation loadMessageJournal(final PostOffice postOffice, final PagingManager pagingManager, final ResourceManager resourceManager, Map<Long, QueueBindingInfo> queueInfos, final Map<SimpleString, List<Pair<byte[], Long>>> duplicateIDMap, final Set<Pair<Long, Long>> pendingLargeMessages, List<PageCountPending> pendingNonTXPageCounter, final JournalLoader journalLoader) throws Exception; long storeHeuristicCompletion(Xid xid, boolean isCommit) throws Exception; void deleteHeuristicCompletion(long id) throws Exception; // BindingsImpl related operations void addQueueBinding(long tx, Binding binding) throws Exception; void deleteQueueBinding(long tx, long queueBindingID) throws Exception; /** * * @param queueID The id of the queue * @param status The current status of the queue. (Reserved for future use, ATM we only use this record for PAUSED) * @return the id of the journal * @throws Exception */ long storeQueueStatus(long queueID, QueueStatus status) throws Exception; void deleteQueueStatus(long recordID) throws Exception; void addAddressBinding(long tx, AddressInfo addressInfo) throws Exception; void deleteAddressBinding(long tx, long addressBindingID) throws Exception; JournalLoadInformation loadBindingJournal(List<QueueBindingInfo> queueBindingInfos, List<GroupingInfo> groupingInfos, List<AddressBindingInfo> addressBindingInfos) throws Exception; // grouping related operations void addGrouping(GroupBinding groupBinding) throws Exception; void deleteGrouping(long tx, GroupBinding groupBinding) throws Exception; void storeAddressSetting(PersistedAddressSetting addressSetting) throws Exception; void deleteAddressSetting(SimpleString addressMatch) throws Exception; List<PersistedAddressSetting> recoverAddressSettings() throws Exception; void storeSecurityRoles(PersistedRoles persistedRoles) throws Exception; void deleteSecurityRoles(SimpleString addressMatch) throws Exception; List<PersistedRoles> recoverPersistedRoles() throws Exception; /** * @return The ID with the stored counter */ long storePageCounter(long txID, long queueID, long value) throws Exception; long storePendingCounter(long queueID, long pageID, int inc) throws Exception; void deleteIncrementRecord(long txID, long recordID) throws Exception; void deletePageCounter(long txID, long recordID) throws Exception; void deletePendingPageCounter(long txID, long recordID) throws Exception; /** * @return the ID with the increment record * @throws Exception */ long storePageCounterInc(long txID, long queueID, int add) throws Exception; /** * @return the ID with the increment record * @throws Exception */ long storePageCounterInc(long queueID, int add) throws Exception; /** * @return the bindings journal */ Journal getBindingsJournal(); /** * @return the message journal */ Journal getMessageJournal(); /** * @see org.apache.activemq.artemis.core.persistence.impl.journal.JournalStorageManager#startReplication(org.apache.activemq.artemis.core.replication.ReplicationManager, org.apache.activemq.artemis.core.paging.PagingManager, String, boolean, long) */ void startReplication(ReplicationManager replicationManager, PagingManager pagingManager, String nodeID, boolean autoFailBack, long initialReplicationSyncTimeout) throws Exception; /** * Write message to page if we are paging. * <p> * This is primarily a {@link PagingStore} call, but as with any other call writing persistent * data, it must go through here. Both for the sake of replication, and also to ensure that it * takes the locks (storage manager and pagingStore) in the right order. Avoiding thus the * creation of dead-locks. * * @return {@code true} if we are paging and have handled the data, {@code false} if the data * needs to be sent to the journal * @throws Exception */ boolean addToPage(PagingStore store, Message msg, Transaction tx, RouteContextList listCtx) throws Exception; /** * Stops the replication of data from the live to the backup. * <p> * Typical scenario is a broken connection. */ void stopReplication(); /** * @param appendFile * @param messageID * @param bytes */ void addBytesToLargeMessage(SequentialFile appendFile, long messageID, byte[] bytes) throws Exception; /** * Stores the id from IDManager. * * @param journalID * @param id * @throws Exception */ void storeID(long journalID, long id) throws Exception; /* Deletes the ID from IDManager. */ void deleteID(long journalD) throws Exception; /** * Read lock the StorageManager. USE WITH CARE! * <p> * The main lock is used to write lock the whole manager when starting replication. Sub-systems, * say Paging classes, that use locks of their own AND also write through the StorageManager MUST * first read lock the storageManager before taking their own locks. Otherwise, we may dead-lock * when starting replication sync. */ void readLock(); /** * Unlock the manager. * * @see StorageManager#readLock() */ void readUnLock(); /** * Closes the {@link IDGenerator} persisting the current record ID. * <p> * Effectively a "pre-stop" method. Necessary due to the "stop"-order at * {@link org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl} */ void persistIdGenerator(); void injectMonitor(FileStoreMonitor monitor) throws Exception; }