Skip to content

Re-using an access context when browsing (Improve network parsing speed)

Thomas Guillem requested to merge tguillem/vlc:smb2-keep-context-wip into master

Please read the MR description before reviewing the commits

The goal

As a reminder, here are the notes from VLC Workshop Summary - 2021-12-06/07

On the communication keep subject, for now, only the stream_extractor has a notion of that kind.

It is proposed to add an optional openat callback in the access modules to keep connection resources between access calls.

This will not be used in VLC4 for now, only in the new preparse application would use it.

-> Both the new preparse design and keepalive optional propositions are globally accepted.

The principal goal is to speed up the medialibrary parsing, that open, close and reopen a socket on the same SMB server when parsing multiples files from a server/share/directory. Improving speed when opening for playback is less important, and we decided not to focus on it.

Quick benchmark

Before working on anything, I hacked the DSM and SMB2 modules to see the potential gain. Here are the gain when opening a directory from a server/share:

  • libsmb2:
    • 200 - 250 ms without any context
    • 20 - 30 ms when keeping the context (and the socket)
  • libdsm:
    • 100 - 150 ms without any context
    • 1 ms when keeping the context (and the socket)

As you can see, the gain is huge, this make it quite mandatory when parsing thousands of files from a network share.

Possible solutions

1/ Keep this MR as it is: use a static cache for each access.

  • Advantage: Quick, no core change.
  • Drawbacks: Cleanup from a timer after a while: ugly.

2/ The open_at solution

Most libraries used by our access modules are not thread-safe. They can be used from only one thread, or the user should take care of locking. Behind most libraries context (smb2_context, smb_session), there is a file descriptor to a socket. Some libraries don't support opening more than one files at a time via the same context/socket.

Therefore, using the open_at solution that we decided during the workshop might be complicated. Indeed, with that solution, more than one accesses, from different threads, could share the same context/socket. To prevent parallel access to the context/socket, we have to add mutexes and this might kill the benefit of a shared context

3/ Override the close callback

Propose a new close callback, like the following

struct vlc_access_context {
    enum module_type;
    void *context;
    void (*free_cb)(void *context);
};
void close_context(access_t *access, struct vlc_access_context *context);

And send the struct vlc_access_context * from the Open callback via:

struct stream_t 
{
    struct vlc_object_t *obj;
...
    union {
        stream_t *s;
        sruct vlc_access_context *ctx;
    };
};

Doing so would require to change all access/stream/stream_filter/demux to use the new static const struct vlc_operations mechanism. Quite a heavy change.

This solution will respect the lifecycle of the access, contrary to the open_at solution. Indeed, one access context will always be used by only one client in parallel. We will only re-use a context when the parent access is closed.

Note: Choosing the 2/ or 3/ solution will require to modify the VLC preparser in order to be able to re-use the context.

What is your favorite solution? Do you have other solutions in mind?

Edited by Thomas Guillem

Merge request reports