server/modules/selva/module/modify.c
static int add_set_values(
    RedisModuleCtx *ctx,
    SelvaModify_Hierarchy *hierarchy,
    RedisModuleKey *alias_key,
    struct SelvaObject *obj,
    RedisModuleString *id,
    const RedisModuleString *field,
    const char *value_ptr,
    size_t value_len,
    int8_t type,
    int remove_diff
) {
    const char *ptr = value_ptr;
    int res = 0;

    if (type == SELVA_MODIFY_OP_SET_TYPE_CHAR ||
        type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE) {
        SVector new_set;

        /* Check that the value divides into elements properly. */
        if ((type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE && (value_len % SELVA_NODE_ID_SIZE)) ||
            (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE && (value_len % sizeof(double))) ||
            (type == SELVA_MODIFY_OP_SET_TYPE_LONG_LONG && (value_len % sizeof(long long)))) {
            return SELVA_EINVAL;
        }

        if (remove_diff) {
            size_t inital_size = (type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE) ? value_len / SELVA_NODE_ID_SIZE : 1;

            SVector_Init(&new_set, inital_size, SelvaSVectorComparator_RMS);
        } else {
            /* If it's empty the destroy function will just skip over. */
            memset(&new_set, 0, sizeof(new_set));
        }

        /*
         * Add missing elements to the set.
         */
        for (size_t i = 0; i < value_len; ) {
            int err;
            RedisModuleString *ref;
            const ssize_t part_len = string2rms(ctx, type, ptr, &ref);

            if (part_len < 0) {
                res = SELVA_EINVAL;
                goto string_err;
            }

            /* Add to the node object. */
            err = SelvaObject_AddStringSet(obj, field, ref);
            if (remove_diff && (err == 0 || err == SELVA_EEXIST)) {
                SVector_InsertFast(&new_set, ref);
            }
            if (err == 0) {
                RedisModule_RetainString(ctx, ref);

                /* Add to the global aliases hash. */
                if (alias_key) {
                    Selva_NodeId node_id;
                    TO_STR(id);

                    Selva_NodeIdCpy(node_id, id_str);
                    Selva_Subscriptions_DeferAliasChangeEvents(ctx, hierarchy, ref);

                    update_alias(ctx, alias_key, id, ref);
                }

                res++;
            } else if (err != SELVA_EEXIST) {
                if (alias_key) {
                    fprintf(stderr, "%s:%d: Alias update failed\n", __FILE__, __LINE__);
                } else {
                    fprintf(stderr, "%s:%d: String set field update failed\n", __FILE__, __LINE__);
                }
                res = err;
                goto string_err;
            }

            /* +1 to skip the NUL if cstring */
            const size_t skip_off = type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE ? SELVA_NODE_ID_SIZE : (size_t)part_len + (type == SELVA_MODIFY_OP_SET_TYPE_CHAR);
            if (skip_off == 0) {
                res = SELVA_EINVAL;
                goto string_err;
            }

            ptr += skip_off;
            i += skip_off;
        }

        /*
         * Remove elements that are not in new_set.
         * This makes the set in obj.field equal to the set defined by value_str.
         */
        if (remove_diff) {
            struct SelvaSetElement *set_el;
            struct SelvaSetElement *tmp;
            struct SelvaSet *objSet = SelvaObject_GetSet(obj, field);

            assert(objSet);
            SELVA_SET_RMS_FOREACH_SAFE(set_el, objSet, tmp) {
                RedisModuleString *el = set_el->value_rms;

                if (!SVector_Search(&new_set, (void *)el)) {
                    /* el doesn't exist in new_set, therefore it should be removed. */
                    SelvaSet_DestroyElement(SelvaSet_Remove(objSet, el));

                    if (alias_key) {
                        Selva_Subscriptions_DeferAliasChangeEvents(ctx, hierarchy, el);
                        RedisModule_HashSet(alias_key, REDISMODULE_HASH_NONE, el, REDISMODULE_HASH_DELETE, NULL);
                    }

                    RedisModule_FreeString(ctx, el);
                    res++; /* This too is a change to the set! */
                }
            }
        }
string_err:
        SVector_Destroy(&new_set);
    } else if (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE ||
               type == SELVA_MODIFY_OP_SET_TYPE_LONG_LONG) {
        /*
         * Add missing elements to the set.
         */
        for (size_t i = 0; i < value_len; ) {
            int err;
            size_t part_len;

            /*
             * We want to be absolutely sure that we don't hit alignment aborts
             * on any architecture even if the received data is unaligned, hence
             * we use memcpy here.
             */
            if (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE) {
                double v;

                part_len = sizeof(double);
                memcpy(&v, ptr, part_len);
                err = SelvaObject_AddDoubleSet(obj, field, v);
            } else {
                long long v;

                part_len = sizeof(long long);
                memcpy(&v, ptr, part_len);
                err = SelvaObject_AddLongLongSet(obj, field, v);
            }
            if (err == 0) {
                res++;
            } else if (err != SELVA_EEXIST) {
                fprintf(stderr, "%s:%d: Set (%s) field update failed: %s\n",
                        __FILE__, __LINE__,
                        (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE) ? "double" : "long long",
                        getSelvaErrorStr(err));
                return err;
            }

            const size_t skip_off = part_len;
            if (skip_off == 0) {
                return SELVA_EINVAL;
            }

            ptr += skip_off;
            i += skip_off;
        }

        /*
         * Remove elements that are not in new_set.
         * This makes the set in obj.field equal to the set defined by value_str.
         */
        if (remove_diff) {
            struct SelvaSetElement *set_el;
            struct SelvaSetElement *tmp;
            struct SelvaSet *objSet = SelvaObject_GetSet(obj, field);

            assert(objSet);
            if (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE && objSet->type == SELVA_SET_TYPE_DOUBLE) {
                SELVA_SET_DOUBLE_FOREACH_SAFE(set_el, objSet, tmp) {
                    int found = 0;
                    const double a = set_el->value_d;

                    /* This is probably faster than any data structure we could use. */
                    for (size_t i = 0; i < value_len; i += sizeof(double)) {
                        double b;

                        /*
                         * We use memcpy here because it's not guranteed that the
                         * array is aligned properly.
                         */
                        memcpy(&b, value_ptr + i, sizeof(double));

                        if (a == b) {
                            found = 1;
                            break;
                        }
                    }

                    if (!found) {
                        SelvaSet_DestroyElement(SelvaSet_RemoveDouble(objSet, a));
                        res++;
                    }
                }
            } else if (type == SELVA_MODIFY_OP_SET_TYPE_LONG_LONG && objSet->type == SELVA_SET_TYPE_LONGLONG) {
                SELVA_SET_LONGLONG_FOREACH_SAFE(set_el, objSet, tmp) {
                    int found = 0;
                    const long long a = set_el->value_ll;

                    /* This is probably faster than any data structure we could use. */
                    for (size_t i = 0; i < value_len; i++) {
                        long long b;

                        /*
                         * We use memcpy here because it's not guranteed that the
                         * array is aligned properly.
                         */
                        memcpy(&b, value_ptr + i, sizeof(long long));

                        if (a == b) {
                            found = 1;
                            break;
                        }
                    }

                    if (!found) {
                        SelvaSet_DestroyElement(SelvaSet_RemoveLongLong(objSet, a));
                        res++;
                    }
                }
            } else {
                abort(); /* Never reached. */
            }
        }
    } else {
        return SELVA_EINTYPE;
    }

    return res;
}
/**
 * Add all values from value_ptr to the set in obj.field.
 * @returns The number of items added; Otherwise a negative Selva error code is returned.
 */
Add all values from value_ptr to the set in obj.field.
@returns The number of items added; Otherwise a negative Selva error code is returned.
Add all values from value_ptr to the set in obj . field . @returns The number of items added ; Otherwise a negative Selva error code is returned .
static int add_set_values(
    RedisModuleCtx *ctx,
    SelvaModify_Hierarchy *hierarchy,
    RedisModuleKey *alias_key,
    struct SelvaObject *obj,
    RedisModuleString *id,
    const RedisModuleString *field,
    const char *value_ptr,
    size_t value_len,
    int8_t type,
    int remove_diff
) {
    const char *ptr = value_ptr;
    int res = 0;
    if (type == SELVA_MODIFY_OP_SET_TYPE_CHAR ||
        type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE) {
        SVector new_set;
        if ((type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE && (value_len % SELVA_NODE_ID_SIZE)) ||
            (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE && (value_len % sizeof(double))) ||
            (type == SELVA_MODIFY_OP_SET_TYPE_LONG_LONG && (value_len % sizeof(long long)))) {
            return SELVA_EINVAL;
        }
        if (remove_diff) {
            size_t inital_size = (type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE) ? value_len / SELVA_NODE_ID_SIZE : 1;
            SVector_Init(&new_set, inital_size, SelvaSVectorComparator_RMS);
        } else {
            memset(&new_set, 0, sizeof(new_set));
        }
        for (size_t i = 0; i < value_len; ) {
            int err;
            RedisModuleString *ref;
            const ssize_t part_len = string2rms(ctx, type, ptr, &ref);
            if (part_len < 0) {
                res = SELVA_EINVAL;
                goto string_err;
            }
            err = SelvaObject_AddStringSet(obj, field, ref);
            if (remove_diff && (err == 0 || err == SELVA_EEXIST)) {
                SVector_InsertFast(&new_set, ref);
            }
            if (err == 0) {
                RedisModule_RetainString(ctx, ref);
                if (alias_key) {
                    Selva_NodeId node_id;
                    TO_STR(id);
                    Selva_NodeIdCpy(node_id, id_str);
                    Selva_Subscriptions_DeferAliasChangeEvents(ctx, hierarchy, ref);
                    update_alias(ctx, alias_key, id, ref);
                }
                res++;
            } else if (err != SELVA_EEXIST) {
                if (alias_key) {
                    fprintf(stderr, "%s:%d: Alias update failed\n", __FILE__, __LINE__);
                } else {
                    fprintf(stderr, "%s:%d: String set field update failed\n", __FILE__, __LINE__);
                }
                res = err;
                goto string_err;
            }
            const size_t skip_off = type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE ? SELVA_NODE_ID_SIZE : (size_t)part_len + (type == SELVA_MODIFY_OP_SET_TYPE_CHAR);
            if (skip_off == 0) {
                res = SELVA_EINVAL;
                goto string_err;
            }
            ptr += skip_off;
            i += skip_off;
        }
        if (remove_diff) {
            struct SelvaSetElement *set_el;
            struct SelvaSetElement *tmp;
            struct SelvaSet *objSet = SelvaObject_GetSet(obj, field);
            assert(objSet);
            SELVA_SET_RMS_FOREACH_SAFE(set_el, objSet, tmp) {
                RedisModuleString *el = set_el->value_rms;
                if (!SVector_Search(&new_set, (void *)el)) {
                    SelvaSet_DestroyElement(SelvaSet_Remove(objSet, el));
                    if (alias_key) {
                        Selva_Subscriptions_DeferAliasChangeEvents(ctx, hierarchy, el);
                        RedisModule_HashSet(alias_key, REDISMODULE_HASH_NONE, el, REDISMODULE_HASH_DELETE, NULL);
                    }
                    RedisModule_FreeString(ctx, el);
                    res++; 
                }
            }
        }
string_err:
        SVector_Destroy(&new_set);
    } else if (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE ||
               type == SELVA_MODIFY_OP_SET_TYPE_LONG_LONG) {
        for (size_t i = 0; i < value_len; ) {
            int err;
            size_t part_len;
            if (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE) {
                double v;
                part_len = sizeof(double);
                memcpy(&v, ptr, part_len);
                err = SelvaObject_AddDoubleSet(obj, field, v);
            } else {
                long long v;
                part_len = sizeof(long long);
                memcpy(&v, ptr, part_len);
                err = SelvaObject_AddLongLongSet(obj, field, v);
            }
            if (err == 0) {
                res++;
            } else if (err != SELVA_EEXIST) {
                fprintf(stderr, "%s:%d: Set (%s) field update failed: %s\n",
                        __FILE__, __LINE__,
                        (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE) ? "double" : "long long",
                        getSelvaErrorStr(err));
                return err;
            }
            const size_t skip_off = part_len;
            if (skip_off == 0) {
                return SELVA_EINVAL;
            }
            ptr += skip_off;
            i += skip_off;
        }
        if (remove_diff) {
            struct SelvaSetElement *set_el;
            struct SelvaSetElement *tmp;
            struct SelvaSet *objSet = SelvaObject_GetSet(obj, field);
            assert(objSet);
            if (type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE && objSet->type == SELVA_SET_TYPE_DOUBLE) {
                SELVA_SET_DOUBLE_FOREACH_SAFE(set_el, objSet, tmp) {
                    int found = 0;
                    const double a = set_el->value_d;
                    for (size_t i = 0; i < value_len; i += sizeof(double)) {
                        double b;
                        memcpy(&b, value_ptr + i, sizeof(double));
                        if (a == b) {
                            found = 1;
                            break;
                        }
                    }
                    if (!found) {
                        SelvaSet_DestroyElement(SelvaSet_RemoveDouble(objSet, a));
                        res++;
                    }
                }
            } else if (type == SELVA_MODIFY_OP_SET_TYPE_LONG_LONG && objSet->type == SELVA_SET_TYPE_LONGLONG) {
                SELVA_SET_LONGLONG_FOREACH_SAFE(set_el, objSet, tmp) {
                    int found = 0;
                    const long long a = set_el->value_ll;
                    for (size_t i = 0; i < value_len; i++) {
                        long long b;
                        memcpy(&b, value_ptr + i, sizeof(long long));
                        if (a == b) {
                            found = 1;
                            break;
                        }
                    }
                    if (!found) {
                        SelvaSet_DestroyElement(SelvaSet_RemoveLongLong(objSet, a));
                        res++;
                    }
                }
            } else {
                abort(); 
            }
        }
    } else {
        return SELVA_EINTYPE;
    }
    return res;
}
static int add_set_values ( RedisModuleCtx * ctx , SelvaModify_Hierarchy * hierarchy , RedisModuleKey * alias_key , struct SelvaObject * obj , RedisModuleString * id , const RedisModuleString * field , const char * value_ptr , size_t value_len , int8_t type , int remove_diff ) { const char * ptr = value_ptr ; int res = 0 ; if ( type == SELVA_MODIFY_OP_SET_TYPE_CHAR || type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE ) { SVector new_set ; if ( ( type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE && ( value_len % SELVA_NODE_ID_SIZE ) ) || ( type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE && ( value_len % sizeof ( double ) ) ) || ( type == SELVA_MODIFY_OP_SET_TYPE_LONG_LONG && ( value_len % sizeof ( long long ) ) ) ) { return SELVA_EINVAL ; } if ( remove_diff ) { size_t inital_size = ( type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE ) ? value_len / SELVA_NODE_ID_SIZE : 1 ; SVector_Init ( & new_set , inital_size , SelvaSVectorComparator_RMS ) ; } else { memset ( & new_set , 0 , sizeof ( new_set ) ) ; } for ( size_t i = 0 ; i < value_len ; ) { int err ; RedisModuleString * ref ; const ssize_t part_len = string2rms ( ctx , type , ptr , & ref ) ; if ( part_len < 0 ) { res = SELVA_EINVAL ; goto string_err ; } err = SelvaObject_AddStringSet ( obj , field , ref ) ; if ( remove_diff && ( err == 0 || err == SELVA_EEXIST ) ) { SVector_InsertFast ( & new_set , ref ) ; } if ( err == 0 ) { RedisModule_RetainString ( ctx , ref ) ; if ( alias_key ) { Selva_NodeId node_id ; TO_STR ( id ) ; Selva_NodeIdCpy ( node_id , id_str ) ; Selva_Subscriptions_DeferAliasChangeEvents ( ctx , hierarchy , ref ) ; update_alias ( ctx , alias_key , id , ref ) ; } res ++ ; } else if ( err != SELVA_EEXIST ) { if ( alias_key ) { fprintf ( stderr , " \n " , __FILE__ , __LINE__ ) ; } else { fprintf ( stderr , " \n " , __FILE__ , __LINE__ ) ; } res = err ; goto string_err ; } const size_t skip_off = type == SELVA_MODIFY_OP_SET_TYPE_REFERENCE ? SELVA_NODE_ID_SIZE : ( size_t ) part_len + ( type == SELVA_MODIFY_OP_SET_TYPE_CHAR ) ; if ( skip_off == 0 ) { res = SELVA_EINVAL ; goto string_err ; } ptr += skip_off ; i += skip_off ; } if ( remove_diff ) { struct SelvaSetElement * set_el ; struct SelvaSetElement * tmp ; struct SelvaSet * objSet = SelvaObject_GetSet ( obj , field ) ; assert ( objSet ) ; SELVA_SET_RMS_FOREACH_SAFE ( set_el , objSet , tmp ) { RedisModuleString * el = set_el -> value_rms ; if ( ! SVector_Search ( & new_set , ( void * ) el ) ) { SelvaSet_DestroyElement ( SelvaSet_Remove ( objSet , el ) ) ; if ( alias_key ) { Selva_Subscriptions_DeferAliasChangeEvents ( ctx , hierarchy , el ) ; RedisModule_HashSet ( alias_key , REDISMODULE_HASH_NONE , el , REDISMODULE_HASH_DELETE , NULL ) ; } RedisModule_FreeString ( ctx , el ) ; res ++ ; } } } string_err : SVector_Destroy ( & new_set ) ; } else if ( type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE || type == SELVA_MODIFY_OP_SET_TYPE_LONG_LONG ) { for ( size_t i = 0 ; i < value_len ; ) { int err ; size_t part_len ; if ( type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE ) { double v ; part_len = sizeof ( double ) ; memcpy ( & v , ptr , part_len ) ; err = SelvaObject_AddDoubleSet ( obj , field , v ) ; } else { long long v ; part_len = sizeof ( long long ) ; memcpy ( & v , ptr , part_len ) ; err = SelvaObject_AddLongLongSet ( obj , field , v ) ; } if ( err == 0 ) { res ++ ; } else if ( err != SELVA_EEXIST ) { fprintf ( stderr , " \n " , __FILE__ , __LINE__ , ( type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE ) ? " " : " " , getSelvaErrorStr ( err ) ) ; return err ; } const size_t skip_off = part_len ; if ( skip_off == 0 ) { return SELVA_EINVAL ; } ptr += skip_off ; i += skip_off ; } if ( remove_diff ) { struct SelvaSetElement * set_el ; struct SelvaSetElement * tmp ; struct SelvaSet * objSet = SelvaObject_GetSet ( obj , field ) ; assert ( objSet ) ; if ( type == SELVA_MODIFY_OP_SET_TYPE_DOUBLE && objSet -> type == SELVA_SET_TYPE_DOUBLE ) { SELVA_SET_DOUBLE_FOREACH_SAFE ( set_el , objSet , tmp ) { int found = 0 ; const double a = set_el -> value_d ; for ( size_t i = 0 ; i < value_len ; i += sizeof ( double ) ) { double b ; memcpy ( & b , value_ptr + i , sizeof ( double ) ) ; if ( a == b ) { found = 1 ; break ; } } if ( ! found ) { SelvaSet_DestroyElement ( SelvaSet_RemoveDouble ( objSet , a ) ) ; res ++ ; } } } else if ( type == SELVA_MODIFY_OP_SET_TYPE_LONG_LONG && objSet -> type == SELVA_SET_TYPE_LONGLONG ) { SELVA_SET_LONGLONG_FOREACH_SAFE ( set_el , objSet , tmp ) { int found = 0 ; const long long a = set_el -> value_ll ; for ( size_t i = 0 ; i < value_len ; i ++ ) { long long b ; memcpy ( & b , value_ptr + i , sizeof ( long long ) ) ; if ( a == b ) { found = 1 ; break ; } } if ( ! found ) { SelvaSet_DestroyElement ( SelvaSet_RemoveLongLong ( objSet , a ) ) ; res ++ ; } } } else { abort ( ) ; } } } else { return SELVA_EINTYPE ; } return res ; }
Add all values from value_ptr to the set in obj.field.
Add all values from value_ptr to the set in obj . field .
/* Check that the value divides into elements properly. */ /* If it's empty the destroy function will just skip over. */ /*
         * Add missing elements to the set.
         */ /* Add to the node object. */ /* Add to the global aliases hash. */ /* +1 to skip the NUL if cstring */ /*
         * Remove elements that are not in new_set.
         * This makes the set in obj.field equal to the set defined by value_str.
         */ /* el doesn't exist in new_set, therefore it should be removed. */ /* This too is a change to the set! */ /*
         * Add missing elements to the set.
         */ /*
             * We want to be absolutely sure that we don't hit alignment aborts
             * on any architecture even if the received data is unaligned, hence
             * we use memcpy here.
             */ /*
         * Remove elements that are not in new_set.
         * This makes the set in obj.field equal to the set defined by value_str.
         */ /* This is probably faster than any data structure we could use. */ /*
                         * We use memcpy here because it's not guranteed that the
                         * array is aligned properly.
                         */ /* This is probably faster than any data structure we could use. */ /*
                         * We use memcpy here because it's not guranteed that the
                         * array is aligned properly.
                         */ /* Never reached. */