Skip to content

[BUG] pendingTimeouts may be incorrect in the HashedWheelTimer #3173

@gagaradio

Description

@gagaradio

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

If a Timeout in HashedWheelTimer has been transferred to a bucket and is canceled before it is actually expired in the goal tick, pendingTimeouts may be repeatedly decremented.
If the user sets a positive maxPendingTimeouts, this bug means that the maximum number of tasks can be potentially increased.

Expected Behavior

The pendingTimeouts in HashedWheelTimer can correctly reflect the number of waiting tasks.

Steps To Reproduce

The following test code reproduces the bug.

final HashedWheelTimer timer = new HashedWheelTimer();
final CountDownLatch barrier = new CountDownLatch(1);
// A total of 11 timeouts with the same delay are submitted here, and they will be processed in the same tick.
timer.newTimeout(t -> {
    barrier.countDown();
    Thread.sleep(1000);
}, 200, TimeUnit.MILLISECONDS);
List<Timeout> timeouts = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    timeouts.add(timer.newTimeout(createNoOpTimerTask(), 200, TimeUnit.MILLISECONDS));
}
barrier.await();
// The simulation here is that the timeout has been transferred to a bucket and is canceled before it is
// actually expired in the goal tick.
timeouts.forEach(Timeout::cancel);
Thread.sleep(2000);
assertEquals(0, timer.pendingTimeouts());
timer.stop();

Got the following test failures and ended up with a negative pendingTimeouts.

Expected :0
Actual   :-10

Environment

HertzBeat version(s): The latest master branch.

Debug logs

No response

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomers

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions