/// <summary> /// Updates expiry of single node in DedupStore if /// 1) Node exists /// 2) All children exist and have sufficient TTL /// If children have insufficient TTL, attempt to extend the expiry of all children before pinning. /// </summary> private async Task <PinResult> TryPinNodeAsync(Context context, VstsDedupIdentifier dedupId, CancellationToken cts) { TryReferenceNodeResponse referenceResult; try { referenceResult = await TryGatedArtifactOperationAsync( context, dedupId.ValueString, "TryKeepUntilReferenceNode", innerCts => DedupStoreClient.Client.TryKeepUntilReferenceNodeAsync(dedupId.CastToNodeDedupIdentifier(), new KeepUntilBlobReference(EndDateTime), null, innerCts), cts); } catch (DedupNotFoundException) { // When VSTS processes response, throws exception when node doesn't exist. referenceResult = new TryReferenceNodeResponse(new DedupNodeNotFound()); } catch (Exception ex) { return(new PinResult(ex)); } PinResult pinResult = PinResult.ContentNotFound; referenceResult.Match( (notFound) => { // Root node has expired. }, async(needAction) => { pinResult = await TryPinChildrenAsync(context, dedupId, needAction.InsufficientKeepUntil, cts); }, (added) => { pinResult = PinResult.Success; }); return(pinResult); }
/// <summary> /// Checks the current keepUntil of a node. Returns null if the node is not found. /// </summary> protected async Task <Result <DateTime?> > CheckNodeKeepUntilAsync(OperationContext context, VstsDedupIdentifier dedupId) { TryReferenceNodeResponse referenceResult; try { // Pinning with keepUntil of now means that, if the content is available, the call will always succeed. referenceResult = await TryGatedArtifactOperationAsync( context, dedupId.ValueString, "TryKeepUntilReferenceNode", innerCts => DedupStoreClient.Client.TryKeepUntilReferenceNodeAsync(dedupId.CastToNodeDedupIdentifier(), new KeepUntilBlobReference(DateTime.UtcNow), null, innerCts)); } catch (Exception ex) { return(new Result <DateTime?>(ex)); } DateTime?keepUntil = null; referenceResult.Match( (notFound) => { /* Do nothing */ }, (needAction) => { // For the reason explained above, this case where children need to be pinned should never happen. // However, as a best approximation, we take the min of all the children, which always outlive the parent. keepUntil = needAction.Receipts.Select(r => r.Value.KeepUntil.KeepUntil).Min(); }, (added) => { keepUntil = added.Receipts[dedupId].KeepUntil.KeepUntil; }); return(new Result <DateTime?>(keepUntil, isNullAllowed: true)); }