Skip to content

Make copies of thread local MessageMetadata when it might be shared - #14556

Closed
lhotari wants to merge 4 commits into
apache:masterfrom
lhotari:lh-message-metadata-thread-local-copy
Closed

Make copies of thread local MessageMetadata when it might be shared#14556
lhotari wants to merge 4 commits into
apache:masterfrom
lhotari:lh-message-metadata-thread-local-copy

Conversation

@lhotari

@lhotari lhotari commented Mar 4, 2022

Copy link
Copy Markdown
Member

Motivation

  • sharing the thread local MessageMetadata instance to other threads will cause issues
    • Thread local variable is org.apache.pulsar.common.protocol.Commands#LOCAL_MESSAGE_METADATA

Additional context

Modifications

  • make a copy when the thread local instance might be shared later

…ight be shared to other threads

- sharing the thread local MessageMetadata instance to other threads will cause issues
  - Thread local variable is org.apache.pulsar.common.protocol.Commands#LOCAL_MESSAGE_METADATA
@lhotari lhotari added the type/bug The PR fixed a bug or issue reported a bug label Mar 4, 2022
@lhotari lhotari added this to the 2.11.0 milestone Mar 4, 2022
@github-actions

github-actions Bot commented Mar 4, 2022

Copy link
Copy Markdown

@lhotari:Thanks for your contribution. For this PR, do we need to update docs?
(The PR template contains info about doc, which helps others know more about the changes. Can you provide doc-related info in this and future PR descriptions? Thanks)

@lhotari lhotari added the doc-not-needed Your PR changes do not impact docs label Mar 4, 2022

@merlimat merlimat left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👍

@github-actions

github-actions Bot commented Mar 4, 2022

Copy link
Copy Markdown

@lhotari:Thanks for providing doc info!

msgMetadata = msgMetadata == null
? Commands.peekMessageMetadata(metadataAndPayload, subscription.toString(), -1)
: msgMetadata;
if (msgMetadata == null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like we will not share msgMetadata to other threads? I have checked where used the msgMetadata, they should run in the same thread. Maybe I missed something.

It's a good motivation, is it better to avoid passing the msgMetadata? Instead, we can create local variable, looks like

boolean hasTxnidMostBits = msgMetadata.hasTxnidMostBits();
int batchSize = msgMetadata.getNumMessagesInBatch();
msgMetadata.clear();

// The followings should use the `hasTxnidMostBits` and `batchSize` directly.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's a good motivation, is it better to avoid passing the msgMetadata? Instead, we can create local variable, looks like

yes, avoiding the instance is a better choice. I'll take a look in the refactoring.

@lhotari lhotari Mar 4, 2022

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I took a look in the possible refactoring. there's a number of fields that are used from MessageMetadata, so it would turn out to be an ugly solution.
It's possible that a copy isn't necessary in this case, but it's hard to tell without checking all accesses. That's why a "defensive copy" is reasonable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok, looks like we should try our best to avoid passing the MessageMetadata to another method, If we have to pass it to another method, we should make a copy.

For example

return delayedDeliveryTracker.get().addMessage(ledgerId, entryId, msgMetadata.getDeliverAtTime());

Use deliverAtTime is enough.

@lhotari lhotari Mar 4, 2022

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

If we have to pass it to another method, we should make a copy.

I guess that would be one way to define a rule when to make a copy. (btw. I wonder if it's intentional that the generated copyFrom code doesn't call "clear" as the first step internally. )

- this would fail with NPE if metadata ever was null

@congbobo184 congbobo184 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

image

when #14436 has been fixed. I will approve this. because I'm worried about the new problem will be happend. So I leave request changes, prevent it from being merged


public static final FilterContext FILTER_CONTEXT_DISABLED = new FilterContext();

public MessageMetadata getMsgMetadata() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This may be problematic because the filter may want to hold a reference to this object (I don't know why but you know users sometimes do silly things)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Please elaborate about the problem. What do you suggest as a solution?

context.consumerEpoch = consumerEpoch;
context.brokerEntryMetadata = brokerEntryMetadata;
context.messageMetadata = messageMetadata;
context.messageMetadata.copyFrom(messageMetadata);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This may be problematic because the filter may want to hold a reference to this object (I don't know why but you know users sometimes do silly things)

@lhotari

lhotari commented Mar 4, 2022

Copy link
Copy Markdown
Member Author

because I'm worried about the new problem will be happend. So I leave request changes, prevent it from being merged

@congbobo184 What new problems could you see happening with these changes?

@congbobo184

Copy link
Copy Markdown
Contributor

because I'm worried about the new problem will be happend. So I leave request changes, prevent it from being merged

@congbobo184 What new problems could you see happening with these changes?

I don't find new problem and #14436 always exist.I don't know what time the msgMetadata is null.

@github-actions

github-actions Bot commented Apr 6, 2022

Copy link
Copy Markdown

The pr had no activity for 30 days, mark with Stale label.

@github-actions

Copy link
Copy Markdown

The pr had no activity for 30 days, mark with Stale label.

@codelipenghui codelipenghui modified the milestones: 2.11.0, 2.12.0 Jul 26, 2022
@lhotari

lhotari commented Dec 20, 2022

Copy link
Copy Markdown
Member Author

It seems #15983 has addressed the issue.

@lhotari lhotari closed this Dec 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc-not-needed Your PR changes do not impact docs lifecycle/stale Stale type/bug The PR fixed a bug or issue reported a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants