漫话Redis源码之九十一

stream相关操作:

#include <string.h>
#include <strings.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>

/* Command which adds a stream entry with automatic ID, like XADD *.
 *
 * Syntax: STREAM.ADD key field1 value1 [ field2 value2 ... ]
 *
 * The response is the ID of the added stream entry or an error message.
 */
int stream_add(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (argc < 2 || argc % 2 != 0) {
        RedisModule_WrongArity(ctx);
        return REDISMODULE_OK;
    }

    RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
    RedisModuleStreamID id;
    if (RedisModule_StreamAdd(key, REDISMODULE_STREAM_ADD_AUTOID, &id,
                              &argv[2], (argc-2)/2) == REDISMODULE_OK) {
        RedisModuleString *id_str = RedisModule_CreateStringFromStreamID(ctx, &id);
        RedisModule_ReplyWithString(ctx, id_str);
        RedisModule_FreeString(ctx, id_str);
    } else {
        RedisModule_ReplyWithError(ctx, "ERR StreamAdd failed");
    }
    RedisModule_CloseKey(key);
    return REDISMODULE_OK;
}

/* Command which adds a stream entry N times.
 *
 * Syntax: STREAM.ADD key N field1 value1 [ field2 value2 ... ]
 *
 * Returns the number of successfully added entries.
 */
int stream_addn(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (argc < 3 || argc % 2 == 0) {
        RedisModule_WrongArity(ctx);
        return REDISMODULE_OK;
    }

    long long n, i;
    if (RedisModule_StringToLongLong(argv[2], &n) == REDISMODULE_ERR) {
        RedisModule_ReplyWithError(ctx, "N must be a number");
        return REDISMODULE_OK;
    }

    RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
    for (i = 0; i < n; i++) {
        if (RedisModule_StreamAdd(key, REDISMODULE_STREAM_ADD_AUTOID, NULL,
                                  &argv[3], (argc-3)/2) == REDISMODULE_ERR)
            break;
    }
    RedisModule_ReplyWithLongLong(ctx, i);
    RedisModule_CloseKey(key);
    return REDISMODULE_OK;
}

/* STREAM.DELETE key stream-id */
int stream_delete(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (argc != 3) return RedisModule_WrongArity(ctx);
    RedisModuleStreamID id;
    if (RedisModule_StringToStreamID(argv[2], &id) != REDISMODULE_OK) {
        return RedisModule_ReplyWithError(ctx, "Invalid stream ID");
    }
    RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
    if (RedisModule_StreamDelete(key, &id) == REDISMODULE_OK) {
        RedisModule_ReplyWithSimpleString(ctx, "OK");
    } else {
        RedisModule_ReplyWithError(ctx, "ERR StreamDelete failed");
    }
    RedisModule_CloseKey(key);
    return REDISMODULE_OK;
}

/* STREAM.RANGE key start-id end-id
 *
 * Returns an array of stream items. Each item is an array on the form
 * [stream-id, [field1, value1, field2, value2, ...]].
 *
 * A funny side-effect used for testing RM_StreamIteratorDelete() is that if any
 * entry has a field named "selfdestruct", the stream entry is deleted. It is
 * however included in the results of this command.
 */
int stream_range(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (argc != 4) {
        RedisModule_WrongArity(ctx);
        return REDISMODULE_OK;
    }

    RedisModuleStreamID startid, endid;
    if (RedisModule_StringToStreamID(argv[2], &startid) != REDISMODULE_OK ||
        RedisModule_StringToStreamID(argv[3], &endid) != REDISMODULE_OK) {
        RedisModule_ReplyWithError(ctx, "Invalid stream ID");
        return REDISMODULE_OK;
    }

    /* If startid > endid, we swap and set the reverse flag. */
    int flags = 0;
    if (startid.ms > endid.ms ||
        (startid.ms == endid.ms && startid.seq > endid.seq)) {
        RedisModuleStreamID tmp = startid;
        startid = endid;
        endid = tmp;
        flags |= REDISMODULE_STREAM_ITERATOR_REVERSE;
    }

    /* Open key and start iterator. */
    int openflags = REDISMODULE_READ | REDISMODULE_WRITE;
    RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], openflags);
    if (RedisModule_StreamIteratorStart(key, flags,
                                        &startid, &endid) != REDISMODULE_OK) {
        /* Key is not a stream, etc. */
        RedisModule_ReplyWithError(ctx, "ERR StreamIteratorStart failed");
        RedisModule_CloseKey(key);
        return REDISMODULE_OK;
    }

    /* Check error handling: Delete current entry when no current entry. */
    assert(RedisModule_StreamIteratorDelete(key) ==
           REDISMODULE_ERR);
    assert(errno == ENOENT);

    /* Check error handling: Fetch fields when no current entry. */
    assert(RedisModule_StreamIteratorNextField(key, NULL, NULL) ==
           REDISMODULE_ERR);
    assert(errno == ENOENT);

    /* Return array. */
    RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_ARRAY_LEN);
    RedisModule_AutoMemory(ctx);
    RedisModuleStreamID id;
    long numfields;
    long len = 0;
    while (RedisModule_StreamIteratorNextID(key, &id,
                                            &numfields) == REDISMODULE_OK) {
        RedisModule_ReplyWithArray(ctx, 2);
        RedisModuleString *id_str = RedisModule_CreateStringFromStreamID(ctx, &id);
        RedisModule_ReplyWithString(ctx, id_str);
        RedisModule_ReplyWithArray(ctx, numfields * 2);
        int delete = 0;
        RedisModuleString *field, *value;
        for (long i = 0; i < numfields; i++) {
            assert(RedisModule_StreamIteratorNextField(key, &field, &value) ==
                   REDISMODULE_OK);
            RedisModule_ReplyWithString(ctx, field);
            RedisModule_ReplyWithString(ctx, value);
            /* check if this is a "selfdestruct" field */
            size_t field_len;
            const char *field_str = RedisModule_StringPtrLen(field, &field_len);
            if (!strncmp(field_str, "selfdestruct", field_len)) delete = 1;
        }
        if (delete) {
            assert(RedisModule_StreamIteratorDelete(key) == REDISMODULE_OK);
        }
        /* check error handling: no more fields to fetch */
        assert(RedisModule_StreamIteratorNextField(key, &field, &value) ==
               REDISMODULE_ERR);
        assert(errno == ENOENT);
        len++;
    }
    RedisModule_ReplySetArrayLength(ctx, len);
    RedisModule_StreamIteratorStop(key);
    RedisModule_CloseKey(key);
    return REDISMODULE_OK;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值