Beispiel #1
0
        private void ReadCompletedCore(BufferedRead bufferedRead, byte[] data)
        {
            bufferedRead.Complete(data);

            lock (_readLock)
            {
                // add item to queue
                _queue.Add(bufferedRead.ChunkIndex, bufferedRead);
                // signal that a chunk has been read or EOF has been reached;
                // in both cases, Read() will eventually also unblock the "read-ahead" thread
                Monitor.PulseAll(_readLock);
            }

            // check if server signaled EOF
            if (data.Length == 0)
            {
                // set a flag to stop read-aheads
                _endOfFileReceived = true;
            }
        }
Beispiel #2
0
        private void StartReadAhead()
        {
            ThreadAbstraction.ExecuteThread(() =>
            {
                while (!_endOfFileReceived && _exception == null)
                {
                    // check if we should continue with the read-ahead loop
                    // note that the EOF and exception check are not included
                    // in this check as they do not require Read() to be
                    // unblocked (or have already done this)
                    if (!ContinueReadAhead())
                    {
                        // unblock the Read()
                        lock (_readLock)
                        {
                            Monitor.PulseAll(_readLock);
                        }
                        // break the read-ahead loop
                        break;
                    }

                    // attempt to obtain the semaphore; this may time out when all semaphores are
                    // in use due to pending read-aheads (which in turn can happen when the server
                    // is slow to respond or when the session is broken)
                    if (!_semaphore.Wait(ReadAheadWaitTimeoutInMilliseconds))
                    {
                        // re-evaluate whether an exception occurred, and - if not - wait again
                        continue;
                    }

                    // don't bother reading any more chunks if we received EOF, an exception has occurred
                    // or the current instance is disposed
                    if (_endOfFileReceived || _exception != null)
                    {
                        break;
                    }

                    // start reading next chunk
                    var bufferedRead = new BufferedRead(_readAheadChunkIndex, _readAheadOffset);

                    try
                    {
                        // even if we know the size of the file and have read up to EOF, we still want
                        // to keep reading (ahead) until we receive zero bytes from the remote host as
                        // we do not want to rely purely on the reported file size
                        //
                        // if the offset of the read-ahead chunk is greater than that file size, then
                        // we can expect to be reading the last (zero-byte) chunk and switch to synchronous
                        // mode to avoid having multiple read-aheads that read beyond EOF
                        if (_fileSize != null && (long)_readAheadOffset > _fileSize.Value)
                        {
                            var asyncResult = _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, null,
                                                                     bufferedRead);
                            var data = _sftpSession.EndRead(asyncResult);
                            ReadCompletedCore(bufferedRead, data);
                        }
                        else
                        {
                            _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, ReadCompleted, bufferedRead);
                        }
                    }
                    catch (Exception ex)
                    {
                        HandleFailure(ex);
                        break;
                    }

                    // advance read-ahead offset
                    _readAheadOffset += _chunkSize;
                    // increment index of read-ahead chunk
                    _readAheadChunkIndex++;
                }

                _readAheadCompleted.Set();
            });
        }