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

kqueue: remove timeout from unix.Kevent() #39

Merged
merged 2 commits into from Mar 6, 2024
Merged

kqueue: remove timeout from unix.Kevent() #39

merged 2 commits into from Mar 6, 2024

Conversation

shogo82148
Copy link
Owner

@shogo82148 shogo82148 commented Mar 6, 2024

port fsnotify/fsnotify#480

The timeout for unix.Kevent() is causing issues; every 100ms it will do a new
unix.Kevent() syscall, which isn't too efficient: even if you have just one
change an hour, you will still keep calling kevent() ten times per second,
resulting in a needlessly high CPU usage.

Without a timeout, kevent() will block indefinitely until there are some events,
which is much more efficient. We can't just remove the timout however, since we
can't interrupt the kevent() call on FreeBSD and NetBSD, and it will hang
forever. This issue is described in more detail here:
fsnotify/fsnotify#262 (comment)

To solve this we register a new kevent() with the file descriptor set to the
closepipe; when this pipe is closed an event is sent and kevent() will stop
blocking.

Summary by CodeRabbit

  • Refactor
    • Enhanced time handling by removing external package dependencies.
    • Introduced a new closing mechanism to improve resource management.
    • Simplified event reading and management for better performance and reliability.

arp242 and others added 2 commits March 6, 2024 23:42
The timeout for unix.Kevent() is causing issues; every 100ms it will do a new
unix.Kevent() syscall, which isn't too efficient: even if you have just one
change an hour, you will still keep calling kevent() ten times per second,
resulting in a needlessly high CPU usage.

Without a timeout, kevent() will block indefinitely until there are some events,
which is much more efficient. We can't just remove the timout however, since we
can't interrupt the kevent() call on FreeBSD and NetBSD, and it will hang
forever. This issue is described in more detail here:
fsnotify/fsnotify#262 (comment)

To solve this we register a new kevent() with the file descriptor set to the
closepipe; when this pipe is closed an event is sent and kevent() will stop
blocking.

This is a rebased version of #124.

Fixes #89
Fixes #237
Fixes #333
Supersedes and closes #124
Supersedes and closes #262
Supersedes and closes #334

Co-authored-by: Felix Lange <fjl@twurst.com>
Copy link

coderabbitai bot commented Mar 6, 2024

Walkthrough

The codebase has undergone a transformative update focused on enhancing time handling and streamlining closing operations. This revamp includes a shift from the time package to a more direct approach, the introduction of a closepipe for more efficient closing processes, and various function modifications to integrate these changes seamlessly. This overhaul not only simplifies the time and event management but also optimizes the system's responsiveness and reliability.

Changes

File(s) Summary of Changes
kqueue.go - Replaced time package with direct handling
- Added closepipe for closing operations
- Refactored NewWatcher to support closepipe
- Updated Close method for closepipe
- Enhanced readEvents for closepipe management
- Modified kqueue for closepipe registration
- Adjusted register for event registration
- Simplified read by removing timeout handling

🐇✨

In the realm of code, where changes abound,

A rabbit hopped in, with ideas profound.

"Let's tweak and turn, refine and test,

Until our code stands above the rest."

With a hop and a skip, the updates were done,

In the glow of the screen, it shone like the sun. 🌟

🎉🐇

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 65c3f23 and 2a8aed8.
Files selected for processing (1)
  • kqueue.go (12 hunks)
Additional comments: 10
kqueue.go (10)
  • 25-28: The introduction of the closepipe field in the Watcher struct is a crucial part of the new mechanism to unblock the kevent() call. This change is well-aligned with the PR's objective to reduce CPU usage by eliminating constant polling. However, it's important to ensure that the closepipe is properly initialized and closed to avoid resource leaks.
  • 46-53: The changes in the NewWatcher function to initialize the kq and closepipe variables are correctly implemented. This setup is essential for the new blocking behavior of unix.Kevent() to work as intended. It's good to see error handling in place for the kqueue() call, ensuring that resources are not leaked if an error occurs during initialization.
  • 89-90: Closing the write-end of the closepipe in the Close method is a critical step to trigger an event that unblocks the kevent() call. This implementation effectively addresses the challenge of interrupting indefinitely blocking syscalls on FreeBSD and NetBSD systems. It's important to verify that the read-end of the closepipe is also closed to prevent resource leaks.
  • 114-115: The use of the register function to unregister a watch by using unix.EV_DELETE is correctly implemented. This is an important part of managing the lifecycle of watches, ensuring that resources are properly released when a watch is no longer needed. It's crucial to ensure that the file descriptor is closed after unregistering the watch to avoid file descriptor leaks.
  • 238-239: The call to register with unix.EV_ADD|unix.EV_CLEAR|unix.EV_ENABLE flags during the addition of a watch is correctly implemented. This setup is necessary for the new event handling mechanism to function properly. It's important to ensure that error handling is in place to close the file descriptor in case the registration fails, preventing resource leaks.
  • 275-284: The deferred function in readEvents to close the kq and closepipe file descriptors and to close the done, Events, and Errors channels is a good practice. This ensures that resources are properly cleaned up when the event reading loop terminates. However, it's crucial to handle potential errors from these close operations, especially for the file descriptors, to ensure that any issues are properly logged or handled.
  • 286-311: The logic to terminate the event reading loop upon receiving a close event from the closepipe is correctly implemented. This mechanism is essential for the new approach to unblocking kevent() calls. It's important to ensure that all events are processed before terminating the loop to avoid losing any events.
  • 491-522: The kqueue function's implementation, which creates a new kernel event queue and registers an event on the closepipe, is crucial for the new mechanism to work as intended. This setup allows kevent() to block indefinitely without polling, while still being able to be unblocked when necessary. It's important to ensure that all resources are properly cleaned up in case of errors to prevent leaks.
  • 525-534: The register function's implementation to register events with the queue is correctly done. Using unix.SetKevent to set up the events and then calling unix.Kevent to register them ensures that the watcher can monitor the specified events. Proper error handling in case the registration fails is crucial to avoid leaving the system in an inconsistent state.
  • 544-545: The simplification of the read function by removing timeout handling and allowing it to block indefinitely until events occur is in line with the PR's objectives. This change contributes to reducing CPU usage by eliminating constant polling. It's important to ensure that error handling is robust, especially for cases where unix.Kevent might return errors other than those expected.

@shogo82148 shogo82148 merged commit 999f629 into main Mar 6, 2024
112 checks passed
@shogo82148 shogo82148 deleted the port-480 branch March 6, 2024 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants