From 29fdac53f0d9d8bcdee45b387d28dcd98bb512fc Mon Sep 17 00:00:00 2001 From: dudu Date: Thu, 20 Sep 2018 22:48:57 +0800 Subject: [PATCH 1/3] Remove try...catch in GetValueOrCreateAsync --- Enyim.Caching/MemcachedClient.cs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Enyim.Caching/MemcachedClient.cs b/Enyim.Caching/MemcachedClient.cs index fe3e6b20..d446a969 100755 --- a/Enyim.Caching/MemcachedClient.cs +++ b/Enyim.Caching/MemcachedClient.cs @@ -214,18 +214,11 @@ public async Task GetValueAsync(string key) public async Task GetValueOrCreateAsync(string key, int cacheSeconds, Func> generator) { - try - { - var result = await GetAsync(key); - if (result.Success) - { - _logger.LogDebug($"Cache is hint. Key is '{key}'."); - return result.Value; - } - } - catch (Exception ex) + var result = await GetAsync(key); + if (result.Success) { - _logger.LogError(ex, $"{nameof(GetAsync)}<{typeof(T)}>(\"{key}\")"); + _logger.LogDebug($"Cache is hint. Key is '{key}'."); + return result.Value; } _logger.LogDebug($"Cache is missed. Key is '{key}'."); From c009b81e11c0ee5f5ea6a840cc5f822f0337eb3f Mon Sep 17 00:00:00 2001 From: dudu Date: Thu, 20 Sep 2018 22:49:20 +0800 Subject: [PATCH 2/3] Improve GetValueOrCreateAsyncTest --- .../MemcachedClientGetTests.cs | 29 +++++++++++++++---- .../MemcachedClientTestsBase.cs | 1 - 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Enyim.Caching.Tests/MemcachedClientGetTests.cs b/Enyim.Caching.Tests/MemcachedClientGetTests.cs index e92a8321..0317f242 100644 --- a/Enyim.Caching.Tests/MemcachedClientGetTests.cs +++ b/Enyim.Caching.Tests/MemcachedClientGetTests.cs @@ -102,16 +102,35 @@ public void When_Getting_SByte_Result_Is_Successful() public async Task GetValueOrCreateAsyncTest() { var key = "GetValueOrCreateAsyncTest_" + Guid.NewGuid(); - await _client.GetValueOrCreateAsync(key, 10, () => GenerateValue()); - var cacheValue = await _client.GetValueAsync(key); - Assert.Equal(nameof(GetValueOrCreateAsyncTest), cacheValue); + var posts1 = await _client.GetValueOrCreateAsync( + key, + 10, + async () => await GenerateValue()); + Assert.NotNull(posts1); + + var posts2 = await _client.GetValueAsync>(key); + Assert.NotNull(posts2); + + Assert.Equal(posts1.First().Title, posts2.First().Title); } - private Task GenerateValue() + private Task> GenerateValue() { - return Task.FromResult(nameof(GetValueOrCreateAsyncTest)); + var posts = new List() + { + new BlogPost{ Title = "test title 1", Body = "test body 1" }, + new BlogPost{ Title = "test title 2", Body = "test body 2" } + }; + + return Task.FromResult(posts.AsEnumerable()); } } + + internal class BlogPost + { + public string Title { get; set; } + public string Body { get; set; } + } } #region [ License information ] diff --git a/Enyim.Caching.Tests/MemcachedClientTestsBase.cs b/Enyim.Caching.Tests/MemcachedClientTestsBase.cs index c05beeef..d1ae4862 100644 --- a/Enyim.Caching.Tests/MemcachedClientTestsBase.cs +++ b/Enyim.Caching.Tests/MemcachedClientTestsBase.cs @@ -39,7 +39,6 @@ protected string GetUniqueKey(string prefix = null) protected IEnumerable GetUniqueKeys(string prefix = null, int max = 5) { - var keys = new List(max); for (int i = 0; i < max; i++) { From 19cafc724f967cb50cee62f9c8842f3d2ada6006 Mon Sep 17 00:00:00 2001 From: dudu Date: Thu, 20 Sep 2018 22:50:28 +0800 Subject: [PATCH 3/3] Revert "Use Span in BinaryConverter" This reverts commit 960895e9345a9fa0f428ad2bbcd1111b59bc079c. --- Enyim.Caching/Memcached/MemcachedNode.cs | 12 +- .../Protocol/Binary/BinaryConverter.cs | 108 +++++++++---- .../Protocol/Binary/BinaryResponse.cs | 30 ++-- .../Memcached/Protocol/Binary/GetOperation.cs | 3 +- .../Protocol/Binary/MutatorOperation.cs | 152 +++++++++--------- 5 files changed, 182 insertions(+), 123 deletions(-) diff --git a/Enyim.Caching/Memcached/MemcachedNode.cs b/Enyim.Caching/Memcached/MemcachedNode.cs index 6e40d6c9..2ae1be4e 100755 --- a/Enyim.Caching/Memcached/MemcachedNode.cs +++ b/Enyim.Caching/Memcached/MemcachedNode.cs @@ -1,3 +1,9 @@ +using Enyim.Caching.Configuration; +using Enyim.Caching.Memcached.Protocol.Binary; +using Enyim.Caching.Memcached.Results; +using Enyim.Caching.Memcached.Results.Extensions; +using Enyim.Collections; +using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Diagnostics; @@ -7,12 +13,6 @@ using System.Security; using System.Threading; using System.Threading.Tasks; -using Enyim.Caching.Configuration; -using Enyim.Caching.Memcached.Protocol.Binary; -using Enyim.Caching.Memcached.Results; -using Enyim.Caching.Memcached.Results.Extensions; -using Enyim.Collections; -using Microsoft.Extensions.Logging; namespace Enyim.Caching.Memcached { diff --git a/Enyim.Caching/Memcached/Protocol/Binary/BinaryConverter.cs b/Enyim.Caching/Memcached/Protocol/Binary/BinaryConverter.cs index 0ea94814..ba454e0d 100644 --- a/Enyim.Caching/Memcached/Protocol/Binary/BinaryConverter.cs +++ b/Enyim.Caching/Memcached/Protocol/Binary/BinaryConverter.cs @@ -5,58 +5,110 @@ namespace Enyim.Caching.Memcached.Protocol.Binary { public static class BinaryConverter { - public static ushort DecodeUInt16(Span buffer, int offset) + public static unsafe ushort DecodeUInt16(byte[] buffer, int offset) { return (ushort)((buffer[offset] << 8) + buffer[offset + 1]); } - public static int DecodeInt32(Span buffer, int offset) + public static unsafe ushort DecodeUInt16(byte* buffer, int offset) { - var slice = buffer.Slice(offset); + return (ushort)((buffer[offset] << 8) + buffer[offset + 1]); + } + + public static unsafe int DecodeInt32(ArraySegment segment, int offset) + { + fixed (byte* buffer = segment.Array) + { + byte* ptr = buffer + segment.Offset + offset; + + return DecodeInt32(buffer, 0); + } + } + + public static unsafe int DecodeInt32(byte* buffer, int offset) + { + buffer += offset; + + return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + } + + public static unsafe int DecodeInt32(byte[] buffer, int offset) + { + return (buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3]; + } - return (slice[0] << 24) | (slice[1] << 16) | (slice[2] << 8) | slice[3]; + public static unsafe ulong DecodeUInt64(byte[] buffer, int offset) + { + fixed (byte* ptr = buffer) + { + return DecodeUInt64(ptr, offset); + } } - public static unsafe ulong DecodeUInt64(Span buffer, int offset) + public static unsafe ulong DecodeUInt64(byte* buffer, int offset) { - var slice = buffer.Slice(offset); + buffer += offset; - var part1 = (uint)((slice[0] << 24) | (slice[1] << 16) | (slice[2] << 8) | slice[3]); - var part2 = (uint)((slice[4] << 24) | (slice[5] << 16) | (slice[6] << 8) | slice[7]); + var part1 = (uint)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); + var part2 = (uint)((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]); return ((ulong)part1 << 32) | part2; } - public static unsafe void EncodeUInt16(uint value, Span buffer, int offset) + public static unsafe void EncodeUInt16(uint value, byte[] buffer, int offset) + { + fixed (byte* bufferPtr = buffer) + { + EncodeUInt16(value, bufferPtr, offset); + } + } + + public static unsafe void EncodeUInt16(uint value, byte* buffer, int offset) { - var slice = buffer.Slice(offset); + byte* ptr = buffer + offset; - slice[0] = (byte)(value >> 8); - slice[1] = (byte)(value & 255); + ptr[0] = (byte)(value >> 8); + ptr[1] = (byte)(value & 255); } - public static unsafe void EncodeUInt32(uint value, Span buffer, int offset) + public static unsafe void EncodeUInt32(uint value, byte[] buffer, int offset) { - var slice = buffer.Slice(offset); + fixed (byte* bufferPtr = buffer) + { + EncodeUInt32(value, bufferPtr, offset); + } + } + + public static unsafe void EncodeUInt32(uint value, byte* buffer, int offset) + { + byte* ptr = buffer + offset; - slice[0] = (byte)(value >> 24); - slice[1] = (byte)(value >> 16); - slice[2] = (byte)(value >> 8); - slice[3] = (byte)(value & 255); + ptr[0] = (byte)(value >> 24); + ptr[1] = (byte)(value >> 16); + ptr[2] = (byte)(value >> 8); + ptr[3] = (byte)(value & 255); } - public static unsafe void EncodeUInt64(ulong value, Span buffer, int offset) + public static unsafe void EncodeUInt64(ulong value, byte[] buffer, int offset) { - var slice = buffer.Slice(offset); + fixed (byte* bufferPtr = buffer) + { + EncodeUInt64(value, bufferPtr, offset); + } + } - slice[0] = (byte)(value >> 56); - slice[1] = (byte)(value >> 48); - slice[2] = (byte)(value >> 40); - slice[3] = (byte)(value >> 32); - slice[4] = (byte)(value >> 24); - slice[5] = (byte)(value >> 16); - slice[6] = (byte)(value >> 8); - slice[7] = (byte)(value & 255); + public static unsafe void EncodeUInt64(ulong value, byte* buffer, int offset) + { + byte* ptr = buffer + offset; + + ptr[0] = (byte)(value >> 56); + ptr[1] = (byte)(value >> 48); + ptr[2] = (byte)(value >> 40); + ptr[3] = (byte)(value >> 32); + ptr[4] = (byte)(value >> 24); + ptr[5] = (byte)(value >> 16); + ptr[6] = (byte)(value >> 8); + ptr[7] = (byte)(value & 255); } public static byte[] EncodeKey(string key) diff --git a/Enyim.Caching/Memcached/Protocol/Binary/BinaryResponse.cs b/Enyim.Caching/Memcached/Protocol/Binary/BinaryResponse.cs index df575c82..bbadc8ca 100644 --- a/Enyim.Caching/Memcached/Protocol/Binary/BinaryResponse.cs +++ b/Enyim.Caching/Memcached/Protocol/Binary/BinaryResponse.cs @@ -1,6 +1,6 @@ using System; -using System.Diagnostics; using System.Text; +using System.Diagnostics; using System.Threading.Tasks; namespace Enyim.Caching.Memcached.Protocol.Binary @@ -64,7 +64,7 @@ public unsafe bool Read(PooledSocket socket) if (dataLength > 0) { var data = new byte[dataLength]; - socket.Read(data, 0, dataLength); + socket.Read(data, 0, dataLength); this.Extra = new ArraySegment(data, 0, extraLength); this.Data = new ArraySegment(data, extraLength, data.Length - extraLength); @@ -207,22 +207,24 @@ private void DoDecodeBody(AsyncIOArgs asyncEvent) if (this.shouldCallNext) this.next(true); } - - private void DeserializeHeader(Span header, out int dataLength, out int extraLength) + private unsafe void DeserializeHeader(byte[] header, out int dataLength, out int extraLength) { - if (header[0] != MAGIC_VALUE) - throw new InvalidOperationException("Expected magic value " + MAGIC_VALUE + ", received: " + header[0]); + fixed (byte* buffer = header) + { + if (buffer[0] != MAGIC_VALUE) + throw new InvalidOperationException("Expected magic value " + MAGIC_VALUE + ", received: " + buffer[0]); - this.DataType = header[HEADER_DATATYPE]; - this.Opcode = header[HEADER_OPCODE]; - this.StatusCode = BinaryConverter.DecodeUInt16(header, HEADER_STATUS); + this.DataType = buffer[HEADER_DATATYPE]; + this.Opcode = buffer[HEADER_OPCODE]; + this.StatusCode = BinaryConverter.DecodeUInt16(buffer, HEADER_STATUS); - this.KeyLength = BinaryConverter.DecodeUInt16(header, HEADER_KEY); - this.CorrelationId = BinaryConverter.DecodeInt32(header, HEADER_OPAQUE); - this.CAS = BinaryConverter.DecodeUInt64(header, HEADER_CAS); + this.KeyLength = BinaryConverter.DecodeUInt16(buffer, HEADER_KEY); + this.CorrelationId = BinaryConverter.DecodeInt32(buffer, HEADER_OPAQUE); + this.CAS = BinaryConverter.DecodeUInt64(buffer, HEADER_CAS); - dataLength = BinaryConverter.DecodeInt32(header, HEADER_BODY); - extraLength = header[HEADER_EXTRA]; + dataLength = BinaryConverter.DecodeInt32(buffer, HEADER_BODY); + extraLength = buffer[HEADER_EXTRA]; + } } private void LogExecutionTime(string title, DateTime startTime, int thresholdMs) diff --git a/Enyim.Caching/Memcached/Protocol/Binary/GetOperation.cs b/Enyim.Caching/Memcached/Protocol/Binary/GetOperation.cs index 7ddad097..6439ce30 100644 --- a/Enyim.Caching/Memcached/Protocol/Binary/GetOperation.cs +++ b/Enyim.Caching/Memcached/Protocol/Binary/GetOperation.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Text; using Enyim.Caching.Memcached.Results; @@ -38,7 +37,7 @@ protected override IOperationResult ProcessResponse(BinaryResponse response) if (status == 0) { - int flags = BinaryConverter.DecodeInt32(response.Extra.AsSpan(), 0); + int flags = BinaryConverter.DecodeInt32(response.Extra, 0); this.result = new CacheItem((ushort)flags, response.Data); this.Cas = response.CAS; diff --git a/Enyim.Caching/Memcached/Protocol/Binary/MutatorOperation.cs b/Enyim.Caching/Memcached/Protocol/Binary/MutatorOperation.cs index 43d3e6e7..0af7d6b3 100644 --- a/Enyim.Caching/Memcached/Protocol/Binary/MutatorOperation.cs +++ b/Enyim.Caching/Memcached/Protocol/Binary/MutatorOperation.cs @@ -1,82 +1,88 @@ using System; -using Enyim.Caching.Memcached.Results; using Enyim.Caching.Memcached.Results.Extensions; using Enyim.Caching.Memcached.Results.Helpers; +using Enyim.Caching.Memcached.Results; namespace Enyim.Caching.Memcached.Protocol.Binary { - public class MutatorOperation : BinarySingleItemOperation, IMutatorOperation - { - private readonly ulong defaultValue; - private readonly ulong delta; - private readonly uint expires; - private readonly MutationMode mode; - private ulong result; - - public MutatorOperation(MutationMode mode, string key, ulong defaultValue, ulong delta, uint expires) - : base(key) - { - if (delta < 0) throw new ArgumentOutOfRangeException("delta", "delta must be >= 0"); - - this.defaultValue = defaultValue; - this.delta = delta; - this.expires = expires; - this.mode = mode; - } - - protected void UpdateExtra(BinaryRequest request) - { - Span buffer = stackalloc byte[20]; - BinaryConverter.EncodeUInt64(this.delta, buffer, 0); - BinaryConverter.EncodeUInt64(this.defaultValue, buffer, 8); - BinaryConverter.EncodeUInt32(this.expires, buffer, 16); - request.Extra = new ArraySegment(buffer.ToArray()); - } - - protected override BinaryRequest Build() - { - var request = new BinaryRequest((OpCode)this.mode) - { - Key = this.Key, - Cas = this.Cas - }; - - this.UpdateExtra(request); - - return request; - } - - protected override IOperationResult ProcessResponse(BinaryResponse response) - { - var result = new BinaryOperationResult(); - var status = response.StatusCode; - this.StatusCode = status; - - if (status == 0) - { - var data = response.Data; - if (data.Count != 8) - return result.Fail("Result must be 8 bytes long, received: " + data.Count, new InvalidOperationException()); - - this.result = BinaryConverter.DecodeUInt64(data.Array, data.Offset); - - return result.Pass(); - } - - var message = ResultHelper.ProcessResponseData(response.Data); - return result.Fail(message); - } - - MutationMode IMutatorOperation.Mode - { - get { return this.mode; } - } - - ulong IMutatorOperation.Result - { - get { return this.result; } - } - } + public class MutatorOperation : BinarySingleItemOperation, IMutatorOperation + { + private ulong defaultValue; + private ulong delta; + private uint expires; + private MutationMode mode; + private ulong result; + + public MutatorOperation(MutationMode mode, string key, ulong defaultValue, ulong delta, uint expires) + : base(key) + { + if (delta < 0) throw new ArgumentOutOfRangeException("delta", "delta must be >= 0"); + + this.defaultValue = defaultValue; + this.delta = delta; + this.expires = expires; + this.mode = mode; + } + + protected unsafe void UpdateExtra(BinaryRequest request) + { + byte[] extra = new byte[20]; + + fixed (byte* buffer = extra) + { + BinaryConverter.EncodeUInt64(this.delta, buffer, 0); + + BinaryConverter.EncodeUInt64(this.defaultValue, buffer, 8); + BinaryConverter.EncodeUInt32(this.expires, buffer, 16); + } + + request.Extra = new ArraySegment(extra); + } + + protected override BinaryRequest Build() + { + var request = new BinaryRequest((OpCode)this.mode) + { + Key = this.Key, + Cas = this.Cas + }; + + this.UpdateExtra(request); + + return request; + } + + protected override IOperationResult ProcessResponse(BinaryResponse response) + { + var result = new BinaryOperationResult(); + var status = response.StatusCode; + this.StatusCode = status; + + if (status == 0) + { + var data = response.Data; + if (data.Count != 8) + return result.Fail("Result must be 8 bytes long, received: " + data.Count, new InvalidOperationException()); + + this.result = BinaryConverter.DecodeUInt64(data.Array, data.Offset); + + return result.Pass(); + } + + var message = ResultHelper.ProcessResponseData(response.Data); + return result.Fail(message); + } + + MutationMode IMutatorOperation.Mode + { + get { return this.mode; } + } + + ulong IMutatorOperation.Result + { + get { return this.result; } + } + } } #region [ License information ]