/// <summary> /// Tries to find a chunk in the chunk list which covers the given <paramref name="start"/> position. /// </summary> /// <param name="start">Start position.</param> /// <param name="addChunkIfNotExists">If set to <c>true</c>, the requested chunk will be added to the cache if it doesn't exist yet.</param> /// <param name="result">Returns the chunk or <c>null</c>, if no chunk was found for the given <paramref name="start"/> position. /// The returned chunk might not be filled yet.</param> /// <returns><c>true</c> if chunk was found.</returns> protected bool GetMatchingChunk(long start, bool addChunkIfNotExists, out HttpRangeChunk result) { if (start >= 0 && start < _length) { for (int i = _chunkCache.Count - 1; i >= 0; i--) { HttpRangeChunk chunk = _chunkCache[i]; if (chunk.StartIndex <= start && chunk.EndIndex > start) { // Reorder LRU cache _chunkCache.RemoveAt(i); if (chunk.IsErroneous) { // Retry if a chunk was erroneous break; } _chunkCache.Add(chunk); result = chunk; return(true); } } if (addChunkIfNotExists) { AddChunk(start, out result); return(true); } } result = null; return(false); }
public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException(); } if (offset + count > buffer.Length) { throw new ArgumentException(); } if (offset < 0 || count < 0) { throw new ArgumentOutOfRangeException(); } if (_chunkCache == null) { throw new ObjectDisposedException("CachedMultiSegmentHttpStream"); } if (_position >= _length) { return(0); } HttpRangeChunk chunk = ProvideReadAhead(_position, NUM_READAHEAD_CHUNKS); if (chunk == null) { throw new IOException(); } int numRead = chunk.Read(_position, buffer, offset, count); _position += numRead; return(numRead); }
/// <summary> /// Adds a new chunk to the cache and returns it. /// </summary> /// <param name="start">Start position.</param> /// <param name="chunk">Returns the cache.</param> /// <returns><c>true</c> if successful.</returns> private void AddChunk(long start, out HttpRangeChunk chunk) { if (_chunkCache.Count == MAX_NUM_CACHES) { // Remove chunk which hasn't been used the longest time _chunkCache[0].Dispose(); _chunkCache.RemoveAt(0); } _chunkCache.Add(chunk = new HttpRangeChunk(start, start + CHUNK_SIZE, Length, _url, _localIpAddress)); }
protected HttpRangeChunk ProvideReadAhead(long position, int numReadaheadChunks) { HttpRangeChunk result; if (!GetMatchingChunk(position, true, out result)) { return(null); } HttpRangeChunk currentChunk = result; for (int i = numReadaheadChunks - 1; i > 0; i--) { if (!GetMatchingChunk(currentChunk.EndIndex, true, out currentChunk)) { break; } } return(result); }
/// <summary> /// Adds a new chunk to the cache and returns it. /// </summary> /// <param name="start">Start position.</param> /// <param name="chunk">Returns the cache.</param> /// <returns><c>true</c> if successful.</returns> private void AddChunk(long start, out HttpRangeChunk chunk) { if (_chunkCache.Count == MAX_NUM_CACHES) { // Remove chunk which hasn't been used the longest time _chunkCache[0].Dispose(); _chunkCache.RemoveAt(0); } _chunkCache.Add(chunk = new HttpRangeChunk(start, start + CHUNK_SIZE, Length, _url, _localIpAddress)); }
/// <summary> /// Tries to find a chunk in the chunk list which covers the given <paramref name="start"/> position. /// </summary> /// <param name="start">Start position.</param> /// <param name="addChunkIfNotExists">If set to <c>true</c>, the requested chunk will be added to the cache if it doesn't exist yet.</param> /// <param name="result">Returns the chunk or <c>null</c>, if no chunk was found for the given <paramref name="start"/> position. /// The returned chunk might not be filled yet.</param> /// <returns><c>true</c> if chunk was found.</returns> protected bool GetMatchingChunk(long start, bool addChunkIfNotExists, out HttpRangeChunk result) { if (start >= 0 && start < _length) { for (int i = _chunkCache.Count - 1; i >= 0; i--) { HttpRangeChunk chunk = _chunkCache[i]; if (chunk.StartIndex <= start && chunk.EndIndex > start) { // Reorder LRU cache _chunkCache.RemoveAt(i); if (chunk.IsErroneous) // Retry if a chunk was erroneous break; _chunkCache.Add(chunk); result = chunk; return true; } } if (addChunkIfNotExists) { AddChunk(start, out result); return true; } } result = null; return false; }