コード例 #1
0
ファイル: async.c プロジェクト: bugou/test
void redisProcessCallbacks(redisAsyncContext *ac) {
    redisContext *c = &(ac->c);
    redisCallback cb = {NULL, NULL, NULL};
    void *reply = NULL;
    int status;

    while((status = redisGetReply(c,&reply)) == REDIS_OK) {
        if (reply == NULL) {
            /* When the connection is being disconnected and there are
             * no more replies, this is the cue to really disconnect. */
            if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0) {
                __redisAsyncDisconnect(ac);
                return;
            }

            /* If monitor mode, repush callback */
            if(c->flags & REDIS_MONITORING) {
                __redisPushCallback(&ac->replies,&cb);
            }

            /* When the connection is not being disconnected, simply stop
             * trying to get replies and wait for the next loop tick. */
            break;
        }

        /* Even if the context is subscribed, pending regular callbacks will
         * get a reply before pub/sub messages arrive. */
        if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) {
            /*
             * A spontaneous reply in a not-subscribed context can be the error
             * reply that is sent when a new connection exceeds the maximum
             * number of allowed connections on the server side.
             *
             * This is seen as an error instead of a regular reply because the
             * server closes the connection after sending it.
             *
             * To prevent the error from being overwritten by an EOF error the
             * connection is closed here. See issue #43.
             *
             * Another possibility is that the server is loading its dataset.
             * In this case we also want to close the connection, and have the
             * user wait until the server is ready to take our request.
             */
            if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) {
                c->err = REDIS_ERR_OTHER;
                snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str);
                c->reader->fn->freeObject(reply);
                __redisAsyncDisconnect(ac);
                return;
            }
            /* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */
            assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING));
            if(c->flags & REDIS_SUBSCRIBED)
                __redisGetSubscribeCallback(ac,reply,&cb);
        }

        if (cb.fn != NULL) {
            __redisRunCallback(ac,&cb,reply);
            c->reader->fn->freeObject(reply);

            /* Proceed with free'ing when redisAsyncFree() was called. */
            if (c->flags & REDIS_FREEING) {
                __redisAsyncFree(ac);
                return;
            }
        } else {
            /* No callback for this reply. This can either be a NULL callback,
             * or there were no callbacks to begin with. Either way, don't
             * abort with an error, but simply ignore it because the client
             * doesn't know what the server will spit out over the wire. */
            c->reader->fn->freeObject(reply);
        }
    }

    /* Disconnect when there was an error reading the reply */
    if (status != REDIS_OK)
        __redisAsyncDisconnect(ac);
}
コード例 #2
0
static int  LogFileWriteRedis(LogFileCtx *file_ctx, const char *string, size_t string_len)
{
    if (file_ctx->redis == NULL) {
        SCConfLogReopenRedis(file_ctx);
        if (file_ctx->redis == NULL) {
            return -1;
        } else {
            SCLogInfo("Reconnected to redis server");
        }
    }
    /* TODO go async here ? */
    if (file_ctx->redis_setup.batch_size) {
        redisAppendCommand(file_ctx->redis, "%s %s %s",
                file_ctx->redis_setup.command,
                file_ctx->redis_setup.key,
                string);
        if (file_ctx->redis_setup.batch_count == file_ctx->redis_setup.batch_size) {
            redisReply *reply;
            int i;
            file_ctx->redis_setup.batch_count = 0;
            for (i = 0; i <= file_ctx->redis_setup.batch_size; i++) {
                if (redisGetReply(file_ctx->redis, (void **)&reply) == REDIS_OK) {
                    freeReplyObject(reply);
                } else {
                    if (file_ctx->redis->err) {
                        SCLogInfo("Error when fetching reply: %s (%d)",
                                file_ctx->redis->errstr,
                                file_ctx->redis->err);
                    }
                    switch (file_ctx->redis->err) {
                        case REDIS_ERR_EOF:
                        case REDIS_ERR_IO:
                            SCLogInfo("Reopening connection to redis server");
                            SCConfLogReopenRedis(file_ctx);
                            if (file_ctx->redis) {
                                SCLogInfo("Reconnected to redis server");
                                return 0;
                            } else {
                                SCLogInfo("Unable to reconnect to redis server");
                                return 0;
                            }
                            break;
                        default:
                            SCLogWarning(SC_ERR_INVALID_VALUE,
                                    "Unsupported error code %d",
                                    file_ctx->redis->err);
                            return 0;
                    }
                }
            }
        } else {
            file_ctx->redis_setup.batch_count++;
        }
    } else {
        redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s",
                file_ctx->redis_setup.command,
                file_ctx->redis_setup.key,
                string);

        switch (reply->type) {
            case REDIS_REPLY_ERROR:
                SCLogWarning(SC_ERR_SOCKET, "Redis error: %s", reply->str);
                SCConfLogReopenRedis(file_ctx);
                break;
            case REDIS_REPLY_INTEGER:
                SCLogDebug("Redis integer %lld", reply->integer);
                break;
            default:
                SCLogError(SC_ERR_INVALID_VALUE,
                        "Redis default triggered with %d", reply->type);
                SCConfLogReopenRedis(file_ctx);
                break;
        }
        freeReplyObject(reply);
    }
    return 0;
}
コード例 #3
0
void doTest()  
{  
    int timeout = 10000;  
    struct timeval tv;  
    tv.tv_sec = timeout / 1000;  
    tv.tv_usec = timeout * 1000;  

    //以带有超时的方式链接Redis服务器,同时获取与Redis连接的上下文对象。  
    //该对象将用于其后所有与Redis操作的函数。  
    redisContext* c = redisConnect((char*)"10.10.10.114", 6379);  
    if (c->err) {  
        redisFree(c);  
        return;  
    }  
    const char* command1 = "set stest1 value9";  
    redisReply* r = (redisReply*)redisCommand(c,command1);  
    //需要注意的是,如果返回的对象是NULL,则表示客户端和服务器之间出现严重错误,必须重新链接。  
    //这里只是举例说明,简便起见,后面的命令就不再做这样的判断了。  
    if (NULL == r) {  
        redisFree(c);  
        return;  
    }  

    //不同的Redis命令返回的数据类型不同,在获取之前需要先判断它的实际类型。  
    //至于各种命令的返回值信息,可以参考Redis的官方文档,或者查看该系列博客的前几篇  
    //有关Redis各种数据类型的博客。:)  
    //字符串类型的set命令的返回值的类型是REDIS_REPLY_STATUS,然后只有当返回信息是"OK"  
    //时,才表示该命令执行成功。后面的例子以此类推,就不再过多赘述了。  
    if (!(r->type == REDIS_REPLY_STATUS && strcasecmp(r->str,"OK") == 0)) {  
        printf("Failed to execute command[%s].\n",command1);  
        freeReplyObject(r);  
        redisFree(c);  
        return;  
    }  
    //由于后面重复使用该变量,所以需要提前释放,否则内存泄漏。  
    freeReplyObject(r);  
    printf("Succeed to execute command[%s].\n",command1);  

    const char* command2 = "strlen stest1";  
    r = (redisReply*)redisCommand(c,command2);  
    if (r->type != REDIS_REPLY_INTEGER) {  
        printf("Failed to execute command[%s].\n",command2);  
        freeReplyObject(r);  
        redisFree(c);  
        return;  
    }  
    int length = r->integer;  
    freeReplyObject(r);  
    printf("The length of 'stest1' is %d.\n",length);  
    printf("Succeed to execute command[%s].\n",command2);  

    const char* command3 = "get stest1";  
    r = (redisReply*)redisCommand(c,command3);  
    if (r->type != REDIS_REPLY_STRING) {  
        printf("Failed to execute command[%s].\n",command3);  
        freeReplyObject(r);  
        redisFree(c);  
        return;  
    }  
    printf("The value of 'stest1' is %s.\n",r->str);  
    freeReplyObject(r);  
    printf("Succeed to execute command[%s].\n",command3);  

    const char* command4 = "get stest2";  
    r = (redisReply*)redisCommand(c,command4);  
    //这里需要先说明一下,由于stest2键并不存在,因此Redis会返回空结果,这里只是为了演示。  
    if (r->type != REDIS_REPLY_NIL) {  
        printf("Failed to execute command[%s].\n",command4);  
        freeReplyObject(r);  
        redisFree(c);  
        return;  
    }  
    freeReplyObject(r);  
    printf("Succeed to execute command[%s].\n",command4);  

    const char* command5 = "mget stest1 stest2";  
    r = (redisReply*)redisCommand(c,command5);  
    //不论stest2存在与否,Redis都会给出结果,只是第二个值为nil。  
    //由于有多个值返回,因为返回应答的类型是数组类型。  
    if (r->type != REDIS_REPLY_ARRAY) {  
        printf("Failed to execute command[%s].\n",command5);  
        freeReplyObject(r);  
        redisFree(c);  
        //r->elements表示子元素的数量,不管请求的key是否存在,该值都等于请求是键的数量。  
        assert(2 == r->elements);  
        return;  
    }  
    int i;  
    for (i = 0; i < r->elements; ++i) {  
        redisReply* childReply = r->element[i];  
        //之前已经介绍过,get命令返回的数据类型是string。  
        //对于不存在key的返回值,其类型为REDIS_REPLY_NIL。  
        if (childReply->type == REDIS_REPLY_STRING)  
            printf("The value is %s.\n",childReply->str);  
    }  
    //对于每一个子应答,无需使用者单独释放,只需释放最外部的redisReply即可。  
    freeReplyObject(r);  
    printf("Succeed to execute command[%s].\n",command5);  

    printf("Begin to test pipeline.\n");  
    //该命令只是将待发送的命令写入到上下文对象的输出缓冲区中,直到调用后面的  
    //redisGetReply命令才会批量将缓冲区中的命令写出到Redis服务器。这样可以  
    //有效的减少客户端与服务器之间的同步等候时间,以及网络IO引起的延迟。  
    //至于管线的具体性能优势,可以考虑该系列博客中的管线主题。  
    /* if (REDIS_OK != redisAppendCommand(c,command1) 
       || REDIS_OK != redisAppendCommand(c,command2) 
       || REDIS_OK != redisAppendCommand(c,command3) 
       || REDIS_OK != redisAppendCommand(c,command4) 
       || REDIS_OK != redisAppendCommand(c,command5)) { 
       redisFree(c); 
       return; 
       } 
       */  

    redisAppendCommand(c,command1);  
    redisAppendCommand(c,command2);  
    redisAppendCommand(c,command3);  
    redisAppendCommand(c,command4);  
    redisAppendCommand(c,command5);  
    redisReply* reply = NULL;  
    //对pipeline返回结果的处理方式,和前面代码的处理方式完全一直,这里就不再重复给出了。  
    if (REDIS_OK != redisGetReply(c,(void**)&reply)) {  
        printf("Failed to execute command[%s] with Pipeline.\n",command1);  
        freeReplyObject(reply);  
        redisFree(c);  
    }  
    freeReplyObject(reply);  
    printf("Succeed to execute command[%s] with Pipeline.\n",command1);  

    if (REDIS_OK != redisGetReply(c,(void**)&reply)) {  
        printf("Failed to execute command[%s] with Pipeline.\n",command2);  
        freeReplyObject(reply);  
        redisFree(c);  
    }  
    freeReplyObject(reply);  
    printf("Succeed to execute command[%s] with Pipeline.\n",command2);  

    if (REDIS_OK != redisGetReply(c,(void**)&reply)) {  
        printf("Failed to execute command[%s] with Pipeline.\n",command3);  
        freeReplyObject(reply);  
        redisFree(c);  
    }  
    freeReplyObject(reply);  
    printf("Succeed to execute command[%s] with Pipeline.\n",command3);  

    if (REDIS_OK != redisGetReply(c,(void**)&reply)) {  
        printf("Failed to execute command[%s] with Pipeline.\n",command4);  
        freeReplyObject(reply);  
        redisFree(c);  
    }  
    freeReplyObject(reply);  
    printf("Succeed to execute command[%s] with Pipeline.\n",command4);  

    if (REDIS_OK != redisGetReply(c,(void**)&reply)) {  
        printf("Failed to execute command[%s] with Pipeline.\n",command5);  
        freeReplyObject(reply);  
        redisFree(c);  
    }  
    freeReplyObject(reply);  
    printf("Succeed to execute command[%s] with Pipeline.\n",command5);  
    //由于所有通过pipeline提交的命令结果均已为返回,如果此时继续调用redisGetReply,  
    //将会导致该函数阻塞并挂起当前线程,直到有新的通过管线提交的命令结果返回。  
    //最后不要忘记在退出前释放当前连接的上下文对象。  
    redisFree(c);  
    return;  
}
コード例 #4
0
// 这其实是一个回调函数,会作为参数传入另外一个函数中
static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
    client c = privdata;
    void *reply = NULL;
    REDIS_NOTUSED(el);
    REDIS_NOTUSED(fd);
    REDIS_NOTUSED(mask);

    /* Calculate latency only for the first read event. This means that the
     * server already sent the reply and we need to parse it. Parsing overhead
     * is not part of the latency, so calculate it only once, here. */
    // 计算延时,然后比较延时,取得第一个read的event事件
    if (c->latency < 0) c->latency = ustime()-(c->start);

    if (redisBufferRead(c->context) != REDIS_OK) {
        // 首先判断是否能读
        fprintf(stderr,"Error: %s\n",c->context->errstr);
        exit(1);
    } else {
        while(c->pending) {
            if (redisGetReply(c->context,&reply) != REDIS_OK) {
                fprintf(stderr,"Error: %s\n",c->context->errstr);
                exit(1);
            }
            if (reply != NULL) {
                if (reply == (void*)REDIS_REPLY_ERROR) {
                    // 如果获取reply回复出错,也会直接退出
                    fprintf(stderr,"Unexpected error reply, exiting...\n");
                    exit(1);
                }

                freeReplyObject(reply);
                /* This is an OK for prefix commands such as auth and select.*/
                if (c->prefix_pending > 0) {
                    c->prefix_pending--;
                    // 执行到这里,请求已经执行成功,等待的请求数-1
                    c->pending--;
                    /* Discard prefix commands on first response.*/
                    if (c->prefixlen > 0) {
                        size_t j;
                        sdsrange(c->obuf, c->prefixlen, -1);
                        /* We also need to fix the pointers to the strings
                        * we need to randomize. */
                        for (j = 0; j < c->randlen; j++)
                            c->randptr[j] -= c->prefixlen;
                        c->prefixlen = 0;
                    }
                    continue;
                }

                if (config.requests_finished < config.requests)
                    config.latency[config.requests_finished++] = c->latency;
                c->pending--;
                // 全部处理完毕,调用客户端done完成后的方法
                if (c->pending == 0) {
                    clientDone(c);
                    break;
                }
            } else {
                break;
            }
        }
    }
}
コード例 #5
0
//-------------------------------------------------------------------------------------
bool DBInterfaceRedis::getQueryReply(redisReply **pRedisReply)
{
	return redisGetReply(pRedisContext_, (void**)pRedisReply) == REDIS_OK;
}
コード例 #6
0
void* publishThreadFunc(void* args)
{
  RedisManager* redisMgr = (RedisManager*)args;
  redisContext* c = redisMgr->pubContext;
  redisReply* r;
  pthread_mutex_t* pubMutex = &(redisMgr->pubMutex);
  pthread_cond_t* pubCond = &(redisMgr->pubCond);
  list<DataPacket*>* pubList = &(redisMgr->pubList);

  DataPacket* data;
  int pktCount = 0;

  while (true)
  {
    pthread_mutex_lock(pubMutex);
    if (pubList->size() == 0)
    {
      // no data for now, wait
      pthread_cond_wait(pubCond, pubMutex);
      if (pubList->size() != 0)
      {
        data = pubList->front();
        pubList->pop_front();
        pthread_mutex_unlock(pubMutex);

        if (data->success)
          redisAppendCommand(c, "PUBLISH %s %s", redisMgr->config->dataBypassChannel, data->payload);
        else
          redisAppendCommand(c, "PUBLISH %s %s", redisMgr->config->dataOutputChannel, data->payload);
      }
    }
    else
    {
      // there's data, go ahead
      data = pubList->front();
      pubList->pop_front();
      pthread_mutex_unlock(pubMutex);

      if (data->success)
        redisAppendCommand(c, "PUBLISH %s %s", redisMgr->config->dataBypassChannel, data->payload);
      else
        redisAppendCommand(c, "PUBLISH %s %s", redisMgr->config->dataOutputChannel, data->payload);
    }

    // clear memory
    //free(data->payload);
    //free(data);

    // Pipelining
    pktCount++;
    if (pktCount >= sysConf->batchSize)
    {
      for (int i=0; i<pktCount; i++)
      {
        redisGetReply(c, (void**)&r);
        freeReplyObject(r);
      }

      pktCount = 0;
    }
  }

  // TO DO : exit pub thread safely

  return NULL;
}
コード例 #7
0
ファイル: redis_client.c プロジェクト: shenya/kamailio
int redisc_exec_pipelined(redisc_server_t *rsrv)
{
	redisc_reply_t *rpl;
	int i;

	LM_DBG("redis server: %.*s\n", rsrv->sname->len,rsrv->sname->s);

	/* if server is disabled do nothing unless the disable time has passed */
	if (redis_check_server(rsrv))
	{
		goto srv_disabled;
	}

	if (rsrv->piped.pending_commands == 0)
	{
		LM_WARN("call for redis_cmd without any pipelined commands\n");
		return -1;
	}
	if(rsrv->ctxRedis==NULL)
	{
		LM_ERR("no redis context for server: %.*s\n", rsrv->sname->len,rsrv->sname->s);
		goto error_exec;
	}

	/* send the commands and retrieve the first reply */
	rpl=rsrv->piped.replies[0];

	if(rpl->rplRedis!=NULL)
	{
		/* clean up previous redis reply */
		freeReplyObject(rpl->rplRedis);
		rpl->rplRedis = NULL;
	}

	redisc_create_pipelined_message(rsrv);
	redisGetReply(rsrv->ctxRedis, (void**) &rpl->rplRedis);

	if (rpl->rplRedis == NULL)
	{
		/* null reply, reconnect and try again */
		if (rsrv->ctxRedis->err)
		{
			LM_ERR("Redis error: %s\n", rsrv->ctxRedis->errstr);
		}
		if (redisc_create_pipelined_message(rsrv) == 0)
		{
			redisGetReply(rsrv->ctxRedis, (void**) &rpl->rplRedis);
			if (rpl->rplRedis == NULL)
			{
				redis_count_err_and_disable(rsrv);
				LM_ERR("Unable to read reply\n");
				goto error_exec;
			}
		}
		else
		{
			redis_count_err_and_disable(rsrv);
			goto error_exec;
		}
	}
	LM_DBG("reply is [%s]",rpl->rplRedis->str);

	/* replies are received just retrieve them */
	for (i=1;i<rsrv->piped.pending_commands;i++)
	{
		rpl=rsrv->piped.replies[i];
		if(rpl->rplRedis!=NULL)
		{
			/* clean up previous redis reply */
			freeReplyObject(rpl->rplRedis);
			rpl->rplRedis = NULL;
		}
		if (redisGetReplyFromReader(rsrv->ctxRedis, (void**) &rpl->rplRedis) != REDIS_OK)
		{
			LM_ERR("Unable to read reply\n");
			continue;
		}
		LM_DBG("reply is [%s]",rpl->rplRedis->str);
	}
	redisc_free_pipelined_cmds(rsrv);
	rsrv->disable.consecutive_errors = 0;
	return 0;

error_exec:
	redisc_free_pipelined_cmds(rsrv);
	return -1;

srv_disabled:
	redisc_free_pipelined_cmds(rsrv);
	return -2;
}
コード例 #8
0
ファイル: redis-cli.c プロジェクト: cycker/redis26
static int cliReadReply(int output_raw_strings) {
    void *_reply;
    redisReply *reply;
    sds out = NULL;
    int output = 1;

    if (redisGetReply(context,&_reply) != REDIS_OK) {
        if (config.shutdown)
            return REDIS_OK;
        if (config.interactive) {
            /* Filter cases where we should reconnect */
            if (context->err == REDIS_ERR_IO && errno == ECONNRESET)
                return REDIS_ERR;
            if (context->err == REDIS_ERR_EOF)
                return REDIS_ERR;
        }
        cliPrintContextError();
        exit(1);
        return REDIS_ERR; /* avoid compiler warning */
    }

    reply = (redisReply*)_reply;

    /* Check if we need to connect to a different node and reissue the
     * request. */
    if (config.cluster_mode && reply->type == REDIS_REPLY_ERROR &&
        (!strncmp(reply->str,"MOVED",5) || !strcmp(reply->str,"ASK")))
    {
        char *p = reply->str, *s;
        int slot;

        output = 0;
        /* Comments show the position of the pointer as:
         *
         * [S] for pointer 's'
         * [P] for pointer 'p'
         */
        s = strchr(p,' ');      /* MOVED[S]3999 127.0.0.1:6381 */
        p = strchr(s+1,' ');    /* MOVED[S]3999[P]127.0.0.1:6381 */
        *p = '\0';
        slot = atoi(s+1);
        s = strchr(p+1,':');    /* MOVED 3999[P]127.0.0.1[S]6381 */
        *s = '\0';
        sdsfree(config.hostip);
        config.hostip = sdsnew(p+1);
        config.hostport = atoi(s+1);
        if (config.interactive)
            printf("-> Redirected to slot [%d] located at %s:%d\n",
                slot, config.hostip, config.hostport);
        config.cluster_reissue_command = 1;
    }

    if (output) {
        if (output_raw_strings) {
            out = cliFormatReplyRaw(reply);
        } else {
            if (config.output == OUTPUT_RAW) {
                out = cliFormatReplyRaw(reply);
                out = sdscat(out,"\n");
            } else if (config.output == OUTPUT_STANDARD) {
                out = cliFormatReplyTTY(reply,"");
            } else if (config.output == OUTPUT_CSV) {
                out = cliFormatReplyCSV(reply);
                out = sdscat(out,"\n");
            }
        }
        fwrite(out,sdslen(out),1,stdout);
        sdsfree(out);
    }
    freeReplyObject(reply);
    return REDIS_OK;
}
コード例 #9
0
bool QTSServerInterface::RedisGetBestRms(string& strRmsIP,string& strRmsPort)//获得当前录像数最小的RMS
{
	//算法描述:获取RMS列表,然后获取每一个RMS的存活信息和正在录像个数
	OSMutexLocker mutexLock(&fRedisMutex);

	if(!ConRedis())
		return false;

	bool bReVal=true;
	char chTemp[128]={0};
	sprintf(chTemp,"smembers RMSName");

	redisReply* reply = (redisReply*)redisCommand(fRedisCon,chTemp);//获得EsayDarWin列表
	if (NULL == reply)//错误,需要进行重连
	{
		redisFree(fRedisCon);
		fIfConSucess=false;
		return false;
	}

	if(reply->elements>0&&reply->type==REDIS_REPLY_ARRAY)//smembers返回的是数组
	{
		//这里可以使用管线
		redisReply* childReply=NULL;
		for(size_t i=0;i<reply->elements;i++)//对于每一个EasyDarWin判断其存活性和RTP属性
		{
			childReply		=	reply->element[i];
			string strChileReply(childReply->str);

			sprintf(chTemp,"exists %s",(strChileReply+"_Live").c_str());//判断RMSn是否存活
			if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			{
				freeReplyObject(reply);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}

			sprintf(chTemp,"hget %s %s",(strChileReply+"_Info").c_str(),"RecordingCount");//获取RMS当前录像个数
			if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			{
				freeReplyObject(reply);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}
		}

		int key=-1,keynum=0;
		redisReply *reply2=NULL,*reply3=NULL;
		for(size_t i=0;i<reply->elements;i++)
		{
			if(redisGetReply(fRedisCon,(void**)&reply2)!=REDIS_OK)
			{
				freeReplyObject(reply);
				freeReplyObject(reply2);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}

			if(redisGetReply(fRedisCon,(void**)&reply3)!=REDIS_OK)
			{
				freeReplyObject(reply);
				freeReplyObject(reply3);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}

			if(reply2->type==REDIS_REPLY_INTEGER&&reply2->integer==1&&
				reply3->type==REDIS_REPLY_STRING)//如果filed对应的value存在,返回REDIS_REPLY_STRING,否则返回REDIS_REPLY_NIL
			{//找到了
				int RecordingNum=atoi(reply3->str);
				if(key==-1)
				{
					key=i;
					keynum=RecordingNum;
				}
				else
				{
					if(RecordingNum<keynum)//找到更好的了
					{
						key=i;
						keynum=RecordingNum;
					}
				}
			}
			freeReplyObject(reply2);
			freeReplyObject(reply3);
		}
		if(key==-1)//没有存活的
		{
			bReVal=false;
		}
		else
		{
			string strIpPort(reply->element[key]->str);
			int ipos	=		strIpPort.find(':');//错误判断
			strRmsIP	=		strIpPort.substr(0,ipos);
			strRmsPort	=		strIpPort.substr(ipos+1,strIpPort.size()-ipos-1);
		}
	}
	else//没有可用的EasyDarWin
	{
		bReVal=false;
	}
	freeReplyObject(reply);
	return bReVal;
}
コード例 #10
0
bool QTSServerInterface::RedisInit()//连接redis成功之后调用该函数执行一些初始化的工作
{
	//每一次与redis连接后,都应该清除上一次的数据存储,使用覆盖或者直接清除的方式,串行命令使用管线更加高效
	char chTemp[128]={0};
	char chPassword[]="~ziguangwulian~iguangwulian~guangwulian~uangwulian";
	do 
	{
		//1,redis密码认证
		sprintf(chTemp,"auth %s",chPassword);
		if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			break;

		//2,CMS唯一信息存储(覆盖上一次的存储)
		sprintf(chTemp,"sadd CMSName %s:%d",fCMSIP.c_str(),fCMSPort);
		if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			break;

		//3,CMS属性存储,设置多个filed使用hmset,单个使用hset(覆盖上一次的存储)
		sprintf(chTemp,"hmset %s:%d_Info IP %s PORT %d",fCMSIP.c_str(),fCMSPort,fCMSIP.c_str(),fCMSPort);
		if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			break;
		//4,清除设备名称存储,因为连接之前和连接之后的设备可能一斤该发生了变化,因此必须先执行清楚操作
		sprintf(chTemp,"del %s:%d_DevName",fCMSIP.c_str(),fCMSPort);
		if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			break;

		OSMutex *mutexMap=fDeviceMap.GetMutex();
		OSHashMap  *deviceMap=fDeviceMap.GetMap();
		OSRefIt itRef;
		string strAllDevices;
		mutexMap->Lock();
		for(itRef=deviceMap->begin();itRef!=deviceMap->end();itRef++)
		{
			strDevice *deviceInfo=(((HTTPSessionInterface*)(itRef->second->GetObjectPtr()))->GetDeviceInfo());
			strAllDevices=strAllDevices+' '+deviceInfo->serial_;
		}
		mutexMap->Unlock();

		char *chNewTemp=new char[strAllDevices.size()+128];//注意,这里不能再使用chTemp,因为长度不确定,可能导致缓冲区溢出
		//5,设备名称存储
		sprintf(chNewTemp,"sadd %s:%d_DevName%s",fCMSIP.c_str(),fCMSPort,strAllDevices.c_str());
		if(redisAppendCommand(fRedisCon,chNewTemp)!=REDIS_OK)
		{
			delete[] chNewTemp;
			break;
		}
		delete[] chNewTemp;

		//6,保活,设置15秒,这之后当前CMS已经开始提供服务了
		sprintf(chTemp,"setex %s:%d_Live 15 1",fCMSIP.c_str(),fCMSPort);
		if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			break;

		bool bBreak=false;
		redisReply* reply = NULL;
		for(int i=0;i<6;i++)
		{
			if(REDIS_OK != redisGetReply(fRedisCon,(void**)&reply))
			{
				bBreak=true;
				freeReplyObject(reply);
				break;
			}
			freeReplyObject(reply);
		}
		if(bBreak)//说明redisGetReply出现了错误
			break;
		return true;
	} while (0);
	//走到这说明出现了错误,需要进行重连,重连操作再下一次执行命令时进行,在这仅仅是置标志位
	redisFree(fRedisCon);
	fIfConSucess=false;
	
	return false;
}
コード例 #11
0
bool QTSServerInterface::RedisGetAssociatedRms(string& strDeviceSerial,string &strCameraSerial,string& strRmsIP,string& strRmsPort)//获得与当前设备序列号和摄像头序列号关联的RMS
{
	//算法描述,获得RMS列表,对于每一个RMS判断其是否存活,如果存活,查找正在录像设备列表
	OSMutexLocker mutexLock(&fRedisMutex);

	if(!ConRedis())
		return false;

	bool bReVal=false;
	string strRecordingDevName=strDeviceSerial+'_'+strCameraSerial;//设备序列号_摄像头序列号
	char chTemp[128]={0};
	sprintf(chTemp,"smembers RMSName");

	redisReply* reply = (redisReply*)redisCommand(fRedisCon,chTemp);//获得RMS列表
	if (NULL == reply)//错误,需要进行重连
	{
		redisFree(fRedisCon);
		fIfConSucess=false;
		return false;
	}

	if(reply->elements>0&&reply->type==REDIS_REPLY_ARRAY)//smembers返回的是数组
	{
		//这里可以使用管线
		redisReply* childReply=NULL;
		for(size_t i=0;i<reply->elements;i++)//对于每一个RMS判断其存活性和(指定设备序列号和摄像头序列号)是否关联
		{
			childReply		=	reply->element[i];
			string strChileReply(childReply->str);

			sprintf(chTemp,"exists %s",(strChileReply+"_Live").c_str());//判断RMS是否存活
			if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			{
				freeReplyObject(reply);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}

			sprintf(chTemp,"sismember %s %s",(strChileReply+"_RecordingDevName").c_str(),strRecordingDevName.c_str());//判断RMS是否对该设备正在录像
			if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			{
				freeReplyObject(reply);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}
		}

		redisReply *reply2=NULL,*reply3=NULL;
		for(size_t i=0;i<reply->elements;i++)
		{
			if(redisGetReply(fRedisCon,(void**)&reply2)!=REDIS_OK)
			{
				freeReplyObject(reply);
				freeReplyObject(reply2);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}

			if(redisGetReply(fRedisCon,(void**)&reply3)!=REDIS_OK)
			{
				freeReplyObject(reply);
				freeReplyObject(reply3);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}

			if(reply2->type==REDIS_REPLY_INTEGER&&reply2->integer==1&&
				reply3->type==REDIS_REPLY_INTEGER&&reply3->integer==1)
			{//找到了
				string strIpPort(reply->element[i]->str);
				int ipos=strIpPort.find(':');//错误判断
				strRmsIP=strIpPort.substr(0,ipos);
				strRmsPort=strIpPort.substr(ipos+1,strIpPort.size()-ipos-1);


				//freeReplyObject(reply2);
				//freeReplyObject(reply3);
				bReVal=true;
				//break;
			}
			freeReplyObject(reply2);
			freeReplyObject(reply3);
		}
	}
	else//没有可用的RMS
	{

	}
	freeReplyObject(reply);
	return bReVal;
}
コード例 #12
0
//以管线的方式执行串行命令,减少等待时间,但是如果下一个命令需要用到上一个命令的返回结果,则无法使用管线。
bool QTSServerInterface::RedisGetAssociatedDarWin(string& strDeviceSerial,string &strCameraSerial,string& strDssIP,string& strDssPort)//获得与当前设备序列号和摄像头序列号关联的EasyDarWin,也就说找到该设备正在推送的EasyDarWin
{
	//算法描述,获得darwin列表,对于每一个darwin判断其是否存活,如果存活,根据查找其正在推流列表看是否存在指定的设备序列号和摄像头序列号
	OSMutexLocker mutexLock(&fRedisMutex);
	
	if(!ConRedis())
		return false;

	bool bReVal=false;
	//由设备序列号和摄像序列号合成推流名称,EasyDarWIn在redis上的存储为:设备序列号/摄像头序列号.sdp
	string strPushName=strDeviceSerial+'/'+strCameraSerial+".sdp";
	char chTemp[128]={0};
	sprintf(chTemp,"smembers EasyDarWinName");

	
	redisReply* reply = (redisReply*)redisCommand(fRedisCon,chTemp);//获得EsayDarWin列表
	if (NULL == reply)//错误,需要进行重连
	{
		redisFree(fRedisCon);
		fIfConSucess=false;
		return false;
	}
	printf("%d\n",reply->type);
	if(reply->elements>0&&reply->type==REDIS_REPLY_ARRAY)//smembers返回的是数组
	{
		//这里可以使用管线
		redisReply* childReply=NULL;
		for(size_t i=0;i<reply->elements;i++)//对于每一个EasyDarWin判断其存活性和(与指定设备序列号和摄像头序列号)关联性
		{
			childReply		=	reply->element[i];
			string strChileReply(childReply->str);

			sprintf(chTemp,"exists %s",(strChileReply+"_Live").c_str());//判断EasyDarWin是否存活
			if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			{
				freeReplyObject(reply);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}
			
			sprintf(chTemp,"sismember %s %s",(strChileReply+"_PushName").c_str(),strPushName.c_str());//判断DarWin上是否存在该推流设备
			if(redisAppendCommand(fRedisCon,chTemp)!=REDIS_OK)
			{
				freeReplyObject(reply);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}
		}

		redisReply *reply2=NULL,*reply3=NULL;
		for(size_t i=0;i<reply->elements;i++)
		{
			if(redisGetReply(fRedisCon,(void**)&reply2)!=REDIS_OK)
			{
				freeReplyObject(reply);
				freeReplyObject(reply2);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}
			if(redisGetReply(fRedisCon,(void**)&reply3)!=REDIS_OK)
			{
				freeReplyObject(reply);
				freeReplyObject(reply3);
				redisFree(fRedisCon);
				fIfConSucess=false;
				return false;
			}

			if(reply2->type==REDIS_REPLY_INTEGER&&reply2->integer==1&&
				reply3->type==REDIS_REPLY_INTEGER&&reply3->integer==1)
			{//找到了
				string strIpPort(reply->element[i]->str);
				int ipos=strIpPort.find(':');//错误判断
				strDssIP=strIpPort.substr(0,ipos);
				strDssPort=strIpPort.substr(ipos+1,strIpPort.size()-ipos-1);
				

				//freeReplyObject(reply2);
				//freeReplyObject(reply3);
				bReVal=true;
				//break;//找到了也不能加break,而是需要执行完,因为对每一个请求必须有一个应答,否则次序就发生了混乱
			}
			freeReplyObject(reply2);
			freeReplyObject(reply3);
		}
	}
	else//没有可用的EasyDarWin
	{

	}
	freeReplyObject(reply);
	return bReVal;
}
コード例 #13
0
ファイル: util-log-redis.c プロジェクト: bmeeks8/suricata
/** \brief SCLogRedisWriteSync() writes string to redis output in sync mode
 *  \param file_ctx Log file context allocated by caller
 *  \param string Buffer to output
 */
static int SCLogRedisWriteSync(LogFileCtx *file_ctx, const char *string)
{
    SCLogRedisContext * ctx = file_ctx->redis;
    int ret = -1;
    redisContext *redis = ctx->sync;
    if (redis == NULL) {
        SCConfLogReopenSyncRedis(file_ctx);
        redis = ctx->sync;
        if (redis == NULL) {
            SCLogDebug("Redis after re-open is not available.");
            return -1;
        }
    }

    /* synchronous mode */
    if (file_ctx->redis_setup.batch_size) {
        redisAppendCommand(redis, "%s %s %s",
                file_ctx->redis_setup.command,
                file_ctx->redis_setup.key,
                string);
        if (ctx->batch_count == file_ctx->redis_setup.batch_size) {
            redisReply *reply;
            int i;
            ctx->batch_count = 0;
            for (i = 0; i <= file_ctx->redis_setup.batch_size; i++) {
                if (redisGetReply(redis, (void **)&reply) == REDIS_OK) {
                    freeReplyObject(reply);
                    ret = 0;
                } else {
                    if (redis->err) {
                        SCLogInfo("Error when fetching reply: %s (%d)",
                                redis->errstr,
                                redis->err);
                    }
                    switch (redis->err) {
                        case REDIS_ERR_EOF:
                        case REDIS_ERR_IO:
                            SCLogInfo("Reopening connection to redis server");
                            SCConfLogReopenSyncRedis(file_ctx);
                            redis = ctx->sync;
                            if (redis) {
                                SCLogInfo("Reconnected to redis server");
                            } else {
                                SCLogInfo("Unable to reconnect to redis server");
                                return -1;
                            }
                            break;
                        default:
                            SCLogWarning(SC_ERR_INVALID_VALUE,
                                    "Unsupported error code %d",
                                    redis->err);
                            return -1;
                    }
                }
            }
        } else {
            ctx->batch_count++;
        }
    } else {
        redisReply *reply = redisCommand(redis, "%s %s %s",
                file_ctx->redis_setup.command,
                file_ctx->redis_setup.key,
                string);
        /* We may lose the reply if disconnection happens*/
        if (reply) {
            switch (reply->type) {
                case REDIS_REPLY_ERROR:
                    SCLogWarning(SC_ERR_SOCKET, "Redis error: %s", reply->str);
                    SCConfLogReopenSyncRedis(file_ctx);
                    break;
                case REDIS_REPLY_INTEGER:
                    SCLogDebug("Redis integer %lld", reply->integer);
                    ret = 0;
                    break;
                default:
                    SCLogError(SC_ERR_INVALID_VALUE,
                            "Redis default triggered with %d", reply->type);
                    SCConfLogReopenSyncRedis(file_ctx);
                    break;
            }
            freeReplyObject(reply);
        } else {
            SCConfLogReopenSyncRedis(file_ctx);
        }
    }
    return ret;
}
コード例 #14
0
int
main (int argc, char *argv[])
{
  FILE *fp = NULL;
  pid_t process_id = 0;
  pid_t sid = 0;

  redisContext *c;
  redisReply *reply;

  GError *error = NULL;

  // Create child process
  process_id = fork ();

  // Indication of fork() failure
  if (process_id < 0) {
    printf ("fork failed!\n");
    // Return failure in exit status
    exit (EXIT_FAILURE);
  }
  // PARENT PROCESS. Need to kill it.
  if (process_id > 0) {
    printf ("process_id of child process %d \n", process_id);
    // return success in exit status
    exit (EXIT_SUCCESS);
  }
  //unmask the file mode
  umask (0);

  //set new session
  sid = setsid ();
  if (sid < 0) {
    // Return failure
    exit (EXIT_FAILURE);
  }
  // Change the current working directory to /tmp.
  if (chdir ("/tmp") < 0) {
    exit (EXIT_FAILURE);
  }
  // Close stdin. stdout and stderr
  //close(STDIN_FILENO);
  //close(STDOUT_FILENO);
  //close(STDERR_FILENO);

  // Open a log file in write mode.
  fp = fopen ("Log.txt", "a+");

  //Connect to redis
  c = redisConnect ("143.54.10.96", 6379);
  if (c->err) {
    fprintf (fp, "Error: %s\n", c->errstr);
  } else {
    fprintf (fp, "Connection Made! \n");
  }
  fflush (fp);

  reply = redisCommand (c, "PSUBSCRIBE bigbluebutton:meeting:participants");
  //freeReplyObject (reply);

  while (1) {
    // Dont block context switches, let the process sleep for some time
    sleep (1);
    time_t rawtime;
    struct tm *timeinfo;

    time (&rawtime);
    timeinfo = localtime (&rawtime);
    fprintf (fp, "Current local time and date: %s", asctime (timeinfo));
    fflush (fp);
    redisGetReply (c, (void **) &reply);

    const gchar *message_json = reply->element[3]->str;

    g_type_init ();

    JsonParser *parser;
    parser = json_parser_new ();

    if (!json_parser_load_from_data (parser, message_json, -1, &error)) {
      fprintf (fp, "Erro ao fazer parser da mensagem json\n");
    }

    JsonNode *root, *node_stream, *node_meeting, *node_status;
    JsonObject *object;
    root = json_parser_get_root (parser);

    object = json_node_get_object (root);
    node_meeting = json_object_get_member (object, "meetingId");
    node_stream = json_object_get_member (object, "value");
    node_status = json_object_get_member (object, "status");

    if (node_meeting != NULL && node_stream != NULL && node_status != NULL
        && strncmp (json_node_get_string (node_status), "hasStream", 9) == 0
        && strncmp (json_node_get_string (node_stream), "true", 4) == 0) {

      //TODO: retrieve host value from config
      const char *host = "143.54.10.96";
      const char *meetingId = json_node_get_string (node_meeting);      //"0009666694da07ee6363e22df5cdac8e079642eb-1359993137281";
      const char *videoId = json_node_get_string (node_stream); //"640x480185-1359999168732";

      //Get the substring (after equal sign)
      //true,stream=1280x720-1360167989810-1360167685014
      int eq_pos = strcspn (videoId, "=");
      int size_id = strlen (videoId) - (eq_pos + 1);
      char *streamId = calloc (size_id + 1, sizeof (char));
      memcpy (streamId, &videoId[12], size_id);
      streamId[size_id] = '\0';

      //printf("%s %s %s %s\n", host, meetingId, videoId,streamId);
      fprintf (fp, "\nhost:%s meetingId:%s streamId:stream%s\n**************\n",
          host, meetingId, streamId);
      fflush (fp);

      pid_t childPID;
      childPID = fork ();

      if (childPID >= 0)        // fork was successful
      {
        if (childPID == 0)      // child process
        {
          //TODO: create gss push server
          const char *chanwebm = "webm";
          const char *chanhls = "hls";
/*
          //Launch pipeline
          if (execl
              ("/home/mconf/bbb-gss-hack/tools/hls",
                  "hls", host, meetingId, streamId, chanhls, NULL) == -1) {
            fprintf (fp, "execl error\n");
            fflush (fp);
            exit (1);
          };
*/
          //Launch pipeline
          if (execl
              ("/home/mconf/bbb-gss-hack/tools/webm",
                  "webm", host, meetingId, streamId, chanwebm, NULL) == -1) {
            fprintf (fp, "execl error\n");
            fflush (fp);
            exit (1);
          };

        } else                  //Parent process
        {
          fprintf (fp, "process_id of gstreamer child process %d \n", childPID);
        }
      } else                    //fork failed
      {
        fprintf (fp, "Fork failed, Gstreamer Pipeline not started\n");
        return 1;
      }
    }
    //freeReplyObject (reply);
  }
  fclose (fp);
  return (0);
}
コード例 #15
0
ファイル: mdbi.c プロジェクト: erichuang1994/fbbs
mdb_res_t *mdb_recv(void)
{
	void *res;
	redisGetReply(_mdb.c, &res);
	return res;
}
コード例 #16
0
ファイル: test.c プロジェクト: Liangzx/hiredis
static void test_throughput(struct config config) {
    redisContext *c = connect(config);
    redisReply **replies;
    int i, num;
    long long t1, t2;

    test("Throughput:\n");
    for (i = 0; i < 500; i++)
        freeReplyObject(redisCommand(c,"LPUSH mylist foo"));

    num = 1000;
    replies = malloc(sizeof(redisReply*)*num);
    t1 = usec();
    for (i = 0; i < num; i++) {
        replies[i] = redisCommand(c,"PING");
        assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS);
    }
    t2 = usec();
    for (i = 0; i < num; i++) freeReplyObject(replies[i]);
    free(replies);
    printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0);

    replies = malloc(sizeof(redisReply*)*num);
    t1 = usec();
    for (i = 0; i < num; i++) {
        replies[i] = redisCommand(c,"LRANGE mylist 0 499");
        assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY);
        assert(replies[i] != NULL && replies[i]->elements == 500);
    }
    t2 = usec();
    for (i = 0; i < num; i++) freeReplyObject(replies[i]);
    free(replies);
    printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0);

    num = 10000;
    replies = malloc(sizeof(redisReply*)*num);
    for (i = 0; i < num; i++)
        redisAppendCommand(c,"PING");
    t1 = usec();
    for (i = 0; i < num; i++) {
        assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK);
        assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS);
    }
    t2 = usec();
    for (i = 0; i < num; i++) freeReplyObject(replies[i]);
    free(replies);
    printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);

    replies = malloc(sizeof(redisReply*)*num);
    for (i = 0; i < num; i++)
        redisAppendCommand(c,"LRANGE mylist 0 499");
    t1 = usec();
    for (i = 0; i < num; i++) {
        assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK);
        assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY);
        assert(replies[i] != NULL && replies[i]->elements == 500);
    }
    t2 = usec();
    for (i = 0; i < num; i++) freeReplyObject(replies[i]);
    free(replies);
    printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);

    disconnect(c, 0);
}
コード例 #17
0
ファイル: newpoststat.c プロジェクト: loverabbit/kbs-redis
void gen_hot_subjects_xml(int mytype)
{
    FILE *fp;
    char curfile[256];
    char xml_buf[256];
    char url_buf[256];
    int i;

    if (mytype==4) {
        gen_blessing_list_xml();
        return;
    }

    sprintf(curfile, "xml/%s.xml", myfile[mytype]);
    if ((fp = fopen(curfile, "w")) != NULL) {
        fprintf(fp, "<?xml version=\"1.0\" encoding=\"GBK\"?>\n");
        fprintf(fp, "<hotsubjects>\n");

        for (i = 0; i < topnum; i++) {
            fprintf(fp, "<hotsubject>\n");
            fprintf(fp, "<title>%s</title>\n", encode_url(url_buf,encode_xml(xml_buf, top[i].title,
                    sizeof(xml_buf)),sizeof(url_buf)));
            fprintf(fp, "<author>%s</author>\n", encode_url(url_buf,top[i].userid,sizeof(url_buf)));
            fprintf(fp, "<board>%s</board>\n", encode_url(url_buf,top[i].board,sizeof(url_buf)));
            fprintf(fp, "<time>%ld</time>\n", top[i].date);
            fprintf(fp, "<number>%d</number>\n", top[i].number);
            fprintf(fp, "<groupid>%d</groupid>\n", top[i].groupid);
            fprintf(fp, "</hotsubject>\n");
        }
        fprintf(fp, "</hotsubjects>\n");

        fclose(fp);
    }

#ifdef REDIS
    redisContext *redis = redisConnect("127.0.0.1", 6379);
    const char *pattern = "stat:%s:%s";
    char key[128];
    char value[512];
    const char *argv[3] = { "RPUSH", key, value };

#define RPUSH(ikey,itype,ivalue) {\
    snprintf(key, 128, pattern, myfile[mytype], ikey);\
    snprintf(value, 512, itype, ivalue);\
    redisAppendCommandArgv(redis, 3, argv, NULL);\
}

#define DEL(ikey) {\
    snprintf(key, 128, pattern, myfile[mytype], ikey);\
    snprintf(value, 512, "DEL %s", key);\
    redisAppendCommand(redis, value);\
}

    DEL("title");
    DEL("author");
    DEL("board");
    DEL("replies");
    DEL("time");
    DEL("id");
    for (i = 0; i < topnum; i++) {
        RPUSH("title"   , "%s"  , top[i].title);
        RPUSH("author"  , "%s"  , top[i].userid);
        RPUSH("board"   , "%s"  , top[i].board);
        RPUSH("replies" , "%lu" , (unsigned long)top[i].number);
        RPUSH("time"    , "%lu" , (unsigned long)top[i].date);
        RPUSH("id"      , "%lu" , (unsigned long)top[i].groupid);
    }
    redisReply *reply;
    redisGetReply(redis, (void*)&reply);
    freeReplyObject(reply);
    redisFree(redis);

#undef RPUSH
#undef DEL
#endif
}