Skip to content

Commit 8dc88f4

Browse files
committed
Add TouchAsync to support "touch" command
1 parent 330348b commit 8dc88f4

File tree

11 files changed

+262
-174
lines changed

11 files changed

+262
-174
lines changed

Enyim.Caching.Tests/MemcachedClientMutateTests.cs

+35-21
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,48 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Text;
5+
using System.Threading.Tasks;
56
using Xunit;
67

78
namespace Enyim.Caching.Tests
89
{
9-
public class MemcachedClientMutateTests : MemcachedClientTestsBase
10-
{
11-
[Fact]
12-
public void When_Incrementing_Value_Result_Is_Successful()
13-
{
14-
var key = GetUniqueKey("mutate");
15-
var mutateResult = _client.ExecuteIncrement(key, 100, 10);
16-
MutateAssertPass(mutateResult, 100);
10+
public class MemcachedClientMutateTests : MemcachedClientTestsBase
11+
{
12+
[Fact]
13+
public void When_Incrementing_Value_Result_Is_Successful()
14+
{
15+
var key = GetUniqueKey("mutate");
16+
var mutateResult = _client.ExecuteIncrement(key, 100, 10);
17+
MutateAssertPass(mutateResult, 100);
1718

18-
mutateResult = _client.ExecuteIncrement(key, 100, 10);
19-
MutateAssertPass(mutateResult, 110);
20-
}
19+
mutateResult = _client.ExecuteIncrement(key, 100, 10);
20+
MutateAssertPass(mutateResult, 110);
21+
}
2122

22-
[Fact]
23-
public void When_Decrementing_Value_Result_Is_Successful()
24-
{
25-
var key = GetUniqueKey("mutate");
26-
var mutateResult = _client.ExecuteDecrement(key, 100, 10);
27-
MutateAssertPass(mutateResult, 100);
23+
[Fact]
24+
public void When_Decrementing_Value_Result_Is_Successful()
25+
{
26+
var key = GetUniqueKey("mutate");
27+
var mutateResult = _client.ExecuteDecrement(key, 100, 10);
28+
MutateAssertPass(mutateResult, 100);
2829

29-
mutateResult = _client.ExecuteDecrement(key, 100, 10);
30-
MutateAssertPass(mutateResult, 90);
31-
}
32-
}
30+
mutateResult = _client.ExecuteDecrement(key, 100, 10);
31+
MutateAssertPass(mutateResult, 90);
32+
}
33+
34+
[Fact]
35+
public async Task When_Touch_Item_Result_Is_Successful()
36+
{
37+
var key = GetUniqueKey("touch");
38+
await _client.AddAsync(key, "value", 1);
39+
Assert.True((await _client.GetAsync<string>(key)).Success);
40+
var result = await _client.TouchAsync(key, TimeSpan.FromSeconds(60));
41+
await Task.Delay(1010);
42+
Assert.True(result.Success, "Success was false");
43+
Assert.True((result.StatusCode ?? 0) == 0, "StatusCode was not null or 0");
44+
Assert.True((await _client.GetAsync<string>(key)).Success);
45+
}
46+
}
3347
}
3448

3549
#region [ License information ]

Enyim.Caching/IMemcachedClient.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public interface IMemcachedClient : IDisposable
1313

1414
bool Set(string key, object value, int cacheSeconds);
1515
Task<bool> SetAsync(string key, object value, int cacheSeconds);
16-
16+
1717
bool Replace(string key, object value, int cacheSeconds);
1818
Task<bool> ReplaceAsync(string key, object value, int cacheSeconds);
1919

@@ -66,6 +66,9 @@ public interface IMemcachedClient : IDisposable
6666
CasResult<ulong> Increment(string key, ulong defaultValue, ulong delta, DateTime expiresAt, ulong cas);
6767
CasResult<ulong> Increment(string key, ulong defaultValue, ulong delta, TimeSpan validFor, ulong cas);
6868

69+
Task<IOperationResult> TouchAsync(string key, DateTime expiresAt);
70+
Task<IOperationResult> TouchAsync(string key, TimeSpan validFor);
71+
6972
bool Remove(string key);
7073
Task<bool> RemoveAsync(string key);
7174

Enyim.Caching/Memcached/Enums.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1+
using Enyim.Caching.Memcached.Protocol.Binary;
12
using System;
23

34
namespace Enyim.Caching.Memcached
45
{
5-
public enum MutationMode : byte { Increment = 0x05, Decrement = 0x06 };
6-
public enum ConcatenationMode : byte { Append = 0x0E, Prepend = 0x0F };
7-
public enum MemcachedProtocol { Binary, Text }
6+
public enum MutationMode : byte { Increment = 0x05, Decrement = 0x06, Touch = OpCode.Touch };
7+
public enum ConcatenationMode : byte { Append = 0x0E, Prepend = 0x0F };
8+
public enum MemcachedProtocol { Binary, Text }
89
}
910

1011
#region [ License information ]
1112
/* ************************************************************
1213
*
13-
* Copyright (c) 2010 Attila Kiskó, enyim.com
14+
* Copyright (c) 2010 Attila Kisk? enyim.com
1415
*
1516
* Licensed under the Apache License, Version 2.0 (the "License");
1617
* you may not use this file except in compliance with the License.

Enyim.Caching/Memcached/IOperationFactory.cs

+11-11
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55

66
namespace Enyim.Caching.Memcached
77
{
8-
public interface IOperationFactory
9-
{
10-
IGetOperation Get(string key);
11-
IMultiGetOperation MultiGet(IList<string> keys);
8+
public interface IOperationFactory
9+
{
10+
IGetOperation Get(string key);
11+
IMultiGetOperation MultiGet(IList<string> keys);
1212

13-
IStoreOperation Store(StoreMode mode, string key, CacheItem value, uint expires, ulong cas);
14-
IDeleteOperation Delete(string key, ulong cas);
15-
IMutatorOperation Mutate(MutationMode mode, string key, ulong defaultValue, ulong delta, uint expires, ulong cas);
16-
IConcatOperation Concat(ConcatenationMode mode, string key, ulong cas, ArraySegment<byte> data);
13+
IStoreOperation Store(StoreMode mode, string key, CacheItem value, uint expires, ulong cas);
14+
IDeleteOperation Delete(string key, ulong cas);
15+
IMutatorOperation Mutate(MutationMode mode, string key, ulong defaultValue, ulong delta, uint expires, ulong cas);
16+
IConcatOperation Concat(ConcatenationMode mode, string key, ulong cas, ArraySegment<byte> data);
1717

18-
IStatsOperation Stats(string type);
19-
IFlushOperation Flush();
20-
}
18+
IStatsOperation Stats(string type);
19+
IFlushOperation Flush();
20+
}
2121
}
2222

2323
#region [ License information ]

Enyim.Caching/Memcached/MemcachedNode.cs

+1
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ protected virtual async Task<IPooledSocketResult> ExecuteOperationAsync(IOperati
863863
}
864864
else
865865
{
866+
_logger.LogInformation($"{op}.{nameof(op.ReadResponseAsync)} result: {readResult.Message}");
866867
readResult.Combine(result);
867868
}
868869
return result;

Enyim.Caching/Memcached/Protocol/Binary/MutatorOperation.cs

+92-79
Original file line numberDiff line numberDiff line change
@@ -2,93 +2,106 @@
22
using Enyim.Caching.Memcached.Results.Extensions;
33
using Enyim.Caching.Memcached.Results.Helpers;
44
using Enyim.Caching.Memcached.Results;
5+
using System.Buffers.Binary;
56

67
namespace Enyim.Caching.Memcached.Protocol.Binary
78
{
8-
public class MutatorOperation : BinarySingleItemOperation, IMutatorOperation
9-
{
10-
private ulong defaultValue;
11-
private ulong delta;
12-
private uint expires;
13-
private MutationMode mode;
14-
private ulong result;
15-
16-
public MutatorOperation(MutationMode mode, string key, ulong defaultValue, ulong delta, uint expires)
17-
: base(key)
18-
{
19-
if (delta < 0) throw new ArgumentOutOfRangeException("delta", "delta must be >= 0");
20-
21-
this.defaultValue = defaultValue;
22-
this.delta = delta;
23-
this.expires = expires;
24-
this.mode = mode;
25-
}
26-
27-
protected unsafe void UpdateExtra(BinaryRequest request)
28-
{
29-
byte[] extra = new byte[20];
30-
31-
fixed (byte* buffer = extra)
32-
{
33-
BinaryConverter.EncodeUInt64(this.delta, buffer, 0);
34-
35-
BinaryConverter.EncodeUInt64(this.defaultValue, buffer, 8);
36-
BinaryConverter.EncodeUInt32(this.expires, buffer, 16);
37-
}
38-
39-
request.Extra = new ArraySegment<byte>(extra);
40-
}
41-
42-
protected override BinaryRequest Build()
43-
{
44-
var request = new BinaryRequest((OpCode)this.mode)
45-
{
46-
Key = this.Key,
47-
Cas = this.Cas
48-
};
49-
50-
this.UpdateExtra(request);
51-
52-
return request;
53-
}
54-
55-
protected override IOperationResult ProcessResponse(BinaryResponse response)
56-
{
57-
var result = new BinaryOperationResult();
58-
var status = response.StatusCode;
59-
this.StatusCode = status;
60-
61-
if (status == 0)
62-
{
63-
var data = response.Data;
64-
if (data.Count != 8)
65-
return result.Fail("Result must be 8 bytes long, received: " + data.Count, new InvalidOperationException());
66-
67-
this.result = BinaryConverter.DecodeUInt64(data.Array, data.Offset);
68-
69-
return result.Pass();
70-
}
71-
72-
var message = ResultHelper.ProcessResponseData(response.Data);
73-
return result.Fail(message);
74-
}
75-
76-
MutationMode IMutatorOperation.Mode
77-
{
78-
get { return this.mode; }
79-
}
80-
81-
ulong IMutatorOperation.Result
82-
{
83-
get { return this.result; }
84-
}
85-
}
9+
public class MutatorOperation : BinarySingleItemOperation, IMutatorOperation
10+
{
11+
private readonly ulong defaultValue;
12+
private readonly ulong delta;
13+
private readonly uint expires;
14+
private readonly MutationMode mode;
15+
private ulong result;
16+
17+
public MutatorOperation(MutationMode mode, string key, ulong defaultValue, ulong delta, uint expires)
18+
: base(key)
19+
{
20+
if (delta < 0) throw new ArgumentOutOfRangeException("delta", "delta must be >= 0");
21+
22+
this.defaultValue = defaultValue;
23+
this.delta = delta;
24+
this.expires = expires;
25+
this.mode = mode;
26+
}
27+
28+
protected unsafe void UpdateExtra(BinaryRequest request)
29+
{
30+
if (mode == MutationMode.Touch)
31+
{
32+
Span<byte> extra = stackalloc byte[4];
33+
BinaryPrimitives.WriteUInt32BigEndian(extra, this.expires);
34+
request.Extra = new ArraySegment<byte>(extra.ToArray());
35+
}
36+
else
37+
{
38+
byte[] extra = new byte[20];
39+
40+
fixed (byte* buffer = extra)
41+
{
42+
BinaryConverter.EncodeUInt64(this.delta, buffer, 0);
43+
44+
BinaryConverter.EncodeUInt64(this.defaultValue, buffer, 8);
45+
BinaryConverter.EncodeUInt32(this.expires, buffer, 16);
46+
}
47+
48+
request.Extra = new ArraySegment<byte>(extra);
49+
}
50+
}
51+
52+
protected override BinaryRequest Build()
53+
{
54+
var request = new BinaryRequest((OpCode)this.mode)
55+
{
56+
Key = this.Key,
57+
Cas = this.Cas
58+
};
59+
60+
this.UpdateExtra(request);
61+
62+
return request;
63+
}
64+
65+
protected override IOperationResult ProcessResponse(BinaryResponse response)
66+
{
67+
var result = new BinaryOperationResult();
68+
var status = response.StatusCode;
69+
this.StatusCode = status;
70+
71+
if (status == 0)
72+
{
73+
if (mode != MutationMode.Touch)
74+
{
75+
var data = response.Data;
76+
if (data.Count != 8)
77+
return result.Fail("Result must be 8 bytes long, received: " + data.Count, new InvalidOperationException());
78+
79+
this.result = BinaryConverter.DecodeUInt64(data.Array, data.Offset);
80+
}
81+
82+
return result.Pass();
83+
}
84+
85+
var message = ResultHelper.ProcessResponseData(response.Data);
86+
return result.Fail(message);
87+
}
88+
89+
MutationMode IMutatorOperation.Mode
90+
{
91+
get { return this.mode; }
92+
}
93+
94+
ulong IMutatorOperation.Result
95+
{
96+
get { return this.result; }
97+
}
98+
}
8699
}
87100

88101
#region [ License information ]
89102
/* ************************************************************
90103
*
91-
* Copyright (c) 2010 Attila Kiskó, enyim.com
104+
* Copyright (c) 2010 Attila Kisk? enyim.com
92105
*
93106
* Licensed under the Apache License, Version 2.0 (the "License");
94107
* you may not use this file except in compliance with the License.

0 commit comments

Comments
 (0)