Beispiel #1
0
 //BIN2
 protected internal abstract BinaryCacheEntity LoadBinaryCacheEntity(int nodeVersionId, int propertyTypeId, out FileStreamData fileStreamData);
Beispiel #2
0
        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);
        }