Esempio n. 1
0
/******************************************************************************
 **函数名称: rtrd_dsvr_dist_data_hdl
 **功    能: 数据分发处理
 **输入参数:
 **     ctx: 全局信息
 **     dsvr: 分发信息
 **输出参数: NONE
 **返    回: 0:成功 !0:失败
 **实现描述:
 **注意事项: WARNNING: 千万勿将共享变量参与MIN()三目运算, 否则可能出现严重错误!!!!且很难找出原因!
 **          原因: MIN()不是原子运算, 使用共享变量可能导致判断成立后, 而返回时共
 **                享变量的值可能被其他进程或线程修改, 导致出现严重错误!
 **作    者: # Qifeng.zou # 2015.06.13 #
 ******************************************************************************/
static int rtrd_dsvr_dist_data_hdl(rtrd_cntx_t *ctx, rtrd_dsvr_t *dsvr)
{
#define RTRD_DISP_POP_NUM   (1024)
    int idx, k, num, d;
    rtmq_frwd_t *frwd;
    void *data[RTRD_DISP_POP_NUM], *addr;

    for (d=0; d<ctx->conf.distq_num; ++d) {
        /* > 计算弹出个数(WARNNING: 勿将共享变量参与MIN()三目运算, 否则可能出现严重错误!!!) */
        num = MIN(queue_used(ctx->distq[d]), RTRD_DISP_POP_NUM);
        if (0 == num) {
            continue;
        }

        /* > 弹出发送数据 */
        num = queue_mpop(ctx->distq[d], data, num);
        if (0 == num) {
            continue;
        }

        log_trace(ctx->log, "Multi-pop num:%d!", num);

        /* > 放入发送队列 */
        for (k=0; k<num; ++k) {
            /* > 获取发送队列 */
            frwd = (rtmq_frwd_t *)data[k];

            idx = rtrd_node_to_svr_map_rand(ctx, frwd->dest);
            if (idx < 0) {
                queue_dealloc(ctx->distq[d], data[k]);
                log_error(ctx->log, "Didn't find dev to svr map! nodeid:%d", frwd->dest);
                continue;
            }

            /* > 申请内存空间 */
            addr = queue_malloc(ctx->sendq[idx], frwd->length+sizeof(rtmq_frwd_t));
            if (NULL == addr) {
                queue_dealloc(ctx->distq[d], data[k]);
                log_error(ctx->log, "Alloc from queue failed! size:%d/%d",
                    frwd->length, queue_size(ctx->sendq[idx]));
                continue;
            }

            memcpy(addr, data[k], frwd->length+sizeof(rtmq_frwd_t));

            queue_push(ctx->sendq[idx], addr);

            queue_dealloc(ctx->distq[d], data[k]);

            /* > 发送分发请求 */
            rtrd_dsvr_cmd_dist_req(ctx, dsvr, idx);
        }
    }

    return RTMQ_OK;
}
Esempio n. 2
0
/******************************************************************************
 **函数名称: sdrd_worker_cmd_proc_req_hdl
 **功    能: 处理请求的处理
 **输入参数:
 **     ctx: 全局对象
 **     worker: 工作对象
 **     cmd: 命令信息
 **输出参数: NONE
 **返    回: 0:成功 !0:失败
 **实现描述:
 **注意事项:
 **作    者: # Qifeng.zou # 2015.01.06 #
 ******************************************************************************/
static int sdrd_worker_cmd_proc_req_hdl(sdrd_cntx_t *ctx, sdtp_worker_t *worker, const sdtp_cmd_t *cmd)
{
    int idx;
    void *addr, *ptr;
    queue_t *rq;
    sdtp_group_t *group;
    sdtp_header_t *head;
    sdtp_reg_t *reg;
    const sdtp_cmd_proc_req_t *work_cmd = (const sdtp_cmd_proc_req_t *)&cmd->args;

    /* 1. 获取接收队列 */
    rq = ctx->recvq[work_cmd->rqidx];

    while (1)
    {
        /* 2. 从接收队列获取数据 */
        addr = queue_pop(rq);
        if (NULL == addr)
        {
            return SDTP_OK;
        }

        group = (sdtp_group_t *)addr;
        ptr = addr + sizeof(sdtp_group_t);

        for (idx=0; idx<group->num; ++idx)
        {
            /* 3. 执行回调函数 */
            head = (sdtp_header_t *)ptr;

            reg = &ctx->reg[head->type];
            if (NULL == reg->proc)
            {
                ptr += head->length + sizeof(sdtp_header_t);
                ++worker->drop_total;   /* 丢弃计数 */
                continue;
            }

            if (reg->proc(head->type, head->nodeid,
                        ptr+sizeof(sdtp_header_t), head->length, reg->args))
            {
                ++worker->err_total;    /* 错误计数 */
            }
            else
            {
                ++worker->proc_total;   /* 处理计数 */
            }

            ptr += head->length + sizeof(sdtp_header_t);
        }

        /* 4. 释放内存空间 */
        queue_dealloc(rq, addr);
    }

    return SDTP_OK;
}
Esempio n. 3
0
static data_xpath_tag_t * data_xpath_search_tag(data_xpath_selector_t * selector,hcchar *tagName,hlist_t filters,InvokeTickDeclare){
	data_xpath_tag_t * tag = data_xpath_find_tag(selector,tagName,filters,InvokeTickArg);
	if(tag == NULL){
		data_xpath_search_tag_param_t param = {queue_alloc(),NULL,tagName,filters};
		data_xpath_selector_t * s;
		map_each(selector->child_tags, data_xpath_search_tag_map_each, &param, NULL);
		
		while(param.result==NULL && (s = queue_out(param.queue))){
			map_each(s->child_tags, data_xpath_search_tag_map_each, &param, NULL);
		}
		
		queue_dealloc(param.queue);
		return param.result;
	}
	else{
		return tag;
	}
}
Esempio n. 4
0
int DecodeVideo::_PrepareFrame(AVFrame * inFrame, uint8_t ** buffer)
{
    uint8_t *outbuf, *outbuf2;
    int outbufSize;
    AVFrame * frameTmp = avcodec_alloc_frame();
    AVFrame * frameTmp2 = avcodec_alloc_frame();

    // aloca buffer da queue e associa ao _tempFrame2
    outbufSize = avpicture_get_size(_codecCtx->pix_fmt, _codecCtx->width, _codecCtx->height);
    if (outbufSize <= 0) return 0;
    outbuf = (uint8_t *) queue_malloc(outbufSize);
    if (!outbuf) return 0;

    avpicture_fill((AVPicture *)frameTmp, outbuf, _codecCtx->pix_fmt, _codecCtx->width, _codecCtx->height);

    // faz desentrelaçamento e coloca resultado no _tempFrame2
    _Deinterlace(inFrame, frameTmp);

    // converte o pix_fmt se necessário
    if (_codecCtx->pix_fmt != _defaultPixFmt.toFfmpeg()) {

        outbuf2 = outbuf; // guarda ponteiro pro buffer temporário

        // novo buffer da queue para os dados finais
        outbufSize = avpicture_get_size(_defaultPixFmt.toFfmpeg(), _codecCtx->width, _codecCtx->height);
        outbuf = (uint8_t *) queue_malloc(outbufSize);
        avpicture_fill((AVPicture *)frameTmp2, outbuf, _defaultPixFmt.toFfmpeg(), _codecCtx->width, _codecCtx->height);

        _ConvertPixFmt(frameTmp, frameTmp2);

        queue_dealloc(outbuf2);
    }

    av_free(frameTmp);
    av_free(frameTmp2);

    *buffer = outbuf;
    return outbufSize;
}
Esempio n. 5
0
/* Smooth a periodic array with a moving average: equal weights and
 * length = 5% of the period. */
int apply_smoother(
    rrd_t *rrd,
    unsigned long rra_idx,
    unsigned long rra_start,
    rrd_file_t *rrd_file)
{
    unsigned long i, j, k;
    unsigned long totalbytes;
    rrd_value_t *rrd_values;
    unsigned long row_length = rrd->stat_head->ds_cnt;
    unsigned long row_count = rrd->rra_def[rra_idx].row_cnt;
    unsigned long offset;
    FIFOqueue **buffers;
    rrd_value_t *working_average;
    rrd_value_t *rrd_values_cpy;
    rrd_value_t *baseline;

    if (atoi(rrd->stat_head->version) >= 4) {
        offset = floor(rrd->rra_def[rra_idx].
                       par[RRA_seasonal_smoothing_window].
                       u_val / 2 * row_count);
    } else {
        offset = floor(0.05 / 2 * row_count);
    }

    if (offset == 0)
        return 0;       /* no smoothing */

    /* allocate memory */
    totalbytes = sizeof(rrd_value_t) * row_length * row_count;
    rrd_values = (rrd_value_t *) malloc(totalbytes);
    if (rrd_values == NULL) {
        rrd_set_error("apply smoother: memory allocation failure");
        return -1;
    }

    /* rra_start is at the beginning of this rra */
    if (rrd_seek(rrd_file, rra_start, SEEK_SET)) {
        rrd_set_error("seek to rra %d failed", rra_start);
        free(rrd_values);
        return -1;
    }

    /* could read all data in a single block, but we need to
     * check for NA values */
    for (i = 0; i < row_count; ++i) {
        for (j = 0; j < row_length; ++j) {
            if (rrd_read
                (rrd_file, &(rrd_values[i * row_length + j]),
                 sizeof(rrd_value_t) * 1)
                != (ssize_t) (sizeof(rrd_value_t) * 1)) {
                rrd_set_error("reading value failed: %s",
                              rrd_strerror(errno));
            }
            if (isnan(rrd_values[i * row_length + j])) {
                /* can't apply smoothing, still uninitialized values */
#ifdef DEBUG
                fprintf(stderr,
                        "apply_smoother: NA detected in seasonal array: %ld %ld\n",
                        i, j);
#endif
                free(rrd_values);
                return 0;
            }
        }
    }

    /* allocate queues, one for each data source */
    buffers = (FIFOqueue **) malloc(sizeof(FIFOqueue *) * row_length);
    for (i = 0; i < row_length; ++i) {
        queue_alloc(&(buffers[i]), 2 * offset + 1);
    }
    /* need working average initialized to 0 */
    working_average = (rrd_value_t *) calloc(row_length, sizeof(rrd_value_t));
    baseline = (rrd_value_t *) calloc(row_length, sizeof(rrd_value_t));

    /* compute sums of the first 2*offset terms */
    for (i = 0; i < 2 * offset; ++i) {
        k = MyMod(i - offset, row_count);
        for (j = 0; j < row_length; ++j) {
            queue_push(buffers[j], rrd_values[k * row_length + j]);
            working_average[j] += rrd_values[k * row_length + j];
        }
    }

    /* as we are working through the value, we have to make sure to not double
       apply the smoothing after wrapping around. so best is to copy the rrd_values first */

    rrd_values_cpy = (rrd_value_t *) calloc(row_length*row_count, sizeof(rrd_value_t));
    memcpy(rrd_values_cpy,rrd_values,sizeof(rrd_value_t)*row_length*row_count);

    /* compute moving averages */
    for (i = offset; i < row_count + offset; ++i) {
        for (j = 0; j < row_length; ++j) {
            k = MyMod(i, row_count);
            /* add a term to the sum */
            working_average[j] += rrd_values_cpy[k * row_length + j];
            queue_push(buffers[j], rrd_values_cpy[k * row_length + j]);

            /* reset k to be the center of the window */
            k = MyMod(i - offset, row_count);
            /* overwrite rdd_values entry, the old value is already
             * saved in buffers */
            rrd_values[k * row_length + j] =
                working_average[j] / (2 * offset + 1);
            baseline[j] += rrd_values[k * row_length + j];

            /* remove a term from the sum */
            working_average[j] -= queue_pop(buffers[j]);
        }
    }

    for (i = 0; i < row_length; ++i) {
        queue_dealloc(buffers[i]);
        baseline[i] /= row_count;
    }
    free(rrd_values_cpy);
    free(buffers);
    free(working_average);

    if (cf_conv(rrd->rra_def[rra_idx].cf_nam) == CF_SEASONAL) {
        rrd_value_t (
    *init_seasonality) (
    rrd_value_t seasonal_coef,
    rrd_value_t intercept);

        switch (cf_conv(rrd->rra_def[hw_dep_idx(rrd, rra_idx)].cf_nam)) {
        case CF_HWPREDICT:
            init_seasonality = hw_additive_init_seasonality;
            break;
        case CF_MHWPREDICT:
            init_seasonality = hw_multiplicative_init_seasonality;
            break;
        default:
            rrd_set_error("apply smoother: SEASONAL rra doesn't have "
                          "valid dependency: %s",
                          rrd->rra_def[hw_dep_idx(rrd, rra_idx)].cf_nam);
            return -1;
        }

        for (j = 0; j < row_length; ++j) {
            for (i = 0; i < row_count; ++i) {
                rrd_values[i * row_length + j] =
                    init_seasonality(rrd_values[i * row_length + j],
                                     baseline[j]);
            }
            /* update the baseline coefficient,
             * first, compute the cdp_index. */
            offset = hw_dep_idx(rrd, rra_idx) * row_length + j;
            (rrd->cdp_prep[offset]).scratch[CDP_hw_intercept].u_val +=
                baseline[j];
        }
/* if we are not running on mmap, lets write stuff to disk now */
#ifndef HAVE_MMAP
        /* flush cdp to disk */
        if (rrd_seek(rrd_file, sizeof(stat_head_t) +
                     rrd->stat_head->ds_cnt * sizeof(ds_def_t) +
                     rrd->stat_head->rra_cnt * sizeof(rra_def_t) +
                     sizeof(live_head_t) +
                     rrd->stat_head->ds_cnt * sizeof(pdp_prep_t), SEEK_SET)) {
            rrd_set_error("apply_smoother: seek to cdp_prep failed");
            free(rrd_values);
            return -1;
        }
        if (rrd_write(rrd_file, rrd->cdp_prep,
                      sizeof(cdp_prep_t) *
                      (rrd->stat_head->rra_cnt) * rrd->stat_head->ds_cnt)
            != (ssize_t) (sizeof(cdp_prep_t) * (rrd->stat_head->rra_cnt) *
                          (rrd->stat_head->ds_cnt))) {
            rrd_set_error("apply_smoother: cdp_prep write failed");
            free(rrd_values);
            return -1;
        }
#endif

    }

    /* endif CF_SEASONAL */
    /* flush updated values to disk */
    if (rrd_seek(rrd_file, rra_start, SEEK_SET)) {
        rrd_set_error("apply_smoother: seek to pos %d failed", rra_start);
        free(rrd_values);
        return -1;
    }
    /* write as a single block */
    if (rrd_write
        (rrd_file, rrd_values, sizeof(rrd_value_t) * row_length * row_count)
        != (ssize_t) (sizeof(rrd_value_t) * row_length * row_count)) {
        rrd_set_error("apply_smoother: write failed to %lu", rra_start);
        free(rrd_values);
        return -1;
    }

    free(rrd_values);
    free(baseline);
    return 0;
}
Esempio n. 6
0
/******************************************************************************
 **函数名称: rtrd_rsvr_dist_data
 **功    能: 分发连接队列中的数据
 **输入参数:
 **     ctx: 全局对象
 **     rsvr: 接收服务
 **输出参数: NONE
 **返    回: 0:成功 !0:失败
 **实现描述:
 **注意事项:
 **作    者: # Qifeng.zou # 2015.06.02 #
 ******************************************************************************/
static int rtrd_rsvr_dist_data(rtrd_cntx_t *ctx, rtrd_rsvr_t *rsvr)
{
#define RTRD_POP_MAX_NUM (1024)
    int len, idx, num;
    queue_t *sendq;
    void *addr;
    void *data[RTRD_POP_MAX_NUM];
    rtmq_frwd_t *frwd;
    list_opt_t opt;
    rtrd_sck_t *sck;
    _conn_list_t cl;
    rtmq_header_t *head;

    sendq = ctx->sendq[rsvr->id];

    while (1) {
        /* > 弹出队列数据 */
        num = MIN(queue_used(sendq), RTRD_POP_MAX_NUM);
        if (0 == num) {
            break;
        }

        num = queue_mpop(sendq, data, num);
        if (0 == num) {
            continue;
        }

        log_trace(ctx->log, "Multi-pop num:%d!", num);

        /* > 逐条处理数据 */
        for (idx=0; idx<num; ++idx) {
            frwd = (rtmq_frwd_t *)data[idx];

            /* > 查找发送连接 */
            memset(&opt, 0, sizeof(opt));

            opt.pool = (void *)NULL;
            opt.alloc = (mem_alloc_cb_t)mem_alloc;
            opt.dealloc = (mem_dealloc_cb_t)mem_dealloc;

            cl.nodeid = frwd->dest;
            cl.list = list_creat(&opt);
            if (NULL == cl.list) {
                queue_dealloc(sendq, data[idx]);
                log_error(rsvr->log, "Create list failed!");
                continue;
            }

            list2_trav(rsvr->conn_list, (list2_trav_cb_t)rtrd_rsvr_get_conn_list_by_nodeid, &cl);
            if (0 == cl.list->num) {
                queue_dealloc(sendq, data[idx]);
                list_destroy(cl.list, NULL, mem_dummy_dealloc);
                log_error(rsvr->log, "Didn't find connection by nodeid [%d]!", cl.nodeid);
                continue;
            }

            sck = (rtrd_sck_t *)list_fetch(cl.list, rand()%cl.list->num);
            
            /* > 设置发送数据 */
            len = sizeof(rtmq_header_t) + frwd->length;

            addr = calloc(1, len);
            if (NULL == addr) {
                queue_dealloc(sendq, data[idx]);
                list_destroy(cl.list, NULL, mem_dummy_dealloc);
                log_error(rsvr->log, "Alloc memory from slab failed!");
                continue;
            }

            head = (rtmq_header_t *)addr;

            head->type = frwd->type;
            head->nodeid = frwd->dest;
            head->flag = RTMQ_EXP_MESG;
            head->checksum = RTMQ_CHECK_SUM;
            head->length = frwd->length;

            memcpy(addr+sizeof(rtmq_header_t), data[idx]+sizeof(rtmq_frwd_t), head->length);

            queue_dealloc(sendq, data[idx]);

            /* > 放入发送链表 */
            if (list_rpush(sck->mesg_list, addr)) {
                FREE(addr);
                log_error(rsvr->log, "Push input list failed!");
            }

            list_destroy(cl.list, NULL, mem_dummy_dealloc); /* 无需是否结点数据空间 */
        }
    }

    return RTMQ_OK;
}
Esempio n. 7
0
int DecodeVideo::decode(uint8_t * input, unsigned int size, unsigned int timestamp,
                        queue_t * outQueue, bool * gotFrame,
                        QueueExtraData * extraData)
{
    if (!(_flags & FLAG_OPENED)) {
        NEW_ERROR(E_DECODE_NOT_OPENED, "");
        return -1;
    }
    if (!outQueue || !input || !size) {
        NEW_ERROR(E_COMMON_NULL_PARAMETER, "outQueue | input | size");
        return -1;
    }

    uint32_t inbufSize = size;
    uint8_t * outbuf;
    int gotFrameInt;
    int outbufSize;
    QueueExtraDataVideo extraNew;

    if (gotFrame) {
        *gotFrame = false;
    }

    // só pode começar a decodificação em um quadro I
    if (_needFrameI) {
        if (_IsFrameI(&input, &inbufSize)) {
            _needFrameI = false;
        } else {
            NEW_WARNING(E_DECODE_WAITING_FRAME_I, "Aguardando um frame I");
            return -1;
        }
    }

    // fica decodificando o buffer até que encontre um frame completo ou até
    // que acabe o buffer disponível
    _codecCtxMutex.lock();
    int usedTotal = 0;
    while ((uint32_t)usedTotal < inbufSize) {
        AVPacket packet;
        av_init_packet(&packet);
        packet.data = input + usedTotal;
        packet.size = inbufSize - usedTotal;
        gotFrameInt = 0;
        int used = avcodec_decode_video2(_codecCtx, _tempFrame, &gotFrameInt, &packet);
        usedTotal += used;

        // se já usou todo buffer mas não completou o frame, tenta decodificar de novo o mesmo
        // buffer pra tentar pegar o frame. isso é necessário ao decodificar mpeg4
        if (usedTotal == inbufSize && !gotFrameInt && used >= 0) {
            used = avcodec_decode_video2(_codecCtx, _tempFrame, &gotFrameInt, &packet);
        }

        av_free_packet(&packet);

        if (used < 0) {
            NEW_ERROR(E_DECODE_VIDEO, "Falha decodificando video.");
            _codecCtxMutex.unlock();
            return -1;
        }

        if (gotFrameInt) { // pegou frame completo!
            break;
        }
    }
    _codecCtxMutex.unlock();

    // guarda variável de saída
    if (gotFrame) {
        *gotFrame = (gotFrameInt != 0);
    }

    // se não pegou um frame inteiro nem prossegue... retorna o que usou do buffer
    if (!(*gotFrame)) {
        return -1;
    }

    // desentrelaçamento, conversão de pix_fmt, cópia para o buffer de saída
    outbufSize = _PrepareFrame(_tempFrame, &outbuf);
    if (outbufSize <= 0) {
        return -1;
    }

    // coloca os dados na queue
    // obs: só coloca se pegou um frame inteiro
    extraNew =_UpdateExtraData((QueueExtraDataVideo *)extraData);
	#ifdef ANDROID    
	if(queue_length(outQueue) < 5){
	if (queue_enqueue(outQueue, outbuf, outbufSize, timestamp, &extraNew) != E_OK) {
        queue_dealloc(outbuf);
        NEW_ERROR(E_DECODE_ENQUEUE, "");
        return -1;
    }
    } else {
    	queue_dealloc(outbuf);
    }
	#else
	if (queue_enqueue(outQueue, outbuf, outbufSize, timestamp, &extraNew) != E_OK) {
        queue_dealloc(outbuf);
        NEW_ERROR(E_DECODE_ENQUEUE, "");
        return -1;
    }
	#endif

    return usedTotal;
}
Esempio n. 8
0
/* Smooth a periodic array with a moving average: equal weights and
 * length = 5% of the period. */
int apply_smoother( rrd_t *rrd, unsigned long rra_idx, unsigned long rra_start,
    rrd_file_t *rrd_file) {
    unsigned long i, j, k;
    unsigned long totalbytes;
    rrd_value_t *rrd_values;
    unsigned long row_length = rrd->stat_head->ds_cnt;
    unsigned long row_count = rrd->rra_def[rra_idx].row_cnt;
    unsigned long offset;
    FIFOqueue **buffers;
    rrd_value_t *working_average;
    rrd_value_t *baseline;
	int ret = 0;

    if (atoi(rrd->stat_head->version) >= 4) {
        offset = floor(rrd->rra_def[rra_idx].
                       par[RRA_seasonal_smoothing_window].
                       u_val / 2 * row_count);
    } else {
        offset = floor(0.05 / 2 * row_count);
    }

    if (offset == 0)
        return 0;       /* no smoothing */

    /* allocate memory */
    totalbytes = sizeof(rrd_value_t) * row_length * row_count;
    rrd_values = (rrd_value_t *) malloc(totalbytes);
    if (rrd_values == NULL) {
        return -RRD_ERR_MALLOC5;
    }

    /* rra_start is at the beginning of this rra */
    if (rrd_seek(rrd_file, rra_start, SEEK_SET)) {
        free(rrd_values);
        return -RRD_ERR_SEEK2;
    }

    /* could read all data in a single block, but we need to
     * check for NA values */
    for (i = 0; i < row_count; ++i) {
        for (j = 0; j < row_length; ++j) {
            if (rrd_read
                (rrd_file, &(rrd_values[i * row_length + j]),
                 sizeof(rrd_value_t) * 1)
                != (ssize_t) (sizeof(rrd_value_t) * 1)) {
				ret = -RRD_ERR_READ2;
            }
            if (isnan(rrd_values[i * row_length + j])) {
                /* can't apply smoothing, still uninitialized values */
#ifdef DEBUG
                fprintf(stderr,
                        "apply_smoother: NA detected in seasonal array: %ld %ld\n",
                        i, j);
#endif
                free(rrd_values);
                return ret;
            }
        }
    }

    /* allocate queues, one for each data source */
    buffers = (FIFOqueue **) malloc(sizeof(FIFOqueue *) * row_length);
    for (i = 0; i < row_length; ++i) {
        queue_alloc(&(buffers[i]), 2 * offset + 1);
    }
    /* need working average initialized to 0 */
    working_average = (rrd_value_t *) calloc(row_length, sizeof(rrd_value_t));
    baseline = (rrd_value_t *) calloc(row_length, sizeof(rrd_value_t));

    /* compute sums of the first 2*offset terms */
    for (i = 0; i < 2 * offset; ++i) {
        k = MyMod(i - offset, row_count);
        for (j = 0; j < row_length; ++j) {
            queue_push(buffers[j], rrd_values[k * row_length + j]);
            working_average[j] += rrd_values[k * row_length + j];
        }
    }

    /* compute moving averages */
    for (i = offset; i < row_count + offset; ++i) {
        for (j = 0; j < row_length; ++j) {
            k = MyMod(i, row_count);
            /* add a term to the sum */
            working_average[j] += rrd_values[k * row_length + j];
            queue_push(buffers[j], rrd_values[k * row_length + j]);

            /* reset k to be the center of the window */
            k = MyMod(i - offset, row_count);
            /* overwrite rdd_values entry, the old value is already
             * saved in buffers */
            rrd_values[k * row_length + j] =
                working_average[j] / (2 * offset + 1);
            baseline[j] += rrd_values[k * row_length + j];

            /* remove a term from the sum */
            working_average[j] -= queue_pop(buffers[j]);
        }
    }

    for (i = 0; i < row_length; ++i) {
        queue_dealloc(buffers[i]);
        baseline[i] /= row_count;
    }
    free(buffers);
    free(working_average);

    if (cf_conv(rrd->rra_def[rra_idx].cf_nam) == CF_SEASONAL) {
        rrd_value_t (
    *init_seasonality) (
    rrd_value_t seasonal_coef,
    rrd_value_t intercept);

        switch (cf_conv(rrd->rra_def[hw_dep_idx(rrd, rra_idx)].cf_nam)) {
        case CF_HWPREDICT:
            init_seasonality = hw_additive_init_seasonality;
            break;
        case CF_MHWPREDICT:
            init_seasonality = hw_multiplicative_init_seasonality;
            break;
        default:
            return -RRD_ERR_DEP1;
        }

        for (j = 0; j < row_length; ++j) {
            for (i = 0; i < row_count; ++i) {
                rrd_values[i * row_length + j] =
                    init_seasonality(rrd_values[i * row_length + j],
                                     baseline[j]);
            }
            /* update the baseline coefficient,
             * first, compute the cdp_index. */
            offset = hw_dep_idx(rrd, rra_idx) * row_length + j;
            (rrd->cdp_prep[offset]).scratch[CDP_hw_intercept].u_val +=
                baseline[j];
        }
        /* flush cdp to disk */
        if (rrd_seek(rrd_file, sizeof(stat_head_t) +
                     rrd->stat_head->ds_cnt * sizeof(ds_def_t) +
                     rrd->stat_head->rra_cnt * sizeof(rra_def_t) +
                     sizeof(live_head_t) +
                     rrd->stat_head->ds_cnt * sizeof(pdp_prep_t), SEEK_SET)) {
            free(rrd_values);
			return -RRD_ERR_SEEK3;
        }
        if (rrd_write(rrd_file, rrd->cdp_prep,
                      sizeof(cdp_prep_t) *
                      (rrd->stat_head->rra_cnt) * rrd->stat_head->ds_cnt)
            != (ssize_t) (sizeof(cdp_prep_t) * (rrd->stat_head->rra_cnt) *
                          (rrd->stat_head->ds_cnt))) {
            free(rrd_values);
            return -RRD_ERR_WRITE1;
        }
    }

    /* endif CF_SEASONAL */
    /* flush updated values to disk */
    if (rrd_seek(rrd_file, rra_start, SEEK_SET)) {
        free(rrd_values);
        return -RRD_ERR_SEEK4;
    }
    /* write as a single block */
    if (rrd_write
        (rrd_file, rrd_values, sizeof(rrd_value_t) * row_length * row_count)
        != (ssize_t) (sizeof(rrd_value_t) * row_length * row_count)) {
        free(rrd_values);
        return -RRD_ERR_WRITE2;
    }

    free(rrd_values);
    free(baseline);
    return 0;
}