use of org.apache.activemq.artemis.core.transaction.Transaction in project activemq-artemis by apache.
the class AbstractJournalStorageManager method loadPreparedTransactions.
private void loadPreparedTransactions(final PostOffice postOffice, final PagingManager pagingManager, final ResourceManager resourceManager, final Map<Long, QueueBindingInfo> queueInfos, final List<PreparedTransactionInfo> preparedTransactions, final Map<SimpleString, List<Pair<byte[], Long>>> duplicateIDMap, final Map<Long, PageSubscription> pageSubscriptions, final Set<Pair<Long, Long>> pendingLargeMessages, JournalLoader journalLoader) throws Exception {
// recover prepared transactions
for (PreparedTransactionInfo preparedTransaction : preparedTransactions) {
XidEncoding encodingXid = new XidEncoding(preparedTransaction.getExtraData());
Xid xid = encodingXid.xid;
Transaction tx = new TransactionImpl(preparedTransaction.getId(), xid, this);
List<MessageReference> referencesToAck = new ArrayList<>();
Map<Long, Message> messages = new HashMap<>();
// first get any sent messages for this tx and recreate
for (RecordInfo record : preparedTransaction.getRecords()) {
byte[] data = record.data;
ActiveMQBuffer buff = ActiveMQBuffers.wrappedBuffer(data);
byte recordType = record.getUserRecordType();
switch(recordType) {
case JournalRecordIds.ADD_LARGE_MESSAGE:
{
messages.put(record.id, parseLargeMessage(messages, buff));
break;
}
case JournalRecordIds.ADD_MESSAGE:
{
break;
}
case JournalRecordIds.ADD_MESSAGE_PROTOCOL:
{
Message message = MessagePersister.getInstance().decode(buff, null);
messages.put(record.id, message);
break;
}
case JournalRecordIds.ADD_REF:
{
long messageID = record.id;
RefEncoding encoding = new RefEncoding();
encoding.decode(buff);
Message message = messages.get(messageID);
if (message == null) {
throw new IllegalStateException("Cannot find message with id " + messageID);
}
journalLoader.handlePreparedSendMessage(message, tx, encoding.queueID);
break;
}
case JournalRecordIds.ACKNOWLEDGE_REF:
{
long messageID = record.id;
RefEncoding encoding = new RefEncoding();
encoding.decode(buff);
journalLoader.handlePreparedAcknowledge(messageID, referencesToAck, encoding.queueID);
break;
}
case JournalRecordIds.PAGE_TRANSACTION:
{
PageTransactionInfo pageTransactionInfo = new PageTransactionInfoImpl();
pageTransactionInfo.decode(buff);
if (record.isUpdate) {
PageTransactionInfo pgTX = pagingManager.getTransaction(pageTransactionInfo.getTransactionID());
pgTX.reloadUpdate(this, pagingManager, tx, pageTransactionInfo.getNumberOfMessages());
} else {
pageTransactionInfo.setCommitted(false);
tx.putProperty(TransactionPropertyIndexes.PAGE_TRANSACTION, pageTransactionInfo);
pagingManager.addTransaction(pageTransactionInfo);
tx.addOperation(new FinishPageMessageOperation());
}
break;
}
case SET_SCHEDULED_DELIVERY_TIME:
{
break;
}
case DUPLICATE_ID:
{
// We need load the duplicate ids at prepare time too
DuplicateIDEncoding encoding = new DuplicateIDEncoding();
encoding.decode(buff);
DuplicateIDCache cache = postOffice.getDuplicateIDCache(encoding.address);
cache.load(tx, encoding.duplID);
break;
}
case ACKNOWLEDGE_CURSOR:
{
CursorAckRecordEncoding encoding = new CursorAckRecordEncoding();
encoding.decode(buff);
encoding.position.setRecordID(record.id);
PageSubscription sub = locateSubscription(encoding.queueID, pageSubscriptions, queueInfos, pagingManager);
if (sub != null) {
sub.reloadPreparedACK(tx, encoding.position);
referencesToAck.add(new PagedReferenceImpl(encoding.position, null, sub));
} else {
ActiveMQServerLogger.LOGGER.journalCannotFindQueueReloadingACK(encoding.queueID);
}
break;
}
case PAGE_CURSOR_COUNTER_VALUE:
{
ActiveMQServerLogger.LOGGER.journalPAGEOnPrepared();
break;
}
case PAGE_CURSOR_COUNTER_INC:
{
PageCountRecordInc encoding = new PageCountRecordInc();
encoding.decode(buff);
PageSubscription sub = locateSubscription(encoding.getQueueID(), pageSubscriptions, queueInfos, pagingManager);
if (sub != null) {
sub.getCounter().applyIncrementOnTX(tx, record.id, encoding.getValue(), encoding.getPersistentSize());
sub.notEmpty();
} else {
ActiveMQServerLogger.LOGGER.journalCannotFindQueueReloadingACK(encoding.getQueueID());
}
break;
}
default:
{
ActiveMQServerLogger.LOGGER.journalInvalidRecordType(recordType);
}
}
}
for (RecordInfo recordDeleted : preparedTransaction.getRecordsToDelete()) {
byte[] data = recordDeleted.data;
if (data.length > 0) {
ActiveMQBuffer buff = ActiveMQBuffers.wrappedBuffer(data);
byte b = buff.readByte();
switch(b) {
case ADD_LARGE_MESSAGE_PENDING:
{
long messageID = buff.readLong();
if (!pendingLargeMessages.remove(new Pair<>(recordDeleted.id, messageID))) {
ActiveMQServerLogger.LOGGER.largeMessageNotFound(recordDeleted.id);
}
installLargeMessageConfirmationOnTX(tx, recordDeleted.id);
break;
}
default:
ActiveMQServerLogger.LOGGER.journalInvalidRecordTypeOnPreparedTX(b);
}
}
}
journalLoader.handlePreparedTransaction(tx, referencesToAck, xid, resourceManager);
}
}
use of org.apache.activemq.artemis.core.transaction.Transaction in project activemq-artemis by apache.
the class ActiveMQServerControlImpl method rollbackPreparedTransaction.
@Override
public synchronized boolean rollbackPreparedTransaction(final String transactionAsBase64) throws Exception {
checkStarted();
clearIO();
try {
List<Xid> xids = resourceManager.getPreparedTransactions();
for (Xid xid : xids) {
if (XidImpl.toBase64String(xid).equals(transactionAsBase64)) {
Transaction transaction = resourceManager.removeTransaction(xid);
transaction.rollback();
long recordID = server.getStorageManager().storeHeuristicCompletion(xid, false);
server.getStorageManager().waitOnOperations();
resourceManager.putHeuristicCompletion(recordID, xid, false);
return true;
}
}
return false;
} finally {
blockOnIO();
}
}
use of org.apache.activemq.artemis.core.transaction.Transaction in project activemq-artemis by apache.
the class PageSubscriptionImpl method cleanupEntries.
/**
* It will cleanup all the records for completed pages
*/
@Override
public void cleanupEntries(final boolean completeDelete) throws Exception {
if (completeDelete) {
counter.delete();
}
if (logger.isTraceEnabled()) {
logger.trace("cleanupEntries", new Exception("trace"));
}
Transaction tx = new TransactionImpl(store);
boolean persist = false;
final ArrayList<PageCursorInfo> completedPages = new ArrayList<>();
// First get the completed pages using a lock
synchronized (consumedPages) {
// lastAckedPosition = null means no acks were done yet, so we are not ready to cleanup
if (lastAckedPosition == null) {
return;
}
for (Entry<Long, PageCursorInfo> entry : consumedPages.entrySet()) {
PageCursorInfo info = entry.getValue();
if (info.isDone() && !info.isPendingDelete()) {
Page currentPage = pageStore.getCurrentPage();
if (currentPage != null && entry.getKey() == pageStore.getCurrentPage().getPageId() && currentPage.isLive()) {
logger.trace("We can't clear page " + entry.getKey() + " now since it's the current page");
} else {
info.setPendingDelete();
completedPages.add(entry.getValue());
}
}
}
}
for (PageCursorInfo infoPG : completedPages) {
// first will mark the page as complete
if (isPersistent()) {
PagePosition completePage = new PagePositionImpl(infoPG.getPageId(), infoPG.getNumberOfMessages());
infoPG.setCompleteInfo(completePage);
store.storePageCompleteTransactional(tx.getID(), this.getId(), completePage);
if (!persist) {
persist = true;
tx.setContainsPersistent();
}
}
// it will delete the page ack records
for (PagePosition pos : infoPG.acks) {
if (pos.getRecordID() >= 0) {
store.deleteCursorAcknowledgeTransactional(tx.getID(), pos.getRecordID());
if (!persist) {
// only need to set it once
tx.setContainsPersistent();
persist = true;
}
}
}
infoPG.acks.clear();
infoPG.acks = Collections.synchronizedSet(new LinkedHashSet<PagePosition>());
infoPG.removedReferences.clear();
infoPG.removedReferences = new ConcurrentHashSet<>();
}
tx.addOperation(new TransactionOperationAbstract() {
@Override
public void afterCommit(final Transaction tx1) {
executor.execute(new Runnable() {
@Override
public void run() {
if (!completeDelete) {
cursorProvider.scheduleCleanup();
}
}
});
}
});
tx.commit();
}
use of org.apache.activemq.artemis.core.transaction.Transaction in project activemq-artemis by apache.
the class PageSubscriptionCounterImpl method delete.
@Override
public void delete() throws Exception {
Transaction tx = new TransactionImpl(storage);
delete(tx);
tx.commit();
}
use of org.apache.activemq.artemis.core.transaction.Transaction in project activemq-artemis by apache.
the class PageSubscriptionCounterImpl method cleanupNonTXCounters.
/**
* Cleanup temporary page counters on non transactional paged messages
*
* @param pageID
*/
@Override
public void cleanupNonTXCounters(final long pageID) throws Exception {
PendingCounter pendingInfo;
synchronized (this) {
pendingInfo = pendingCounters.remove(pageID);
}
if (pendingInfo != null) {
final int valueCleaned = pendingInfo.getCount();
final long valueSizeCleaned = pendingInfo.getPersistentSize();
Transaction tx = new TransactionImpl(storage);
storage.deletePendingPageCounter(tx.getID(), pendingInfo.getId());
// To apply the increment of the value just being cleaned
increment(tx, valueCleaned, valueSizeCleaned);
tx.addOperation(new TransactionOperationAbstract() {
@Override
public void afterCommit(Transaction tx) {
pendingValue.addAndGet(-valueCleaned);
pendingPersistentSize.updateAndGet(val -> val >= valueSizeCleaned ? val - valueSizeCleaned : 0);
}
});
tx.commit();
}
}
Aggregations