Skip to content

Conversation

@poorbarcode
Copy link
Contributor

@poorbarcode poorbarcode commented Jul 28, 2023

Motivation

  • The task trim ledgers runs in the thread BkMainThreadPool.choose(ledgerName)
  • The task write entries to BK runs in the thread BkMainThreadPool.choose(ledgerId)

So the two tasks above may run concurrently/

The task trim ledgers work as the flow below:

  • find the ledgers which are no longer to read, the result is {Ledgers before the slowest read}.
  • check if the {Ledgers before the slowest read} is out of retention policy, the result is {Ledgers to be deleted}.
    • if the create time of the ledger is lower than the earliest retention time, mark it should be deleted
    • if after deleting this ledger, the rest ledgers are still larger than the retention size, mark it should be deleted
  • delete the{Ledgers to be deleted}

In step-3-2, the implementation is like this:

long totalSizeToDelete = 0;
for (Ledger ledger : ledegrs) {
    totalSizeToDelete += ledger.size;
    if (calculateTotalSizeWrited() - totalSizeToDelete >= sizeShouldRetention ){
       // mark the ledger should be deleted.
    }
}

see: https://github.com/apache/pulsar/blob/branch-3.0/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java#L2671-L2698

(Highlight) There is a scenario that causes the task trim ledgers did discontinuous ledger deletion, resulting consume messages discontinuous:

  • context:
    • ledgers: [{id=1, size=100}, {id=2,size=100}]
    • retention size: 150
    • no cursor there
  • Check ledger 1, skip by retention check (200 - 100) < 150
  • One in-flight writing is finished, the calculateTotalSizeWrited() would return 300 now.
  • Check ledger 2, retention check (300 - 100) > 150, mark the ledger-2 should be deleted.
  • Delete the ledger 2.
  • Create a new consumer. It will receive messages from [ledger-1, ledegr-3], but the ledger-2 will be skipped.

Modifications

once the retention constraint has been met, break the loop.

Documentation

  • doc
  • doc-required
  • doc-not-needed
  • doc-complete

Matching PR in forked repository

PR in forked repository: x

@poorbarcode poorbarcode self-assigned this Jul 28, 2023
@github-actions github-actions bot added the doc-not-needed Your PR changes do not impact docs label Jul 28, 2023
@poorbarcode poorbarcode added type/bug The PR fixed a bug or issue reported a bug and removed doc-not-needed Your PR changes do not impact docs labels Jul 28, 2023
@poorbarcode poorbarcode added this to the 3.2.0 milestone Jul 28, 2023
@github-actions github-actions bot added the doc-not-needed Your PR changes do not impact docs label Jul 28, 2023
@poorbarcode poorbarcode requested a review from mattisonchao July 28, 2023 10:59
poorbarcode and others added 2 commits July 28, 2023 19:15
@poorbarcode poorbarcode requested a review from mattisonchao July 28, 2023 11:16
Copy link
Member

@mattisonchao mattisonchao left a comment

Choose a reason for hiding this comment

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

LGTM :)

}

long slowestReaderLedgerId = -1;
final long slowestNonDurationLedgerId = getTheSlowestNonDurationReadPosition().getLedgerId();
Copy link
Member

@mattisonchao mattisonchao Jul 28, 2023

Choose a reason for hiding this comment

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

We can introduce a new API to the cursor container to get this position and explain cursors.getSlowestReaderPosition() only can get the nonDurable cursor in the future by #17273. :)

Copy link
Contributor Author

@poorbarcode poorbarcode Jul 28, 2023

Choose a reason for hiding this comment

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

Yes, we can improve it in the future

Copy link
Contributor

@lifepuzzlefun lifepuzzlefun left a comment

Choose a reason for hiding this comment

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

Nice catch !

LedgerInfo ls = ledgerInfoIterator.next();
releaseReadHandleIfNoLongerRead(ls.getLedgerId(), slowestNonDurationLedgerId.getValue());
}

Copy link
Member

Choose a reason for hiding this comment

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

Can we break out of loops early?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, all the ledgers in the collection may no longer need to be read

Copy link
Member

Choose a reason for hiding this comment

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

Can we break out of loops early, if ledgerId >= slowestNonDurationLedgerId?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good suggestion, fixed.

// Handle the -1 size limit as "infinite" size quota
return config.getRetentionSizeInMB() >= 0
&& TOTAL_SIZE_UPDATER.get(this) - sizeToDelete >= config.getRetentionSizeInMB() * MegaByte;
return retentionSizeInMB >= 0 && TOTAL_SIZE_UPDATER.get(this) - sizeToDelete >= retentionSizeInMB * MegaByte;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use an immutable value to instead of TOTAL_SIZE_UPDATER.get(this)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gaoran10

Sorry, I misunderstood this before. It was fixed now, could you take a look again?

@poorbarcode poorbarcode requested review from coderzc and gaoran10 August 1, 2023 02:55
Copy link
Contributor

@Technoboy- Technoboy- left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@gaoran10 gaoran10 left a comment

Choose a reason for hiding this comment

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

LGTM

@codecov-commenter
Copy link

codecov-commenter commented Aug 1, 2023

Codecov Report

❌ Patch coverage is 88.23529% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.09%. Comparing base (9be0b52) to head (c1a3400).
⚠️ Report is 1783 commits behind head on master.

Files with missing lines Patch % Lines
...che/bookkeeper/mledger/impl/ManagedLedgerImpl.java 85.71% 2 Missing and 2 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##             master   #20898      +/-   ##
============================================
- Coverage     73.23%   73.09%   -0.15%     
- Complexity     3762    32129   +28367     
============================================
  Files          1874     1875       +1     
  Lines        139377   139403      +26     
  Branches      15328    15328              
============================================
- Hits         102068   101890     -178     
- Misses        29297    29450     +153     
- Partials       8012     8063      +51     
Flag Coverage Δ
inttests 24.12% <41.17%> (-0.27%) ⬇️
systests 25.16% <61.76%> (-0.12%) ⬇️
unittests 72.38% <88.23%> (-0.12%) ⬇️

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

Files with missing lines Coverage Δ
...g/apache/pulsar/common/util/LazyLoadableValue.java 100.00% <100.00%> (ø)
...che/bookkeeper/mledger/impl/ManagedLedgerImpl.java 81.32% <85.71%> (-0.48%) ⬇️

... and 79 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@poorbarcode poorbarcode merged commit 782e91f into apache:master Aug 1, 2023
@poorbarcode poorbarcode deleted the fix/skipped_trim_ledger branch August 1, 2023 14:38
poorbarcode added a commit that referenced this pull request Aug 1, 2023
- The task `trim ledgers` runs in the thread `BkMainThreadPool.choose(ledgerName)`
- The task `write entries to BK` runs in the thread `BkMainThreadPool.choose(ledgerId)`

So the two tasks above may run concurrently/

The task `trim ledgers` work as the flow below:
- find the ledgers which are no longer to read, the result is `{Ledgers before the slowest read}`.
- check if the `{Ledgers before the slowest read}` is out of retention policy, the result is `{Ledgers to be deleted}`.
  - if the create time of the ledger is lower than the earliest retention time, mark it should be deleted
  - if after deleting this ledger, the rest ledgers are still larger than the retention size, mark it should be deleted
- delete the`{Ledgers to be deleted}`

**(Highlight)** There is a scenario that causes the task `trim ledgers` did  discontinuous ledger deletion, resulting consume messages discontinuous:
- context:
  - ledgers: `[{id=1, size=100}, {id=2,size=100}]`
  - retention size: 150
  - no cursor there
- Check `ledger 1`, skip by retention check `(200 - 100) < 150`
- One in-flight writing is finished, the `calculateTotalSizeWrited()` would return `300` now.
- Check `ledger 2`, retention check `(300 - 100) > 150`, mark the ledger-2 should be deleted.
- Delete the `ledger 2`.
- Create a new consumer. It will receive messages from `[ledger-1, ledegr-3]`, but the `ledger-2` will be skipped.

Once the retention constraint has been met, break the loop.

(cherry picked from commit 782e91f)
poorbarcode added a commit that referenced this pull request Aug 1, 2023
- The task `trim ledgers` runs in the thread `BkMainThreadPool.choose(ledgerName)`
- The task `write entries to BK` runs in the thread `BkMainThreadPool.choose(ledgerId)`

So the two tasks above may run concurrently/

The task `trim ledgers` work as the flow below:
- find the ledgers which are no longer to read, the result is `{Ledgers before the slowest read}`.
- check if the `{Ledgers before the slowest read}` is out of retention policy, the result is `{Ledgers to be deleted}`.
  - if the create time of the ledger is lower than the earliest retention time, mark it should be deleted
  - if after deleting this ledger, the rest ledgers are still larger than the retention size, mark it should be deleted
- delete the`{Ledgers to be deleted}`

**(Highlight)** There is a scenario that causes the task `trim ledgers` did  discontinuous ledger deletion, resulting consume messages discontinuous:
- context:
  - ledgers: `[{id=1, size=100}, {id=2,size=100}]`
  - retention size: 150
  - no cursor there
- Check `ledger 1`, skip by retention check `(200 - 100) < 150`
- One in-flight writing is finished, the `calculateTotalSizeWrited()` would return `300` now.
- Check `ledger 2`, retention check `(300 - 100) > 150`, mark the ledger-2 should be deleted.
- Delete the `ledger 2`.
- Create a new consumer. It will receive messages from `[ledger-1, ledegr-3]`, but the `ledger-2` will be skipped.

Once the retention constraint has been met, break the loop.

(cherry picked from commit 782e91f)
poorbarcode added a commit that referenced this pull request Aug 1, 2023
### Motivation

- The task `trim ledgers` runs in the thread `BkMainThreadPool.choose(ledgerName)`
- The task `write entries to BK` runs in the thread `BkMainThreadPool.choose(ledgerId)`

So the two tasks above may run concurrently/

The task `trim ledgers` work as the flow below:
- find the ledgers which are no longer to read, the result is `{Ledgers before the slowest read}`.
- check if the `{Ledgers before the slowest read}` is out of retention policy, the result is `{Ledgers to be deleted}`.
  - if the create time of the ledger is lower than the earliest retention time, mark it should be deleted
  - if after deleting this ledger, the rest ledgers are still larger than the retention size, mark it should be deleted
- delete the`{Ledgers to be deleted}`

**(Highlight)** There is a scenario that causes the task `trim ledgers` did  discontinuous ledger deletion, resulting consume messages discontinuous:
- context:
  - ledgers: `[{id=1, size=100}, {id=2,size=100}]`
  - retention size: 150
  - no cursor there
- Check `ledger 1`, skip by retention check `(200 - 100) < 150`
- One in-flight writing is finished, the `calculateTotalSizeWrited()` would return `300` now.
- Check `ledger 2`, retention check `(300 - 100) > 150`, mark the ledger-2 should be deleted.
- Delete the `ledger 2`.
- Create a new consumer. It will receive messages from `[ledger-1, ledegr-3]`, but the `ledger-2` will be skipped.

### Modifications

Once the retention constraint has been met, break the loop.

(cherry picked from commit 782e91f)
mukesh-ctds pushed a commit to datastax/pulsar that referenced this pull request Apr 13, 2024
### Motivation

- The task `trim ledgers` runs in the thread `BkMainThreadPool.choose(ledgerName)`
- The task `write entries to BK` runs in the thread `BkMainThreadPool.choose(ledgerId)`

So the two tasks above may run concurrently/

The task `trim ledgers` work as the flow below:
- find the ledgers which are no longer to read, the result is `{Ledgers before the slowest read}`.
- check if the `{Ledgers before the slowest read}` is out of retention policy, the result is `{Ledgers to be deleted}`.
  - if the create time of the ledger is lower than the earliest retention time, mark it should be deleted
  - if after deleting this ledger, the rest ledgers are still larger than the retention size, mark it should be deleted
- delete the`{Ledgers to be deleted}`

**(Highlight)** There is a scenario that causes the task `trim ledgers` did  discontinuous ledger deletion, resulting consume messages discontinuous:
- context:
  - ledgers: `[{id=1, size=100}, {id=2,size=100}]`
  - retention size: 150
  - no cursor there
- Check `ledger 1`, skip by retention check `(200 - 100) < 150`
- One in-flight writing is finished, the `calculateTotalSizeWrited()` would return `300` now.
- Check `ledger 2`, retention check `(300 - 100) > 150`, mark the ledger-2 should be deleted.
- Delete the `ledger 2`.
- Create a new consumer. It will receive messages from `[ledger-1, ledegr-3]`, but the `ledger-2` will be skipped.

### Modifications

Once the retention constraint has been met, break the loop.

(cherry picked from commit 782e91f)
(cherry picked from commit b87c0fb)
mukesh-ctds pushed a commit to datastax/pulsar that referenced this pull request Apr 19, 2024
### Motivation

- The task `trim ledgers` runs in the thread `BkMainThreadPool.choose(ledgerName)`
- The task `write entries to BK` runs in the thread `BkMainThreadPool.choose(ledgerId)`

So the two tasks above may run concurrently/

The task `trim ledgers` work as the flow below:
- find the ledgers which are no longer to read, the result is `{Ledgers before the slowest read}`.
- check if the `{Ledgers before the slowest read}` is out of retention policy, the result is `{Ledgers to be deleted}`.
  - if the create time of the ledger is lower than the earliest retention time, mark it should be deleted
  - if after deleting this ledger, the rest ledgers are still larger than the retention size, mark it should be deleted
- delete the`{Ledgers to be deleted}`

**(Highlight)** There is a scenario that causes the task `trim ledgers` did  discontinuous ledger deletion, resulting consume messages discontinuous:
- context:
  - ledgers: `[{id=1, size=100}, {id=2,size=100}]`
  - retention size: 150
  - no cursor there
- Check `ledger 1`, skip by retention check `(200 - 100) < 150`
- One in-flight writing is finished, the `calculateTotalSizeWrited()` would return `300` now.
- Check `ledger 2`, retention check `(300 - 100) > 150`, mark the ledger-2 should be deleted.
- Delete the `ledger 2`.
- Create a new consumer. It will receive messages from `[ledger-1, ledegr-3]`, but the `ledger-2` will be skipped.

### Modifications

Once the retention constraint has been met, break the loop.

(cherry picked from commit 782e91f)
(cherry picked from commit b87c0fb)
srinath-ctds pushed a commit to datastax/pulsar that referenced this pull request Apr 23, 2024
### Motivation

- The task `trim ledgers` runs in the thread `BkMainThreadPool.choose(ledgerName)`
- The task `write entries to BK` runs in the thread `BkMainThreadPool.choose(ledgerId)`

So the two tasks above may run concurrently/

The task `trim ledgers` work as the flow below:
- find the ledgers which are no longer to read, the result is `{Ledgers before the slowest read}`.
- check if the `{Ledgers before the slowest read}` is out of retention policy, the result is `{Ledgers to be deleted}`.
  - if the create time of the ledger is lower than the earliest retention time, mark it should be deleted
  - if after deleting this ledger, the rest ledgers are still larger than the retention size, mark it should be deleted
- delete the`{Ledgers to be deleted}`

**(Highlight)** There is a scenario that causes the task `trim ledgers` did  discontinuous ledger deletion, resulting consume messages discontinuous:
- context:
  - ledgers: `[{id=1, size=100}, {id=2,size=100}]`
  - retention size: 150
  - no cursor there
- Check `ledger 1`, skip by retention check `(200 - 100) < 150`
- One in-flight writing is finished, the `calculateTotalSizeWrited()` would return `300` now.
- Check `ledger 2`, retention check `(300 - 100) > 150`, mark the ledger-2 should be deleted.
- Delete the `ledger 2`.
- Create a new consumer. It will receive messages from `[ledger-1, ledegr-3]`, but the `ledger-2` will be skipped.

### Modifications

Once the retention constraint has been met, break the loop.

(cherry picked from commit 782e91f)
(cherry picked from commit b87c0fb)
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.

7 participants