void __finish_log(struct io_log *log, const char *name) { unsigned int i; void *buf; FILE *f; f = fopen(name, "a"); if (!f) { perror("fopen log"); return; } buf = set_file_buffer(f); for (i = 0; i < log->nr_samples; i++) { fprintf(f, "%lu, %lu, %u, %u\n", (unsigned long) log->log[i].time, (unsigned long) log->log[i].val, log->log[i].ddir, log->log[i].bs); } fclose(f); clear_file_buffer(buf); free(log->log); free(log); }
static int writeFileBuffer() { unsigned int bw; const int rc = f_write(g_logfile, fileBuffer.buffer, fileBuffer.index, &bw); clear_file_buffer(); return rc; }
/* * Inflate stored compressed chunks, or write them directly to the log * file if so instructed. */ static int inflate_gz_chunks(struct io_log *log, FILE *f) { struct inflate_chunk_iter iter = { .chunk_sz = log->log_gz, }; z_stream stream; while (!flist_empty(&log->chunk_list)) { struct iolog_compress *ic; ic = flist_first_entry(&log->chunk_list, struct iolog_compress, list); flist_del(&ic->list); if (log->log_gz_store) { size_t ret; dprint(FD_COMPRESS, "log write chunk size=%lu, " "seq=%u\n", (unsigned long) ic->len, ic->seq); ret = fwrite(ic->buf, ic->len, 1, f); if (ret != 1 || ferror(f)) { iter.err = errno; log_err("fio: error writing compressed log\n"); } } else inflate_chunk(ic, log->log_gz_store, f, &stream, &iter); free_chunk(ic); } if (iter.seq) { finish_chunk(&stream, f, &iter); free(iter.buf); } return iter.err; } /* * Open compressed log file and decompress the stored chunks and * write them to stdout. The chunks are stored sequentially in the * file, so we iterate over them and do them one-by-one. */ int iolog_file_inflate(const char *file) { struct inflate_chunk_iter iter = { .chunk_sz = 64 * 1024 * 1024, }; struct iolog_compress ic; z_stream stream; struct stat sb; ssize_t ret; size_t total; void *buf; FILE *f; f = fopen(file, "r"); if (!f) { perror("fopen"); return 1; } if (stat(file, &sb) < 0) { fclose(f); perror("stat"); return 1; } ic.buf = buf = malloc(sb.st_size); ic.len = sb.st_size; ic.seq = 1; ret = fread(ic.buf, ic.len, 1, f); if (ret < 0) { perror("fread"); fclose(f); return 1; } else if (ret != 1) { log_err("fio: short read on reading log\n"); fclose(f); return 1; } fclose(f); /* * Each chunk will return Z_STREAM_END. We don't know how many * chunks are in the file, so we just keep looping and incrementing * the sequence number until we have consumed the whole compressed * file. */ total = ic.len; do { size_t ret; ret = inflate_chunk(&ic, 1, stdout, &stream, &iter); total -= ret; if (!total) break; if (iter.err) break; ic.seq++; ic.len -= ret; ic.buf += ret; } while (1); if (iter.seq) { finish_chunk(&stream, stdout, &iter); free(iter.buf); } free(buf); return iter.err; } #else static int inflate_gz_chunks(struct io_log *log, FILE *f) { return 0; } int iolog_file_inflate(const char *file) { log_err("fio: log inflation not possible without zlib\n"); return 1; } #endif void flush_log(struct io_log *log) { void *buf; FILE *f; f = fopen(log->filename, "w"); if (!f) { perror("fopen log"); return; } buf = set_file_buffer(f); inflate_gz_chunks(log, f); flush_samples(f, log->log, log->nr_samples * log_entry_sz(log)); fclose(f); clear_file_buffer(buf); }