/// <summary> /// Find the data block for stream position 'position'. If it is already been fetched great! /// If not return a block that can be filled in (but has NOT been). You can tell because /// block.m_filled == false in that case. It is also possible that the block is being filled /// so you have to wait on it (outside the StreamCache lock), before returning it. /// </summary> private DataBlock FindBlockForPosition(long position) { // We assume the StreamCache lock is held! DataBlock block = m_blocks; DataBlock freeBlock = null; for (; ;) { if (block.m_position <= position && position < block.m_position + block.m_len) { return(block); } if (freeBlock == null && block.m_refCount == 0 && !block.m_beingFilled) { freeBlock = block; } if (block == m_blocks) { // TODO, if we have not hit our concurrency limit, and it looks like we are streaming, // add more workers, as the workers can't seem to keep up. if (freeBlock == null) { freeBlock = m_blocks.m_next = new DataBlock(m_blocks.m_data.Length, this, m_blocks.m_next); } Debug.Assert(!block.m_beingFilled && block.m_refCount == 0); block = freeBlock; block.Clear(position); break; } } return(block); }
/// <summary> /// This routine returns a block that we have determined is useful to prefetch. If we can't /// find a good block to prefetch, we return null. /// </summary> private DataBlock GetDataBlockToFetch() { // We assume the StreamCache lock is held! // Our heuristic is simple: Just read ahead from the block at m_block DataBlock block = m_blocks.m_next; long positionToPrefetch = m_blocks.m_position + m_blocks.m_len; long length = Length; for (; ;) { // If we have not already done the readahead if (block.m_position != positionToPrefetch) { if (positionToPrefetch >= length) // past end of stream { return(null); } // It is not in use one way or the other if (block.m_refCount == 0 && !block.m_beingFilled) { // Then go ahead and use it to prefetch. block.Clear(positionToPrefetch); return(block); } } else { positionToPrefetch = block.m_position + block.m_len; } if (block == m_blocks) { return(null); } } }