#include #include #include #include #include #include #include #include "etcache.h" #include "easygraph.h" #include "blend.h" #include "accesscache.h" /****************************************************************************/ /* 構造体EasyGraphの内容を表示する(デバッグ用) */ /****************************************************************************/ void dumpEasyGraph(FILE *fp, EasyGraph *eg) { fprintf(fp, "[%10p] EasyGraph {\n", eg); fprintf(fp, "[%10p] char target=%s\n", eg->target, eg->target); fprintf(fp, "[%10p] off_t start=%d\n",&eg->start, (int)eg->start); fprintf(fp, "[%10p] off_t end=%d\n", &eg->end, (int)eg->end); fprintf(fp, "[%10p] off_t unit=%d\n", &eg->unit, (int)eg->unit); fprintf(fp, "[%10p] int valuenum=%d\n", &eg->valuenum, eg->valuenum); fprintf(fp, "[%10p] EG_VALUE *values=(%p - %p)\n", &eg->values, eg->values, eg->values + eg->valuenum); fprintf(fp, "[%10p] char url=%s\n", &eg->url, eg->url); fprintf(fp, "[%10p] char filename=%s\n", &eg->filename, eg->filename); fprintf(fp, " COLOR color=%d,%d,%d\n", eg->color.red, eg->color.green, eg->color.blue); fprintf(fp, "[%10p] int optnum=%d\n", &eg->optnum, eg->optnum); fprintf(fp, "[%10p] int optareanum=%d\n", &eg->optareanum, eg->optareanum); fprintf(fp, "[%10p] OPTATTR *optattrs=%p\n", &eg->optattrs, eg->optattrs); fprintf(fp, " }\n"); } /****************************************************************************/ /* 構造体EasyGraphTrackの内容を表示する(デバッグ用) */ /****************************************************************************/ void dumpEasyGraphTrack(FILE *fp, EasyGraphTrack *egt) { fprintf(fp, "EasyGraphTrack {\n"); fprintf(fp, " ET_TYPE ettype=%d\n", egt->ettype); fprintf(fp, " char name=%s\n", egt->name); fprintf(fp, " char comment=%s\n", egt->comment); fprintf(fp, " char desc_url=%s\n", egt->desc_url); fprintf(fp, " COLOR color=%d,%d,%d\n", egt->color.red, egt->color.green, egt->color.blue); fprintf(fp, " char species=%s\n", egt->species); fprintf(fp, " char revision=%s\n", egt->revision); fprintf(fp, " char species_url=%s\n", egt->species_url); fprintf(fp, " EG_VALUE max=%g\n", egt->max); fprintf(fp, " EG_VALUE min=%g\n", egt->min); fprintf(fp, " BLEND blend=%d\n", egt->blend); fprintf(fp, " int graphnum=%d\n", egt->graphnum); fprintf(fp, " int graphareanum=%d\n", egt->graphareanum); fprintf(fp, " EasyGraph **graphs=%p\n", egt->graphs); fprintf(fp, " char date=%s\n", egt->date); fprintf(fp, " char optattr=%s\n", egt->optattr); fprintf(fp, "}\n"); } /****************************************************************************/ /* 問合せの情報を標準エラー出力に表示する */ /****************************************************************************/ static void printGraphStatus(EasyGraphTrack *egt, ssize_t filesize, off_t start, off_t end, off_t unit, ssize_t width, BLEND policy) { char blend_name[NAME_MAX_LEN + 1]; /* 管理情報を標準エラー出力へ出力 */ getBlendName(policy, blend_name, NAME_MAX_LEN + 1); fprintf(stderr, "*******************************************************************************\n"); fprintf(stderr, "* ENTRY_SIZE:%d, BUFSIZE:%d, BUF_ENTRIES:%d, BUFNUM:%d\n", ENTRY_SIZE, BUFSIZE, BUF_ENTRIES, BUFNUM); fprintf(stderr, "* CacheFile=%s\n", egt->graphs[0]->filename); fprintf(stderr, "* range=[%d,%d] %d entries (%d bytes)\n", 1, filesize/ENTRY_SIZE, filesize/ENTRY_SIZE, filesize); fprintf(stderr, "* start=%d, end=%d (num:%d), unit=%d (width=%d), blend=%s\n", (int)(start + 1), (int)(end + 1), (int)(end - start + 1), (int)unit, (int)width, blend_name); if (policy == NOBLEND && unit > 1) { fprintf(stderr, "!!!! You must set BLEND when unit is greater than 1.\n"); } fprintf(stderr, "*******************************************************************************\n"); } /****************************************************************************/ /* graph行を指定ストリームに出力する */ /****************************************************************************/ void printEasyGraph(FILE *fp, EasyGraph *eg) { int i; if (!eg) { fprintf(fp, "EasyGraph is null.\n"); return; } fprintf(fp, "graph target=%s range=%d,%d unit=%d nums=", eg->target, (int)eg->start, (int)eg->end, (int)eg->unit); if (eg->values == NULL) { fprintf(stderr, "printEasyGraph: graph values is null.\n"); } else { for (i = 0; i < eg->valuenum - 1; i++) { fprintf(fp, "%g,", eg->values[i]); } fprintf(fp, "%g", eg->values[i]); } if (eg->url[0] != '\0') fprintf(fp, " url=\"%s\"", eg->url); if (eg->optattrs) { for (i = 0; i < eg->optnum; i++) { fprintf(fp, " %s=%s", eg->optattrs[i].name, eg->optattrs[i].value); } } fprintf(fp, "\n"); } /****************************************************************************/ /* graphTrack行を指定ストリームに出力する */ /****************************************************************************/ void printEasyGraphTrackHeader(FILE *fp, EasyGraphTrack *egt) { fprintf(fp, "graphTrack"); fprintf(fp, " name=%s", egt->name); if (egt->comment[0] != '\0') fprintf(fp, " comment=\"%s\"", egt->comment); if (egt->desc_url[0] != '\0') fprintf(fp, " description_url=\"%s\"", egt->desc_url); // color設定が無い場合は、DBに-1を設定する。 if (egt->color.red != -1) fprintf(fp, " color=%d,%d,%d", egt->color.red, egt->color.green, egt->color.blue); fprintf(fp, " species=%s", egt->species); fprintf(fp, " revision=%s", egt->revision); if (egt->species_url[0] != '\0') fprintf(fp, " species_url=%s", egt->species_url); fprintf(fp, " max=%g min=%g", egt->max, egt->min); switch (egt->blend) { case mode: fprintf(fp, " blend=mode"); break; case average: fprintf(fp, " blend=average"); break; case min: fprintf(fp, " blend=min"); break; case max: fprintf(fp, " blend=max"); break; case NOBLEND: break; default: fprintf(stderr, "*** invalid blend ***\n"); } if (egt->date[0] != '\0') fprintf(fp, " date=%s", egt->date); if (egt->optattr[0] != '\0') fprintf(fp, " optattr=\"%s\"", egt->optattr); fprintf(fp, "\n"); } /****************************************************************************/ /* EasyGraphTrack全体を指定ストリームに出力する */ /****************************************************************************/ void printEasyGraphTrack(FILE *fp, EasyGraphTrack *egt) { int i; EasyGraph **eg; if (!egt) { fprintf(fp, "EasyGraphTrack is null.\n"); return; } printEasyGraphTrackHeader(fp, egt); eg = egt->graphs; for (i = 0; i < egt->graphnum; i++) { printEasyGraph(fp, *eg); eg++; } } /****************************************************************************/ /* EasyGraph構造体の内容をヌルクリアする */ /****************************************************************************/ void clearEasyGraph(EasyGraph *eg) { if (eg->values) { free(eg->values); onmemValues--; /* Value */ } if (eg->optattrs) { free(eg->optattrs); onmemOptAttrs--; /* OptAttr */ } memset(eg, 0, sizeof(EasyGraph)); } /****************************************************************************/ /* EasyGraphTrack構造体の内容をヌルクリアする */ /****************************************************************************/ void clearEasyGraphTrack(EasyGraphTrack *egt) { int i; EasyGraph *eg; if (!egt) return; if (egt->graphs) { for (i = 0; i < egt->graphnum; i++) { eg = egt->graphs[i]; destroyEasyGraph(&eg); } free(egt->graphs); onmemPointers--; /* Pointer */ } memset(egt, 0, sizeof(EasyGraphTrack)); } /****************************************************************************/ /* EasyGraph構造体を解放する */ /****************************************************************************/ void destroyEasyGraph(EasyGraph **eg) { if (!eg) return; if (*eg) { clearEasyGraph(*eg); free(*eg); onmemEGraphNum--; /* EasyGraph */ *eg = NULL; } } /****************************************************************************/ /* EasyGraphTrack構造体を解放する */ /****************************************************************************/ void destroyEasyGraphTrack(EasyGraphTrack **egt) { if (!egt) return; if (*egt) { clearEasyGraphTrack(*egt); free(*egt); onmemEGraphTrackNum--; /* EasyGraphTrack */ *egt = NULL; } } /****************************************************************************/ /* メモリ領域を確保してファイルからグラフ値を読み取る */ /****************************************************************************/ EG_VALUE *getValues(char *filename, off_t start, off_t end) { EG_VALUE *buf; off_t num, tmp; int fd; fd = open(filename, O_RDONLY); if (fd == -1) return NULL; if (start > end) { tmp = end; end = start; start = tmp; } num = end - start + 1; buf = (EG_VALUE *)malloc(num * ENTRY_SIZE); if (!buf) return NULL; onmemValues++; tmp = lseek(fd, start * ENTRY_SIZE, SEEK_SET); if (tmp == -1) { fprintf(stderr, "seek error.\n"); exit(1); } tmp = read(fd, buf, num); if (tmp < 0) { free(buf); onmemValues--; /* Value */ buf = NULL; } return buf; } /****************************************************************************/ /* 指定範囲のグラフ値をブレンドして指定ストリームに出力する */ /* [戻り値] 1:成功 0:失敗 */ /****************************************************************************/ int outputGraphCache(EasyGraphTrack *egt, /* EasyGraphTrack構造体 */ char *outstream, /* 出力ストリーム */ off_t start, /* 開始位置(bp) */ off_t end, /* 終了位置(bp) */ int width, /* 表示ピクセル数 */ BLEND policy) /* 合成ポリシ */ { int rfd; off_t tmp; int unit; off_t unit_index; ssize_t filesize; ssize_t i, j; ssize_t num_in_buf; ssize_t remain; ssize_t readnum; ssize_t entrynum; EG_VALUE *buf; EG_VALUE blend_value; EG_VALUE *blend_buf; struct stat statdata; EasyGraph *graph = NULL; int graphnum; FILE *ofp; off_t fileend; /* 出力ストリームを開く */ if (outstream == NULL || strcmp(outstream, "") == 0 || strcmp(outstream, "stdout") == 0) { ofp = stdout; } else { ofp = fopen(outstream, "w"); if (!ofp) { fprintf(stderr, "Could not open Output stream file: %s\n", outstream); return 0; } } /* バッファの用意 */ buf = (EG_VALUE *)malloc(BUFSIZE); if (!buf) { fprintf(stderr, "Could not allocate memory (size: %d)\n", BUFSIZE); return 0; } onmemValues++; /* startとendの調整。小さい方をstartとする。 */ /* startが0より小さければ0にする。 */ /* endがファイルサイズを越えている場合、オーバー部分のデータを全て0とする */ if (start > end) { tmp = start; start = end; end = tmp; } if (start < 0) start = 0; if (end < 0) end = 0; /* 表示ピクセル幅の調整。 */ entrynum = end - start + 1; adjustWidth(entrynum, &unit, &width); /* EasyGraphTrackのデータを指定ストリームへ出力 */ printEasyGraphTrackHeader(ofp, egt); graphnum = egt->graphnum; if (egt->graphs) graph = *egt->graphs; /* graphの数だけ出力 */ for (j = 0; j < graphnum; j++) { /* キャッシュファイルを開く */ rfd = open(graph->filename, O_RDONLY); if (rfd == -1) { fprintf(stderr, "Could not open Cache data file: %s\n", graph->filename); graph++; continue; } /* 指定された箇所へファイルポインタを移動 */ tmp = lseek(rfd, start * ENTRY_SIZE, SEEK_SET); if (tmp == -1) { fprintf(stderr, "seek error.\n"); close(rfd); graph++; continue; } graph->start = start; graph->end = end; graph->unit = unit; graph->valuenum = entrynum; fprintf(ofp, "graph target=%s range=%d,%d unit=%d nums=", graph->target, (int)graph->start+1, (int)graph->end + 1, (int)graph->unit); unit_index = 0; blend_buf = (EG_VALUE *)malloc(unit * ENTRY_SIZE); if (!blend_buf) { fprintf(stderr, "outputGraphCache: memory allocation error\n"); free(buf); onmemValues--; return 0; } onmemValues++; remain = entrynum; while (remain > 0) { num_in_buf = (remain < BUF_ENTRIES) ? remain : BUF_ENTRIES; readnum = read(rfd, buf, num_in_buf * ENTRY_SIZE); if (readnum < num_in_buf * ENTRY_SIZE) { memset((char*)buf + readnum, 0, BUFSIZE - readnum); } for (i = 0; i < num_in_buf - 1; i++) { blend_buf[unit_index] = buf[i]; unit_index++; if (unit_index == unit) { blend_value = blendGraph(blend_buf, unit, policy); fprintf(ofp, "%g,", blend_value); unit_index = 0; } } // fprintf(stderr, "unit_index=%d (unit=%d)\n", (int)unit_index, unit); blend_buf[unit_index] = buf[i]; unit_index++; if (unit_index == unit) { blend_value = blendGraph(blend_buf, unit, policy); if (i == num_in_buf - 1 && remain == num_in_buf) { fprintf(ofp, "%g", blend_value); } else { fprintf(ofp, "%g,", blend_value); } unit_index = 0; } else if (remain < BUF_ENTRIES) { blend_value = blendGraph(blend_buf, unit_index, policy); fprintf(ofp, "%g", blend_value); break; } remain -= BUF_ENTRIES; } if (graph->url[0] != '\0') fprintf(ofp, " url=\"%s\"\n", graph->url); else fprintf(ofp, "\n"); /* 管理情報を標準エラー出力へ出力 */ lstat(graph->filename, &statdata); filesize = statdata.st_size; fileend = filesize / ENTRY_SIZE - 1; printGraphStatus(egt, filesize, start, end, unit, width, policy); graph++; free(blend_buf); onmemValues--; /* Value */ close(rfd); } free(buf); onmemValues--; /* Value */ return 1; } /*****************************************************************************/ /* EasyGraphTrack構造体にEasyGraph構造体を追加する */ /* [戻り値] 成功: 現在のEasyGraphの個数 失敗: 0 */ /*****************************************************************************/ int addGraphToTrack(EasyGraphTrack *egt, EasyGraph *eg) { EasyGraph **graphs; if (!egt || !eg) { fprintf(stderr, "addGraphToTrack: invalid arguments.\n"); return 0; } if (egt->graphnum == 0 || egt->graphnum == egt->graphareanum) { graphs = (EasyGraph **)malloc( sizeof(EasyGraph *) * (egt->graphareanum + DEFAULT_GRAPH_ENTRY)); if (!graphs) { fprintf(stderr, "addGraphToTrack: memory allocation error.\n"); return 0; } onmemPointers++; if (egt->graphs) { memcpy(graphs, egt->graphs, sizeof(EasyGraph *) * egt->graphareanum); free(egt->graphs); onmemPointers--; /* Pointer */ } egt->graphs = graphs; egt->graphareanum += DEFAULT_GRAPH_ENTRY; } egt->graphs[egt->graphnum] = eg; egt->graphnum++; return egt->graphnum; } /*****************************************************************************/ /* 全てのEasyGraphが持つグラフ値をバイナリファイルに出力する */ /*****************************************************************************/ int writeGraphValues(EasyGraphTrack *egt) { int i; char path[PATH_MAX_LEN + 1]; if (!egt) { fprintf(stderr, "writeGraphFiles: invalid argument.\n"); return 0; } if (!egt->graphs) return 0; if (egt->graphnum == 0) return 0; dumpEasyGraphTrack(stderr, egt); for (i = 0; i < egt->graphnum; i++) { assembleCacheFileName(egt->name, egt->species, egt->revision, egt->graphs[i]->target, path, PATH_MAX_LEN); if (i == 0) unlink(path); writeGraphValue(egt->graphs[i], path); fprintf(stderr, "wrote %d graph data to a file.\n", i); } return i; } /*****************************************************************************/ /* EasyGraphが持つグラフ値をバイナリファイルに出力する */ /*****************************************************************************/ int writeGraphValue(EasyGraph *eg, char *path) { FILE *fp; int unit; int start; int orgpos; int i; EG_VALUE *v1 = NULL; EG_VALUE *v2 = NULL; int datasize = 0; fp = fopen(path, "r+"); if (!fp) fp = fopen(path, "w"); if (!fp) return 0; unit = (eg->unit) ? eg->unit : 1; start = (eg->start) ? eg->start - 1 : 0; /* 内部的には0-origin */ // dumpEasyGraph(stderr, eg); if (unit == 1) { fseek(fp, start * sizeof(EG_VALUE), SEEK_SET); fwrite(eg->values, sizeof(EG_VALUE), eg->valuenum, fp); } else { /* unit数だけグラフ値をコピーしてファイルに保存する */ datasize = eg->valuenum * sizeof(EG_VALUE) * unit; if (datasize > shared_area_size) { if (shared_area) { free(shared_area); onmemSharedArea--; /* SharedArea */ shared_area_size = 0; } shared_area = (EG_VALUE *)malloc(datasize); if (!shared_area) { fprintf(stderr, "writeGraphValue: memory allocation error.\n"); return 0; } shared_area_size = datasize; onmemSharedArea++; memset(shared_area, 0, datasize); } v1 = eg->values; v2 = shared_area; for (orgpos = 0; orgpos < eg->valuenum; orgpos++) { for (i = 0; i < unit; i++) { *v2 = *v1; v2++; } v1++; } fseek(fp, start * sizeof(EG_VALUE), SEEK_SET); fwrite(shared_area, sizeof(EG_VALUE), unit * eg->valuenum, fp); shared_area_size = 0; } fclose(fp); return 1; } /*****************************************************************************/ /* EasyGraphが持つグラフ値を正規化する */ /*****************************************************************************/ int regularizeGraphData(EasyGraphTrack *egt) { EasyGraph *eg; /* 現在のEasyGraph */ int i; int v1pos, v2pos; EG_VALUE *newarea = NULL; EG_VALUE *v1; EG_VALUE *v2; if (!egt) { fprintf(stderr, "regularizeGraphData: invalid argument.\n"); return 0; } for (i = 0; i < egt->graphnum; i++) { eg = egt->graphs[i]; // fprintf(stderr, "[[%d]] %p (unit=%d)\n", i, eg, (int)eg->unit); if (eg->unit > 1) { newarea = (EG_VALUE *)malloc(eg->unit * eg->valuenum * sizeof(EG_VALUE)); if (!newarea) { fprintf(stderr, "regularizeGraphData: memory allocation error.\n"); return 0; } onmemValues++; v1 = eg->values; v2 = newarea; // fprintf(stderr, " v1:%p v2:%p\n", v1, v2); for (v1pos = 0; v1pos < eg->valuenum; v1pos++) { for (v2pos = 0; v2pos < eg->unit; v2pos++) { *v2 = *v1; v2++; } v1++; } free(eg->values); onmemValues--; /* Value */ eg->values = newarea; eg->unit = 1; } } return 1; }