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

[fix][broker] Copy proto command fields into final variables in ServerCnx #18987

Merged
merged 5 commits into from
Dec 20, 2022

Conversation

michaeljmarshall
Copy link
Member

@michaeljmarshall michaeljmarshall commented Dec 19, 2022

Motivation

In the PulsarDecoder, we use a single BaseCommand object and overwrite it for each incoming protocol message. As a result, it is not safe to publish any references to a proto command to other threads.

Here is the single BaseCommand:

private final BaseCommand cmd = new BaseCommand();

Here is the method call that resets the object:

Note that the call to parseFrom first calls clear(), which resets all values on the object.

This PR copies relevant values or objects into other variables.

Modifications

  • Replace command with tcId since the latter is a final variable meant to be published to another thread.
  • Move logic to copy certain command fields to earlier in method for handleSubscribe
  • Copy ack object to new CommandAck when there is a broker interceptor. Note that copying this command is likely somewhat costly, so we only do it when there is an interceptor configured.

Verifying this change

This is a trivial change that is already covered by tests.

Documentation

  • doc-not-needed

This is an internal change.

Matching PR in forked repository

PR in forked repository: michaeljmarshall#8

@michaeljmarshall michaeljmarshall added type/bug The PR fixed a bug or issue reported a bug area/broker area/transaction doc-not-needed Your PR changes do not impact docs labels Dec 19, 2022
@michaeljmarshall michaeljmarshall added this to the 2.12.0 milestone Dec 19, 2022
@michaeljmarshall michaeljmarshall self-assigned this Dec 19, 2022
@michaeljmarshall michaeljmarshall changed the title [fix][txn] Use correct tcId variable to prevent data race [fix][Broker] Copy proto command fields into final variables in ServerCnx Dec 19, 2022
@michaeljmarshall michaeljmarshall changed the title [fix][Broker] Copy proto command fields into final variables in ServerCnx [fix][broker] Copy proto command fields into final variables in ServerCnx Dec 19, 2022
@codecov-commenter
Copy link

codecov-commenter commented Dec 19, 2022

Codecov Report

Merging #18987 (886796a) into master (feb3cb4) will increase coverage by 0.06%.
The diff coverage is 71.42%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master   #18987      +/-   ##
============================================
+ Coverage     46.35%   46.41%   +0.06%     
- Complexity     8939    10461    +1522     
============================================
  Files           597      703     +106     
  Lines         56858    68866   +12008     
  Branches       5905     7389    +1484     
============================================
+ Hits          26357    31967    +5610     
- Misses        27616    33292    +5676     
- Partials       2885     3607     +722     
Flag Coverage Δ
unittests 46.41% <71.42%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...va/org/apache/pulsar/broker/service/ServerCnx.java 47.48% <66.66%> (-1.49%) ⬇️
...che/bookkeeper/mledger/impl/ManagedLedgerImpl.java 53.81% <100.00%> (ø)
...lsar/broker/loadbalance/impl/ThresholdShedder.java 3.27% <0.00%> (-27.05%) ⬇️
...ar/broker/loadbalance/impl/BundleSplitterTask.java 60.00% <0.00%> (-20.00%) ⬇️
...roker/loadbalance/impl/ModularLoadManagerImpl.java 58.72% <0.00%> (-9.57%) ⬇️
...org/apache/pulsar/broker/loadbalance/LoadData.java 58.33% <0.00%> (-8.34%) ⬇️
.../pulsar/broker/service/BrokerServiceException.java 38.88% <0.00%> (-7.41%) ⬇️
...er/loadbalance/impl/ModularLoadManagerWrapper.java 78.04% <0.00%> (-7.32%) ⬇️
...g/apache/pulsar/client/impl/ConnectionHandler.java 50.00% <0.00%> (-5.32%) ⬇️
...rg/apache/pulsar/broker/service/AbstractTopic.java 61.61% <0.00%> (-3.60%) ⬇️
... and 151 more

@lhotari
Copy link
Member

lhotari commented Dec 20, 2022

I added #18997 and #18998 as follow ups for this PR. Please review

@michaeljmarshall
Copy link
Member Author

When attempting to cherry-pick this to branch-2.11, I ran into conflicts with #18193. Looking to see if we need to cherry pick that one first.

michaeljmarshall added a commit that referenced this pull request Dec 21, 2022
…rCnx (#18987)

In the `PulsarDecoder`, we use a single `BaseCommand` object and overwrite it for each incoming protocol message. As a result, it is not safe to publish any references to a proto command to other threads.

Here is the single `BaseCommand`:

https://github.com/apache/pulsar/blob/82237d3684fe506bcb6426b3b23f413422e6e4fb/pulsar-common/src/main/java/org/apache/pulsar/common/protocol/PulsarDecoder.java#L99

Here is the method call that resets the object:

https://github.com/apache/pulsar/blob/82237d3684fe506bcb6426b3b23f413422e6e4fb/pulsar-common/src/main/java/org/apache/pulsar/common/protocol/PulsarDecoder.java#L114

Note that the call to `parseFrom` first calls `clear()`, which resets all values on the object.

This PR copies relevant values or objects into other variables.

* Replace `command` with `tcId` since the latter is a final variable meant to be published to another thread.
* Move logic to copy certain command fields to earlier in method for `handleSubscribe`
* Copy `ack` object to new `CommandAck` when there is a broker interceptor. Note that copying this command is likely somewhat costly, so we only do it when there is an interceptor configured.

This is a trivial change that is already covered by tests.

- [x] `doc-not-needed`

This is an internal change.

PR in forked repository: michaeljmarshall#8

(cherry picked from commit a408e9e)
michaeljmarshall added a commit that referenced this pull request Dec 21, 2022
…rCnx (#18987)

In the `PulsarDecoder`, we use a single `BaseCommand` object and overwrite it for each incoming protocol message. As a result, it is not safe to publish any references to a proto command to other threads.

Here is the single `BaseCommand`:

https://github.com/apache/pulsar/blob/82237d3684fe506bcb6426b3b23f413422e6e4fb/pulsar-common/src/main/java/org/apache/pulsar/common/protocol/PulsarDecoder.java#L99

Here is the method call that resets the object:

https://github.com/apache/pulsar/blob/82237d3684fe506bcb6426b3b23f413422e6e4fb/pulsar-common/src/main/java/org/apache/pulsar/common/protocol/PulsarDecoder.java#L114

Note that the call to `parseFrom` first calls `clear()`, which resets all values on the object.

This PR copies relevant values or objects into other variables.

* Replace `command` with `tcId` since the latter is a final variable meant to be published to another thread.
* Move logic to copy certain command fields to earlier in method for `handleSubscribe`
* Copy `ack` object to new `CommandAck` when there is a broker interceptor. Note that copying this command is likely somewhat costly, so we only do it when there is an interceptor configured.

This is a trivial change that is already covered by tests.

- [x] `doc-not-needed`

This is an internal change.

PR in forked repository: michaeljmarshall#8

(cherry picked from commit a408e9e)
michaeljmarshall added a commit that referenced this pull request Dec 21, 2022
…rCnx (#18987)

In the `PulsarDecoder`, we use a single `BaseCommand` object and overwrite it for each incoming protocol message. As a result, it is not safe to publish any references to a proto command to other threads.

Here is the single `BaseCommand`:

https://github.com/apache/pulsar/blob/82237d3684fe506bcb6426b3b23f413422e6e4fb/pulsar-common/src/main/java/org/apache/pulsar/common/protocol/PulsarDecoder.java#L99

Here is the method call that resets the object:

https://github.com/apache/pulsar/blob/82237d3684fe506bcb6426b3b23f413422e6e4fb/pulsar-common/src/main/java/org/apache/pulsar/common/protocol/PulsarDecoder.java#L114

Note that the call to `parseFrom` first calls `clear()`, which resets all values on the object.

This PR copies relevant values or objects into other variables.

* Replace `command` with `tcId` since the latter is a final variable meant to be published to another thread.
* Move logic to copy certain command fields to earlier in method for `handleSubscribe`
* Copy `ack` object to new `CommandAck` when there is a broker interceptor. Note that copying this command is likely somewhat costly, so we only do it when there is an interceptor configured.

This is a trivial change that is already covered by tests.

- [x] `doc-not-needed`

This is an internal change.

PR in forked repository: michaeljmarshall#8

(cherry picked from commit a408e9e)
@michaeljmarshall michaeljmarshall added the cherry-picked/branch-2.9 Archived: 2.9 is end of life label Dec 21, 2022
michaeljmarshall added a commit to datastax/pulsar that referenced this pull request Dec 21, 2022
…rCnx (apache#18987)

In the `PulsarDecoder`, we use a single `BaseCommand` object and overwrite it for each incoming protocol message. As a result, it is not safe to publish any references to a proto command to other threads.

Here is the single `BaseCommand`:

https://github.com/apache/pulsar/blob/82237d3684fe506bcb6426b3b23f413422e6e4fb/pulsar-common/src/main/java/org/apache/pulsar/common/protocol/PulsarDecoder.java#L99

Here is the method call that resets the object:

https://github.com/apache/pulsar/blob/82237d3684fe506bcb6426b3b23f413422e6e4fb/pulsar-common/src/main/java/org/apache/pulsar/common/protocol/PulsarDecoder.java#L114

Note that the call to `parseFrom` first calls `clear()`, which resets all values on the object.

This PR copies relevant values or objects into other variables.

* Replace `command` with `tcId` since the latter is a final variable meant to be published to another thread.
* Move logic to copy certain command fields to earlier in method for `handleSubscribe`
* Copy `ack` object to new `CommandAck` when there is a broker interceptor. Note that copying this command is likely somewhat costly, so we only do it when there is an interceptor configured.

This is a trivial change that is already covered by tests.

- [x] `doc-not-needed`

This is an internal change.

PR in forked repository: michaeljmarshall#8

(cherry picked from commit a408e9e)
@michaeljmarshall michaeljmarshall deleted the use-final-variable branch January 23, 2023 22:54
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.

None yet

7 participants