@Override public void addBindings(PersistedType type, String name, String... address) throws Exception { Pair<PersistedType, String> key = new Pair<>(type, name); long tx = idGenerator.generateID(); PersistedBindings currentBindings = mapBindings.get(key); if (currentBindings != null) { jmsJournal.appendDeleteRecordTransactional(tx, currentBindings.getId()); } else { currentBindings = new PersistedBindings(type, name); } mapBindings.put(key, currentBindings); for (String adItem : address) { currentBindings.addBinding(adItem); } long newId = idGenerator.generateID(); currentBindings.setId(newId); jmsJournal.appendAddRecordTransactional(tx, newId, BINDING_RECORD, currentBindings); jmsJournal.appendCommitRecord(tx, true); }
@Override public void deleteBindings(PersistedType type, String name, String address) throws Exception { Pair<PersistedType, String> key = new Pair<>(type, name); long tx = idGenerator.generateID(); PersistedBindings currentBindings = mapBindings.get(key); if (currentBindings == null) { return; } else { jmsJournal.appendDeleteRecordTransactional(tx, currentBindings.getId()); } currentBindings.deleteBinding(address); if (currentBindings.getBindings().size() == 0) { mapBindings.remove(key); } else { long newId = idGenerator.generateID(); currentBindings.setId(newId); jmsJournal.appendAddRecordTransactional(tx, newId, BINDING_RECORD, currentBindings); } jmsJournal.appendCommitRecord(tx, true); }
@Override public synchronized void stop() throws Exception { if (!started) { return; } // Channel may be null if there isn't a connection to a live server if (channel != null) { channel.close(); } for (ReplicatedLargeMessage largeMessage : largeMessages.values()) { largeMessage.releaseResources(); } largeMessages.clear(); for (Entry<JournalContent, Map<Long, JournalSyncFile>> entry : filesReservedForSync.entrySet()) { for (JournalSyncFile filesReserved : entry.getValue().values()) { filesReserved.close(); } } filesReservedForSync.clear(); if (journals != null) { for (Journal j : journals) { if (j instanceof FileWrapperJournal) j.stop(); } } for (ConcurrentMap<Integer, Page> map : pageIndex.values()) { for (Page page : map.values()) { try { page.sync(); page.close(); } catch (Exception e) { ActiveMQServerLogger.LOGGER.errorClosingPageOnReplication(e); } } } pageManager.stop(); pageIndex.clear(); final CountDownLatch latch = new CountDownLatch(1); executor.execute( new Runnable() { @Override public void run() { latch.countDown(); } }); latch.await(30, TimeUnit.SECONDS); // Storage needs to be the last to stop storageManager.stop(); started = false; }
/** @param packet */ private void handleCommitRollback(final ReplicationCommitMessage packet) throws Exception { Journal journalToUse = getJournal(packet.getJournalID()); if (packet.isRollback()) { journalToUse.appendRollbackRecord(packet.getTxId(), noSync); } else { journalToUse.appendCommitRecord(packet.getTxId(), noSync); } }
/** @param packet */ private void handleAppendAddTXRecord(final ReplicationAddTXMessage packet) throws Exception { Journal journalToUse = getJournal(packet.getJournalID()); if (packet.getOperation() == ADD_OPERATION_TYPE.UPDATE) { journalToUse.appendUpdateRecordTransactional( packet.getTxId(), packet.getId(), packet.getRecordType(), packet.getRecordData()); } else { journalToUse.appendAddRecordTransactional( packet.getTxId(), packet.getId(), packet.getRecordType(), packet.getRecordData()); } }
/** * Reserves files (with the given fileID) in the specified journal, and places a {@link * FileWrapperJournal} in place to store messages while synchronization is going on. * * @param packet * @throws Exception * @return if the incoming packet indicates the synchronization is finished then return an * acknowledgement otherwise return an empty response */ private ReplicationResponseMessageV2 handleStartReplicationSynchronization( final ReplicationStartSyncMessage packet) throws Exception { ReplicationResponseMessageV2 replicationResponseMessage = new ReplicationResponseMessageV2(); if (activation.isRemoteBackupUpToDate()) { throw ActiveMQMessageBundle.BUNDLE.replicationBackupUpToDate(); } synchronized (this) { if (!started) return replicationResponseMessage; if (packet.isSynchronizationFinished()) { finishSynchronization(packet.getNodeID()); replicationResponseMessage.setSynchronizationIsFinishedAcknowledgement(true); return replicationResponseMessage; } switch (packet.getDataType()) { case LargeMessages: for (long msgID : packet.getFileIds()) { createLargeMessage(msgID, true); } break; case JournalBindings: case JournalMessages: if (wantedFailBack && !packet.isServerToFailBack()) { ActiveMQServerLogger.LOGGER.autoFailBackDenied(); } final JournalContent journalContent = SyncDataType.getJournalContentType(packet.getDataType()); final Journal journal = journalsHolder.get(journalContent); if (packet.getNodeID() != null) { // At the start of replication, we still do not know which is the nodeID that the live // uses. // This is the point where the backup gets this information. backupQuorum.liveIDSet(packet.getNodeID()); } Map<Long, JournalSyncFile> mapToFill = filesReservedForSync.get(journalContent); for (Entry<Long, JournalFile> entry : journal.createFilesForBackupSync(packet.getFileIds()).entrySet()) { mapToFill.put(entry.getKey(), new JournalSyncFile(entry.getValue())); } FileWrapperJournal syncJournal = new FileWrapperJournal(journal); registerJournal(journalContent.typeByte, syncJournal); break; default: throw ActiveMQMessageBundle.BUNDLE.replicationUnhandledDataType(); } } return replicationResponseMessage; }
/** * @param packet * @throws Exception */ private void handleAppendAddRecord(final ReplicationAddMessage packet) throws Exception { Journal journalToUse = getJournal(packet.getJournalID()); if (packet.getRecord() == ADD_OPERATION_TYPE.UPDATE) { if (ReplicationEndpoint.trace) { ActiveMQServerLogger.LOGGER.trace("Endpoint appendUpdate id = " + packet.getId()); } journalToUse.appendUpdateRecord( packet.getId(), packet.getJournalRecordType(), packet.getRecordData(), noSync); } else { if (ReplicationEndpoint.trace) { ActiveMQServerLogger.LOGGER.trace("Endpoint append id = " + packet.getId()); } journalToUse.appendAddRecord( packet.getId(), packet.getJournalRecordType(), packet.getRecordData(), noSync); } }
@Override public void deleteDestination(final PersistedType type, final String name) throws Exception { PersistedDestination destination = destinations.remove(new Pair<>(type, name)); if (destination != null) { jmsJournal.appendDeleteRecord(destination.getId(), false); } }
@Override public void deleteConnectionFactory(final String cfName) throws Exception { PersistedConnectionFactory oldCF = mapFactories.remove(cfName); if (oldCF != null) { jmsJournal.appendDeleteRecord(oldCF.getId(), false); } }
@Override public void storeDestination(final PersistedDestination destination) throws Exception { deleteDestination(destination.getType(), destination.getName()); long id = idGenerator.generateID(); destination.setId(id); jmsJournal.appendAddRecord(id, DESTINATION_RECORD, destination, true); destinations.put(new Pair<>(destination.getType(), destination.getName()), destination); }
@Override public void start() throws Exception { checkAndCreateDir(config.getBindingsLocation(), createDir); jmsJournal.start(); started = true; }
@Override public void storeConnectionFactory(final PersistedConnectionFactory connectionFactory) throws Exception { deleteConnectionFactory(connectionFactory.getName()); long id = idGenerator.generateID(); connectionFactory.setId(id); jmsJournal.appendAddRecord(id, CF_RECORD, connectionFactory, true); mapFactories.put(connectionFactory.getName(), connectionFactory); }
@Override public void deleteBindings(PersistedType type, String name) throws Exception { Pair<PersistedType, String> key = new Pair<>(type, name); PersistedBindings currentBindings = mapBindings.remove(key); if (currentBindings != null) { jmsJournal.appendDeleteRecord(currentBindings.getId(), true); } }
private void finishSynchronization(String liveID) throws Exception { for (JournalContent jc : EnumSet.allOf(JournalContent.class)) { Journal journal = journalsHolder.remove(jc); journal.synchronizationLock(); try { // files should be already in place. filesReservedForSync.remove(jc); registerJournal(jc.typeByte, journal); journal.stop(); journal.start(); journal.loadSyncOnly(JournalState.SYNCING_UP_TO_DATE); } finally { journal.synchronizationUnlock(); } } ByteBuffer buffer = ByteBuffer.allocate(4 * 1024); for (Entry<Long, ReplicatedLargeMessage> entry : largeMessages.entrySet()) { ReplicatedLargeMessage lm = entry.getValue(); if (lm instanceof LargeServerMessageInSync) { LargeServerMessageInSync lmSync = (LargeServerMessageInSync) lm; lmSync.joinSyncedData(buffer); } } journalsHolder = null; backupQuorum.liveIDSet(liveID); activation.setRemoteBackupUpToDate(); ActiveMQServerLogger.LOGGER.backupServerSynched(server); return; }
@Override public void postLoad( Journal messageJournal, ResourceManager resourceManager, Map<SimpleString, List<Pair<byte[], Long>>> duplicateIDMap) throws Exception { for (Queue queue : queues.values()) { queue.resume(); } if (System.getProperty("org.apache.activemq.opt.directblast") != null) { messageJournal.runDirectJournalBlast(); } }
@Override public void load() throws Exception { mapFactories.clear(); List<RecordInfo> data = new ArrayList<>(); ArrayList<PreparedTransactionInfo> list = new ArrayList<>(); jmsJournal.load(data, list, null); for (RecordInfo record : data) { long id = record.id; ActiveMQBuffer buffer = ActiveMQBuffers.wrappedBuffer(record.data); byte rec = record.getUserRecordType(); if (rec == CF_RECORD) { PersistedConnectionFactory cf = new PersistedConnectionFactory(); cf.decode(buffer); cf.setId(id); mapFactories.put(cf.getName(), cf); } else if (rec == DESTINATION_RECORD) { PersistedDestination destination = new PersistedDestination(); destination.decode(buffer); destination.setId(id); destinations.put(new Pair<>(destination.getType(), destination.getName()), destination); } else if (rec == BINDING_RECORD) { PersistedBindings bindings = new PersistedBindings(); bindings.decode(buffer); bindings.setId(id); Pair<PersistedType, String> key = new Pair<>(bindings.getType(), bindings.getName()); mapBindings.put(key, bindings); } else { throw new IllegalStateException("Invalid record type " + rec); } } }
@Override public void stop() throws Exception { this.started = false; jmsJournal.stop(); }
/** @param packet */ private void handlePrepare(final ReplicationPrepareMessage packet) throws Exception { Journal journalToUse = getJournal(packet.getJournalID()); journalToUse.appendPrepareRecord(packet.getTxId(), packet.getRecordData(), noSync); }
/** @param packet */ private void handleAppendDeleteTX(final ReplicationDeleteTXMessage packet) throws Exception { Journal journalToUse = getJournal(packet.getJournalID()); journalToUse.appendDeleteRecordTransactional( packet.getTxId(), packet.getId(), packet.getRecordData()); }
/** @param packet */ private void handleAppendDelete(final ReplicationDeleteMessage packet) throws Exception { Journal journalToUse = getJournal(packet.getJournalID()); journalToUse.appendDeleteRecord(packet.getId(), noSync); }