//BIN2 protected internal abstract BinaryCacheEntity LoadBinaryCacheEntity(int nodeVersionId, int propertyTypeId, out FileStreamData fileStreamData);
public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset + count > buffer.Length) { throw new ArgumentException("Offset + count must not be greater than the buffer length."); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset), "The offset must be greater than zero."); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), "The count must be greater than zero."); } // Calculate the maximum count of the bytes that can be read. // Return immediately if nothing to read. var maximumReadableByteCount = Length - Position; if (maximumReadableByteCount < 1) { return(0); } var isLocalTransaction = false; var realCount = (int)Math.Min(count, maximumReadableByteCount); if (CanInnerBufferHandleReadRequest(realCount)) { Array.Copy(_innerBuffer, Position - _innerBufferFirstPostion, buffer, offset, realCount); } else { if (!TransactionScope.IsActive) { // make sure we do not use an obsolete value FileStreamData = null; // Start a new transaction here to serve the needs of the SqlFileStream type. TransactionScope.Begin(); isLocalTransaction = true; } try { // Load transaction data for SqlFilestream. If this is not a local transaction, // than we will be able to use this data in the future if the client calls // the Read method multiple times and will not have to execute SQL queries // every time. var ctx = BlobStorageBase.GetBlobStorageContext(this.FileId); if (ctx != null) { if (ctx.Provider == BlobStorageBase.BuiltInProvider) { FileStreamData = ((SqlClient.BuiltinBlobProviderData)ctx.BlobProviderData).FileStreamData; } } if (FileStreamData == null) { throw new InvalidOperationException("Transaction data and file path could not be retrieved for SqlFilestream"); } using (var fs = new SqlFileStream(FileStreamData.Path, FileStreamData.TransactionContext, FileAccess.Read, FileOptions.SequentialScan, 0)) { fs.Seek(Position, SeekOrigin.Begin); _innerBuffer = null; var bytesRead = 0; var bytesStoredInInnerBuffer = 0; while (bytesRead < realCount) { var bytesToReadInThisIteration = (int)Math.Min(this.Length - Position - bytesRead, BlobStorage.BinaryChunkSize); var bytesToStoreInThisIteration = Math.Min(bytesToReadInThisIteration, realCount - bytesRead); var tempBuffer = new byte[bytesToReadInThisIteration]; // copy the bytes from the file stream to the temp buffer // (it is possible that we loaded a lot more bytes than the client requested) fs.Read(tempBuffer, 0, bytesToReadInThisIteration); // first iteration: create inner buffer for caching a part of the stream in memory if (_innerBuffer == null) { _innerBuffer = new byte[GetInnerBufferSize(realCount)]; _innerBufferFirstPostion = Position; } // store a fragment of the data in the inner buffer if possible if (bytesStoredInInnerBuffer < _innerBuffer.Length) { var bytesToStoreInInnerBuffer = Math.Min(bytesToReadInThisIteration, _innerBuffer.Length - bytesStoredInInnerBuffer); Array.Copy(tempBuffer, 0, _innerBuffer, bytesStoredInInnerBuffer, bytesToStoreInInnerBuffer); bytesStoredInInnerBuffer += bytesToStoreInInnerBuffer; } // copy the chunk from the temp buffer to the buffer of the caller Array.Copy(tempBuffer, 0, buffer, bytesRead, bytesToStoreInThisIteration); bytesRead += bytesToReadInThisIteration; } } } catch { // ReSharper disable once InvertIf if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); // cleanup isLocalTransaction = false; FileStreamData = null; } throw; } finally { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Commit(); // Set filestream data to null as this was a local transaction and we cannot use it anymore FileStreamData = null; } } } Position += realCount; return(realCount); }