/// <inheritdoc /> public async Task <PinResult> PinAsync(Context context, ContentHash contentHash) { StructResult <int> sessionResult = await _sessionState.GetIdAsync(); if (!sessionResult.Succeeded) { return(new PinResult(sessionResult)); } int sessionId = sessionResult.Data; DateTime startTime = DateTime.UtcNow; PinResponse response = await RunClientActionAndThrowIfFailedAsync( context, async() => await _client.PinAsync( new PinRequest { HashType = (int)contentHash.HashType, ContentHash = contentHash.ToByteString(), Header = new RequestHeader(context.Id, sessionId) })); long ticksWaited = response.Header.ServerReceiptTimeUtcTicks - startTime.Ticks; _tracer.TrackClientWaitForServerTicks(ticksWaited); await ResetOnUnknownSessionAsync(context, response.Header, sessionId); return(UnpackPinResult(response.Header)); }
private async Task SendHeartbeatAsync(Context context) { StructResult <int> sessionResult = await _sessionState.GetIdAsync(); if (!sessionResult.Succeeded) { // We do not even attempt to send a heartbeat if we can't get a session ID. return; } int sessionId = sessionResult.Data; try { HeartbeatResponse response = await _client.HeartbeatAsync(new HeartbeatRequest { Header = new RequestHeader(context.Id, sessionId) }); // Check for null header here as a workaround to a known service bug, which returns null headers on successful heartbeats. if (response?.Header != null && !response.Header.Succeeded) { _tracer.Warning( context, $"Heartbeat failed: ErrorMessage=[{response.Header.ErrorMessage}] Diagnostics=[{response.Header.Diagnostics}]"); // Nor do we attempt to reset a session ID based on a failed heartbeat. } } catch (Exception ex) { string message = (ex is RpcException rpcEx) && (rpcEx.Status.StatusCode == StatusCode.Unavailable) ? "Heartbeat failed to detect running service." : $"Heartbeat failed: [{ex}]"; _tracer.Debug(context, message); } }
public void RemoveFromTrackerStop(Context context, StructResult <long> result) { if (context.IsEnabled) { TracerOperationFinished(context, result, $"{Name}.{_removeFromTrackerName} stop {result.DurationMs}ms result=[{result}]"); } _removeFromTrackerCallCounter.Completed(result.Duration.Ticks); }
/// <inheritdoc /> public async Task <BoolResult> ShutdownAsync(Context context) { ShutdownStarted = true; try { _heartbeatTimer?.Dispose(); if (_sessionState == null) { // _sessionState is null if initialization has failed. return(BoolResult.Success); } StructResult <int> sessionResult = await _sessionState.GetIdAsync(); if (!sessionResult.Succeeded) { return(new BoolResult(sessionResult)); } int sessionId = sessionResult.Data; if (_serviceUnavailable) { context.Debug("Skipping session shutdown because service is unavailable."); } else { try { await _client.ShutdownSessionAsync(new ShutdownRequest { Header = new RequestHeader(context.Id, sessionId) }); } catch (RpcException e) { context.Error($"Failed to shut down session with error: {e}"); } } await _channel.ShutdownAsync(); ShutdownCompleted = true; return(BoolResult.Success); } catch (Exception ex) { // Catching all exceptions, even ClientCanRetryExceptions, because the teardown steps aren't idempotent. // In the worst case, the shutdown call comes while the service is offline, the service never receives it, // and then the service times out the session 10 minutes later (by default). ShutdownCompleted = true; return(new BoolResult(ex)); } }
/// <summary> /// Remove local location from the content tracker. /// </summary> public async Task <StructResult <long> > RemoveFromTrackerAsync(Context context) { if (_enableRepairHandling && InnerContentStore is ILocalContentStore localStore) { var result = await _contentLocationStore.InvalidateLocalMachineAsync(context, localStore, CancellationToken.None); if (!result) { return(new StructResult <long>(result)); } } // New logic doesn't have the content removed count return(StructResult.Create((long)0)); }
private async Task <ObjectResult <ContentHashListWithCacheMetadata> > UnpackBlobContentHashListAsync(Context context, BlobContentHashListWithCacheMetadata blobCacheMetadata) { Contract.Assert(blobCacheMetadata != null); if (blobCacheMetadata.ContentHashListWithDeterminism.BlobIdentifier == null) { return(new ObjectResult <ContentHashListWithCacheMetadata>( new ContentHashListWithCacheMetadata( new ContentHashListWithDeterminism(null, blobCacheMetadata.Determinism), blobCacheMetadata.GetRawExpirationTimeUtc(), blobCacheMetadata.ContentGuarantee, blobCacheMetadata.HashOfExistingContentHashList))); } BlobIdentifier blobId = blobCacheMetadata.ContentHashListWithDeterminism.BlobIdentifier; Func <ContentHash, CancellationToken, Task <ObjectResult <Stream> > > openStreamFunc = async(hash, cts) => { OpenStreamResult openStreamResult = await _blobContentSession.OpenStreamAsync(context, hash, cts); if (openStreamResult.Succeeded) { return(new ObjectResult <Stream>(openStreamResult.Stream)); } return(new ObjectResult <Stream>(openStreamResult)); }; StructResult <ContentHashListWithDeterminism> contentHashListResult = await BlobContentHashListExtensions.UnpackFromBlob( openStreamFunc, blobId); if (contentHashListResult.Succeeded) { var contentHashListWithCacheMetadata = new ContentHashListWithCacheMetadata( contentHashListResult.Data, blobCacheMetadata.GetRawExpirationTimeUtc(), blobCacheMetadata.ContentGuarantee, blobCacheMetadata.HashOfExistingContentHashList); return(new ObjectResult <ContentHashListWithCacheMetadata>(contentHashListWithCacheMetadata)); } else { return(new ObjectResult <ContentHashListWithCacheMetadata>(contentHashListResult)); } }
/// <inheritdoc /> public async Task <PutResult> PutFileAsync( Context context, HashType hashType, AbsolutePath path, FileRealizationMode realizationMode) { StructResult <int> sessionResult = await _sessionState.GetIdAsync(); if (!sessionResult.Succeeded) { return(new PutResult(sessionResult, new ContentHash(hashType))); } int sessionId = sessionResult.Data; return(await PutFileAsync(context, hashType, path, realizationMode, sessionId)); }
private async Task <IEnumerable <Task <Indexed <PinResult> > > > PinBatchAsync(Context context, int baseIndex, IReadOnlyList <ContentHash> chunk) { StructResult <int> sessionResult = await _sessionState.GetIdAsync(); if (!sessionResult.Succeeded) { PinResult pinResult = new PinResult(sessionResult); return(chunk.Select((ContentHash h) => pinResult).AsIndexed().AsTasks()); } int sessionId = sessionResult.Data; var pinResults = new List <Indexed <PinResult> >(); var bulkPinRequest = new PinBulkRequest { Header = new RequestHeader(context.Id, sessionId) }; foreach (var contentHash in chunk) { bulkPinRequest.Hashes.Add( new ContentHashAndHashTypeData { HashType = (int)contentHash.HashType, ContentHash = contentHash.ToByteString() }); } DateTime startTime = DateTime.UtcNow; PinBulkResponse underlyingBulkPinResponse = await RunClientActionAndThrowIfFailedAsync( context, async() => await _client.PinBulkAsync(bulkPinRequest)); long ticksWaited = underlyingBulkPinResponse.Header.Values.First().ServerReceiptTimeUtcTicks - startTime.Ticks; _tracer.TrackClientWaitForServerTicks(ticksWaited); foreach (var response in underlyingBulkPinResponse.Header) { await ResetOnUnknownSessionAsync(context, response.Value, sessionId); pinResults.Add(UnpackPinResult(response.Value).WithIndex(response.Key + baseIndex)); } _tracer.LogPinResults(context, pinResults.Select(r => chunk[r.Index - baseIndex]).ToList(), pinResults.Select(r => r.Item).ToList()); return(pinResults.AsTasks()); }
/// <inheritdoc /> public IAsyncEnumerable <StructResult <StrongFingerprint> > EnumerateStrongFingerprints(Context context) { context.Debug($"{nameof(SQLiteMemoizationStore)}.{nameof(EnumerateStrongFingerprints)}({context.Id})"); return(AsyncEnumerable.CreateEnumerable( () => { const long pageLimit = 100; long offset = 0; IEnumerator <StrongFingerprint> strongFingerprints = null; StructResult <StrongFingerprint> error = null; return AsyncEnumerable.CreateEnumerator( async cancellationToken => { try { if (error != null) { return false; } if (strongFingerprints == null || !strongFingerprints.MoveNext()) { // ReSharper disable once GenericEnumeratorNotDisposed strongFingerprints = (await EnumerateStrongFingerprintsAsync(pageLimit, offset)).GetEnumerator(); if (!strongFingerprints.MoveNext()) { return false; } } offset++; return true; } catch (Exception e) { error = new StructResult <StrongFingerprint>(e); return true; } }, () => error ?? new StructResult <StrongFingerprint>(strongFingerprints.Current), () => { strongFingerprints?.Dispose(); }); })); }
/// <inheritdoc /> public async Task <PlaceFileResult> PlaceFileAsync( Context context, ContentHash contentHash, AbsolutePath path, FileAccessMode accessMode, FileReplacementMode replacementMode, FileRealizationMode realizationMode) { StructResult <int> sessionResult = await _sessionState.GetIdAsync(); if (!sessionResult.Succeeded) { return(new PlaceFileResult(sessionResult)); } int sessionId = sessionResult.Data; return(await PlaceFileAsync(context, contentHash, path, accessMode, replacementMode, realizationMode, sessionId)); }
/// <inheritdoc /> public async Task <ObjectResult <ContentHashListWithCacheMetadata> > AddContentHashListAsync( Context context, string cacheNamespace, StrongFingerprint strongFingerprint, ContentHashListWithCacheMetadata valueToAdd) { try { Func <System.IO.Stream, System.Threading.CancellationToken, Task <StructResult <ContentHash> > > putStreamFunc = async(stream, cts) => { PutResult putResult = await _blobContentSession.PutStreamAsync(context, HashType.Vso0, stream, cts); if (putResult.Succeeded) { return(new StructResult <ContentHash>(putResult.ContentHash)); } return(new StructResult <ContentHash>(putResult)); }; StructResult <ContentHash> blobIdOfContentHashListResult = await BlobContentHashListExtensions.PackInBlob( putStreamFunc, valueToAdd.ContentHashListWithDeterminism); if (!blobIdOfContentHashListResult.Succeeded) { return(new ObjectResult <ContentHashListWithCacheMetadata>(blobIdOfContentHashListResult)); } var blobContentHashListWithDeterminism = new BlobContentHashListWithDeterminism( valueToAdd.ContentHashListWithDeterminism.Determinism.EffectiveGuid, BlobIdentifierToContentHashExtensions.ToBlobIdentifier(blobIdOfContentHashListResult.Data)); var blobContentHashListWithCacheMetadata = new BlobContentHashListWithCacheMetadata( blobContentHashListWithDeterminism, valueToAdd.GetRawExpirationTimeUtc(), valueToAdd.ContentGuarantee, valueToAdd.HashOfExistingContentHashList); BlobContentHashListResponse addResult = await ArtifactHttpClientErrorDetectionStrategy.ExecuteWithTimeoutAsync( context, "AddContentHashList", innerCts => _buildCacheHttpClient.AddContentHashListAsync( cacheNamespace, strongFingerprint, blobContentHashListWithCacheMetadata), CancellationToken.None).ConfigureAwait(false); DownloadUriCache.Instance.BulkAddDownloadUris(addResult.BlobDownloadUris); // add succeeded but returned an empty contenthashlistwith cache metadata. correct this. if (addResult.ContentHashListWithCacheMetadata == null) { return (new ObjectResult <ContentHashListWithCacheMetadata>( new ContentHashListWithCacheMetadata( new ContentHashListWithDeterminism(null, blobContentHashListWithCacheMetadata.Determinism), blobContentHashListWithCacheMetadata.GetRawExpirationTimeUtc(), blobContentHashListWithCacheMetadata.ContentGuarantee))); } else { return(await UnpackBlobContentHashListAsync(context, addResult.ContentHashListWithCacheMetadata)); } } catch (Exception ex) { return(new ObjectResult <ContentHashListWithCacheMetadata>(ex)); } }
private async Task <IEnumerable <StructResult <StrongFingerprint> > > EnumerateStrongFingerprintsAsync(OperationContext context) { var result = await Database.EnumerateStrongFingerprintsAsync(context); return(result.Select(r => StructResult.FromResult(r))); }