aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
authorPawel Jakub Dawidek <[email protected]>2012-05-29 10:50:50 -0700
committerBrian Behlendorf <[email protected]>2012-06-14 09:49:04 -0700
commit0cee24064a79f9c01fc4521543c37acea538405f (patch)
treecc7429b7bc14f057aade9bea66a72a39e6a5a23c /cmd
parent74497b7ab6af69434453e03c755d3f6e6e655aee (diff)
Speed up 'zfs list -t snapshot -o name -s name'
FreeBSD #xxx: Dramatically optimize listing snapshots when user requests only snapshot names and wants to sort them by name, ie. when executes: # zfs list -t snapshot -o name -s name Because only name is needed we don't have to read all snapshot properties. Below you can find how long does it take to list 34509 snapshots from a single disk pool before and after this change with cold and warm cache: before: # time zfs list -t snapshot -o name -s name > /dev/null cold cache: 525s warm cache: 218s after: # time zfs list -t snapshot -o name -s name > /dev/null cold cache: 1.7s warm cache: 1.1s NOTE: This patch only appears in FreeBSD. If/when Illumos picks up the change we may want to drop this patch and adopt their version. However, for now this addresses a real issue. Ported-by: Brian Behlendorf <[email protected]> Issue #450
Diffstat (limited to 'cmd')
-rw-r--r--cmd/zfs/zfs_iter.c30
-rw-r--r--cmd/zfs/zfs_iter.h2
-rw-r--r--cmd/zfs/zfs_main.c14
3 files changed, 42 insertions, 4 deletions
diff --git a/cmd/zfs/zfs_iter.c b/cmd/zfs/zfs_iter.c
index e2ab90eaf..6239a8f6b 100644
--- a/cmd/zfs/zfs_iter.c
+++ b/cmd/zfs/zfs_iter.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 Pawel Jakub Dawidek <[email protected]>.
*/
#include <libintl.h>
@@ -129,8 +130,11 @@ zfs_callback(zfs_handle_t *zhp, void *data)
cb->cb_depth++;
if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)
(void) zfs_iter_filesystems(zhp, zfs_callback, data);
- if ((zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) && include_snaps)
- (void) zfs_iter_snapshots(zhp, zfs_callback, data);
+ if ((zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) && include_snaps) {
+ (void) zfs_iter_snapshots(zhp,
+ (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback,
+ data);
+ }
cb->cb_depth--;
}
@@ -184,6 +188,13 @@ zfs_free_sort_columns(zfs_sort_column_t *sc)
}
}
+int
+zfs_sort_only_by_name(const zfs_sort_column_t *sc)
+{
+ return (sc != NULL && sc->sc_next == NULL &&
+ sc->sc_prop == ZFS_PROP_NAME);
+}
+
/* ARGSUSED */
static int
zfs_compare(const void *larg, const void *rarg, void *unused)
@@ -224,7 +235,13 @@ zfs_compare(const void *larg, const void *rarg, void *unused)
lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
- if (lcreate < rcreate)
+ /*
+ * Both lcreate and rcreate being 0 means we don't have
+ * properties and we should compare full name.
+ */
+ if (lcreate == 0 && rcreate == 0)
+ ret = strcmp(lat + 1, rat + 1);
+ else if (lcreate < rcreate)
ret = -1;
else if (lcreate > rcreate)
ret = 1;
@@ -290,7 +307,14 @@ zfs_sort(const void *larg, const void *rarg, void *data)
if (rvalid)
verify(nvlist_lookup_string(rval,
ZPROP_VALUE, &rstr) == 0);
+ } else if (psc->sc_prop == ZFS_PROP_NAME) {
+ lvalid = rvalid = B_TRUE;
+
+ (void) strlcpy(lbuf, zfs_get_name(l), sizeof(lbuf));
+ (void) strlcpy(rbuf, zfs_get_name(r), sizeof(rbuf));
+ lstr = lbuf;
+ rstr = rbuf;
} else if (zfs_prop_is_string(psc->sc_prop)) {
lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf,
sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0);
diff --git a/cmd/zfs/zfs_iter.h b/cmd/zfs/zfs_iter.h
index 8c6b9fdef..7f740e75e 100644
--- a/cmd/zfs/zfs_iter.h
+++ b/cmd/zfs/zfs_iter.h
@@ -43,11 +43,13 @@ typedef struct zfs_sort_column {
#define ZFS_ITER_PROP_LISTSNAPS (1 << 2)
#define ZFS_ITER_DEPTH_LIMIT (1 << 3)
#define ZFS_ITER_RECVD_PROPS (1 << 4)
+#define ZFS_ITER_SIMPLE (1 << 5)
int zfs_for_each(int, char **, int options, zfs_type_t,
zfs_sort_column_t *, zprop_list_t **, int, zfs_iter_f, void *);
int zfs_add_sort_column(zfs_sort_column_t **, const char *, boolean_t);
void zfs_free_sort_columns(zfs_sort_column_t *);
+int zfs_sort_only_by_name(const zfs_sort_column_t *);
#ifdef __cplusplus
}
diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c
index e20d57000..0f00688b3 100644
--- a/cmd/zfs/zfs_main.c
+++ b/cmd/zfs/zfs_main.c
@@ -2650,7 +2650,12 @@ print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted)
first = B_FALSE;
}
- if (pl->pl_prop != ZPROP_INVAL) {
+ if (pl->pl_prop == ZFS_PROP_NAME) {
+ (void) strlcpy(property, zfs_get_name(zhp),
+ sizeof(property));
+ propstr = property;
+ right_justify = zfs_prop_align_right(pl->pl_prop);
+ } else if (pl->pl_prop != ZPROP_INVAL) {
if (zfs_prop_get(zhp, pl->pl_prop, property,
sizeof (property), NULL, NULL, 0, B_FALSE) != 0)
propstr = "-";
@@ -2811,6 +2816,13 @@ zfs_do_list(int argc, char **argv)
fields = default_fields;
/*
+ * If we are only going to list snapshot names and sort by name,
+ * then we can use faster version.
+ */
+ if (strcmp(fields, "name") == 0 && zfs_sort_only_by_name(sortcol))
+ flags |= ZFS_ITER_SIMPLE;
+
+ /*
* If "-o space" and no types were specified, don't display snapshots.
*/
if (strcmp(fields, "space") == 0 && types_specified == B_FALSE)