Skip to content
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

add some redis list commands #201

Merged
merged 3 commits into from
Jul 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 85 additions & 7 deletions src/data_structure/ziplist/ziplist.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ _ziplist_prev(zipentry_p ze)
return ze - *(ze - 1); /* *(ze - 1) : length of the previous entry */
}

/* do NOT call this function on the last zip entry, use ziplist_prev */
/* do NOT call this function on the last zip entry, use ziplist_next */
static inline zipentry_p
_ziplist_next(zipentry_p ze)
{
Expand Down Expand Up @@ -343,6 +343,7 @@ ziplist_remove_val(uint32_t *removed, ziplist_p zl, const struct blob *val,
zipentry_p z;
uint8_t *end;
bool forward = (count > 0);
uint32_t nrem = 0;

if (zl == NULL || val == NULL) {
return ZIPLIST_ERROR;
Expand All @@ -354,11 +355,10 @@ ziplist_remove_val(uint32_t *removed, ziplist_p zl, const struct blob *val,
}

if (count == 0) {
return ZIPLIST_EINVALID;
goto done;
}

atmost = forward ? count : -count;
*removed = 0;

/* Encoding one struct blob and follow up with many simple memcmp should be
* faster than decoding each of the zentries being compared.
Expand All @@ -372,19 +372,24 @@ ziplist_remove_val(uint32_t *removed, ziplist_p zl, const struct blob *val,
while (memcmp(z, ze_buf, MIN(end - z + 1, len)) != 0) {
if (forward) {
if (z == _ziplist_tail(zl)) {
return ZIPLIST_OK;
goto done;
}
z = _ziplist_next(z);
} else {
if (z == _ziplist_head(zl)) {
return ZIPLIST_OK;
goto done;
}
z = _ziplist_prev(z);
}
}

_ziplist_remove(zl, z, _ziplist_next(z), 1);
*removed += 1;
++nrem;
}

done:
if (removed != NULL) {
*removed = nrem;
}

return ZIPLIST_OK;
Expand All @@ -402,7 +407,7 @@ ziplist_remove(ziplist_p zl, int64_t idx, int64_t count)
}

if (count == 0) {
return ZIPLIST_EINVALID;
return ZIPLIST_OK;
}

nentry = ziplist_nentry(zl);
Expand Down Expand Up @@ -470,6 +475,79 @@ ziplist_insert(ziplist_p zl, struct blob *val, int64_t idx)
return ZIPLIST_OK;
}

ziplist_rstatus_e
ziplist_trim(ziplist_p zl, int64_t idx, int64_t count)
{
ziplist_rstatus_e status;

if (zl == NULL) {
return ZIPLIST_ERROR;
}

idx += (idx < 0) * ziplist_nentry(zl);
if (idx < 0 || idx >= ziplist_nentry(zl)) {
return ZIPLIST_EOOB;
}

if (count > 0) { /* counting forward from idx */
/* remove from begin to idx */
status = ziplist_truncate(zl, idx);
ASSERT(status == ZIPLIST_OK);

/* truncate to count entries from end */
if (count < ziplist_nentry(zl)) {
status = ziplist_truncate(zl, -(ziplist_nentry(zl) - count));
ASSERT(status == ZIPLIST_OK);
}
} else { /* counting backward from idx */
/* remove from end to idx */
status = ziplist_truncate(zl, -(ziplist_nentry(zl) - idx));
ASSERT(status == ZIPLIST_OK);

/* truncate to -count entries from beginning */
if (-count < ziplist_nentry(zl)) {
status = ziplist_truncate(zl, ziplist_nentry(zl) + count);
ASSERT(status == ZIPLIST_OK);
}
}

return ZIPLIST_OK;
}

ziplist_rstatus_e
ziplist_truncate(ziplist_p zl, int64_t count)
{
zipentry_p begin, end;
ziplist_rstatus_e status;

if (zl == NULL) {
return ZIPLIST_ERROR;
}

if (count == 0) {
return ZIPLIST_OK;
}

/* if abs(count) >= num entries in ziplist, remove all */
if (count >= ziplist_nentry(zl) || -count >= ziplist_nentry(zl)) {
return ziplist_reset(zl);
}

if (count > 0) {
begin = _ziplist_head(zl);
status = ziplist_locate(&end, zl, count);
ASSERT(status == ZIPLIST_OK);
} else {
count = -count;
end = (zipentry_p)_ziplist_end(zl) + 1;
status = ziplist_locate(&begin, zl, ziplist_nentry(zl) - count);
ASSERT(status == ZIPLIST_OK);
}

_ziplist_remove(zl, begin, end, count);
return ZIPLIST_OK;
}

ziplist_rstatus_e
ziplist_push(ziplist_p zl, struct blob *val)
{
Expand Down
16 changes: 16 additions & 0 deletions src/data_structure/ziplist/ziplist.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,22 @@ ziplist_rstatus_e ziplist_remove_val(uint32_t *removed, ziplist_p zl, const stru
* CALLER MUST MAKE SURE THERE IS ENOUGH MEMORY!!!
*/
ziplist_rstatus_e ziplist_insert(ziplist_p zl, struct blob *val, int64_t idx);
/*
* trim list down to contain at most count entries, starting at idx. a negative count means
* starting from the end, and gives a list that is non inclusive of idx.
*
* e.g.
* if list contains { 0, 1, 2, 3, 4, 5 }, and we call ziplist_trim(zl, 4, -3),
* the trimmed list will be { 1, 2, 3 }.
*
* if there are fewer than count entries, all entries starting at idx are preserved
*/
ziplist_rstatus_e ziplist_trim(ziplist_p zl, int64_t idx, int64_t count);

This comment was marked as spam.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I probably haven't thought about this carefully enough either. The most obvious benefit of ziplist_trim as currently implemented right now is it saves on one remove call if we are trimming in the middle of the list. But for other cases, it is essentially the same as remove. Having this API obviously simplifies trim commands, but I can't think of too many other uses for it at the moment.

/*
* if count is positive, remove count entries starting at the beginning
* if count is negative, remove -count entries starting at the end
*/
ziplist_rstatus_e ziplist_truncate(ziplist_p zl, int64_t count);
ziplist_rstatus_e ziplist_push(ziplist_p zl, struct blob *val); /* a shorthand for insert at idx == nentry */
/* remove tail & return, if val is NULL it is equivalent to remove at idx -1 */
ziplist_rstatus_e ziplist_pop(struct blob *val, ziplist_p zl);
Expand Down
2 changes: 1 addition & 1 deletion src/protocol/data/redis/cmd_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* List.delete KEY [VALUE [COUNT]]
*
* trim: trimming a list
* List.trim KEY INDEX [COUNT]
* List.trim KEY INDEX COUNT
*
* len: return number of entries in list
* List.len KEY
Expand Down
2 changes: 1 addition & 1 deletion src/protocol/data/redis/request.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ typedef enum cmd_type {
#undef GET_TYPE

/*
* Note: though redis supports unboudned number of variables in some commands,
* Note: though redis supports unbounded number of variables in some commands,
* implementation cannot operate with performance guarantee when this number
* gets too big. It also introduces uncertainty around resources. Therefore, we
* are limiting it to REQ_NTOKEN minus the # required args. For each command, if
Expand Down
Loading