public void TestCloneOrNull() { EncodedImage encodedImage = new EncodedImage(_byteBufferRef); encodedImage.Format = ImageFormat.JPEG; encodedImage.RotationAngle = 0; encodedImage.Width = 1; encodedImage.Height = 2; encodedImage.SampleSize = 4; EncodedImage encodedImage2 = EncodedImage.CloneOrNull(encodedImage); Assert.AreEqual(3, _byteBufferRef.GetUnderlyingReferenceTestOnly().GetRefCountTestOnly()); Assert.AreSame( encodedImage.GetByteBufferRef().GetUnderlyingReferenceTestOnly(), encodedImage2.GetByteBufferRef().GetUnderlyingReferenceTestOnly()); Assert.AreEqual(encodedImage.Format, encodedImage2.Format); Assert.AreEqual(encodedImage.RotationAngle, encodedImage2.RotationAngle); Assert.AreEqual(encodedImage.Height, encodedImage2.Height); Assert.AreEqual(encodedImage.Width, encodedImage2.Width); Assert.AreEqual(encodedImage.SampleSize, encodedImage2.SampleSize); encodedImage = new EncodedImage(_inputStreamSupplier, 100); encodedImage.Format = ImageFormat.JPEG; encodedImage.RotationAngle = 0; encodedImage.Width = 1; encodedImage.Height = 2; encodedImage2 = EncodedImage.CloneOrNull(encodedImage); Assert.AreSame(encodedImage.GetInputStream(), encodedImage2.GetInputStream()); Assert.AreEqual(encodedImage2.Size, encodedImage.Size); }
public void TestCloneOrNull_WithInvalidOrNullReferences() { Assert.AreEqual(null, EncodedImage.CloneOrNull(null)); EncodedImage encodedImage = new EncodedImage(_byteBufferRef); encodedImage.Dispose(); Assert.AreEqual(null, EncodedImage.CloneOrNull(encodedImage)); }
/// <summary> /// Associates encodedImage with given key in disk cache. /// Disk write is performed on background thread, so the /// caller of this method is not blocked. /// </summary> public Task Put(ICacheKey key, EncodedImage encodedImage) { Preconditions.CheckNotNull(key); Preconditions.CheckArgument(EncodedImage.IsValid(encodedImage)); // Store encodedImage in staging area _stagingArea.Put(key, encodedImage); // Write to disk cache. This will be executed on background thread, // so increment the ref count. When this write completes // (with success/failure), then we will bump down the ref count again. EncodedImage finalEncodedImage = EncodedImage.CloneOrNull(encodedImage); try { Task writeTask = _writeExecutor.Execute(() => { try { WriteToDiskCache(key, finalEncodedImage); } finally { _stagingArea.Remove(key, finalEncodedImage); EncodedImage.CloseSafely(finalEncodedImage); // Removes write task after it's completed. Task writeTaskCompleted = default(Task); _writeToDiskCacheTasks.TryRemove(key, out writeTaskCompleted); } }); _writeToDiskCacheTasks.TryAdd(key, writeTask); return(writeTask); } catch (Exception) { // We failed to enqueue cache write. Log failure and decrement ref count // TODO: 3697790 Debug.WriteLine($"Failed to schedule disk-cache write for { key.ToString() }"); _stagingArea.Remove(key, encodedImage); EncodedImage.CloseSafely(finalEncodedImage); // Removes write task due to error. Task writeTaskCompleted = default(Task); _writeToDiskCacheTasks.TryRemove(key, out writeTaskCompleted); throw; } }
/// <summary> /// Updates the job. /// /// <para />This just updates the job, but it doesn't schedule it. /// In order to be executed, the job has to be scheduled after /// being set. In case there was a previous job scheduled that has /// not yet started, this new job will be executed instead. /// </summary> /// <returns> /// Whether the job was successfully updated. /// </returns> public bool UpdateJob(EncodedImage encodedImage, bool isLast) { if (!ShouldProcess(encodedImage, isLast)) { return(false); } EncodedImage oldEncodedImage; lock (_gate) { oldEncodedImage = _encodedImage; _encodedImage = EncodedImage.CloneOrNull(encodedImage); _isLast = isLast; } EncodedImage.CloseSafely(oldEncodedImage); return(true); }
/// <summary> /// Stores key-value in this StagingArea. /// </summary> /// <param name="key">The cache key.</param> /// <param name="encodedImage"> /// EncodedImage to be associated with key. /// </param> public void Put(ICacheKey key, EncodedImage encodedImage) { lock (_mapGate) { Preconditions.CheckNotNull(key); Preconditions.CheckArgument(EncodedImage.IsValid(encodedImage)); // We're making a 'copy' of this reference - so duplicate it EncodedImage oldEntry = default(EncodedImage); if (_map.TryGetValue(key, out oldEntry)) { _map.Remove(key); } _map.Add(key, EncodedImage.CloneOrNull(encodedImage)); EncodedImage.CloseSafely(oldEntry); #if DEBUG_STAGING_AREA LogStats(); #endif // DEBUG_STAGING_AREA } }
/// <summary> /// Gets the encoded image. /// </summary> /// <returns> /// Value associated with given key or null if no value is associated. /// </returns> public EncodedImage Get(ICacheKey key) { lock (_mapGate) { Preconditions.CheckNotNull(key); EncodedImage storedEncodedImage = default(EncodedImage); if (_map.TryGetValue(key, out storedEncodedImage)) { if (!EncodedImage.IsValid(storedEncodedImage)) { // Reference is not valid, this means that someone // cleared reference while it was still in use. // Log error TODO: 3697790 _map.Remove(key); Debug.WriteLine($"Found closed reference { storedEncodedImage.GetHashCode() } for key { key.ToString() } ({ key.GetHashCode() })"); return(null); } storedEncodedImage = EncodedImage.CloneOrNull(storedEncodedImage); } return(storedEncodedImage); } }
/// <summary> /// Clones the result. /// </summary> public override EncodedImage CloneOrNull(EncodedImage encodedImage) { return(EncodedImage.CloneOrNull(encodedImage)); }