summaryrefslogtreecommitdiffstats
path: root/api/src/glfs-fops.c
diff options
context:
space:
mode:
authorSoumya Koduri <skoduri@redhat.com>2017-04-21 16:30:20 +0530
committerJeff Darcy <jeff@pl.atyp.us>2017-05-02 23:33:13 +0000
commit41000cd0b57a81c4ace4a1d3da0fcc352a11f146 (patch)
treeb8bebcf014eca1e2c1c493316ce7634c2f3a292a /api/src/glfs-fops.c
parent316e3300cfaa646b7fa45fcc7f57b81c7bb15a0e (diff)
gfapi/handleops: Introducing glfs_xreaddirplus_r() fop for handleops
Its known that readdirplus operation fetches stat as well for each of the dirents. But often applications may need extra information, like for eg., NFS-Ganesha which operates on handles needs handles for each of those dirents returned. So this would require extra calls to the backend, in this case LOOKUP (which is very expensive operation) resulting in very low readdir performance. To address that introducing this new API using which applications can make request for any extra information to be returned as part of readdirplus response. Currently this new api returns stat and handles as demanded by application. The synopsis of the API is noted in glfs.h. @todo: * Enhance test script using this new API Below were the perf results on single brick volume with and without these changes - Dataset used - 10*100 directories and each directory containing 100 empty files. I used NFS-Ganesha application to test these changes - >for i in {1..5}; do systemctl restart nfs-ganesha; sleep 10; mount -t nfs -o vers=4 localhost:/brick_vol /mnt; cd /mnt; echo "ITERATION$i"; date; find . > tmp-nfs.log; date; cd /; umount /mnt; sleep 2; done; Without these changes - ITERATION1 Mon Mar 20 17:22:26 IST 2017 Mon Mar 20 17:23:18 IST 2017 ITERATION2 Mon Mar 20 17:23:39 IST 2017 Mon Mar 20 17:24:28 IST 2017 ITERATION3 Mon Mar 20 17:24:49 IST 2017 Mon Mar 20 17:25:36 IST 2017 ITERATION4 Mon Mar 20 17:30:57 IST 2017 Mon Mar 20 17:31:37 IST 2017 ITERATION5 Mon Mar 20 17:31:57 IST 2017 Mon Mar 20 17:32:40 IST 2017 [root@dhcp35-197 /]# On an average ~46.2 sec With these changes applied - ITERATION1 Mon Mar 20 17:35:03 IST 2017 Mon Mar 20 17:35:15 IST 2017 ITERATION2 Mon Mar 20 17:35:36 IST 2017 Mon Mar 20 17:35:46 IST 2017 ITERATION3 Mon Mar 20 17:36:06 IST 2017 Mon Mar 20 17:36:17 IST 2017 ITERATION4 Mon Mar 20 17:41:38 IST 2017 Mon Mar 20 17:41:49 IST 2017 ITERATION5 Mon Mar 20 17:42:10 IST 2017 Mon Mar 20 17:42:20 IST 2017 On an average ~10.8 sec Updates #174 BUG: 1442950 Change-Id: I0f74f74dc62085ca4c4a23c38e3edc84bd850876 Signed-off-by: Soumya Koduri <skoduri@redhat.com> Reviewed-on: https://review.gluster.org/15663 Smoke: Gluster Build System <jenkins@build.gluster.org> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org> Reviewed-by: Niels de Vos <ndevos@redhat.com> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
Diffstat (limited to 'api/src/glfs-fops.c')
-rw-r--r--api/src/glfs-fops.c137
1 files changed, 136 insertions, 1 deletions
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
index 0e5b206b98c..1bb958fc1b7 100644
--- a/api/src/glfs-fops.c
+++ b/api/src/glfs-fops.c
@@ -2792,7 +2792,7 @@ glfd_entry_next (struct glfs_fd *glfd, int plus)
}
-static struct dirent *
+struct dirent *
glfs_readdirbuf_get (struct glfs_fd *glfd)
{
struct dirent *buf = NULL;
@@ -4608,3 +4608,138 @@ out:
invalid_fs:
return ret;
}
+
+/*
+ * Given glfd of a directory, this function does readdirp and returns
+ * xstat along with dirents.
+ */
+int
+pub_glfs_xreaddirplus_r (struct glfs_fd *glfd, uint32_t flags,
+ struct glfs_xreaddirp_stat **xstat_p,
+ struct dirent *ext,
+ struct dirent **res)
+{
+ int ret = -1;
+ gf_dirent_t *entry = NULL;
+ struct dirent *buf = NULL;
+ struct glfs_xreaddirp_stat *xstat = NULL;
+
+ DECLARE_OLD_THIS;
+ __GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
+
+ GF_REF_GET (glfd);
+
+ GF_VALIDATE_OR_GOTO (THIS->name, xstat_p, out);
+ GF_VALIDATE_OR_GOTO (THIS->name, res, out);
+
+ errno = 0;
+
+ if (ext)
+ buf = ext;
+ else
+ buf = glfs_readdirbuf_get (glfd);
+
+ if (!buf)
+ goto out;
+
+ xstat = GF_CALLOC(1, sizeof(struct glfs_xreaddirp_stat),
+ glfs_mt_xreaddirp_stat_t);
+
+ if (!xstat)
+ goto out;
+
+ /* this is readdirplus operation */
+ entry = glfd_entry_next (glfd, 1);
+
+ /* XXX: Ideally when we reach EOD, errno should have been
+ * set to ENOENT. But that doesn't seem to be the case.
+ *
+ * The only way to confirm if its EOD at this point is that
+ * errno == 0 and entry == NULL
+ */
+ if (errno)
+ goto out;
+
+ if (!entry) {
+ /* reached EOD, ret = 0 */
+ ret = 0;
+ *res = NULL;
+ goto out;
+ }
+
+ *res = buf;
+ gf_dirent_to_dirent (entry, buf);
+
+ if (flags & GFAPI_XREADDIRP_STAT) {
+ glfs_iatt_to_stat (glfd->fs, &entry->d_stat, &xstat->st);
+ xstat->flags_handled |= GFAPI_XREADDIRP_STAT;
+ }
+
+ if ((flags & GFAPI_XREADDIRP_HANDLE) &&
+ /* skip . and .. */
+ strcmp(buf->d_name, ".")
+ && strcmp(buf->d_name, "..")) {
+
+ /* Now create object.
+ * We can use "glfs_h_find_handle" as well as inodes would have
+ * already got linked as part of 'gf_link_inodes_from_dirent' */
+ xstat->object = glfs_h_create_from_handle (glfd->fs,
+ entry->d_stat.ia_gfid,
+ GFAPI_HANDLE_LENGTH,
+ NULL);
+
+ if (xstat->object) { /* success */
+ /* note: xstat->object->inode->ref is taken
+ * This shall be unref'ed when application does
+ * glfs_free(xstat) */
+ xstat->flags_handled |= GFAPI_XREADDIRP_HANDLE;
+ }
+ }
+
+ ret = xstat->flags_handled;
+ *xstat_p = xstat;
+
+out:
+ gf_msg_debug (THIS->name, 0,
+ "xreaddirp- requested_flags (%x) , processed_flags (%x)",
+ flags, xstat->flags_handled);
+
+ GF_REF_PUT (glfd);
+
+ if (ret < 0) {
+ gf_msg (THIS->name, GF_LOG_WARNING, errno,
+ API_MSG_XREADDIRP_R_FAILED,
+ "glfs_x_readdirp_r failed - reason (%s)",
+ strerror(errno));
+
+ if (xstat)
+ glfs_free (xstat);
+ }
+
+ __GLFS_EXIT_FS;
+
+ return ret;
+
+invalid_fs:
+ return -1;
+}
+GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_xreaddirplus_r, 3.11.0);
+
+struct stat*
+pub_glfs_xreaddirplus_get_stat (struct glfs_xreaddirp_stat *xstat)
+{
+ GF_VALIDATE_OR_GOTO ("glfs_xreaddirplus_get_stat", xstat, out);
+
+ if (!xstat->flags_handled & GFAPI_XREADDIRP_STAT)
+ gf_msg (THIS->name, GF_LOG_ERROR, errno,
+ LG_MSG_INVALID_ARG,
+ "GFAPI_XREADDIRP_STAT is not set. Flags"
+ "handled for xstat(%p) are (%x)",
+ xstat, xstat->flags_handled);
+ return &xstat->st;
+
+out:
+ return NULL;
+}
+GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_xreaddirplus_get_stat, 3.11.0);
+