public async Task <Possible <CasHash, Failure> > AddToCasAsync( string filename, FileState fileState, CasHash?hash, UrgencyHint urgencyHint, Guid activityId) { Contract.Requires(!IsClosed); Contract.Requires(filename != null); Contract.Assert(!IsReadOnly); using (var counter = m_counters.AddToCasCounterFile()) { using (var eventing = new AddToCasFilenameActivity(BasicFilesystemCache.EventSource, activityId, this)) { eventing.Start(filename, fileState, urgencyHint); Possible <CasHash, Failure> result; // First we need to do the hash of the file // We do this "in place" since the CAS may be // on "slow" storage and this is local try { // We keep the file open during this such that others can't modify it // until the add-to-cas has completed. It also happens to be needed // in order to compute the hash. using (var fileData = await m_cache.ContendedOpenStreamAsync(filename, FileMode.Open, FileAccess.Read, FileShare.Read, handlePendingDelete: false)) { counter.ContentSize(fileData.Length); CasHash casHash = new CasHash(await ContentHashingUtilities.HashContentStreamAsync(fileData)); try { if (!await m_cache.AddToCasAsync(filename, casHash)) { counter.DuplicatedContent(); } // Pin it and return the hash m_pinnedToCas.TryAdd(casHash, 0); result = casHash; } catch (Exception e) { counter.Failed(); result = new AddToCasFailure(CacheId, casHash, filename, e); } } } catch (Exception e) { counter.Failed(); result = new HashFailure(CacheId, filename, e); } return(eventing.Returns(result)); } } }
public async Task <Possible <CasHash, Failure> > AddToCasAsync(Stream filestream, CasHash?hash, UrgencyHint urgencyHint, Guid activityId) { Contract.Requires(!IsClosed); Contract.Requires(filestream != null); Contract.Assert(!IsReadOnly); // We have this interesting issue - we are not sure if the stream is rewindable // and the target CAS may not be local so we will end up streaming this to // a temporary file just to pass it up. (Implementation detail) using (var counter = m_counters.AddToCasCounterStream()) { using (var eventing = new AddToCasStreamActivity(BasicFilesystemCache.EventSource, activityId, this)) { eventing.Start(filestream, urgencyHint); Possible <CasHash, Failure> result; string tmpFile = await m_cache.CreateTempFile(); // Since these are longer operations that are synchronous, we wrap them // into a task for potential parallelism try { CasHash casHash = await HashStreamToFileAsync(filestream, tmpFile); try { counter.ContentSize(new FileInfo(tmpFile).Length); if (!await m_cache.AddToCasAsync(tmpFile, casHash)) { counter.DuplicatedContent(); } // Pin it and return the hash m_pinnedToCas.TryAdd(casHash, 0); result = casHash; } catch (Exception e) { counter.Failed(); result = new AddToCasFailure(CacheId, casHash, "<stream>", e); } } catch (Exception e) { counter.Failed(); result = new HashFailure(CacheId, "<stream>", e); } finally { try { File.Delete(tmpFile); } #pragma warning disable ERP022 // TODO: This should really handle specific errors catch { // Ignore the failure - it is likely caused by // a semantic breaking tool such as most virus scanners // or disk indexers. The file was a local teporary file // in the temp directory } #pragma warning restore ERP022 // Unobserved exception in generic exception handler } return(eventing.Returns(result)); } } }