Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Transaction] TransactionBuffer Refactor #8347

Merged
merged 14 commits into from
Oct 30, 2020

Conversation

gaoran10
Copy link
Contributor

@gaoran10 gaoran10 commented Oct 22, 2020

Fix https://github.com/streamnative/pulsar/issues/1575
Fix issue #8378

Motivation

image

Use the above approach instead of the sidecar approach.

Modifications

  1. Produce transaction messages to the topic partition.
  2. The commit marker needs to record the related message-id list of its transaction.
  3. When the dispatcher read a transaction marker, get the messages of the transaction by message-id list in the marker and send them to the consumer.
  4. TransactionBuffer doesn't maintain any index data.

Verifying this change

This change added tests and can be verified as follows:

  • Added unit tests for produce transaction messages and end transaction and read the messages

    org.apache.pulsar.broker.transaction.TransactionProduceTest
    org.apache.pulsar.broker.transaction.TransactionConsumeTest

Does this pull request potentially affect one of the following parts:

If yes was chosen, please highlight the changes

  • Dependencies (does it add or upgrade a dependency): (no)
  • The public API: (yes)
  • The schema: (no)
  • The default values of configurations: (no)
  • The wire protocol: (yes)
  • The rest endpoints: (no)
  • The admin cli options: (no)
  • Anything that affects deployment: (no)

Documentation

  • Does this pull request introduce a new feature? (yes / no)

@@ -80,10 +80,12 @@ message ClusterMessageId {
message MessageIdData {
required uint64 ledger_id = 1;
required uint64 entry_id = 2;
optional int32 partition = 3 [default = -1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need partition information in the marker? A marker can only belong to a single partition right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll fix this.

Comment on lines 89 to 90
optional MessageIdData message_id = 1;
repeated MessageIdData messageIdList = 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can keep repeated MessageIdData message_ids here. Since we don't need to consider the compatibility guarantee for the first transaction release.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@@ -34,6 +34,7 @@
/**
* Persistent transaction buffer provider.
*/
@Deprecated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's some of the old codes are not useful, we can delete them directly. we don't want to tell users there some deprecated components in the first transaction release.

Please check all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@codelipenghui codelipenghui added this to the 2.7.0 milestone Oct 26, 2020
@Slf4j
public class TopicTransactionBuffer implements TransactionBuffer {

private PersistentTopic topic;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private PersistentTopic topic;
private final PersistentTopic topic;

Comment on lines +50 to +52
public CompletableFuture<TransactionMeta> getTransactionMeta(TxnID txnID) {
return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we need this method?

CompletableFuture<Position> completableFuture = new CompletableFuture<>();
topic.publishMessage(buffer, (e, ledgerId, entryId) -> {
if (e != null) {
log.error("Failed to appendBufferToTxn for txn {}", txnId, e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
log.error("Failed to appendBufferToTxn for txn {}", txnId, e);
log.error("Failed to append buffer to txn {}", txnId, e);

}

private List<PulsarMarkers.MessageIdData> getMessageIdDataList(List<MessageIdData> sendMessageIdList) {
List<PulsarMarkers.MessageIdData> messageIdDataList = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
List<PulsarMarkers.MessageIdData> messageIdDataList = new ArrayList<>();
List<PulsarMarkers.MessageIdData> messageIdDataList = new ArrayList<>(sendMessageIdList.size());

.setLedgerId(msgIdData.getLedgerId())
.setEntryId(msgIdData.getEntryId()).build());
}
return messageIdDataList;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recycle the MessageIdData list before return?


try {
return Commands.serializeMetadataAndPayload(ChecksumType.Crc32c, msgMetadata, payload);
} finally {
payload.release();
msgMetadata.recycle();
msgMetadataBuilder.recycle();
if (commitMarkerBuilder != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commitMarkerBuilder always not null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix this.

PulsarMarkers.TxnCommitMarker.Builder commitMarkerBuilder = PulsarMarkers.TxnCommitMarker.newBuilder();

messageIdDataList.ifPresent(commitMarkerBuilder::addAllMessageId);
PulsarMarkers.TxnCommitMarker commitMarker = commitMarkerBuilder.build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commitMarker also should be recycled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@@ -236,7 +238,16 @@ public void handleAddSubscriptionToTxnResponse(PulsarApi.CommandAddSubscriptionT
return callback;
}
long requestId = client.newRequestId();
ByteBuf cmd = Commands.newEndTxn(requestId, txnID.getLeastSigBits(), txnID.getMostSigBits(), PulsarApi.TxnAction.COMMIT);
List<PulsarApi.MessageIdData> messageIdDataList = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be recycled after no longer use

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@@ -255,7 +266,17 @@ public void handleAddSubscriptionToTxnResponse(PulsarApi.CommandAddSubscriptionT
return callback;
}
long requestId = client.newRequestId();
ByteBuf cmd = Commands.newEndTxn(requestId, txnID.getLeastSigBits(), txnID.getMostSigBits(), PulsarApi.TxnAction.ABORT);

List<PulsarApi.MessageIdData> messageIdDataList = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be recycled after no longer use

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

CompletableFuture<TxnID> cb = new CompletableFuture<>();
if (!canSendRequest(cb)) {
return cb;
}
long requestId = requestIdGenerator.getAndIncrement();
ByteBuf cmd = Commands.newEndTxnOnPartition(requestId, txnIdLeastBits, txnIdMostBits, topic, action);
List<PulsarApi.MessageIdData> messageIdDataList = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be recycled after no longer use

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

import org.apache.bookkeeper.mledger.ManagedLedger;
import org.apache.pulsar.broker.PulsarService;

public class TransactionMessageDeduplication extends MessageDeduplication {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks not related to this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove this class.

@@ -73,9 +77,11 @@
private final ServiceConfiguration serviceConfig;
private volatile ScheduledFuture<?> readOnActiveConsumerTask = null;

LongPairSet messagesToRedeliver = new ConcurrentSortedLongPairSet(128, 2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only instantiate when the transaction is enabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix this.

@@ -115,4 +115,9 @@ default void cursorIsReset() {
default void acknowledgementWasProcessed() {
// No-op
}

default void addMessageToRedelivery(long ledgerId, long entryId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
default void addMessageToRedelivery(long ledgerId, long entryId) {
default void addMessageToReplay(long ledgerId, long entryId) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think use replay is more reasonable here. The redeliver looks like the consumer receiver the messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

transactionReader.read(messagesToRead, consumer, this);
if (havePendingReplayRead) {
if (log.isDebugEnabled()) {
log.debug("have pending replay read");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to print the topic name ,subscription name in the log. You can refer to other log patterns in the PersistentDispatcherSingleActiveConsumer.java

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

private final Dispatcher dispatcher;
private final Executor executor;

private final ConcurrentLongPairSet pendingReadPosition;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have messageToRedeliver in the Dispatcher, why need to add a pendingReadPosition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove the class TransactionMessageReader.

int totalMessages = 0;
long totalBytes = 0;
int totalChunkedMessages = 0;

boolean afterTxnCommitMarker = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
boolean afterTxnCommitMarker = false;
boolean isAfterTxnCommitMarker = false;

@codelipenghui codelipenghui merged commit 9173174 into apache:master Oct 30, 2020
huangdx0726 pushed a commit to huangdx0726/pulsar that referenced this pull request Nov 13, 2020
Fix https://github.com/streamnative/pulsar/issues/1575
Fix issue apache#8378 

### Motivation

![image](https://user-images.githubusercontent.com/15029908/96908159-d38d3f80-14ce-11eb-9e52-ee066434d960.png)

Use the above approach instead of the sidecar approach.

### Modifications

1. Produce transaction messages to the topic partition.
2. The commit marker needs to record the related message-id list of its transaction.
3. When the dispatcher read a transaction marker, get the messages of the transaction by message-id list in the marker and send them to the consumer.
2. TransactionBuffer doesn't maintain any index data.
flowchartsman pushed a commit to flowchartsman/pulsar that referenced this pull request Nov 17, 2020
Fix https://github.com/streamnative/pulsar/issues/1575
Fix issue apache#8378 

### Motivation

![image](https://user-images.githubusercontent.com/15029908/96908159-d38d3f80-14ce-11eb-9e52-ee066434d960.png)

Use the above approach instead of the sidecar approach.

### Modifications

1. Produce transaction messages to the topic partition.
2. The commit marker needs to record the related message-id list of its transaction.
3. When the dispatcher read a transaction marker, get the messages of the transaction by message-id list in the marker and send them to the consumer.
2. TransactionBuffer doesn't maintain any index data.
codelipenghui pushed a commit that referenced this pull request Nov 20, 2020
### Motivation

Currently, sending transaction messages in a sync way is disabled, because the design of the `TransactionBuffer` had some changes(refer to #8347), sending transaction messages in a sync way is allowed.

### Modifications

Remove the transaction check in the `send` method of the class `TypedMessageBuilderImpl`.
@cytnju
Copy link

cytnju commented Feb 21, 2022

Would you please tell me why pulsar finally chose to replace sidecar's appraoch with marker's appraoch, which seems different from the conclusion in the previous PIP-31 ? @gaoran10

@eolivelli
Copy link
Contributor

Would you please tell me why pulsar finally chose to replace sidecar's appraoch with marker's appraoch, which seems different from the conclusion in the previous PIP-31 ? @gaoran10

@cytnju please ask your question on dev@pulsar.apache.org
This is not the right place for discussions, a few people follow the notifications especially for merged prs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Transaction] TransactionBuffer Refactor
4 participants