[sheepdog] [PATCH] sheep: improve durability when creating object file.
Liu Yuan
namei.unix at gmail.com
Wed Mar 4 08:04:28 CET 2015
On Wed, Mar 04, 2015 at 02:18:02PM +0800, Xu Yifeng wrote:
> When creating a new file, make sure all data is written to disk, this is
> implemented in two steps:
>
> 1. Temporary file is written and committed to disk, this includes file system
> meta data and application data.
>
> 2. The temporary file is renamed, the action should also be commited to disk
> by calling fsync() on its directory.
>
> Signed-off-by: Xu Yifeng <skypexu at gmail.com>
> ---
> sheep/plain_store.c | 40 +++++++++++++++++++++++++++++++++-------
> 1 file changed, 33 insertions(+), 7 deletions(-)
>
> diff --git a/sheep/plain_store.c b/sheep/plain_store.c
> index 5ea2946..3284e97 100644
> --- a/sheep/plain_store.c
> +++ b/sheep/plain_store.c
> @@ -27,10 +27,11 @@ static inline bool iocb_is_aligned(const struct siocb *iocb)
>
> static int prepare_iocb(uint64_t oid, const struct siocb *iocb, bool create)
> {
> - int flags = O_DSYNC | O_RDWR;
> + int syncflag = create ? O_SYNC : O_DSYNC;
> + int flags = syncflag | O_RDWR;
>
> if (uatomic_is_true(&sys->use_journal) || sys->nosync == true)
> - flags &= ~O_DSYNC;
> + flags &= ~syncflag;
>
> if (sys->backend_dio && iocb_is_aligned(iocb)) {
> if (!is_aligned_to_pagesize(iocb->buf))
> @@ -391,7 +392,7 @@ int default_read(uint64_t oid, const struct siocb *iocb)
>
> int default_create_and_write(uint64_t oid, const struct siocb *iocb)
> {
> - char path[PATH_MAX], tmp_path[PATH_MAX];
> + char path[PATH_MAX], tmp_path[PATH_MAX], *dir;
> int flags = prepare_iocb(oid, iocb, true);
> int ret, fd;
> uint32_t len = iocb->length;
> @@ -409,7 +410,7 @@ int default_create_and_write(uint64_t oid, const struct siocb *iocb)
> != SD_RES_SUCCESS) {
> sd_err("turn off journaling");
> uatomic_set_false(&sys->use_journal);
> - flags |= O_DSYNC;
> + flags |= O_SYNC;
> sync();
> }
>
> @@ -455,18 +456,43 @@ int default_create_and_write(uint64_t oid, const struct siocb *iocb)
> goto out;
> }
>
> + close(fd);
> + fd = -1;
> ret = rename(tmp_path, path);
> if (ret < 0) {
> sd_err("failed to rename %s to %s: %m", tmp_path, path);
> ret = err_to_sderr(path, oid, errno);
> - goto out;
> + }
> +
> +out:
> + if (ret != SD_RES_SUCCESS) {
> + unlink(tmp_path);
at least we need printf error message if unlink() fails.
> + if (fd != -1)
> + (void)close(fd);
we recommend close(fd) instead of (void)close().
> + return ret;
> + }
> +
> + if (uatomic_is_true(&sys->use_journal))
> + return ret;
> +
> + dir = dirname(path);
> + fd = open(dir, O_DIRECTORY|O_RDONLY);
> + if (fd < 0) {
> + sd_err("failed to open directory %s: %m", dir);
> + return err_to_sderr(path, oid, errno);
> + }
> +
> + if (fsync(fd) != 0) {
> + sd_err("failed to write directory. %m");
> + ret = err_to_sderr(path, oid, errno);
> + goto out2;
> }
The error handling is obscure with normal code processing. I'd suggest following
code flow:
normal code path...
out_xxx:
handle_error_xxx;
return or fallthrough;
out_yyy:
handle_error_yyy;
return or fallthrough;
out_zzz:
....
Mix error handling and normal code path will make the code difficult to read.
Thanks,
Yuan
More information about the sheepdog
mailing list