+/* Submits all the caches used by WAFL. Uses "submit_cache_ratio". */
+static int submit_wafl_data (const char *hostname, const char *instance, /* {{{ */
+ cfg_wafl_t *old_data, const cfg_wafl_t *new_data)
+{
+ /* Submit requested counters */
+ if (HAS_ALL_FLAGS (old_data->flags, CFG_WAFL_NAME_CACHE | HAVE_WAFL_NAME_CACHE)
+ && HAS_ALL_FLAGS (new_data->flags, HAVE_WAFL_NAME_CACHE))
+ submit_cache_ratio (hostname, instance, "name_cache_hit",
+ new_data->name_cache_hit, new_data->name_cache_miss,
+ old_data->name_cache_hit, old_data->name_cache_miss,
+ new_data->timestamp);
+
+ if (HAS_ALL_FLAGS (old_data->flags, CFG_WAFL_DIR_CACHE | HAVE_WAFL_FIND_DIR)
+ && HAS_ALL_FLAGS (new_data->flags, HAVE_WAFL_FIND_DIR))
+ submit_cache_ratio (hostname, instance, "find_dir_hit",
+ new_data->find_dir_hit, new_data->find_dir_miss,
+ old_data->find_dir_hit, old_data->find_dir_miss,
+ new_data->timestamp);
+
+ if (HAS_ALL_FLAGS (old_data->flags, CFG_WAFL_BUF_CACHE | HAVE_WAFL_BUF_HASH)
+ && HAS_ALL_FLAGS (new_data->flags, HAVE_WAFL_BUF_HASH))
+ submit_cache_ratio (hostname, instance, "buf_hash_hit",
+ new_data->buf_hash_hit, new_data->buf_hash_miss,
+ old_data->buf_hash_hit, old_data->buf_hash_miss,
+ new_data->timestamp);
+
+ if (HAS_ALL_FLAGS (old_data->flags, CFG_WAFL_INODE_CACHE | HAVE_WAFL_INODE_CACHE)
+ && HAS_ALL_FLAGS (new_data->flags, HAVE_WAFL_INODE_CACHE))
+ submit_cache_ratio (hostname, instance, "inode_cache_hit",
+ new_data->inode_cache_hit, new_data->inode_cache_miss,
+ old_data->inode_cache_hit, old_data->inode_cache_miss,
+ new_data->timestamp);
+
+ /* Clear old HAVE_* flags */
+ old_data->flags &= ~HAVE_WAFL_ALL;
+
+ /* Copy all counters */
+ old_data->timestamp = new_data->timestamp;
+ old_data->name_cache_hit = new_data->name_cache_hit;
+ old_data->name_cache_miss = new_data->name_cache_miss;
+ old_data->find_dir_hit = new_data->find_dir_hit;
+ old_data->find_dir_miss = new_data->find_dir_miss;
+ old_data->buf_hash_hit = new_data->buf_hash_hit;
+ old_data->buf_hash_miss = new_data->buf_hash_miss;
+ old_data->inode_cache_hit = new_data->inode_cache_hit;
+ old_data->inode_cache_miss = new_data->inode_cache_miss;
+
+ /* Copy HAVE_* flags */
+ old_data->flags |= (new_data->flags & HAVE_WAFL_ALL);
+
+ return (0);
+} /* }}} int submit_wafl_data */
+
+/* Submits volume performance data to the daemon, taking care to honor and
+ * update flags appropriately. */
+static int submit_volume_perf_data (const host_config_t *host, /* {{{ */
+ volume_t *volume,
+ const data_volume_perf_t *new_data)
+{
+ /* Check for and submit disk-octet values */
+ if (HAS_ALL_FLAGS (volume->perf_data.flags, CFG_VOLUME_PERF_IO)
+ && HAS_ALL_FLAGS (new_data->flags, HAVE_VOLUME_PERF_BYTES_READ | HAVE_VOLUME_PERF_BYTES_WRITE))
+ {
+ submit_two_counters (host->name, volume->name, "disk_octets", /* type instance = */ NULL,
+ (counter_t) new_data->read_bytes, (counter_t) new_data->write_bytes, new_data->timestamp);
+ }
+
+ /* Check for and submit disk-operations values */
+ if (HAS_ALL_FLAGS (volume->perf_data.flags, CFG_VOLUME_PERF_OPS)
+ && HAS_ALL_FLAGS (new_data->flags, HAVE_VOLUME_PERF_OPS_READ | HAVE_VOLUME_PERF_OPS_WRITE))
+ {
+ submit_two_counters (host->name, volume->name, "disk_ops", /* type instance = */ NULL,
+ (counter_t) new_data->read_ops, (counter_t) new_data->write_ops, new_data->timestamp);
+ }
+
+ /* Check for, calculate and submit disk-latency values */
+ if (HAS_ALL_FLAGS (volume->perf_data.flags, CFG_VOLUME_PERF_LATENCY
+ | HAVE_VOLUME_PERF_OPS_READ | HAVE_VOLUME_PERF_OPS_WRITE
+ | HAVE_VOLUME_PERF_LATENCY_READ | HAVE_VOLUME_PERF_LATENCY_WRITE)
+ && HAS_ALL_FLAGS (new_data->flags, HAVE_VOLUME_PERF_OPS_READ | HAVE_VOLUME_PERF_OPS_WRITE
+ | HAVE_VOLUME_PERF_LATENCY_READ | HAVE_VOLUME_PERF_LATENCY_WRITE))
+ {
+ gauge_t latency_per_op_read;
+ gauge_t latency_per_op_write;
+
+ latency_per_op_read = NAN;
+ latency_per_op_write = NAN;
+
+ /* Check if a counter wrapped around. */
+ if ((new_data->read_ops > volume->perf_data.read_ops)
+ && (new_data->read_latency > volume->perf_data.read_latency))
+ {
+ uint64_t diff_ops_read;
+ uint64_t diff_latency_read;
+
+ diff_ops_read = new_data->read_ops - volume->perf_data.read_ops;
+ diff_latency_read = new_data->read_latency - volume->perf_data.read_latency;
+
+ if (diff_ops_read > 0)
+ latency_per_op_read = ((gauge_t) diff_latency_read) / ((gauge_t) diff_ops_read);
+ }
+
+ if ((new_data->write_ops > volume->perf_data.write_ops)
+ && (new_data->write_latency > volume->perf_data.write_latency))
+ {
+ uint64_t diff_ops_write;
+ uint64_t diff_latency_write;
+
+ diff_ops_write = new_data->write_ops - volume->perf_data.write_ops;
+ diff_latency_write = new_data->write_latency - volume->perf_data.write_latency;
+
+ if (diff_ops_write > 0)
+ latency_per_op_write = ((gauge_t) diff_latency_write) / ((gauge_t) diff_ops_write);
+ }
+
+ submit_two_gauge (host->name, volume->name, "disk_latency", /* type instance = */ NULL,
+ latency_per_op_read, latency_per_op_write, new_data->timestamp);
+ }
+
+ /* Clear all HAVE_* flags. */
+ volume->perf_data.flags &= ~HAVE_VOLUME_PERF_ALL;
+
+ /* Copy all counters */
+ volume->perf_data.timestamp = new_data->timestamp;
+ volume->perf_data.read_bytes = new_data->read_bytes;
+ volume->perf_data.write_bytes = new_data->write_bytes;
+ volume->perf_data.read_ops = new_data->read_ops;
+ volume->perf_data.write_ops = new_data->write_ops;
+ volume->perf_data.read_latency = new_data->read_latency;
+ volume->perf_data.write_latency = new_data->write_latency;
+
+ /* Copy the HAVE_* flags */
+ volume->perf_data.flags |= (new_data->flags & HAVE_VOLUME_PERF_ALL);
+
+ return (0);
+} /* }}} int submit_volume_perf_data */
+
+/*
+ * Query functions
+ *
+ * These functions are called with appropriate data returned by the libnetapp
+ * interface which is parsed and submitted with the above functions.
+ */
+/* Data corresponding to <WAFL /> */
+static int cna_handle_wafl_data (const char *hostname, cfg_wafl_t *cfg_wafl, /* {{{ */
+ na_elem_t *data)
+{
+ cfg_wafl_t perf_data;