diff --git a/src/buffered_file_writer.c b/src/buffered_file_writer.c new file mode 100644 index 0000000..ad53d31 --- /dev/null +++ b/src/buffered_file_writer.c @@ -0,0 +1,214 @@ +/** +* Copyright (C) 2008 Happy Fish / YuQing +* +* FastDFS may be copied only under the terms of the GNU General +* Public License V3, which may be found in the FastDFS source kit. +* Please visit the FastDFS Home Page http://www.fastken.com/ for more detail. +**/ + +#include +#include +#include +#include +#include +#include +#include +#include "shared_func.h" +#include "logger.h" +#include "buffered_file_writer.h" + +int buffered_file_writer_open_ex(BufferedFileWriter *writer, + const char *filename, const int buffer_size, + const int max_written_once, const int mode) +{ + int result; + int written_once; + + writer->buffer_size = (buffer_size > 0) ? buffer_size : 64 * 1024; + written_once = (max_written_once > 0) ? max_written_once : 256; + if (written_once > writer->buffer_size) + { + logError("file: "__FILE__", line: %d, " + "max_written_once: %d > buffer_size: %d", + __LINE__, written_once, writer->buffer_size); + return EINVAL; + } + + writer->buff = (char *)malloc(writer->buffer_size); + if (writer->buff == NULL) + { + logError("file: "__FILE__", line: %d, " + "malloc %d bytes fail", + __LINE__, writer->buffer_size); + return ENOMEM; + } + + snprintf(writer->filename, sizeof(writer->filename), "%s", filename); + writer->fd = open(writer->filename, O_WRONLY | O_CREAT | O_TRUNC, mode); + if (writer->fd < 0) + { + result = errno != 0 ? errno : EIO; + logError("file: "__FILE__", line: %d, " + "open file %s fail, " + "errno: %d, error info: %s", + __LINE__, writer->filename, + result, STRERROR(result)); + + free(writer->buff); + writer->buff = NULL; + return result; + } + + writer->current = writer->buff; + writer->buff_end = writer->buff + writer->buffer_size; + writer->water_mark = writer->buff_end - written_once; + + return 0; +} + +int buffered_file_writer_close(BufferedFileWriter *writer) +{ + int result; + + if (writer->buff == NULL) + { + return EINVAL; + } + + result = buffered_file_writer_flush(writer); + if (result == 0 && fsync(writer->fd) != 0) + { + result = errno != 0 ? errno : EIO; + logError("file: "__FILE__", line: %d, " + "fsync file %s fail, " + "errno: %d, error info: %s", + __LINE__, writer->filename, + result, STRERROR(result)); + } + + if (close(writer->fd) != 0) + { + if (result == 0) + { + result = errno != 0 ? errno : EIO; + } + logError("file: "__FILE__", line: %d, " + "close file %s fail, " + "errno: %d, error info: %s", + __LINE__, writer->filename, + errno, STRERROR(errno)); + } + + free(writer->buff); + writer->buff = NULL; + + return result; +} + +int buffered_file_writer_flush(BufferedFileWriter *writer) +{ + int result; + int len; + + len = writer->current - writer->buff; + if (len == 0) + { + return 0; + } + + if (fc_safe_write(writer->fd, writer->buff, len) != len) + { + result = errno != 0 ? errno : EIO; + logError("file: "__FILE__", line: %d, " + "write to file %s fail, " + "errno: %d, error info: %s", __LINE__, + writer->filename, result, STRERROR(result)); + return result; + } + + writer->current = writer->buff; + return 0; +} + +int buffered_file_writer_append(BufferedFileWriter *writer, + const char *format, ...) +{ + va_list ap; + int result; + int remain_size; + int len; + int i; + + result = 0; + for (i=0; i<2; i++) + { + remain_size = writer->buff_end - writer->current; + va_start(ap, format); + len = vsnprintf(writer->current, remain_size, format, ap); + va_end(ap); + + if (len < remain_size) + { + writer->current += len; + if (writer->current > writer->water_mark) + { + result = buffered_file_writer_flush(writer); + } + + break; + } + + if (len > writer->buffer_size) + { + result = ENOSPC; + logError("file: "__FILE__", line: %d, " + "too large output buffer, %d > %d!", + __LINE__, len, writer->buffer_size); + break; + } + + //maybe full, try again + if ((result=buffered_file_writer_flush(writer)) != 0) + { + break; + } + } + + return result; +} + +int buffered_file_writer_append_buff(BufferedFileWriter *writer, + const char *buff, const int len) +{ + int result; + + if (len >= writer->water_mark - writer->current) + { + if ((result=buffered_file_writer_flush(writer)) != 0) + { + return result; + } + + if (fc_safe_write(writer->fd, buff, len) != len) + { + result = errno != 0 ? errno : EIO; + logError("file: "__FILE__", line: %d, " + "write to file %s fail, " + "errno: %d, error info: %s", __LINE__, + writer->filename, result, STRERROR(result)); + return result; + } + + return 0; + } + + memcpy(writer->current, buff, len); + writer->current += len; + if (writer->current > writer->water_mark) + { + return buffered_file_writer_flush(writer); + } + + return 0; +} + diff --git a/src/buffered_file_writer.h b/src/buffered_file_writer.h new file mode 100644 index 0000000..988229f --- /dev/null +++ b/src/buffered_file_writer.h @@ -0,0 +1,72 @@ +/** +* Copyright (C) 2008 Happy Fish / YuQing +* +* FastDFS may be copied only under the terms of the GNU General +* Public License V3, which may be found in the FastDFS source kit. +* Please visit the FastDFS Home Page http://www.fastken.com/ for more detail. +**/ + +#ifndef BUFFERED_FILE_WRITER_H +#define BUFFERED_FILE_WRITER_H + +#include "common_define.h" + +typedef struct +{ + int fd; + int buffer_size; + char filename[MAX_PATH_SIZE]; + char *buff; + char *current; + char *buff_end; + char *water_mark; +} BufferedFileWriter; + +#ifdef __cplusplus +extern "C" { +#endif + +/** open buffered file writer + * parameters: + * writer: the writer + * filename: the filename to write + * buffer_size: the buffer size, <= 0 for recommend 64KB + * max_written_once: max written bytes per call, <= 0 for 256 + * mode: the file privilege such as 0644 + * return: error code, 0 for success, != 0 for errno + */ +int buffered_file_writer_open_ex(BufferedFileWriter *writer, + const char *filename, const int buffer_size, + const int max_written_once, const int mode); + +static inline int buffered_file_writer_open(BufferedFileWriter *writer, + const char *filename) +{ + const int buffer_size = 0; + const int max_written_once = 0; + const int mode = 0644; + return buffered_file_writer_open_ex(writer, filename, + buffer_size, max_written_once, mode); +} + +/** close buffered file writer + * parameters: + * writer: the writer + * return: error code, 0 for success, != 0 for errno + */ +int buffered_file_writer_close(BufferedFileWriter *writer); + +int buffered_file_writer_append(BufferedFileWriter *writer, + const char *format, ...); + +int buffered_file_writer_append_buff(BufferedFileWriter *writer, + const char *buff, const int len); + +int buffered_file_writer_flush(BufferedFileWriter *writer); + +#ifdef __cplusplus +} +#endif + +#endif +