/****************************************************************************** **函数名称: 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; }
/****************************************************************************** **函数名称: 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; }
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, ¶m, NULL); while(param.result==NULL && (s = queue_out(param.queue))){ map_each(s->child_tags, data_xpath_search_tag_map_each, ¶m, NULL); } queue_dealloc(param.queue); return param.result; } else{ return tag; } }
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; }
/* 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; }
/****************************************************************************** **函数名称: 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; }
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; }
/* 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; }