/// <summary>
        /// Gets the serialized form of <paramref name="contentHash"/> but returns a handled to a pooled byte array instead of allocating a new one.
        /// </summary>
        public static ByteArrayPool.PoolHandle ToPooledByteArray(this in ShortHash contentHash)
        {
            var handle = ShortHashBytesArrayPool.Get();

            contentHash.Serialize(handle.Value);
            return(handle);
        }
Example #2
0
 internal PoolingPayloadTokenStream(TestPayloads enclosingInstance, ByteArrayPool pool)
 {
     InitBlock(enclosingInstance);
     this.pool = pool;
     payload   = pool.Get();
     Enclosing_Instance.GenerateRandomData(payload);
     term       = pool.BytesToString(payload);
     first      = true;
     payloadAtt = AddAttribute <IPayloadAttribute>();
     termAtt    = AddAttribute <ITermAttribute>();
 }
Example #3
0
 internal PoolingPayloadTokenStream(TestPayloads outerInstance, ByteArrayPool pool)
 {
     this.outerInstance = outerInstance;
     this.pool          = pool;
     payload            = pool.Get();
     this.outerInstance.GenerateRandomData(payload);
     term       = Encoding.UTF8.GetString(payload);
     first      = true;
     payloadAtt = AddAttribute <IPayloadAttribute>();
     termAtt    = AddAttribute <ICharTermAttribute>();
 }
Example #4
0
 internal PoolingPayloadTokenStream(TestPayloads outerInstance, ByteArrayPool pool)
 {
     this.OuterInstance = outerInstance;
     this.Pool          = pool;
     Payload            = pool.Get();
     OuterInstance.GenerateRandomData(Payload);
     Term       = Encoding.UTF8.GetString((byte[])(Array)Payload);
     First      = true;
     PayloadAtt = AddAttribute <IPayloadAttribute>();
     TermAtt    = AddAttribute <ICharTermAttribute>();
 }
Example #5
0
        public async Task <PushFileResult> PushFileAsync(OperationContext context, ContentHash hash, Stream stream, CopyOptions options)
        {
            using var cts = CancellationTokenSource.CreateLinkedTokenSource(context.Token);
            var            token              = cts.Token;
            bool           exceptionThrown    = false;
            TimeSpan?      headerResponseTime = null;
            PushFileResult?result             = null;

            try
            {
                var startingPosition = stream.Position;

                var pushRequest = new PushRequest(hash, traceId: context.TracingContext.Id);
                var headers     = pushRequest.GetMetadata();

                using var call = _client.PushFile(options: GetDefaultGrpcOptions(headers, token));
                var      requestStream = call.RequestStream;
                Metadata responseHeaders;

                var stopwatch = StopwatchSlim.Start();
                try
                {
                    var timeout = GetResponseHeadersTimeout(options);
                    responseHeaders = await call.ResponseHeadersAsync.WithTimeoutAsync(timeout, token);

                    headerResponseTime = stopwatch.Elapsed;
                }
                catch (TimeoutException t)
                {
                    cts.Cancel();
                    result = new PushFileResult(GetCopyResultCodeForGetResponseHeaderTimeout(), t);
                    return(result);
                }

                // If the remote machine couldn't be contacted, GRPC returns an empty
                // header collection. To avoid an exception, exit early instead.
                if (responseHeaders.Count == 0)
                {
                    result = PushFileResult.ServerUnavailable();
                    return(result);
                }

                var pushResponse = PushResponse.FromMetadata(responseHeaders);
                if (!pushResponse.ShouldCopy)
                {
                    result = PushFileResult.Rejected(pushResponse.Rejection);
                    return(result);
                }

                // If we get a response before we finish streaming, it must be that the server cancelled the operation.
                var responseStream   = call.ResponseStream;
                var responseMoveNext = responseStream.MoveNext(token);

                var responseCompletedTask = responseMoveNext.ContinueWith(
                    t =>
                {
                    // It is possible that the next operation in this method will fail
                    // causing stack unwinding that will dispose serverIsDoneSource.
                    //
                    // Then when responseMoveNext is done serverIsDoneSource is already disposed and
                    // serverIsDoneSource.Cancel will throw ObjectDisposedException.
                    // This exception is not observed because the stack could've been unwound before
                    // the result of this method is awaited.
                    IgnoreObjectDisposedException(() => cts.Cancel());
                });

                result = await _bandwidthChecker.CheckBandwidthAtIntervalAsync(
                    context,
                    innerToken => pushFileImplementation(stream, options, startingPosition, requestStream, responseStream, responseMoveNext, responseCompletedTask, innerToken),
                    options,
                    getErrorResult : diagnostics => PushFileResult.BandwidthTimeout(diagnostics));

                return(result);
            }
            catch (RpcException r)
            {
                result = new PushFileResult(r);
                return(result);
            }
            catch (Exception)
            {
                exceptionThrown = true;
                throw;
            }
            finally
            {
                // Even though we don't expect exceptions in this method, we can't assume they won't happen.
                // So asserting that the result is not null only when the method completes successfully or with a known errors.
                Contract.Assert(exceptionThrown || result != null);
                if (result != null)
                {
                    result.HeaderResponseTime = headerResponseTime;
                }
            }

            async Task <PushFileResult> pushFileImplementation(Stream stream, CopyOptions options, long startingPosition, IClientStreamWriter <PushFileRequest> requestStream, IAsyncStreamReader <PushFileResponse> responseStream, Task <bool> responseMoveNext, Task responseCompletedTask, CancellationToken token)
            {
                using (var primaryBufferHandle = _pool.Get())
                    using (var secondaryBufferHandle = _pool.Get())
                    {
                        await StreamContentAsync(stream, primaryBufferHandle.Value, secondaryBufferHandle.Value, requestStream, options, token);
                    }

                token.ThrowIfCancellationRequested();

                await requestStream.CompleteAsync();

                await responseCompletedTask;

                // Make sure that we only attempt to read response when it is available.
                var responseIsAvailable = await responseMoveNext;

                if (!responseIsAvailable)
                {
                    return(new PushFileResult("Failed to get final response."));
                }

                var response = responseStream.Current;

                var size = stream.Position - startingPosition;

                return(response.Header.Succeeded
                    ? PushFileResult.PushSucceeded(size)
                    : new PushFileResult(response.Header.ErrorMessage));
            }
        }
Example #6
0
			internal PoolingPayloadTokenStream(TestPayloads enclosingInstance, ByteArrayPool pool)
			{
				InitBlock(enclosingInstance);
				this.pool = pool;
				payload = pool.Get();
				Enclosing_Instance.GenerateRandomData(payload);
				term = pool.BytesToString(payload);
				first = true;
				payloadAtt = (PayloadAttribute) AddAttribute(typeof(PayloadAttribute));
				termAtt = (TermAttribute) AddAttribute(typeof(TermAttribute));
			}
Example #7
0
        private async Task CopyFileAsync(CopyFileRequest request, IServerStreamWriter <CopyFileResponse> responseStream, ServerCallContext context)
        {
            // Get the content stream.
            Context          cacheContext = new Context(new Guid(request.TraceId), Logger);
            ContentHash      hash         = request.GetContentHash();
            long             size         = -1;
            OpenStreamResult result       = await GetFileStreamAsync(cacheContext, hash);

            // If result is unsuccessful, then result.Stream is null, but using(null) is just a no op.
            using (result.Stream)
            {
                // Figure out response headers.
                CopyCompression compression = CopyCompression.None;
                Metadata        headers     = new Metadata();
                switch (result.Code)
                {
                case OpenStreamResult.ResultCode.ContentNotFound:
                    headers.Add("Exception", "ContentNotFound");
                    headers.Add("Message", $"Requested content at {hash} not found.");
                    break;

                case OpenStreamResult.ResultCode.Error:
                    Contract.AssertNotNull(result.Exception);
                    headers.Add("Exception", result.Exception.GetType().Name);
                    headers.Add("Message", result.Exception.Message);
                    break;

                case OpenStreamResult.ResultCode.Success:
                    Contract.AssertNotNull(result.Stream);
                    size = result.Stream.Length;
                    headers.Add("FileSize", size.ToString());
                    if ((request.Compression == CopyCompression.Gzip) && (size > _gzipSizeBarrier))
                    {
                        compression = CopyCompression.Gzip;
                    }
                    headers.Add("Compression", compression.ToString());
                    headers.Add("ChunkSize", _bufferSize.ToString());
                    break;

                default:
                    throw new NotImplementedException($"Unknown result.Code '{result.Code}'.");
                }

                // Send the response headers.
                await context.WriteResponseHeadersAsync(headers);

                // Send the content.
                if (result.Succeeded)
                {
                    // Need to cancel the operation when the instance is shut down.
                    using var shutdownTracker = TrackShutdown(cacheContext, context.CancellationToken);
                    var operationContext = shutdownTracker.Context;

                    using var arrayHandle          = _pool.Get();
                    using var arraySecondaryHandle = _pool.Get();
                    StreamContentDelegate streamContent = compression == CopyCompression.None ? (StreamContentDelegate)StreamContentAsync : StreamContentWithCompressionAsync;

                    byte[] buffer          = arrayHandle.Value;
                    byte[] secondaryBuffer = arraySecondaryHandle.Value;
                    await operationContext.PerformOperationAsync(
                        _tracer,
                        () => streamContent(result.Stream !, buffer, secondaryBuffer, responseStream, operationContext.Token),
                        traceOperationStarted : false, // Tracing only stop messages
                        extraEndMessage : r => $"Hash={hash.ToShortString()}, GZip={(compression == CopyCompression.Gzip ? "on" : "off")}, Size=[{size}], Sender=[{context.Host}].")
                    .IgnoreFailure();                  // The error was already logged.
                }
            }
        }
			internal PoolingPayloadTokenStream(ByteArrayPool pool)
			{
				this.pool = pool;
				payload = pool.Get();
				Lucene.Net.Index.TestPayloads.GenerateRandomData(payload);
				first = true;
			}
Example #9
0
 internal PoolingPayloadTokenStream(TestPayloads outerInstance, ByteArrayPool pool)
 {
     this.OuterInstance = outerInstance;
     this.Pool = pool;
     Payload = pool.Get();
     OuterInstance.GenerateRandomData(Payload);
     Term = Encoding.UTF8.GetString((byte[])(Array)Payload);
     First = true;
     PayloadAtt = AddAttribute<IPayloadAttribute>();
     TermAtt = AddAttribute<ICharTermAttribute>();
 }