public AcceptableEntry(PipFingerprintEntry entry) { Contract.Requires(entry != null); Entry = entry; }
/// <summary> /// Attempts to store a fingerprint entry; this is a compare-exchange operation, in which <paramref name="previousEntry"/> /// must match what is currently stored (or must be <c>null</c> if no entry is currently stored). /// This operation will fail if the previous entry doesn't match, or if the store could not normally proceed. /// </summary> public async Task <Possible <CacheEntryPublishResult, Failure> > TryStoreFingerprintEntryAsync( ContentFingerprint fingerprint, PipFingerprintEntry entry, PipFingerprintEntry previousEntry = null, bool replaceExisting = true, CacheQueryData cacheQueryData = null) { Contract.Assume(entry != null); Analysis.IgnoreArgument(previousEntry); // See class remarks; replace semantics are broken. // We have in hand a PipFingerprintEntry which the underlyign m_twoPhaseStore does not understand. // We will serialize it and store it to the CAS, and that CAS hash will be the stored entry's MetadataHash. // See symmetric deserialization in TryGetFingerprintEntryAsync. Possible <ContentHash, Failure> maybeStored = await m_contentCache.TrySerializeAndStoreContent(entry); if (!maybeStored.Succeeded) { return(maybeStored.Failure.Annotate("Failed to store cache-entry metadata to the CAS")); } ContentHash metadataHash = maybeStored.Result; // The metadata (single-phase entry) is stored, so now we can construct an entry that references it. // From now on, 'twoPhaseEntry' will mean 'the entry we are actually storing in the two-phase store'. // Meanwhile, like any implementation, we assume that the referenced content (e.g. output files) // were stored by the caller already. ContentHash[] twoPhaseReferencedHashes = entry.OutputContentHashes.Select(b => b.ToContentHash()).Where(hash => !hash.IsSpecialValue()).ToArray(); CacheEntry twoPhaseEntry = new CacheEntry(metadataHash, null, ArrayView <ContentHash> .FromArray(twoPhaseReferencedHashes)); StrongContentFingerprint dummyFingerprint = ComputeDummyStrongFingerprint( m_pathTable, fingerprint); var weakFingerprint = new WeakContentFingerprint(fingerprint.Hash); Possible <CacheEntryPublishResult, Failure> maybePublished = await m_twoPhaseStore.TryPublishCacheEntryAsync( weakFingerprint : weakFingerprint, pathSetHash : s_dummyPathSetHash, strongFingerprint : dummyFingerprint, entry : twoPhaseEntry, mode : replaceExisting?CacheEntryPublishMode.CreateNewOrReplaceExisting : CacheEntryPublishMode.CreateNew); if (cacheQueryData != null) { cacheQueryData.WeakContentFingerprint = weakFingerprint; cacheQueryData.PathSetHash = s_dummyPathSetHash; cacheQueryData.StrongContentFingerprint = dummyFingerprint; cacheQueryData.ContentCache = m_contentCache; } if (maybePublished.Succeeded) { if (maybePublished.Result.Status == CacheEntryPublishStatus.Published || (!replaceExisting && maybePublished.Result.Status == CacheEntryPublishStatus.RejectedDueToConflictingEntry)) { return(maybePublished.Result); } else { // ISinglePhaseFingerprintStore represents conflicts as failures. return(new Failure <string>( "Failed to publish a cache entry; the underlying two-phase store indicated an entry conflict (maybe it does not allow replacement of existing entries).")); } } else { return(maybePublished.Failure); } }