-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
lib/config: Allow sub-second watcher delay (fixes #7859) #7864
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
lib/config: Allow sub-second watcher delay (fixes #7859) #7864
Conversation
This comment was marked as off-topic.
This comment was marked as off-topic.
No delay at all isn't ok. notify sometimes creates multiple events for a single change, at least those should be aggregated. |
@imsodin What is the minimum delay that would be fine in your opinion? Would 100ms be ok? |
I just don't want == 0, as that means multiple triggered scans by design if there are duplicate events. Even back to back events in our tests are reported in <1ms, so a 10ms lower limit should be very save and that's already below human perception. |
I opened the original #7859 and was going to add a comment, but @imsodin said it already. I originally suggested that |
I've given this a shot. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without a rename FSWatcherDelayS
needs to remain seconds. The option was to change it to float in the proto so it stays compatible with current values and one can specify fractions of a second.
Keeping in mind once again that I have limited experience with Go and even less with this codebase, so apologies if I'm not making any sense: I thought implementing that strategy could be limited to something like this: func notifyTimeout(eventDelayS int) time.Duration {
shortDelayS := 10
shortDelayMultiplicator := 6
longDelayS := 60
longDelayTimeout := time.Duration(1) * time.Minute
if eventDelayS < shortDelayS {
return time.Duration(eventDelayS*shortDelayMultiplicator) * time.Second
}
if eventDelayS < longDelayS {
return longDelayTimeout
}
- return time.Duration(eventDelayS) * time.Second
+ if (eventDelayS === 0) {
+ // Clamp at 10ms minimum
+ return time.Duration(10) * time.Millisecond
+ } else {
+ return time.Duration(eventDelayS) * time.Second
+ }
} So basically just special-casing |
I've modified the code to follow the suggestion by @bard, because it seems much simpler, while doing the same job.
Is it really bad to just allow What I basically mean that |
Maybe. Zero values and defaults are a minefield (if you are interested, some thoughts on that and other things are here: https://github.com/syncthing/syncthing/wiki/Configuration). Maybe this is fine, maybe it isn't - it doesn't matter because the actually simple and least surprising option is keeping the current behaviour, just allowing fractions of a second as a value. Simple in terms of just needing some special casing somewhere in the code is not a good criterium. |
From my understanding, the value in question is meant to capture user intent, not a software contract. Theoretically, if the value were part of a contract between different modules of syncthing, or between syncthing and other programs, I'd agree with you — if one module/program promises 500 X's and delivers 510 X's, it makes the job of the module/program on the other side more complicated. ("Theoretically" because, when dealing with time, the case isn't that clear-cut — distributed systems have little choice but to accept and plan for variability, or be fragile.) When it comes to user intent, I think it's important to stay aware of what the number (or the string, or any vehicle of meaning) is supposed to encode. If I tap my phone's screen, and my fingertip ends up touching just one pixel below a hyperlink, where nothing clickable is present, is the browser's code doing me a favor and "special-casing" by activating the hyperlink, or is it fulfilling its contract with me, which consists in interpreting my intent correctly? Ideally, user configuration values take intent into account as well. If I say, "sync at 10 seconds", I'm not really saying "sync at 10000ms" — 9500ms or 10500ms or anything in between captures my intent just as correctly. If I want to say "sync immediately", to say "sync at 0 seconds" captures my intent fine, too. All IMHO, of course. (Perhaps the crux here is just that a user value shouldn't wait too long and until it's too deep into the stack before intent is extracted from it?) |
I incorrectly assumed the |
@imsodin if you mean allowing fractions of a second as a value, it was also my first suggestion in the original issue, and the argument against it was the cost of migrating configuration. |
|
I have tried to convert the value from int to float, and it does seem to work, but don't really have confidence regarding my modifications. I had to edit quite some code related to usage reporting, including migration, and I don't know whether it works or not. Also, if I set the type to When it comes to generating proto itself, I used the precompiled binary mentioned in https://forum.syncthing.net/t/exec-protoc-executable-file-not-found-in-path/17307, so I also hope that the generated code is fine. |
Allow the watcher delay to take fractional values, effectively allowing for much shorter delays. The minimum value is limited at 0.01, which effectively translates to 10ms. This is required in order to guarantee that there is still enough time to aggregate multiple single change events. Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
05263df
to
1339e4e
Compare
Ah, fair enough, I didn't realize that addressed the objection, I thought the migration would be necessary regardless. |
|
Looks like this needs a |
Just to confirm, I should revert the usage reporting changes, keeping the value as |
That sounds reasonable to me, yes. The few non-integer values we have in the config today are |
🤖 beep boop I'm going to close this pull request as it has been idle for more than 90 days. This is not a rejection, merely a removal from the list of active pull requests that is periodically reviewed by humans. The pull request can be reopened when there is new activity, and merged once any remaining issues are resolved. |
* main: (424 commits) gui, man, authors: Update docs, translations, and contributors lib/protocol: Cache expensive key operations (fixes syncthing#8599) (syncthing#8820) gui: Add Persian (fa) translation template (syncthing#8822) lib: Correctly handle encrypted trailer size (fixes syncthing#8556) (syncthing#8563) gui: Disable Restore Versions filters when no versioned files exist (fixes syncthing#5408) (syncthing#8539) build(deps): bump github.com/chmduquesne/rollinghash from 0.0.0-20180912150627-a60f8e7142b5 to 4.0.0+incompatible (syncthing#8804) build: Update dependencies (syncthing#8821) lib/api: Expose `blocksHash` in file info (syncthing#8810) gui, man, authors: Update docs, translations, and contributors lib/discover: Don't leak relay-tokens to discovery (syncthing#8762) gui, man, authors: Update docs, translations, and contributors gui: Add Croatian (hr) translation template (syncthing#8801) build(deps): bump github.com/quic-go/quic-go from 0.32.0 to 0.33.0 (syncthing#8800) cmd/stupgrades: Cache should apply to HEAD as well as GET build: Add more GitHub Actions gui: Remove non-existent customicons.css file reference (fixes syncthing#8797) (syncthing#8798) Only fail after chmod error if permissions differ (e.g. on config file) (syncthing#8771) gui, man, authors: Update docs, translations, and contributors build: Use Go 1.19.6 for Windows build: Update dependencies ...
* main: (28 commits) build: Update dependencies (syncthing#8869) lib/model: Improve path generation for auto accepted folders (fixes syncthing#8859) (syncthing#8860) docs: fix typo (syncthing#8857) gui, man, authors: Update docs, translations, and contributors lib/syncthing: Handle successful global migration (fixes syncthing#8851) (syncthing#8852) gui, man, authors: Update docs, translations, and contributors lib/model: Set enc. trailer size on pull (ref syncthing#8563, syncthing#8556) (syncthing#8839) lib/model: Fix file size inconsistency due to enc. trailer (syncthing#8840) gui, man, authors: Update docs, translations, and contributors cmd/stdiscorv: Fix database test (fixes syncthing#8828) lib/ur: Fix custom releases URL comparison gui: Remove untranslated strings from JSON files (syncthing#8836) all: Fix typos found by codespell (syncthing#8833) gui: Hide download progress legend when download progress is disabled gui, man, authors: Update docs, translations, and contributors lib/protocol: Handle encrypted requests without encrypted hash (fixes syncthing#8277) (syncthing#8827) build(deps): bump github.com/hashicorp/golang-lru/v2 from 2.0.1 to 2.0.2 (syncthing#8826) lib/config: Allow sub-second watcher delay (fixes syncthing#7859) (syncthing#7864) gui, man, authors: Update docs, translations, and contributors lib/protocol: Cache expensive key operations (fixes syncthing#8599) (syncthing#8820) ...
Allow the watcher delay to take fractional values, effectively allowing
for much shorter delays. The minimum value is limited at 0.01, which
effectively translates to 10ms. This is required in order to guarantee
that there is still enough time to aggregate multiple single change
events.
Signed-off-by: Tomasz Wilczyński twilczynski@naver.com