Hone logo
Hone
Problems

Implement a Go Netpoller

You are tasked with building a network poller in Go. A network poller is a component that efficiently monitors multiple network connections (sockets) for readiness to perform I/O operations (read or write). This is crucial for high-performance network servers that need to handle many concurrent connections without blocking on individual I/O calls.

Problem Description

Your goal is to implement a Netpoller struct in Go that can:

  1. Register file descriptors (network sockets) for monitoring.
  2. Unregister file descriptors that are no longer needed.
  3. Poll for readiness. This involves waiting for one or more registered file descriptors to become ready for a specified duration.
  4. Report which file descriptors are ready and for what type of event (read or write).

You should leverage Go's standard library for this task, specifically looking into mechanisms designed for efficient I/O multiplexing.

Key Requirements:

  • The Netpoller should be thread-safe for registration and unregistration operations, but polling can be synchronous or asynchronous as long as the API is clear.
  • It must support monitoring for both readability and writability on a given file descriptor.
  • The polling mechanism should have a timeout.
  • The Netpoller should be able to handle a large number of concurrently registered file descriptors.

Expected Behavior:

When Poll is called, it should return a list of events. Each event should indicate which file descriptor is ready and whether it's ready for reading, writing, or both. If the timeout expires before any events occur, Poll should return an empty list or an indication of timeout.

Edge Cases:

  • Registering a file descriptor that is already registered (should likely be an error or a no-op).
  • Unregistering a file descriptor that has not been registered (should likely be an error or a no-op).
  • Polling with a zero or negative timeout.
  • What happens if a file descriptor is closed while registered? The poller should ideally handle this gracefully.

Examples

Let's consider a simplified scenario where we are monitoring two sockets, fd1 and fd2.

Example 1: Simulating a Read Event

  • Input:
    • Netpoller is created.
    • fd1 is registered for reading.
    • fd2 is registered for writing.
    • Poll is called with a timeout of 5 seconds.
    • After 1 second, data arrives on fd1.
  • Output: A list of events containing one event: [{FD: fd1, Events: Read}, ...]. fd2 is not reported as ready.

Example 2: Simulating a Write Event

  • Input:
    • Netpoller is created.
    • fd1 is registered for reading.
    • fd2 is registered for writing.
    • Poll is called with a timeout of 5 seconds.
    • After 2 seconds, fd2 becomes writable (e.g., its output buffer is no longer full).
  • Output: A list of events containing one event: [{FD: fd2, Events: Write}, ...]. fd1 is not reported as ready.

Example 3: Timeout

  • Input:
    • Netpoller is created.
    • fd1 is registered for reading.
    • fd2 is registered for writing.
    • Poll is called with a timeout of 1 second.
    • No I/O events occur on fd1 or fd2 within 1 second.
  • Output: An empty list of events: [].

Constraints

  • The Netpoller should be able to handle at least 10,000 concurrent file descriptors.
  • Input file descriptors will be valid integers representing network sockets.
  • The Poll method should not introduce significant latency beyond the underlying OS polling mechanism and the specified timeout.
  • The solution should be written in Go.

Notes

  • Think about the underlying operating system primitives for I/O multiplexing. Go provides interfaces to these.
  • Consider how to represent events clearly. An Event struct with fields like FD and Events (perhaps a bitmask or an enum) would be suitable.
  • Error handling is crucial. What should happen if OS calls fail?
  • The choice of the Go package to use for polling is a key part of the challenge. Explore syscall and potentially net package internals, or specialized third-party libraries if necessary (though the standard library is preferred for this challenge).
  • For simplicity in testing, you might need to create mock file descriptors or use actual network connections (e.g., net.Pipe or net.Listen/net.Dial).
Loading editor...
go