-
Notifications
You must be signed in to change notification settings - Fork 490
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
Support multiple connections #132
Conversation
The -o max_conns=N option causes multiple SSH processes and response processing threads to be created. Each file handle is locked to the connection which was used for opening it. One-off requests can use any connection. The connection is chosen by checking the per-connection statistics: 1. Choose connection with least outstanding requests; if it's a tie, 2. choose connection with least directory handles; if it's a tie, 3. choose connection with least file handles; if it's a tie, 4. choose connection which has already been established. The implementation assumes that the max_conns values will be small; it uses linear search. The primary purpose of this feature is to improve the responsiveness of a file system during large file transfers. It also helps in scenarios where the bandwidth of a single connection is limited, but multiple connections are allowed, and the aggregate bandwidth limit is larger.
@tsavola Did you have a chance too look at this? I'd really like to merge the feature. |
I quickly looked at it. It seems that sshfs just dies in the test which builds using undefined behavior sanitizer. I couldn't replicate it on my workstation. No idea how to proceed. |
I think you're looking at a different issue - for me it does not die and does not depend on using the sanitizer:
and on a different console:
...and sshfs is still running happily:
Does this really work for you? |
friendly ping. Do you think you'll have time to look at this at some point? |
Would absolutely love to see this merged. This is a big pain point for me whenever I use sshfs. We could then use file transfer programs that use multithreading in order to make use of multiple parallel connections, thereby increasing total transfer speed. This latter point is especially a problem when using sshfs over internet. |
I'll try to look at this this week. |
That was one long week. I'm sorry about that. I have identified the problem. The implementation is supposed to use the same connection for all operations on the same file handle, but the write and fstat calls get executed on different connections. It works if the write is synchronous, but it's asynchronous by default. The reason why the operations use different connections is that FUSE calls sshfs_getattrs with NULL file info. libfuse's documentation for getattr says "fi will always be NULL if the file is not currently open, but may also be NULL if the file is open." When looking at tst_truncate_fd's debug output, getattr's file info is non-NULL in at least one call, but it's NULL in most calls. I got the truncation tests working by creating a hash table which maps paths to sshfs_files, but the tst_open_unlink fails if I don't also track unlinks and renames. That's doable, but soon gets complicated. It also doesn't solve the problem of choosing the correct file handle if there are several open with the same path. My quick-and-dirty hack is at https://github.com/tsavola/sshfs/tree/parallel_conns-on-3.5.0. I have to give it some more though, but currently I don't see a solution other than forcing |
Thanks for looking into this! That sounds like a tricky problem indeed. Having FUSE always provide a filehandle would be a very nice solution, but unfortunately exactly that was discussed on the kernel mailing list a few months ago and met strong opposition. As I understand, it would require major changes in the kernel. If you can't find a good solution, there's also the option of simply documenting this behavior prominently. As long as we understand what's happening and why, having mtime's lag a little even after a write has completed is no worse than eg. the lack of hardlink support or rename() not being able to overwrite the destination. |
The tests fail because st_size is incorrect because the write hasn't happened yet. I think that's a more subtle breaking of a file descriptor's invariant, than the unsupported features you mention. |
I wonder if it's possible to get the id of the thread (or something resembling that) which requests the FUSE operation? |
Would that help? I think you'd just make the problem a little more difficult to discover, because it would appear when write() and getattr() get called from different threads. |
Could you possibly force the same connection for each inode (rather than file handle)? |
I suppose so. It probably wouldn't hurt real-world performance either. (How often do you do parallel transfers targetting the same file?) |
Any update? |
382bb0f
to
d299217
Compare
I am working on this now, based on the pull request. |
(This is a re-submit of PR #103 which was merged but then rolled back after tests failed)
Original description:
The -o max_conns=N option causes multiple SSH processes and response
processing threads to be created. Each file handle is locked to the
connection which was used for opening it. One-off requests can use any
connection.
The connection is chosen by checking the per-connection statistics:
The implementation assumes that the max_conns values will be small; it
uses linear search.
The primary purpose of this feature is to improve the responsiveness of a
file system during large file transfers. It also helps in scenarios
where the bandwidth of a single connection is limited, but multiple
connections are allowed, and the aggregate bandwidth limit is larger.
https://sourceforge.net/p/fuse/mailman/message/36076333/