diff options
author | Raghavendra G <rgowdapp@redhat.com> | 2015-11-17 12:57:54 +0530 |
---|---|---|
committer | Raghavendra G <rgowdapp@redhat.com> | 2015-12-22 01:55:57 -0800 |
commit | 3fcead2de7bcdb4e1312f37e7e750abd8d9d9770 (patch) | |
tree | 6df073e7faf75ed55e997692201494fed547ce84 /tests | |
parent | d73f5c9eae0f5c8796598fa1930844c15c2c37d4 (diff) |
performance/write-behind: retry "failed syncs to backend"
1. When sync fails, the cached-write is still preserved unless there
is a flush/fsync waiting on it.
2. When a sync fails and there is a flush/fsync waiting on the
cached-write, the cache is thrown away and no further retries will
be made. In other words flush/fsync act as barriers for all the
previous writes. The behaviour of fsync acting as a barrier is
controlled by an option (see below for details). All previous
writes are either successfully synced to backend or forgotten in
case of an error. Without such barrier fop (especially flush which
is issued prior to a close), we end up retrying for ever even after
fd is closed.
3. If a fop is waiting on cached-write and syncing to backend fails,
the waiting fop is failed.
4. sync failures when no fop is waiting are ignored and are not
propagated to application. For eg.,
a. first attempt of sync of a cached-write w1 fails
b. second attempt of sync of w1 succeeds
If there are no fops dependent on w1 are issued b/w a and b,
application won't know about failure encountered in a.
5. The effect of repeated sync failures is that, there will be no
cache for future writes and they cannot be written behind.
fsync as a barrier and resync of cached writes post fsync failure:
==================================================================
Whether to keep retrying failed syncs post fsync is controlled by an
option "resync-failed-syncs-after-fsync". By default, this option is
set to "off".
If sync of "cached-writes issued before fsync" (to backend) fails,
this option configures whether to retry syncing them after fsync or
forget them. If set to on, cached-writes are retried till a "flush"
fop (or a successful sync) on sync failures. fsync itself is failed
irrespective of the value of this option, when there is a sync failure
of any cached-writes issued before fsync.
Change-Id: I6097c9257bfb9ee5b15616fbe6a0576ae9af369a
Signed-off-by: Raghavendra G <rgowdapp@redhat.com>
BUG: 1279730
Reviewed-on: http://review.gluster.org/12594
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/bugs/rdma/bug-765473.t | 35 | ||||
-rw-r--r-- | tests/bugs/write-behind/bug-1279730.c | 131 | ||||
-rwxr-xr-x | tests/bugs/write-behind/bug-1279730.t | 31 |
3 files changed, 162 insertions, 35 deletions
diff --git a/tests/bugs/rdma/bug-765473.t b/tests/bugs/rdma/bug-765473.t deleted file mode 100755 index 9f595a1d479..00000000000 --- a/tests/bugs/rdma/bug-765473.t +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -. $(dirname $0)/../../include.rc -. $(dirname $0)/../../volume.rc -. $(dirname $0)/../../fileio.rc - -cleanup; - -function clients_connected() -{ - volname=$1 - gluster volume status $volname clients | grep -i 'Clients connected' | sed -e 's/[^0-9]*\(.*\)/\1/g' -} - -## Start and create a volume -TEST glusterd; -TEST pidof glusterd; -TEST $CLI volume create $V0 $H0:$B0/${V0}1 -TEST $CLI volume start $V0; - -TEST glusterfs --direct-io-mode=yes --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0; - -TEST fd=`fd_available` -TEST fd_open $fd 'w' "$M0/testfile" -TEST fd_write $fd "content" -TEST $CLI volume stop $V0 -# write some content which will result in marking fd bad -fd_write $fd "more content" -sync $V0 -TEST $CLI volume start $V0 -EXPECT 'Started' volinfo_field $V0 'Status'; -EXPECT_WITHIN $PROCESS_UP_TIMEOUT 2 clients_connected $V0 -TEST ! fd_write $fd "still more content" - -cleanup diff --git a/tests/bugs/write-behind/bug-1279730.c b/tests/bugs/write-behind/bug-1279730.c new file mode 100644 index 00000000000..535d289c582 --- /dev/null +++ b/tests/bugs/write-behind/bug-1279730.c @@ -0,0 +1,131 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <assert.h> + +int +main (int argc, char *argv[]) +{ + int fd = -1, ret = -1, len = 0; + char *path = NULL, buf[128] = {0, }, *cmd = NULL; + struct stat stbuf = {0, }; + int write_to_child[2] = {0, }, write_to_parent[2] = {0, }; + + path = argv[1]; + cmd = argv[2]; + + assert (argc == 3); + + ret = pipe (write_to_child); + if (ret < 0) { + fprintf (stderr, "creation of write-to-child pipe failed " + "(%s)\n", strerror (errno)); + goto out; + } + + ret = pipe (write_to_parent); + if (ret < 0) { + fprintf (stderr, "creation of write-to-parent pipe failed " + "(%s)\n", strerror (errno)); + goto out; + } + + ret = fork (); + switch (ret) { + case 0: + close (write_to_child[1]); + close (write_to_parent[0]); + + /* child, wait for instructions to execute command */ + ret = read (write_to_child[0], buf, 128); + if (ret < 0) { + fprintf (stderr, "child: read on pipe failed (%s)\n", + strerror (errno)); + goto out; + } + + system (cmd); + + ret = write (write_to_parent[1], "1", 2); + if (ret < 0) { + fprintf (stderr, "child: write to pipe failed (%s)\n", + strerror (errno)); + goto out; + } + break; + + case -1: + fprintf (stderr, "fork failed (%s)\n", strerror (errno)); + goto out; + + default: + close (write_to_parent[1]); + close (write_to_child[0]); + + fd = open (path, O_CREAT | O_RDWR | O_APPEND, S_IRWXU); + if (fd < 0) { + fprintf (stderr, "open failed (%s)\n", + strerror (errno)); + goto out; + } + + len = strlen ("test-content") + 1; + ret = write (fd, "test-content", len); + + if (ret < len) { + fprintf (stderr, "write failed %d (%s)\n", ret, + strerror (errno)); + } + + ret = pread (fd, buf, 128, 0); + if ((ret == len) && (strcmp (buf, "test-content") == 0)) { + fprintf (stderr, "read should've failed as previous " + "write would've failed with EDQUOT, but its " + "successful"); + ret = -1; + goto out; + } + + ret = write (write_to_child[1], "1", 2); + if (ret < 0) { + fprintf (stderr, "parent: write to pipe failed (%s)\n", + strerror (errno)); + goto out; + } + + ret = read (write_to_parent[0], buf, 128); + if (ret < 0) { + fprintf (stderr, "parent: read from pipe failed (%s)\n", + strerror (errno)); + goto out; + } + + /* this will force a sync on cached-write and now that quota + limit is increased, sync will be successful. ignore return + value as fstat would fail with EDQUOT (picked up from + cached-write because of previous sync failure. + */ + fstat (fd, &stbuf); + + ret = pread (fd, buf, 128, 0); + if (ret != len) { + fprintf (stderr, "post cmd read failed %d (data:%s) " + "(error:%s)\n", ret, buf, strerror (errno)); + goto out; + } + + if (strcmp (buf, "test-content")) { + fprintf (stderr, "wrong data (%s)\n", buf); + goto out; + } + } + + ret = 0; + +out: + return ret; +} diff --git a/tests/bugs/write-behind/bug-1279730.t b/tests/bugs/write-behind/bug-1279730.t new file mode 100755 index 00000000000..38e564b7afc --- /dev/null +++ b/tests/bugs/write-behind/bug-1279730.t @@ -0,0 +1,31 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../fileio.rc + +cleanup; + +## Start and create a volume +TEST glusterd; +TEST pidof glusterd; +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/$V0; +TEST $CLI volume start $V0; +TEST $CLI volume quota $V0 enable +TEST $CLI volume quota $V0 limit-usage / 4 + +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 + +# compile the test program and run it +TEST $CC -O0 -g3 $(dirname $0)/bug-1279730.c -o $(dirname $0)/bug-1279730 + +TEST $(dirname $0)/bug-1279730 $M0/file "\"$CLI volume quota $V0 limit-usage / 1024\"" + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; + +cleanup; |