-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
redis script command support #677
Open
lukemakeit
wants to merge
1
commit into
twitter:master
Choose a base branch
from
lukemakeit:add-script-support
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -283,6 +283,7 @@ redis_argn(const struct msg *r) | |
case MSG_REQ_REDIS_GEOSEARCHSTORE: | ||
|
||
case MSG_REQ_REDIS_RESTORE: | ||
case MSG_REQ_REDIS_SCRIPT: | ||
return true; | ||
|
||
default: | ||
|
@@ -1009,6 +1010,11 @@ redis_parse_req(struct msg *r) | |
break; | ||
} | ||
|
||
if (str6icmp(m, 's', 'c', 'r', 'i', 'p', 't')) { | ||
r->type = MSG_REQ_REDIS_SCRIPT; | ||
break; | ||
} | ||
|
||
break; | ||
|
||
case 7: | ||
|
@@ -2585,12 +2591,18 @@ redis_copy_bulk(struct msg *dst, struct msg *src) | |
} | ||
|
||
p = mbuf->pos; | ||
ASSERT(*p == '$'); | ||
// ASSERT(*p == '$'); | ||
p++; | ||
|
||
if (p[0] == '-' && p[1] == '1') { | ||
len = 1 + 2 + CRLF_LEN; /* $-1\r\n */ | ||
p = mbuf->pos + len; | ||
} else if ((mbuf->pos)[0] == ':') { | ||
for (; p < mbuf->last && isdigit(*p);) { | ||
p++; | ||
} | ||
len = (p - mbuf->pos); | ||
len += CRLF_LEN; | ||
} else { | ||
len = 0; | ||
for (; p < mbuf->last && isdigit(*p); p++) { | ||
|
@@ -2643,6 +2655,8 @@ redis_pre_coalesce(struct msg *r) | |
{ | ||
struct msg *pr = r->peer; /* peer request */ | ||
struct mbuf *mbuf; | ||
uint8_t *key; | ||
struct keypos *kpos; | ||
|
||
ASSERT(!r->request); | ||
ASSERT(pr->request); | ||
|
@@ -2653,6 +2667,9 @@ redis_pre_coalesce(struct msg *r) | |
} | ||
pr->frag_owner->nfrag_done++; | ||
|
||
kpos = array_get(pr->keys, 0); | ||
key = kpos->start; | ||
|
||
switch (r->type) { | ||
case MSG_RSP_REDIS_INTEGER: | ||
/* only redis 'del' fragmented request sends back integer reply */ | ||
|
@@ -2677,7 +2694,7 @@ redis_pre_coalesce(struct msg *r) | |
|
||
case MSG_RSP_REDIS_MULTIBULK: | ||
/* only redis 'mget' fragmented request sends back multi-bulk reply */ | ||
ASSERT(pr->type == MSG_REQ_REDIS_MGET); | ||
ASSERT(pr->type == MSG_REQ_REDIS_MGET || pr->type == MSG_REQ_REDIS_SCRIPT); | ||
|
||
mbuf = STAILQ_FIRST(&r->mhdr); | ||
/* | ||
|
@@ -2693,6 +2710,26 @@ redis_pre_coalesce(struct msg *r) | |
r->mlen -= (uint32_t)(r->narg_end - r->narg_start); | ||
mbuf->pos = r->narg_end; | ||
|
||
if (pr->type == MSG_REQ_REDIS_SCRIPT && str6icmp(key, 'e', 'x', 'i', 's', 't', 's')) { | ||
uint8_t *p; | ||
uint32_t len = 0; | ||
p = r->narg_start; | ||
ASSERT(p[0] == '*'); | ||
p++; | ||
|
||
if (p[0] == '-' && p[1] == '1') { | ||
r->frag_multibulk_len = 0; | ||
} else { | ||
for(;p < r->narg_end && isdigit(*p); p++){ | ||
len = 10*len + (uint32_t)(*p - '0'); | ||
} | ||
r->frag_multibulk_len = len; | ||
} | ||
} | ||
|
||
break; | ||
|
||
case MSG_RSP_REDIS_BULK: | ||
break; | ||
|
||
case MSG_RSP_REDIS_STATUS: | ||
|
@@ -2945,10 +2982,97 @@ redis_fragment_argx(struct msg *r, uint32_t nserver, struct msg_tqh *frag_msgq, | |
return NC_OK; | ||
} | ||
|
||
static rstatus_t redis_fragment_script(struct msg *r, struct msg_tqh *frag_msgq) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we can implement a function |
||
struct server_pool *sp = r->owner->owner; | ||
struct msg **sub_msgs; | ||
uint32_t i,n; | ||
struct mbuf *mbuf,*nbuf,*rbuf; | ||
size_t mlen; | ||
rstatus_t status; | ||
struct keypos *rkpos; | ||
uint32_t rklen; | ||
uint32_t rkey_offset; | ||
|
||
ASSERT(sp != NULL); | ||
|
||
n = array_n(&sp->server); | ||
log_debug(LOG_VVERB,"server_name: %.*s,server_count:%i",sp->name.len,sp->name.data,n); | ||
|
||
sub_msgs = nc_zalloc(n * sizeof(*sub_msgs)); | ||
if (sub_msgs == NULL) { | ||
return NC_ENOMEM; | ||
} | ||
|
||
ASSERT(r->frag_seq == NULL); | ||
r->frag_seq = nc_alloc(n * sizeof(*r->frag_seq)); | ||
if (r->frag_seq == NULL) { | ||
nc_free(sub_msgs); | ||
return NC_ENOMEM; | ||
} | ||
|
||
r->frag_id = msg_gen_frag_id(); | ||
r->nfrag = 0; | ||
r->frag_owner = r; | ||
|
||
ASSERT(array_n(r->keys)>0); | ||
rkpos=array_get(r->keys,0); // key position in original request | ||
rklen = (uint32_t)(rkpos->end - rkpos->start); // the keylen in original request | ||
rbuf = STAILQ_FIRST(&r->mhdr); | ||
if (rbuf == NULL) { | ||
return NC_ERROR; | ||
} | ||
rkey_offset = (uint32_t)(rkpos->start - rbuf->pos); // the offset of key->start from rbuf->pos | ||
|
||
for (i = 0; i < n; i++) { /* create a sub_msg for per server */ | ||
struct msg *sub_msg; | ||
uint32_t idx = i; | ||
if (sub_msgs[idx] == NULL) { | ||
sub_msgs[idx] = msg_get(r->owner, r->request, r->redis); | ||
if (sub_msgs[idx] == NULL) { | ||
nc_free(sub_msgs); | ||
return NC_ENOMEM; | ||
} | ||
} | ||
r->frag_seq[i] = sub_msg = sub_msgs[idx]; | ||
|
||
sub_msg->narg = r->narg; | ||
sub_msg->redis_script_idx = idx; | ||
//copy r->mhdr | ||
for (mbuf=STAILQ_FIRST(&r->mhdr);mbuf!=NULL;mbuf=nbuf) { | ||
nbuf=STAILQ_NEXT(mbuf,next); | ||
if(mbuf_empty(mbuf)) continue; | ||
|
||
mlen=mbuf_length(mbuf); | ||
status=msg_append(sub_msg,mbuf->pos,mlen); | ||
if (status != NC_OK) return status; | ||
} | ||
struct keypos *kpos; | ||
kpos = array_push(sub_msg->keys); | ||
if (kpos == NULL) { | ||
return NC_ENOMEM; | ||
} | ||
mbuf = STAILQ_FIRST(&sub_msg->mhdr); | ||
if (mbuf == NULL) { | ||
return NC_ERROR; | ||
} | ||
kpos->start=mbuf->pos + rkey_offset; //confirm sub_msg key position | ||
kpos->end=kpos->start + rklen; | ||
|
||
sub_msg->type = r->type; | ||
sub_msg->frag_id = r->frag_id; | ||
sub_msg->frag_owner = r->frag_owner; | ||
TAILQ_INSERT_TAIL(frag_msgq, sub_msg, m_tqe); | ||
r->nfrag++; | ||
} | ||
|
||
nc_free(sub_msgs); | ||
return NC_OK; | ||
} | ||
|
||
rstatus_t | ||
redis_fragment(struct msg *r, uint32_t nserver, struct msg_tqh *frag_msgq) | ||
{ | ||
if (1 == array_n(r->keys)){ | ||
if (1 == array_n(r->keys) && r->type != MSG_REQ_REDIS_SCRIPT){ | ||
return NC_OK; | ||
} | ||
|
||
|
@@ -2962,7 +3086,8 @@ redis_fragment(struct msg *r, uint32_t nserver, struct msg_tqh *frag_msgq) | |
/* TODO: MSETNX - instead of responding with OK, respond with 1 if all fragments respond with 1 */ | ||
case MSG_REQ_REDIS_MSET: | ||
return redis_fragment_argx(r, nserver, frag_msgq, 2); | ||
|
||
case MSG_REQ_REDIS_SCRIPT: | ||
return redis_fragment_script(r,frag_msgq); | ||
default: | ||
return NC_OK; | ||
} | ||
|
@@ -3053,6 +3178,61 @@ redis_post_coalesce_mget(struct msg *request) | |
} | ||
} | ||
|
||
static void redis_post_coalesce_script(struct msg *request) | ||
{ | ||
struct msg *response = request->peer; | ||
struct msg *sub_msg; | ||
rstatus_t status; | ||
uint32_t i,j; | ||
uint8_t *key; | ||
struct keypos *kpos; | ||
|
||
kpos = array_get(request->keys, 0); | ||
key = kpos->start; | ||
|
||
for (i = 0; i < request->nfrag; i++) { /* for each key */ | ||
sub_msg = request->frag_seq[i]->peer; /* get it's peer response */ | ||
if (sub_msg == NULL) { | ||
response->owner->err = 1; | ||
return; | ||
} | ||
/* Only one response data is retained and the rest is discarded */ | ||
if(i ==0){ | ||
if(str6icmp(key, 'e', 'x', 'i', 's', 't', 's')){ | ||
status = msg_prepend_format(response, "*%d\r\n", sub_msg->frag_multibulk_len); | ||
if (status != NC_OK) { | ||
response->owner->err = 1; | ||
return; | ||
} | ||
for(j=0;j<sub_msg->frag_multibulk_len;j++){ | ||
status = redis_copy_bulk(response, sub_msg); | ||
if (status != NC_OK) { | ||
response->owner->err = 1; | ||
return; | ||
} | ||
} | ||
}else{ | ||
status = redis_copy_bulk(response, sub_msg); | ||
} | ||
}else{ | ||
if(str6icmp(key, 'e', 'x', 'i', 's', 't', 's')){ | ||
for(j=0;j<sub_msg->frag_multibulk_len;j++){ | ||
status = redis_copy_bulk(NULL, sub_msg); | ||
if (status != NC_OK) { | ||
response->owner->err = 1; | ||
return; | ||
} | ||
} | ||
}else{ | ||
status = redis_copy_bulk(NULL, sub_msg); | ||
} | ||
} | ||
if (status != NC_OK) { | ||
response->owner->err = 1; | ||
return; | ||
} | ||
} | ||
} | ||
/* | ||
* Post-coalesce handler is invoked when the message is a response to | ||
* the fragmented multi vector request - 'mget' or 'del' and all the | ||
|
@@ -3083,6 +3263,9 @@ redis_post_coalesce(struct msg *r) | |
case MSG_REQ_REDIS_MSET: | ||
return redis_post_coalesce_mset(r); | ||
|
||
case MSG_REQ_REDIS_SCRIPT: | ||
return redis_post_coalesce_script(r); | ||
|
||
default: | ||
NOT_REACHED(); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a member named
server_index
instruct msg
. If the value is >=0, usemsg->server_index
as target server index. In this way, we don't needredis_script_idx
andscan_server_idx
at all.