Skip to content

[Proposal]: Map responses back to requests #136

Closed
@jch

Description

@jch

I'd like to propose tracking requests and responses by message id to support interleaved responses on the shared socket in Net::LDAP::Connection.

The Problem

Searches (and other operations) done on one instance of Net::LDAP::Connection share the same TCPSocket (code). This allows the caller to initiate requests before responses for prior requests have completed. Net::LDAP uses a shared variable @open_connection to memoize existing connections before executing an operation.

We run into trouble because we do not inspect the response message id's and try to map them back to their original requests. Consider the following:

# search1: This will instantiate an instance of `Net::LDAP::Connection`  and store it in `@open_connection`.
Net::LDAP.search(...) do |outer_entry|
   # search2: sub-search based on some attributes of entry
  Net::LDAP.search(:filter => ...) do |inner_entry|
  end
end

Because we don't map the message id back to the original search request, results can be interleaved:

client: search1         search2
-------------------------------------------------------------------------> time
server:         1  1  1          1  1  1  2  2  2  2  1  1  1
                                 ^  ^  ^
                                 |  |  |
                                 \  |  /
                                  \ | /
                   server is still responding to search1,
                   but search2 may see search1 results
                   because we're on the same socket

The Proposal

I created a proof of concept using fibers to control the execution flow, and adding Request and Response classes to track message ids and to buffer any incoming results that don't match the current request.

As a user of the API, you don't have to reason about when results come in. Your code will block until it starts seeing results that match your request message_id.

Although the gist I posted is a proof of concept, I think it maps pretty closely to the existing code. We would need to add additional state to the Net::LDAP::Connection class, but we could leave the existing public API intact. This also opens up the option for abandoning requests, though that would be in a separate PR.

For additional context, check out #133 and github/github-ldap@620ce32

cc @mtodd @schaary

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions