Skip to content

Instantly share code, notes, and snippets.

@dvirsky
Last active August 6, 2017 14:18
Show Gist options
  • Save dvirsky/79890afe580a7f239d404b84010ab5c8 to your computer and use it in GitHub Desktop.
Save dvirsky/79890afe580a7f239d404b84010ab5c8 to your computer and use it in GitHub Desktop.
/* Helloblock module -- An example of blocking command implementation
* with threads.
*
* -----------------------------------------------------------------------------
*
* Copyright (c) 2016, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "../redismodule.h"
/* Reply callback for blocking command HELLO.BLOCK */
int HelloBlock_Reply(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
struct timespec *start = RedisModule_GetBlockedClientPrivateData(ctx);
RedisModule_ReplyWithString(
ctx, RedisModule_CreateStringPrintf(
ctx, "Hello reply after %.02fms\n",
(double)((1000 * now.tv_sec + now.tv_nsec / 1000000) -
(1000 * start->tv_sec + start->tv_nsec / 1000000)))
);
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
return REDISMODULE_OK;
}
/* Timeout callback for blocking command HELLO.BLOCK */
int HelloBlock_Timeout(RedisModuleCtx *ctx, RedisModuleString **argv,
int argc) {
RedisModule_ReplyWithSimpleString(ctx, "Timeout");
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
return REDISMODULE_OK;
}
/* Private data freeing callback for HELLO.BLOCK command. */
void HelloBlock_FreeData(void *privdata) { RedisModule_Free(privdata); }
/* The thread entry point that actually executes the blocking part
* of the command HELLO.BLOCK. */
void *HelloBlock_ThreadMain(void *arg) {
RedisModuleBlockedClient *bc = arg;
// sleep(delay);
struct timespec *tm = RedisModule_Alloc(sizeof(*tm));
clock_gettime(CLOCK_REALTIME, tm);
RedisModule_UnblockClient(bc, tm);
return NULL;
}
/* HELLO.BLOCK <delay> <timeout> -- Block for <count> seconds, then reply with
* a random number. Timeout is the command timeout, so that you can test
* what happens when the delay is greater than the timeout. */
int HelloBlock_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
int argc) {
pthread_t tid;
RedisModuleBlockedClient *bc = RedisModule_BlockClient(
ctx, HelloBlock_Reply, HelloBlock_Timeout, HelloBlock_FreeData, 0);
/* Now that we setup a blocking client, we need to pass the control
* to the thread. However we need to pass arguments to the thread:
* the delay and a reference to the blocked client handle. */
if (pthread_create(&tid, NULL, HelloBlock_ThreadMain, bc) != 0) {
RedisModule_AbortBlock(bc);
return RedisModule_ReplyWithError(ctx, "-ERR Can't start thread");
}
return REDISMODULE_OK;
}
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv,
int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "helloblock", 1, REDISMODULE_APIVER_1) ==
REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "hello.block", HelloBlock_RedisCommand, "",
0, 0, 0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
return REDISMODULE_OK;
}
@rfyiamcool
Copy link

good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment