Skip to content

Commit c22df00

Browse files
committed
FEATURE: Add gat command
add get and touch command
1 parent 447601d commit c22df00

File tree

3 files changed

+156
-3
lines changed

3 files changed

+156
-3
lines changed

docs/ascii-protocol/ch04-command-key-value.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,30 @@ decr <key> <delta> [<flags> <exptime> <initial>] [noreply]\r\n
110110
| "TYPE_MISMATCH" | 해당 아이템이 key-value 타입이 아님
111111
| "CLIENT_ERROR" | 클라이언트에서 잘못된 질의를 했음을 의미. 이어 나오는 문자열을 통해 오류의 원인을 파악 가능. 예) invalid numeric delta argument, cannot increment or decrement non-numeric value
112112
| "SERVER ERROR" | 서버 측의 오류로 연산하지 못했음을 의미. 이어 나오는 문자열을 통해 오류의 원인을 파악 가능. 예) out of memory
113+
114+
## gat/gats (get and touch)
115+
116+
gat, gats 명령은 item을 가져옴과 동시에 exptime을 재설정합니다.
117+
118+
```
119+
gat <exptime> <key>*\r\n
120+
gats <exptime> <key>*\r\n
121+
```
122+
123+
- \<key\>* - 대상 item의 key string 복수개의 key를 공백을 두고 지정할 수 있습니다.
124+
- \<exptime\> - 재설정할 expiretime 값 입니다.
125+
126+
gat 명령이 정상 수행되었을 경우, Response string 은 아래와 같이 구성된다.
127+
128+
- key hit된 아이템 정보를 모두 출력
129+
- key miss된 아이템은 별도 response 없이 생략
130+
- 응답의 끝에 "END\r\n" 출력
131+
132+
gats 명령의 경우 cas value 도 같이 출력됩니다.
133+
134+
실패시 string은 아래와 같습니다.
135+
136+
| Response String | 설명 |
137+
|----------------------|------------------------ |
138+
| "CLIENT_ERROR" | 클라이언트에서 잘못된 질의를 했음을 의미. 이어 나오는 문자열을 통해 오류의 원인을 파악 가능. 예) bad command line format
139+
| "SERVER ERROR" | 서버 측의 오류로 조회하지 못했음을 의미. 이어 나오는 문자열을 통해 오류의 원인을 파악 가능. 예) out of memory writing get response

memcached.c

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8345,11 +8345,21 @@ static void process_stats_command(conn *c, token_t *tokens, const size_t ntokens
83458345
}
83468346

83478347
/* ntokens is overwritten here... shrug.. */
8348-
static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens, bool return_cas)
8348+
static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens, bool return_cas, bool should_touch)
83498349
{
83508350
assert(c != NULL);
83518351
token_t *key_token = &tokens[KEY_TOKEN];
83528352
ENGINE_ERROR_CODE ret = ENGINE_SUCCESS;
8353+
int64_t exptime = 0;
8354+
8355+
if (should_touch) {
8356+
// For get and touch commands, use first token as exptime
8357+
if (!safe_strtoll(tokens[1].value, &exptime)) {
8358+
out_string(c, "CLIENT_ERROR invalid exptime argument");
8359+
return;
8360+
}
8361+
key_token++;
8362+
}
83538363

83548364
do {
83558365
while (key_token->length != 0) {
@@ -8362,6 +8372,19 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
83628372
if (ret != ENGINE_SUCCESS) {
83638373
break; /* ret == ENGINE_ENOMEM */
83648374
}
8375+
if (should_touch) {
8376+
ENGINE_ITEM_ATTR attr_id = ATTR_EXPIRETIME;
8377+
ENGINE_ERROR_CODE gat_ret = ENGINE_SUCCESS;
8378+
item_attr attr_data;
8379+
8380+
attr_data.exptime = realtime(exptime);
8381+
gat_ret = mc_engine.v1->setattr(mc_engine.v0, c, key_token->value, key_token->length,
8382+
&attr_id, 1, &attr_data, 0);
8383+
CONN_CHECK_AND_SET_EWOULDBLOCK(gat_ret, c);
8384+
if (settings.detail_enabled) {
8385+
stats_prefix_record_setattr(key_token->value, key_token->length);
8386+
}
8387+
}
83658388
key_token++;
83668389
}
83678390
if (ret != ENGINE_SUCCESS) break;
@@ -13124,11 +13147,19 @@ static void process_command_ascii(conn *c, char *command, int cmdlen)
1312413147

1312513148
if ((ntokens >= 3) && (strcmp(tokens[COMMAND_TOKEN].value, "get") == 0))
1312613149
{
13127-
process_get_command(c, tokens, ntokens, false);
13150+
process_get_command(c, tokens, ntokens, false, false);
1312813151
}
1312913152
else if ((ntokens >= 3) && (strcmp(tokens[COMMAND_TOKEN].value, "gets") == 0))
1313013153
{
13131-
process_get_command(c, tokens, ntokens, true);
13154+
process_get_command(c, tokens, ntokens, true, false);
13155+
}
13156+
else if ((ntokens >= 3) && (strcmp(tokens[COMMAND_TOKEN].value, "gat") == 0))
13157+
{
13158+
process_get_command(c, tokens, ntokens, false, true);
13159+
}
13160+
else if ((ntokens >= 3) && (strcmp(tokens[COMMAND_TOKEN].value, "gats") == 0))
13161+
{
13162+
process_get_command(c, tokens, ntokens, true, true);
1313213163
}
1313313164
else if ((ntokens == 4) && (strcmp(tokens[COMMAND_TOKEN].value, "mget") == 0))
1313413165
{

t/gat.t

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#!/usr/bin/perl
2+
3+
use strict;
4+
use Test::More tests =>19;
5+
use FindBin qw($Bin);
6+
use lib "$Bin/lib";
7+
use MemcachedTest;
8+
9+
my $engine = shift;
10+
my $server = get_memcached($engine);
11+
my $sock = $server->sock;
12+
13+
my $cmd;
14+
my $val;
15+
my $rst;
16+
my $expire;
17+
18+
# Initialize
19+
$cmd = "set key 0 0 5"; $val = "datum"; $rst = "STORED";
20+
mem_cmd_is($sock, $cmd, $val, $rst);
21+
$cmd = "lop create lkey 0 0 1 error"; $rst = "CREATED";
22+
mem_cmd_is($sock, $cmd, "", $rst);
23+
$cmd = "sop create skey 0 0 1 error"; $rst = "CREATED";
24+
mem_cmd_is($sock, $cmd, "", $rst);
25+
$cmd = "mop create mkey 0 0 1 error"; $rst = "CREATED";
26+
mem_cmd_is($sock, $cmd, "", $rst);
27+
$cmd = "bop create bkey 0 0 1 error"; $rst = "CREATED";
28+
mem_cmd_is($sock, $cmd, "", $rst);
29+
30+
# Success Cases
31+
# key value
32+
$cmd = "gat 1 key";
33+
$rst = "VALUE key 0 5\n"
34+
. "datum\n"
35+
. "END";
36+
mem_cmd_is($sock, $cmd, "", $rst);
37+
$cmd = "getattr key expiretime";
38+
$rst = "ATTR expiretime=1\n"
39+
. "END";
40+
mem_cmd_is($sock, $cmd, "", $rst);
41+
# gat key with KV and collection
42+
$cmd = "gat 1 key lkey skey mkey bkey";
43+
$rst = "VALUE key 0 5\n"
44+
. "datum\n"
45+
. "END";
46+
mem_cmd_is($sock, $cmd, "", $rst);
47+
$cmd = "getattr key expiretime";
48+
$rst = "ATTR expiretime=1\n"
49+
. "END";
50+
mem_cmd_is($sock, $cmd, "", $rst);
51+
$cmd = "getattr lkey expiretime";
52+
$rst = "ATTR expiretime=1\n"
53+
. "END";
54+
mem_cmd_is($sock, $cmd, "", $rst);
55+
$cmd = "getattr skey expiretime";
56+
$rst = "ATTR expiretime=1\n"
57+
. "END";
58+
mem_cmd_is($sock, $cmd, "", $rst);
59+
$cmd = "getattr mkey expiretime";
60+
$rst = "ATTR expiretime=1\n"
61+
. "END";
62+
mem_cmd_is($sock, $cmd, "", $rst);
63+
$cmd = "getattr bkey expiretime";
64+
$rst = "ATTR expiretime=1\n"
65+
. "END";
66+
mem_cmd_is($sock, $cmd, "", $rst);
67+
# gats command
68+
$cmd = "gats 1 key";
69+
$rst = "VALUE key 0 5 1\n"
70+
. "datum\n"
71+
. "END";
72+
mem_cmd_is($sock, $cmd, "", $rst);
73+
$cmd = "getattr key expiretime";
74+
$rst = "ATTR expiretime=1\n"
75+
. "END";
76+
mem_cmd_is($sock, $cmd, "", $rst);
77+
78+
# Fail Cases
79+
# bad value
80+
$cmd = "set key 0 0 5"; $val = "datum"; $rst = "STORED";
81+
mem_cmd_is($sock, $cmd, $val, $rst);
82+
$cmd = "gat str key"; $rst = "CLIENT_ERROR invalid exptime argument";
83+
mem_cmd_is($sock, $cmd, "", $rst);
84+
# not exist key
85+
$expire = time() - 1;
86+
$cmd = "gat $expire key";
87+
$rst = "VALUE key 0 5\n"
88+
. "datum\n"
89+
. "END";
90+
mem_cmd_is($sock, $cmd, "", $rst);
91+
$cmd = "gat 1 key"; $rst = "END";
92+
mem_cmd_is($sock, $cmd, "", $rst);
93+
94+
# after test
95+
release_memcached($engine, $server);

0 commit comments

Comments
 (0)