mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
Following @mattsta's friendly review:
1. memory leak in t_set.c has been fixed 2. end-of-line spaces has been removed (from all over the place) 3. for loops have been ordered up to match existing Redis style (less weird) 4. comments format has been fixed (added * in the beggining of every comment line)
This commit is contained in:
parent
e3436dd9b8
commit
d74a5a0880
38
src/intset.c
38
src/intset.c
@ -263,20 +263,17 @@ int64_t intsetRandom(intset *is) {
|
||||
|
||||
/* How many times bigger should the set length be compared to the requested
|
||||
* count of members for us to use the Floyd algorithm instead of
|
||||
the Knuth algorithm */
|
||||
* the Knuth algorithm */
|
||||
#define RANDOMMEMBERS_ALGORITHM_SELECTION_RATIO (2)
|
||||
|
||||
/* Copies 'count' random members from the set into the 'values' array.
|
||||
'values' must be an array of int64_t values, of length 'count'.
|
||||
Returns the amount of items returned. If this amount is less than 'count',
|
||||
then the remaining 'values' are left uninitialized. */
|
||||
* 'values' must be an array of int64_t values, of length 'count'.
|
||||
* Returns the amount of items returned. If this amount is less than 'count',
|
||||
* then the remaining 'values' are left uninitialized. */
|
||||
int intsetRandomMembers(intset *is, int64_t* values, int count) {
|
||||
|
||||
/* We don't check that is and values are non-NULL - the caller must
|
||||
play nice. */
|
||||
/* redisAssert(is != NULL);
|
||||
redisAssert(values != NULL);
|
||||
redisAssert(count > 0); */
|
||||
* play nice. */
|
||||
|
||||
int length = intsetLen(is);
|
||||
|
||||
@ -286,19 +283,17 @@ int intsetRandomMembers(intset *is, int64_t* values, int count) {
|
||||
}
|
||||
|
||||
/* Choose between the Knuth shuffle algorithm, O(1) space, O(length) time,
|
||||
and the Floyd algorithm, O(length) space, O(count) time. */
|
||||
* and the Floyd algorithm, O(length) space, O(count) time. */
|
||||
if ((RANDOMMEMBERS_ALGORITHM_SELECTION_RATIO * count) > length) {
|
||||
|
||||
/* If the count of members requested is almost the length of the set,
|
||||
use the Knuth shuffle algorithm, O(1) space, O(length) time. */
|
||||
* use the Knuth shuffle algorithm, O(1) space, O(length) time. */
|
||||
|
||||
/* First, fill the values array with unique random indexes inside
|
||||
the set. */
|
||||
* the set. */
|
||||
int in, im, rn, rm;
|
||||
im = 0;
|
||||
for (in = 0;
|
||||
in < length && im < count;
|
||||
in++) {
|
||||
for (in = 0; in < length && im < count; in++) {
|
||||
|
||||
rn = length - in;
|
||||
rm = count - im;
|
||||
@ -310,9 +305,9 @@ int intsetRandomMembers(intset *is, int64_t* values, int count) {
|
||||
} else {
|
||||
|
||||
/* If the length is considerably more than the count of members
|
||||
requested, use Robert Floyd's algorithm, O(length) space,
|
||||
O(count) time.
|
||||
Based on Jon Bentley's Programming Pearls */
|
||||
* requested, use Robert Floyd's algorithm, O(length) space,
|
||||
* O(count) time.
|
||||
* Based on Jon Bentley's Programming Pearls */
|
||||
|
||||
int64_t *is_used = zcalloc(sizeof(int64_t) * length);
|
||||
int in, im, r;
|
||||
@ -320,16 +315,13 @@ int intsetRandomMembers(intset *is, int64_t* values, int count) {
|
||||
r = 0;
|
||||
im = 0;
|
||||
|
||||
for (in = length - count;
|
||||
in < length && im < count;
|
||||
in++) {
|
||||
for (in = length - count; in < length && im < count; in++) {
|
||||
|
||||
/* Generate a random number r */
|
||||
r = rand() % (in + 1);
|
||||
|
||||
/* Do we already have the value in r? */
|
||||
if (is_used[r]) {
|
||||
|
||||
/* Use in instead of the generated number */
|
||||
r = in;
|
||||
}
|
||||
@ -345,9 +337,7 @@ int intsetRandomMembers(intset *is, int64_t* values, int count) {
|
||||
|
||||
/* Replace each random index with the value stored there in the intset */
|
||||
uint8_t encoding = intrev32ifbe(is->encoding);
|
||||
for (int currentValue = 0;
|
||||
currentValue < count;
|
||||
currentValue++) {
|
||||
for (int currentValue = 0; currentValue < count; currentValue++) {
|
||||
values[currentValue] =
|
||||
_intsetGetEncoded(is, values[currentValue], encoding);
|
||||
}
|
||||
|
58
src/t_set.c
58
src/t_set.c
@ -225,28 +225,30 @@ int setTypeRandomElement(robj *setobj, robj **objele, int64_t *llele) {
|
||||
* at producing N elements, and the elements are guaranteed to be non
|
||||
* repeating.
|
||||
*/
|
||||
unsigned long setTypeRandomElements(robj *set, unsigned long count, robj *aux_set) {
|
||||
unsigned long setTypeRandomElements(robj *set, unsigned long count,
|
||||
robj *aux_set) {
|
||||
unsigned long set_size;
|
||||
unsigned long elements_to_return = count;
|
||||
unsigned long elements_copied = 0;
|
||||
unsigned long current_element = 0;
|
||||
|
||||
/* Like all setType* functions, we assume good behavior on part of the caller,
|
||||
* so no extra parameter checks are made. */
|
||||
/* Like all setType* functions, we assume good behavior on part of the
|
||||
* caller, so no extra parameter checks are made. */
|
||||
|
||||
/* If the number of elements in the the set is less than the count
|
||||
requested, just return all of them. */
|
||||
* requested, just return all of them. */
|
||||
set_size = setTypeSize(set);
|
||||
if (set_size < count) {
|
||||
elements_to_return = set_size;
|
||||
}
|
||||
|
||||
/* TODO: It is definitely faster adding items to the set by directly handling the Dict
|
||||
or intset inside it, avoiding the constant encoding checks inside setTypeAdd().
|
||||
However, We don't want to touch the set internals in non setType* functions.
|
||||
So, we just call setTypeAdd() multiple times, but this isn't an optimial
|
||||
solution.
|
||||
Another option would be to create a bulk-add function: setTypeAddBulk(). */
|
||||
/* TODO: It is definitely faster adding items to the set by directly
|
||||
* handling the Dict or intset inside it, avoiding the constant encoding
|
||||
* checks inside setTypeAdd(). However, We don't want to touch the set
|
||||
* internals in non setType* functions. So, we just call setTypeAdd()
|
||||
* multiple times, but this isn't an optimal solution.
|
||||
* Another option would be to create a bulk-add function:
|
||||
* setTypeAddBulk(). */
|
||||
if (set->encoding == REDIS_ENCODING_HT) {
|
||||
/* Allocate result array */
|
||||
dictEntry **random_elements =
|
||||
@ -258,20 +260,21 @@ unsigned long setTypeRandomElements(robj *set, unsigned long count, robj *aux_se
|
||||
redisAssert(elements_copied == elements_to_return);
|
||||
|
||||
/* Put them into the set */
|
||||
for (current_element = 0;
|
||||
current_element < elements_copied;
|
||||
for (current_element = 0; current_element < elements_copied;
|
||||
current_element++) {
|
||||
|
||||
/* We get the key and duplicate it, as we know it is a string */
|
||||
setTypeAdd(aux_set,
|
||||
dupStringObject(dictGetKey(random_elements[current_element])));
|
||||
dictGetKey(random_elements[current_element]));
|
||||
}
|
||||
|
||||
zfree(random_elements);
|
||||
|
||||
} else if (set->encoding == REDIS_ENCODING_INTSET) {
|
||||
/* Allocate result array */
|
||||
int64_t *random_elements = zmalloc(sizeof(int64_t) * elements_to_return);
|
||||
int64_t *random_elements =
|
||||
zmalloc(sizeof(int64_t) * elements_to_return);
|
||||
robj* element_as_str = NULL;
|
||||
|
||||
elements_copied =
|
||||
intsetRandomMembers((intset*) set->ptr,
|
||||
@ -281,14 +284,17 @@ unsigned long setTypeRandomElements(robj *set, unsigned long count, robj *aux_se
|
||||
redisAssert(elements_copied == elements_to_return);
|
||||
|
||||
/* Put them into the set */
|
||||
for (current_element = 0;
|
||||
current_element < elements_copied;
|
||||
for (current_element = 0; current_element < elements_copied;
|
||||
current_element++) {
|
||||
|
||||
element_as_str = createStringObjectFromLongLong(
|
||||
random_elements[current_element]);
|
||||
|
||||
/* Put the values in the set */
|
||||
setTypeAdd(aux_set,
|
||||
createStringObjectFromLongLong(
|
||||
random_elements[current_element]));
|
||||
element_as_str);
|
||||
|
||||
decrRefCount(element_as_str);
|
||||
}
|
||||
|
||||
zfree(random_elements);
|
||||
@ -494,19 +500,19 @@ void spopWithCountCommand(redisClient *c) {
|
||||
}
|
||||
|
||||
/* Make sure a key with the name inputted exists, and that it's type is
|
||||
indeed a set. Otherwise, return nil */
|
||||
* indeed a set. Otherwise, return nil */
|
||||
if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk))
|
||||
== NULL || checkType(c,set,REDIS_SET)) return;
|
||||
|
||||
/* If count is zero, serve an empty multibulk ASAP to avoid special
|
||||
cases later. */
|
||||
* cases later. */
|
||||
if (count == 0) {
|
||||
addReply(c,shared.emptymultibulk);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the size of the set. It is always > 0, as empty sets get
|
||||
deleted. */
|
||||
* deleted. */
|
||||
size = setTypeSize(set);
|
||||
|
||||
/* Generate an SPOP keyspace notification */
|
||||
@ -537,13 +543,13 @@ void spopWithCountCommand(redisClient *c) {
|
||||
* of elements inside the set. */
|
||||
|
||||
/* We need an auxiliary set. Optimistically, we create a set using an
|
||||
Intset internally. */
|
||||
* Intset internally. */
|
||||
aux = createStringObjectFromLongLong(0);
|
||||
aux_set = setTypeCreate(aux);
|
||||
decrRefCount(aux);
|
||||
|
||||
/* Get the count requested of random elements from the set into our
|
||||
auxiliary set. */
|
||||
* auxiliary set. */
|
||||
elements_returned = setTypeRandomElements(set, count, aux_set);
|
||||
redisAssert(elements_returned == count);
|
||||
|
||||
@ -569,7 +575,7 @@ void spopWithCountCommand(redisClient *c) {
|
||||
}
|
||||
else if (element_encoding == REDIS_ENCODING_INTSET) {
|
||||
/* TODO: setTypeRemove() forces us to convert all of the ints
|
||||
to string... isn't there a nicer way to do this? */
|
||||
* to string... isn't there a nicer way to do this? */
|
||||
objele = createStringObjectFromLongLong(llele);
|
||||
addReplyBulk(c, objele);
|
||||
|
||||
@ -590,7 +596,7 @@ void spopWithCountCommand(redisClient *c) {
|
||||
}
|
||||
|
||||
/* Free the auxiliary set - we need it no more. */
|
||||
freeSetObject(aux_set);
|
||||
decrRefCount(aux_set);
|
||||
}
|
||||
|
||||
void spopCommand(redisClient *c) {
|
||||
@ -607,7 +613,7 @@ void spopCommand(redisClient *c) {
|
||||
}
|
||||
|
||||
/* Make sure a key with the name inputted exists, and that it's type is
|
||||
indeed a set */
|
||||
* indeed a set */
|
||||
if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
|
||||
checkType(c,set,REDIS_SET)) return;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user