WIP Faster SFTP with libssh2 (Bug #14038)
#16
I've already been looking at your code, and something seems strange to me. It's about how you created a new bufferqueue to save a stack of sftp requests that you execute asynchronously. It seems like this means you are still using a separate buffer/cache in order to receive those requests (i also saw some memcpy and memmove stuff, not sure if that was related), but according to Memphiz a separate cache would not be accepted in xbmc. So if it would not be accepted, it doesn't seem like it would be a good solution. I could also be wrong about this, because i can't quite follow all of it.

As for the actual implementation of asynchronous read in xbmc, wouldn't it be possible to only change the CSFTPSession::Read() and CSFTPFile::Read method (based on the current code in xbmc master)? You would have to do the sftp_async_read_begin and a check for ssh_again, ssh_error and eof in CSFTPFile::Read() and the actual sftp_async_read in CSFTPSession::Read(). The queuing would be handled by CFileCache which is used whenever buffering in XBMC is enabled. It would keep asking for chunks to read until reaching the required XBMC buffer size. It also waits till each chunk is read before processing it. This seems like the easiest and most consistent way to enable asynchronous reads in XBMC. Of course, i'm assuming that the way CFileCache works is compatible with the way sftp does asynchronous reads and i'm assuming that the asynchronous reads would also still work without a buffer (albeit with stuttering in the video/audio when the bandwidth drops, which is to be expected when you don't have a buffer).

I couldn't quite work out if the above would actually be enough to make it work. Perhaps you've already tried it, then you could tell me what happened and why it didn't work. If not, I'd be glad to hear it too, then i might give it a try. I would also love for this to make it into the next xbmc/kodi release.
Reply
#17
Maybe I should add that this is the first thing I've coded for XBMC. I don't realy know about the functions of the CFileCache, the way you describe it it seems like I'm doing double work. If the Cache requests data until it is full it should be fine. sftp_async_read blocks if the data is not yet available, so it should also work if caching is disabled.

It's quite some time since I developed the code, but there were some issues about the sftp_async_read function, which caused strange behavior (as far as I understand the documentation of libssh: bugs), if used async read on multiple files over a single connection. That's why I open that additional connections and changed the SessionManager.

I'll be on vacation for approx. 3 weeks and will look into that afterwards. If you get a simple solution by just changing the two read methods it would be great. I'll have to take a deeper look in the differences of the File::Read() and the Session::Read(), i'll do that than I'm back
Reply
#18
I'll try it out and let you know how it goes then. That minor bugfix i mentioned earlier was also the first thing i submitted to XBMC, so I don't know that much about the codebase either. But i guess we'll just have to find out then.
Reply
#19
Unfortunately, it doesn't seem like this will be that easy to implement

From what I can tell, the actual caching of data is done in CFileCache:Tonguerocess() where the Read() call is executed, then checked how much data was read and that data is immediately written to the buffer. So it seems like CFileCache itself doesn't really support async reads since it expects the read to have returned its data immediately.

Since this seemed to contradict the performance that you get with regular FTP, I checked the CCurlFile implementation and it seems like they are using their own separate cache (CRingBuffer). Whenever a Read() call is received, they read the requested amount from their own buffer. So it seems like a separate cache is acceptable in XBMC after all.

So your implementation might not have been that far off. I'll try to look at it again. I'd like to note that although CRingBuffer (from xbmc/utils/RingBuffer.cpp) is used in CCurlFile, this is a circular cache object which has also been implemented in CCircularCache (from xbmc/filesystems/CircularCache.cpp). The latter of these as the default buffer for XBMC, so the other might be a duplicate of the same functionality. Maybe you can use this CircularCache instead of creating your own BufferQueue?

Anyway, I thought you might like to know about these findings.
Reply
#20
I've worked on this a bit more now, and I've managed to change CFileCache in such a way that it should allow asynchronous reads but still works with blocking reads. I've also changed SFTPFile to allow for asynchronous reads, but it seems like whenever I use the async read methods from libssh, the file no longer plays correctly in XBMC. If I leave everything as is, but change the libssh read method to the standard blocking read method, it works correctly again. Perhaps someone who knows a bit more about libssh can take a look at this. I'm also pretty new to C++ so I might've made some mistakes there.

If the problems are really caused by libssh, it might be another reason to try to switch to libssh2. From what I've read about it, it seems like libssh2 allows all of their methods to work asynchronously, instead of just the read method for libssh. This meant that I had to use 2 sessions for every file, one blocking and one async. I'd like to try if it works better with libssh2 but I don't really know how to change that. If anyone can let me know, I can see if it's easier to make it work with libssh2 (assuming there's no easy/known fix to make it work with libssh).

The code is available at https://github.com/arucard21/xbmc/tree/i...erformance
Reply
#21
Is there still anybody working on this issue?

I have this problem on my firetv stick. My whole library is added by sftp. But when I want to watch movies with higher resolution I have to switch to HTTP as protocol.

The GUI is telling me it needs to "buffer" so I guess the limitation comes from the network.
On the other hand sftp is capable of the required speeds, as my laptop has no problem at all.

Thank you in advance and sorry for bumping such an old thread.
Reply
#22
I've worked on this a bit more since my last post and I think it should even be possible with libssh. I would need a different approach than I previously tried because I was getting all kinds of strange problems, but I haven't really been working on this lately. I'll try to look into this again soon.
Reply
#23
Oh wow - sounds great. Your work is highly appreciated.
If there is a way to make it working with libssh there might be a higher chance by the devs to accept it.

Good luck Smile
Reply
#24
Hi guys

I'm here exactly for this reason.
I setup perfectly my server and everything for kodi but I didn't see before the lack of performance in sftp mode with Kodi. it's horrible.
I can't read more than 5 min without a problem of buffer.
So is there a way to avoid this ? Smile. I don't want use if possible an other way like https etc. If I can stay with sftp. It's perfect for me

Thank you in advance
Reply

Logout Mark Read Team Forum Stats Members Help
Faster SFTP with libssh2 (Bug #14038)1