-
Notifications
You must be signed in to change notification settings - Fork 404
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
TimerWheel usually ignores Timers execution if tickDuration is more than 1ns #73
Comments
This is currently not something we use and therefore not something we intend to address. Feel free to send a PR, though. But it is not something we currently support. Originally the design of TimerWheel assumed a tickDuration of at least millisecond for the use case. Also, it assumes you don't schedule too close to the current time. |
Implementation is broken with any values > 1 nanosecond. So, for a millisecond it's broken too.
Unrelated. Tick is 10ms, schedule timeout for 69ms - it would be broken too according to this code. |
The statement, that you have code in a pretty new library that you don't use and support looks very strange. Before using a class from Agrona I should ask if this class you use and support? I will think about PR :) |
Good point. We shall look into getting rid of TimerWheel. |
Removing functionality from general-purpose project released with description "High Performance data structures and utility methods for Java and C++" only because somebody, even if it's parent project, doesn't use this it anymore? Cool general purpose library. Ok, I got how do you feel about Agrona, it's unsafe to use in external projects. |
As with ANY library or piece of OSS code, you use at your own discretion. In addition, the support of any OSS code is up to the author(s). This work has graciously been sponsored to produce a set of OSS projects. We have moved those pieces that are generic into this project for people to use as they desire without using the entire larger project. TimerWheel, specifically, we stopped using because we have a better means to handle timers. But we kept it around for others to use here. As we don't have the time, resources, nor interest in the support of the current TimerWheel, there might be no reason to keep it around. However, I have asked some users if they require it. If so, we will support it on our own time. |
The question is not about licenses and definitions, it's about attitude. It's fine to don't develop some piece of general purpose libraries you don't interested in right now, but leave things in just a broken state, or respond with meanings "we don't use, nobody cares" is not fine for general purpose library and public APIs. Yes, you are fine with the formal point, but it's not safe to use a library with such attitude of maintainers - nothing more. About PRs - of course, no sense to contribute to general purpose library with such an attitude. There are others. |
It was suggested some time ago that the TimerWheel be migrated to a project such as JCTools. I think it is the only class in here that is not being actively used. Even so I put in the time to review and integrate your PR this morning. I also did it with a quick turn around. How you choose to see the world I cannot have any influence over. We do care. We also have to be practical. If no one is using it that wants to help contribute then who should support it? I'm willing to put in some time but there is only so much I can give. |
@mjpt777 Quick review, feedback and merging PR is beautiful, thanks for this! It was a first positive opinion. On the same time, a reaction like "we don't use this - we don't support this, even if it's broken" above for general purpose library looks pretty strange for me - that's all that I'm talking about.
For example, I use this class and I want to contribute because I have a problem. I already made some new stuff on the morning. And I can prepare a fix for the current problem too. So I spent time to describe it in issue description and put it in a review for maintainers. What I'm waiting for is something like
So, I'm waiting for some feedback, if it actually looks like a bug, or I just don't understand something. If I propose different ways of solving the problem - I'm waiting for some recommendations, which is a preferable way from maintainers point of view. Or right way is completely different. Instead, I see:
This answer is really a "Too long to read, nobody cares here, you can prepare PR as much as you want". So, an answer to your question - everyone should support this who use this. And I don't require you to come and fix this right now because something is broken. And I didn't talk about it. I supposed to prepare fix for this issue and just waited some adequate advice of maintainer, not "TL;DR We don't use it - we don't support this". Hope, I described how I see the world. And in the most open-source projects, I contributed in, my view of the world matches to culture and attitudes in this projects. About subject: |
@Spikhalskiy my apologies for phrasing things incorrectly initially. We do care. However, TimerWheel is not something we do use for various reasons. And, unfortunately, not something we can devote a lot of time to. As you submitted an issue instead of a PR for this, I was under the impression you wanted us to address it. Now that you have explained your meaning, it is clearer. Thanks! I think it is worth explaining what is not in the Javadoc for TimerWheel to frame the discussion on usage. The intended initial usage of TimerWheel (which, again, we don't use) was to repeatedly call There are many ways to address this as you mention. Removing the deadline check is fine if timer ordering is not a concern. But insufficient. The expiration logic is quite flawed. If I had the time, I would completely rewrite this with a slightly different approach. As I do not, the best way to go is to migrate this out of Agrona unless its usage is required. |
@tmontgomery Thanks. Apologies for too sensitive reaction from my side too.
Maybe it was initial usage, but it doesn't looks right with the current code. We have a tickDurationNs. Each call to expireTimers() we increase current tick pointer. It looks like we should call expireTimers() once per tickDurationNs nanosecond. If we do it another way - ticks and putting Timer to specific tick in array has no sense and works not according to the idea, so position of task in array has no sense because we would just very quickly check whole array. In any case - failing test for this scenario:
One more test that could help to figure out bug that I'm talking about (tests below are with reasonable calling
If we will trigger timer each 1800ms instead of 2s - task would never be executed at all. Just never. Triggering of timer a bit earlier at least once could leave to completely loosing task. Take a look, triggering expireTimers() 1ns before right time (in terms of our NanoClock time) leads to completely task loosing:
The source of all of this is the mistake in design, that we mix information about time in a discreet form:
I would take this implementation and will make something based on NanoClock only as a time source or based on expireTimers() calls count only. Would send PR when it would be done, maybe you will want to adopt it here. If not - would just keep in my project. |
Yes, calling This is why the usage guarded the call. The original usage in the busy spin was (going from memory) of the form: if (computeDelayInMs() <= 0)
{
expireTimers();
} The intention was to only call The test |
Put the class here https://github.com/Spikhalskiy/hashed-wheel-timer, simplified and fixed unsafe stuff, time/tick managing design. Would continue development in this repo, but it should be very close to the original version. |
Looks like currently TimerWheel is effectively broken.
Test:
This test pass. So... tick is 10ns. We schedule execution on 12ns timestamp. Nothing executed on 10ns, nothing executed on 20ns. You can put any value in TICK_PERIOD_NS which % TICK_PERIOD_NS != 0.
Reason:
TimerWheel#
So... we schedule Timer to tick number in the "floor" div mode and after that we usually get now <= timer.deadline() if now is around right tick time. As a result - we mark Timer as Expired and do nothing + remove it with timer.remove().
Proposals:
WheelTimer already depends on the external scheduler accuracy, because it fully depends on triggering ticks more or less on right intervals outside. So, it should be fine to check only remainingRounds on current tick.
*) Another approach to fix design - stop doing
currentTick++;
on eachexpireTimers()
invocation and rework tick triggering logic. So, when we trigger expireTimers() outside - we calculate how much ticks passed since previous execution usingclock
and expire-run all Timers in passed ticks. This is even better, because we stop to be dependent on accuracy of external scheduler not in terms of frequency, but in terms of accuracy and things like STW pauses which could cause ticks loosing.And one more note about this code:
now >= timer.deadline
is fine if we work with milliseconds. But incorrect for nanoseconds because of long overflow. The only correct way to compare nanosecond timestamps is:
now - timer.deadline >= 0
The text was updated successfully, but these errors were encountered: