+/*
+ * MySQL query cache
+ *
+ * 4.* uses the "mysql_qcache" type which mixes different types of
+ * information. In 5.* this has been broken up.
+ */
+static int v5_mysql_qcache(const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+
+ if (vl->values_len != 5)
+ return FC_TARGET_STOP;
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy(&new_vl, vl, sizeof(new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &(value_t){.gauge = NAN};
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ /* Change the type to "cache_result" */
+ sstrncpy(new_vl.type, "cache_result", sizeof(new_vl.type));
+
+ /* Dispatch new value lists instead of this one */
+ new_vl.values[0].derive = (derive_t)vl->values[0].counter;
+ sstrncpy(new_vl.type_instance, "qcache-hits", sizeof(new_vl.type_instance));
+ plugin_dispatch_values(&new_vl);
+
+ new_vl.values[0].derive = (derive_t)vl->values[1].counter;
+ sstrncpy(new_vl.type_instance, "qcache-inserts",
+ sizeof(new_vl.type_instance));
+ plugin_dispatch_values(&new_vl);
+
+ new_vl.values[0].derive = (derive_t)vl->values[2].counter;
+ sstrncpy(new_vl.type_instance, "qcache-not_cached",
+ sizeof(new_vl.type_instance));
+ plugin_dispatch_values(&new_vl);
+
+ new_vl.values[0].derive = (derive_t)vl->values[3].counter;
+ sstrncpy(new_vl.type_instance, "qcache-prunes", sizeof(new_vl.type_instance));
+ plugin_dispatch_values(&new_vl);
+
+ /* The last data source is a gauge value, so we have to use a different type
+ * here. */
+ new_vl.values[0].gauge = vl->values[4].gauge;
+ sstrncpy(new_vl.type, "cache_size", sizeof(new_vl.type));
+ sstrncpy(new_vl.type_instance, "qcache", sizeof(new_vl.type_instance));
+ plugin_dispatch_values(&new_vl);
+
+ /* Abort processing */
+ return FC_TARGET_STOP;
+} /* }}} int v5_mysql_qcache */
+
+/*
+ * MySQL thread count
+ *
+ * 4.* uses the "mysql_threads" type which mixes different types of
+ * information. In 5.* this has been broken up.
+ */
+static int v5_mysql_threads(const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+
+ if (vl->values_len != 4)
+ return FC_TARGET_STOP;
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy(&new_vl, vl, sizeof(new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &(value_t){.gauge = NAN};
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ /* Change the type to "threads" */
+ sstrncpy(new_vl.type, "threads", sizeof(new_vl.type));
+
+ /* Dispatch new value lists instead of this one */
+ new_vl.values[0].gauge = vl->values[0].gauge;
+ sstrncpy(new_vl.type_instance, "running", sizeof(new_vl.type_instance));
+ plugin_dispatch_values(&new_vl);
+
+ new_vl.values[0].gauge = vl->values[1].gauge;
+ sstrncpy(new_vl.type_instance, "connected", sizeof(new_vl.type_instance));
+ plugin_dispatch_values(&new_vl);
+
+ new_vl.values[0].gauge = vl->values[2].gauge;
+ sstrncpy(new_vl.type_instance, "cached", sizeof(new_vl.type_instance));
+ plugin_dispatch_values(&new_vl);
+
+ /* The last data source is a counter value, so we have to use a different
+ * type here. */
+ new_vl.values[0].derive = (derive_t)vl->values[3].counter;
+ sstrncpy(new_vl.type, "total_threads", sizeof(new_vl.type));
+ sstrncpy(new_vl.type_instance, "created", sizeof(new_vl.type_instance));
+ plugin_dispatch_values(&new_vl);
+
+ /* Abort processing */
+ return FC_TARGET_STOP;
+} /* }}} int v5_mysql_threads */
+
+/*
+ * ZFS ARC hit and miss counters
+ *
+ * 4.* uses the flawed "arc_counts" type. In 5.* this has been replaced by the
+ * more generic "cache_result" type.
+ */
+static int v5_zfs_arc_counts(const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+ _Bool is_hits;
+
+ if (vl->values_len != 4)
+ return FC_TARGET_STOP;
+
+ if (strcmp("hits", vl->type_instance) == 0)
+ is_hits = 1;
+ else if (strcmp("misses", vl->type_instance) == 0)
+ is_hits = 0;
+ else
+ return FC_TARGET_STOP;
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy(&new_vl, vl, sizeof(new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &(value_t){.gauge = NAN};
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ /* Change the type to "cache_result" */
+ sstrncpy(new_vl.type, "cache_result", sizeof(new_vl.type));
+
+ /* Dispatch new value lists instead of this one */
+ new_vl.values[0].derive = (derive_t)vl->values[0].counter;
+ snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), "demand_data-%s",
+ is_hits ? "hit" : "miss");
+ plugin_dispatch_values(&new_vl);
+
+ new_vl.values[0].derive = (derive_t)vl->values[1].counter;
+ snprintf(new_vl.type_instance, sizeof(new_vl.type_instance),
+ "demand_metadata-%s", is_hits ? "hit" : "miss");
+ plugin_dispatch_values(&new_vl);
+
+ new_vl.values[0].derive = (derive_t)vl->values[2].counter;
+ snprintf(new_vl.type_instance, sizeof(new_vl.type_instance),
+ "prefetch_data-%s", is_hits ? "hit" : "miss");
+ plugin_dispatch_values(&new_vl);
+
+ new_vl.values[0].derive = (derive_t)vl->values[3].counter;
+ snprintf(new_vl.type_instance, sizeof(new_vl.type_instance),
+ "prefetch_metadata-%s", is_hits ? "hit" : "miss");
+ plugin_dispatch_values(&new_vl);
+
+ /* Abort processing */
+ return FC_TARGET_STOP;
+} /* }}} int v5_zfs_arc_counts */
+
+/*
+ * ZFS ARC L2 bytes
+ *
+ * "arc_l2_bytes" -> "io_octets-L2".
+ */
+static int v5_zfs_arc_l2_bytes(const data_set_t *ds, value_list_t *vl) /* {{{ */