1/*
2 * namespace.c
3 *
4 * Copyright (C) 2012-2014 Aerospike, Inc.
5 *
6 * Portions may be licensed to Aerospike, Inc. under one or more contributor
7 * license agreements.
8 *
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU Affero General Public License as published by the Free
11 * Software Foundation, either version 3 of the License, or (at your option) any
12 * later version.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see http://www.gnu.org/licenses/
21 */
22
23//==========================================================
24// Includes.
25//
26
27#include <stdbool.h>
28#include <stddef.h>
29#include <stdint.h>
30#include <string.h>
31
32#include "citrusleaf/alloc.h"
33#include "citrusleaf/cf_atomic.h"
34#include "citrusleaf/cf_hash_math.h"
35
36#include "dynbuf.h"
37#include "fault.h"
38#include "hist.h"
39#include "linear_hist.h"
40#include "vmapx.h"
41#include "xmem.h"
42
43#include "base/cfg.h"
44#include "base/datamodel.h"
45#include "base/index.h"
46#include "base/proto.h"
47#include "base/secondary_index.h"
48#include "base/truncate.h"
49#include "fabric/partition.h"
50#include "fabric/roster.h"
51#include "storage/storage.h"
52
53
54//==========================================================
55// Typedefs & constants.
56//
57
58
59//==========================================================
60// Globals.
61//
62
63
64//==========================================================
65// Forward declarations.
66//
67
68static void append_set_props(as_set *p_set, cf_dyn_buf *db);
69
70
71//==========================================================
72// Inlines & macros.
73//
74
75static inline uint32_t
76ns_name_hash(char *name)
77{
78 uint32_t hv = cf_hash_fnv32((const uint8_t *)name, strlen(name));
79
80 // Don't collide with a ns-id.
81 if (hv <= AS_NAMESPACE_SZ) {
82 hv += AS_NAMESPACE_SZ;
83 }
84
85 return hv;
86}
87
88
89//==========================================================
90// Public API.
91//
92
93as_namespace *
94as_namespace_create(char *name)
95{
96 cf_assert_nostack(strlen(name) < AS_ID_NAMESPACE_SZ,
97 AS_NAMESPACE, "{%s} namespace name too long (max length is %u)",
98 name, AS_ID_NAMESPACE_SZ - 1);
99
100 cf_assert_nostack(g_config.n_namespaces < AS_NAMESPACE_SZ,
101 AS_NAMESPACE, "too many namespaces (max is %u)", AS_NAMESPACE_SZ);
102
103 uint32_t namehash = ns_name_hash(name);
104
105 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
106 as_namespace *ns = g_config.namespaces[ns_ix];
107
108 if (strcmp(ns->name, name) == 0) {
109 cf_crash_nostack(AS_NAMESPACE, "{%s} duplicate namespace", name);
110 }
111
112 // Check for CE also, in case deployment later becomes EE with XDR.
113 if (ns->namehash == namehash) {
114 cf_crash_nostack(AS_XDR, "{%s} {%s} namespace name hashes collide",
115 ns->name, name);
116 }
117 }
118
119 as_namespace *ns = cf_malloc(sizeof(as_namespace));
120
121 g_config.namespaces[g_config.n_namespaces++] = ns;
122
123 // Set all members 0/NULL/false to start with.
124 memset(ns, 0, sizeof(as_namespace));
125
126 strcpy(ns->name, name);
127 ns->id = g_config.n_namespaces; // note that id is 1-based
128 ns->namehash = namehash;
129
130 ns->jem_arena = cf_alloc_create_arena();
131 cf_info(AS_NAMESPACE, "{%s} uses JEMalloc arena %d", name, ns->jem_arena);
132
133 ns->cold_start = false; // try warm or cool restart unless told not to
134 ns->arena = NULL; // can't create the arena until the configuration has been done
135
136 //--------------------------------------------
137 // Non-0/NULL/false configuration defaults.
138 //
139
140 ns->xmem_type = CF_XMEM_TYPE_UNDEFINED;
141
142 ns->cfg_replication_factor = 2;
143 ns->replication_factor = 0; // gets set on rebalance
144
145 ns->sets_enable_xdr = true; // ship all the sets by default
146 ns->ns_allow_nonxdr_writes = true; // allow nonxdr writes by default
147 ns->ns_allow_xdr_writes = true; // allow xdr writes by default
148 cf_vector_pointer_init(&ns->xdr_dclist_v, 3, 0);
149
150 ns->background_scan_max_rps = 10000; // internal write generation limit
151 ns->conflict_resolution_policy = AS_NAMESPACE_CONFLICT_RESOLUTION_POLICY_UNDEF;
152 ns->evict_hist_buckets = 10000; // for 30 day TTL, bucket width is 4 minutes 20 seconds
153 ns->evict_tenths_pct = 5; // default eviction amount is 0.5%
154 ns->hwm_disk_pct = 50; // evict when device usage exceeds 50%
155 ns->hwm_memory_pct = 60; // evict when memory usage exceeds 50% of namespace memory-size
156 ns->index_stage_size = 1024L * 1024L * 1024L; // 1G
157 ns->migrate_order = 5;
158 ns->migrate_retransmit_ms = 1000 * 5; // 5 seconds
159 ns->migrate_sleep = 1;
160 ns->nsup_hist_period = 60 * 60; // 1 hour
161 ns->nsup_period = 2 * 60; // 2 minutes
162 ns->n_nsup_threads = 1;
163 ns->read_consistency_level = AS_READ_CONSISTENCY_LEVEL_PROTO;
164 ns->stop_writes_pct = 90; // stop writes when 90% of either memory or disk is used
165 ns->n_single_scan_threads = 4; // maximum number of threads a single scan may run
166 ns->tomb_raider_eligible_age = 60 * 60 * 24; // 1 day
167 ns->tomb_raider_period = 60 * 60 * 24; // 1 day
168 ns->transaction_pending_limit = 20;
169 ns->n_truncate_threads = 4;
170 ns->tree_shared.n_sprigs = NUM_LOCK_PAIRS; // can't be less than number of lock pairs, 256 per partition
171 ns->write_commit_level = AS_WRITE_COMMIT_LEVEL_PROTO;
172
173 ns->mounts_hwm_pct = 80; // evict when persisted index usage exceeds 80%
174
175 ns->storage_type = AS_STORAGE_ENGINE_MEMORY;
176 ns->storage_data_in_memory = true;
177 // Note - default true is consistent with AS_STORAGE_ENGINE_MEMORY, but
178 // cfg.c will set default false for AS_STORAGE_ENGINE_SSD.
179
180 ns->storage_scheduler_mode = NULL; // null indicates default is to not change scheduler mode
181 ns->storage_write_block_size = 1024 * 1024;
182 ns->storage_defrag_lwm_pct = 50; // defrag if occupancy of block is < 50%
183 ns->storage_defrag_sleep = 1000; // sleep this many microseconds between each wblock
184 ns->storage_defrag_startup_minimum = 10; // defrag until >= 10% disk is writable before joining cluster
185 ns->storage_encryption = AS_ENCRYPTION_AES_128;
186 ns->storage_flush_max_us = 1000 * 1000; // wait this many microseconds before flushing inactive current write buffer (0 = never)
187 ns->storage_max_write_cache = 1024 * 1024 * 64;
188 ns->storage_min_avail_pct = 5; // stop writes when < 5% disk is writable
189 ns->storage_post_write_queue = 256; // number of wblocks per device used as post-write cache
190 ns->storage_tomb_raider_sleep = 1000; // sleep this many microseconds between each device read
191
192 ns->sindex_num_partitions = DEFAULT_PARTITIONS_PER_INDEX;
193
194 ns->geo2dsphere_within_strict = true;
195 ns->geo2dsphere_within_min_level = 1;
196 ns->geo2dsphere_within_max_level = 30;
197 ns->geo2dsphere_within_max_cells = 12;
198 ns->geo2dsphere_within_level_mod = 1;
199 ns->geo2dsphere_within_earth_radius_meters = 6371000; // Wikipedia, mean
200
201 // Special defaults that differ between CE and EE.
202 as_config_init_namespace(ns);
203
204 return ns;
205}
206
207
208void
209as_namespaces_init(bool cold_start_cmd, uint32_t instance)
210{
211 as_namespaces_setup(cold_start_cmd, instance);
212
213 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
214 as_namespace *ns = g_config.namespaces[ns_ix];
215
216 // Done with temporary sets configuration array.
217 if (ns->sets_cfg_array) {
218 cf_free(ns->sets_cfg_array);
219 }
220
221 for (uint32_t pid = 0; pid < AS_PARTITIONS; pid++) {
222 as_partition_init(ns, pid);
223 }
224
225 as_namespace_finish_setup(ns, instance);
226
227 as_truncate_init(ns);
228 as_sindex_init(ns);
229 }
230
231 as_roster_init_smd();
232 as_truncate_init_smd();
233 as_sindex_init_smd(); // before as_storage_init() populates the indexes
234}
235
236
237bool
238as_namespace_configure_sets(as_namespace *ns)
239{
240 for (uint32_t i = 0; i < ns->sets_cfg_count; i++) {
241 uint32_t idx;
242 cf_vmapx_err result = cf_vmapx_put_unique(ns->p_sets_vmap,
243 ns->sets_cfg_array[i].name, &idx);
244
245 if (result == CF_VMAPX_OK || result == CF_VMAPX_ERR_NAME_EXISTS) {
246 as_set* p_set = NULL;
247
248 if ((result = cf_vmapx_get_by_index(ns->p_sets_vmap, idx,
249 (void**)&p_set)) != CF_VMAPX_OK) {
250 // Should be impossible - just verified idx.
251 cf_crash(AS_NAMESPACE, "vmap error %d", result);
252 }
253
254 // Transfer configurable metadata.
255 p_set->stop_writes_count = ns->sets_cfg_array[i].stop_writes_count;
256 p_set->disable_eviction = ns->sets_cfg_array[i].disable_eviction;
257 p_set->enable_xdr = ns->sets_cfg_array[i].enable_xdr;
258 }
259 else {
260 // Maybe exceeded max sets allowed, but try failing gracefully.
261 cf_warning(AS_NAMESPACE, "vmap error %d", result);
262 return false;
263 }
264 }
265
266 return true;
267}
268
269
270as_namespace *
271as_namespace_get_byname(char *name)
272{
273 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
274 as_namespace *ns = g_config.namespaces[ns_ix];
275
276 if (strcmp(ns->name, name) == 0) {
277 return ns;
278 }
279 }
280
281 return NULL;
282}
283
284
285as_namespace *
286as_namespace_get_byid(uint32_t id)
287{
288 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
289 as_namespace *ns = g_config.namespaces[ns_ix];
290
291 if (id == ns->id) {
292 return ns;
293 }
294 }
295
296 return NULL;
297}
298
299
300as_namespace *
301as_namespace_get_bybuf(uint8_t *buf, size_t len)
302{
303 if (len >= AS_ID_NAMESPACE_SZ) {
304 return NULL;
305 }
306
307 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
308 as_namespace *ns = g_config.namespaces[ns_ix];
309
310 if (memcmp(buf, ns->name, len) == 0 && ns->name[len] == 0) {
311 return ns;
312 }
313 }
314
315 return NULL;
316}
317
318
319as_namespace *
320as_namespace_get_bymsgfield(as_msg_field *fp)
321{
322 return as_namespace_get_bybuf(fp->data, as_msg_field_get_value_sz(fp));
323}
324
325
326const char *
327as_namespace_get_set_name(as_namespace *ns, uint16_t set_id)
328{
329 // Note that set_id is 1-based, but cf_vmap index is 0-based.
330 // (This is because 0 in the index structure means 'no set'.)
331
332 if (set_id == INVALID_SET_ID) {
333 return NULL;
334 }
335
336 as_set *p_set;
337
338 return cf_vmapx_get_by_index(ns->p_sets_vmap, (uint32_t)set_id - 1,
339 (void**)&p_set) == CF_VMAPX_OK ? p_set->name : NULL;
340}
341
342
343uint16_t
344as_namespace_get_set_id(as_namespace *ns, const char *set_name)
345{
346 uint32_t idx;
347
348 return cf_vmapx_get_index(ns->p_sets_vmap, set_name, &idx) == CF_VMAPX_OK ?
349 (uint16_t)(idx + 1) : INVALID_SET_ID;
350}
351
352
353// At the moment this is only used by the enterprise build security feature.
354uint16_t
355as_namespace_get_create_set_id(as_namespace *ns, const char *set_name)
356{
357 if (! set_name) {
358 // Should be impossible.
359 cf_warning(AS_NAMESPACE, "null set name");
360 return INVALID_SET_ID;
361 }
362
363 uint32_t idx;
364 cf_vmapx_err result = cf_vmapx_get_index(ns->p_sets_vmap, set_name, &idx);
365
366 if (result == CF_VMAPX_OK) {
367 return (uint16_t)(idx + 1);
368 }
369
370 if (result == CF_VMAPX_ERR_NAME_NOT_FOUND) {
371 result = cf_vmapx_put_unique(ns->p_sets_vmap, set_name, &idx);
372
373 if (result == CF_VMAPX_ERR_NAME_EXISTS) {
374 return (uint16_t)(idx + 1);
375 }
376
377 if (result == CF_VMAPX_ERR_BAD_PARAM) {
378 cf_warning(AS_NAMESPACE, "set name %s too long", set_name);
379 return INVALID_SET_ID;
380 }
381
382 if (result == CF_VMAPX_ERR_FULL) {
383 cf_warning(AS_NAMESPACE, "can't add %s (at sets limit)", set_name);
384 return INVALID_SET_ID;
385 }
386
387 if (result != CF_VMAPX_OK) {
388 // Currently, remaining errors are all some form of out-of-memory.
389 cf_warning(AS_NAMESPACE, "can't add %s (%d)", set_name, result);
390 return INVALID_SET_ID;
391 }
392
393 return (uint16_t)(idx + 1);
394 }
395
396 // Should be impossible.
397 cf_warning(AS_NAMESPACE, "unexpected error %d", result);
398 return INVALID_SET_ID;
399}
400
401
402int
403as_namespace_set_set_w_len(as_namespace *ns, const char *set_name, size_t len,
404 uint16_t *p_set_id, bool apply_restrictions)
405{
406 as_set *p_set;
407
408 if (as_namespace_get_create_set_w_len(ns, set_name, len, &p_set,
409 p_set_id) != 0) {
410 return -1;
411 }
412
413 if (apply_restrictions && as_set_stop_writes(p_set)) {
414 return -2;
415 }
416
417 cf_atomic64_incr(&p_set->n_objects);
418
419 return 0;
420}
421
422
423int
424as_namespace_get_create_set_w_len(as_namespace *ns, const char *set_name,
425 size_t len, as_set **pp_set, uint16_t *p_set_id)
426{
427 cf_assert(set_name, AS_NAMESPACE, "null set name");
428 cf_assert(len != 0, AS_NAMESPACE, "empty set name");
429
430 uint32_t idx;
431 cf_vmapx_err result = cf_vmapx_get_index_w_len(ns->p_sets_vmap, set_name,
432 len, &idx);
433
434 if (result == CF_VMAPX_ERR_NAME_NOT_FOUND) {
435 // Special case handling for name too long.
436 if (len >= AS_SET_NAME_MAX_SIZE) {
437 char bad_name[AS_SET_NAME_MAX_SIZE];
438
439 memcpy(bad_name, set_name, AS_SET_NAME_MAX_SIZE - 1);
440 bad_name[AS_SET_NAME_MAX_SIZE - 1] = 0;
441
442 cf_warning(AS_NAMESPACE, "set name %s... too long", bad_name);
443 return -1;
444 }
445
446 result = cf_vmapx_put_unique_w_len(ns->p_sets_vmap, set_name, len,
447 &idx);
448
449 // Since this function can be called via many functions simultaneously.
450 // Need to handle race, So handle CF_VMAPX_ERR_NAME_EXISTS.
451 if (result == CF_VMAPX_ERR_FULL) {
452 cf_warning(AS_NAMESPACE, "at set names limit, can't add set");
453 return -1;
454 }
455
456 if (result != CF_VMAPX_OK && result != CF_VMAPX_ERR_NAME_EXISTS) {
457 cf_warning(AS_NAMESPACE, "error %d, can't add set", result);
458 return -1;
459 }
460 }
461 else if (result != CF_VMAPX_OK) {
462 // Should be impossible.
463 cf_warning(AS_NAMESPACE, "unexpected error %d", result);
464 return -1;
465 }
466
467 if (pp_set) {
468 if ((result = cf_vmapx_get_by_index(ns->p_sets_vmap, idx,
469 (void**)pp_set)) != CF_VMAPX_OK) {
470 // Should be impossible - just verified idx.
471 cf_warning(AS_NAMESPACE, "unexpected error %d", result);
472 return -1;
473 }
474 }
475
476 if (p_set_id) {
477 *p_set_id = (uint16_t)(idx + 1);
478 }
479
480 return 0;
481}
482
483
484as_set *
485as_namespace_get_set_by_name(as_namespace *ns, const char *set_name)
486{
487 uint32_t idx;
488
489 if (cf_vmapx_get_index(ns->p_sets_vmap, set_name, &idx) != CF_VMAPX_OK) {
490 return NULL;
491 }
492
493 as_set *p_set;
494
495 if (cf_vmapx_get_by_index(ns->p_sets_vmap, idx, (void**)&p_set) !=
496 CF_VMAPX_OK) {
497 // Should be impossible - just verified idx.
498 cf_crash(AS_NAMESPACE, "unexpected vmap error");
499 }
500
501 return p_set;
502}
503
504
505as_set *
506as_namespace_get_set_by_id(as_namespace *ns, uint16_t set_id)
507{
508 if (set_id == INVALID_SET_ID) {
509 return NULL;
510 }
511
512 as_set *p_set;
513
514 if (cf_vmapx_get_by_index(ns->p_sets_vmap, set_id - 1, (void**)&p_set) !=
515 CF_VMAPX_OK) {
516 // Should be impossible.
517 cf_warning(AS_NAMESPACE, "unexpected - record with set-id not in vmap");
518 return NULL;
519 }
520
521 return p_set;
522}
523
524
525as_set *
526as_namespace_get_record_set(as_namespace *ns, const as_record *r)
527{
528 return as_namespace_get_set_by_id(ns, as_index_get_set_id(r));
529}
530
531
532void
533as_namespace_get_set_info(as_namespace *ns, const char *set_name,
534 cf_dyn_buf *db)
535{
536 as_set *p_set;
537
538 if (set_name) {
539 if (cf_vmapx_get_by_name(ns->p_sets_vmap, set_name, (void**)&p_set) ==
540 CF_VMAPX_OK) {
541 append_set_props(p_set, db);
542 }
543
544 return;
545 }
546
547 for (uint32_t idx = 0; idx < cf_vmapx_count(ns->p_sets_vmap); idx++) {
548 if (cf_vmapx_get_by_index(ns->p_sets_vmap, idx, (void**)&p_set) ==
549 CF_VMAPX_OK) {
550 cf_dyn_buf_append_string(db, "ns=");
551 cf_dyn_buf_append_string(db, ns->name);
552 cf_dyn_buf_append_char(db, ':');
553 cf_dyn_buf_append_string(db, "set=");
554 cf_dyn_buf_append_string(db, p_set->name);
555 cf_dyn_buf_append_char(db, ':');
556 append_set_props(p_set, db);
557 }
558 }
559}
560
561
562void
563as_namespace_adjust_set_memory(as_namespace *ns, uint16_t set_id,
564 int64_t delta_bytes)
565{
566 if (set_id == INVALID_SET_ID) {
567 return;
568 }
569
570 as_set *p_set;
571
572 if (cf_vmapx_get_by_index(ns->p_sets_vmap, set_id - 1, (void**)&p_set) !=
573 CF_VMAPX_OK) {
574 cf_warning(AS_NAMESPACE, "set-id %u - failed vmap get", set_id);
575 return;
576 }
577
578 if (cf_atomic64_add(&p_set->n_bytes_memory, delta_bytes) < 0) {
579 cf_warning(AS_NAMESPACE, "set-id %u - negative memory!", set_id);
580 }
581}
582
583
584void
585as_namespace_release_set_id(as_namespace *ns, uint16_t set_id)
586{
587 if (set_id == INVALID_SET_ID) {
588 return;
589 }
590
591 as_set *p_set;
592
593 if (cf_vmapx_get_by_index(ns->p_sets_vmap, set_id - 1, (void**)&p_set) !=
594 CF_VMAPX_OK) {
595 return;
596 }
597
598 if (cf_atomic64_decr(&p_set->n_objects) < 0) {
599 cf_warning(AS_NAMESPACE, "set-id %u - negative objects!", set_id);
600 }
601}
602
603
604void
605as_namespace_get_bins_info(as_namespace *ns, cf_dyn_buf *db, bool show_ns)
606{
607 if (show_ns) {
608 cf_dyn_buf_append_string(db, ns->name);
609 cf_dyn_buf_append_char(db, ':');
610 }
611
612 if (ns->single_bin) {
613 cf_dyn_buf_append_string(db, "[single-bin]");
614 }
615 else {
616 uint32_t bin_count = cf_vmapx_count(ns->p_bin_name_vmap);
617
618 cf_dyn_buf_append_string(db, "bin_names=");
619 cf_dyn_buf_append_uint32(db, bin_count);
620 cf_dyn_buf_append_string(db, ",bin_names_quota=");
621 cf_dyn_buf_append_uint32(db, BIN_NAMES_QUOTA);
622
623 for (uint16_t i = 0; i < (uint16_t)bin_count; i++) {
624 cf_dyn_buf_append_char(db, ',');
625 cf_dyn_buf_append_string(db, as_bin_get_name_from_id(ns, i));
626 }
627 }
628
629 if (show_ns) {
630 cf_dyn_buf_append_char(db, ';');
631 }
632}
633
634
635// e.g. for ttl:
636// units=seconds:hist-width=2582800:bucket-width=25828:buckets=0,0,0 ...
637//
638// e.g. for object-size-linear:
639// units=bytes:hist-width=131072:bucket-width=128:buckets=16000,8000,0,0 ...
640//
641// e.g. for object-size:
642// units=bytes:[64-128)=16000:[128-256)=8000 ...
643void
644as_namespace_get_hist_info(as_namespace *ns, char *set_name, char *hist_name,
645 cf_dyn_buf *db)
646{
647 if (set_name == NULL || set_name[0] == 0) {
648 if (strcmp(hist_name, "ttl") == 0) {
649 linear_hist_get_info(ns->ttl_hist, db);
650 }
651 else if (strcmp(hist_name, "object-size") == 0) {
652 if (ns->storage_type == AS_STORAGE_ENGINE_SSD) {
653 histogram_get_info(ns->obj_size_log_hist, db);
654 }
655 else {
656 cf_dyn_buf_append_string(db, "hist-not-applicable");
657 }
658 }
659 else if (strcmp(hist_name, "object-size-linear") == 0) {
660 if (ns->storage_type == AS_STORAGE_ENGINE_SSD) {
661 linear_hist_get_info(ns->obj_size_lin_hist, db);
662 }
663 else {
664 cf_dyn_buf_append_string(db, "hist-not-applicable");
665 }
666 }
667 else {
668 cf_dyn_buf_append_string(db, "error-unknown-hist-name");
669 }
670
671 return;
672 }
673
674 uint16_t set_id = as_namespace_get_set_id(ns, set_name);
675
676 if (set_id == INVALID_SET_ID) {
677 cf_dyn_buf_append_string(db, "error-unknown-set-name");
678 return;
679 }
680
681 if (strcmp(hist_name, "ttl") == 0) {
682 if (ns->set_ttl_hists[set_id]) {
683 linear_hist_get_info(ns->set_ttl_hists[set_id], db);
684 }
685 else {
686 cf_dyn_buf_append_string(db, "hist-unavailable");
687 }
688 }
689 else if (strcmp(hist_name, "object-size") == 0) {
690 if (ns->storage_type == AS_STORAGE_ENGINE_SSD) {
691 if (ns->set_obj_size_log_hists[set_id]) {
692 histogram_get_info(ns->set_obj_size_log_hists[set_id], db);
693 }
694 else {
695 cf_dyn_buf_append_string(db, "hist-unavailable");
696 }
697 }
698 else {
699 cf_dyn_buf_append_string(db, "hist-not-applicable");
700 }
701 }
702 else if (strcmp(hist_name, "object-size-linear") == 0) {
703 if (ns->storage_type == AS_STORAGE_ENGINE_SSD) {
704 if (ns->set_obj_size_lin_hists[set_id]) {
705 linear_hist_get_info(ns->set_obj_size_lin_hists[set_id], db);
706 }
707 else {
708 cf_dyn_buf_append_string(db, "hist-unavailable");
709 }
710 }
711 else {
712 cf_dyn_buf_append_string(db, "hist-not-applicable");
713 }
714 }
715 else {
716 cf_dyn_buf_append_string(db, "error-unknown-hist-name");
717 }
718}
719
720
721//==========================================================
722// Local helpers.
723//
724
725static void
726append_set_props(as_set *p_set, cf_dyn_buf *db)
727{
728 // Statistics:
729
730 cf_dyn_buf_append_string(db, "objects=");
731 cf_dyn_buf_append_uint64(db, cf_atomic64_get(p_set->n_objects));
732 cf_dyn_buf_append_char(db, ':');
733
734 cf_dyn_buf_append_string(db, "tombstones=");
735 cf_dyn_buf_append_uint64(db, cf_atomic64_get(p_set->n_tombstones));
736 cf_dyn_buf_append_char(db, ':');
737
738 cf_dyn_buf_append_string(db, "memory_data_bytes=");
739 cf_dyn_buf_append_uint64(db, cf_atomic64_get(p_set->n_bytes_memory));
740 cf_dyn_buf_append_char(db, ':');
741
742 cf_dyn_buf_append_string(db, "truncate_lut=");
743 cf_dyn_buf_append_uint64(db, p_set->truncate_lut);
744 cf_dyn_buf_append_char(db, ':');
745
746 // Configuration:
747
748 cf_dyn_buf_append_string(db, "stop-writes-count=");
749 cf_dyn_buf_append_uint64(db, cf_atomic64_get(p_set->stop_writes_count));
750 cf_dyn_buf_append_char(db, ':');
751
752 cf_dyn_buf_append_string(db, "set-enable-xdr=");
753
754 if (cf_atomic32_get(p_set->enable_xdr) == AS_SET_ENABLE_XDR_TRUE) {
755 cf_dyn_buf_append_string(db, "true");
756 }
757 else if (cf_atomic32_get(p_set->enable_xdr) == AS_SET_ENABLE_XDR_FALSE) {
758 cf_dyn_buf_append_string(db, "false");
759 }
760 else if (cf_atomic32_get(p_set->enable_xdr) == AS_SET_ENABLE_XDR_DEFAULT) {
761 cf_dyn_buf_append_string(db, "use-default");
762 }
763 else {
764 cf_dyn_buf_append_uint32(db, cf_atomic32_get(p_set->enable_xdr));
765 }
766
767 cf_dyn_buf_append_char(db, ':');
768
769 cf_dyn_buf_append_string(db, "disable-eviction=");
770 cf_dyn_buf_append_bool(db, IS_SET_EVICTION_DISABLED(p_set));
771 cf_dyn_buf_append_char(db, ';');
772}
773