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 | |
68 | static void append_set_props(as_set *p_set, cf_dyn_buf *db); |
69 | |
70 | |
71 | //========================================================== |
72 | // Inlines & macros. |
73 | // |
74 | |
75 | static inline uint32_t |
76 | ns_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 | |
93 | as_namespace * |
94 | as_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 | |
208 | void |
209 | as_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 | |
237 | bool |
238 | as_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 | |
270 | as_namespace * |
271 | as_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 | |
285 | as_namespace * |
286 | as_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 | |
300 | as_namespace * |
301 | as_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 | |
319 | as_namespace * |
320 | as_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 | |
326 | const char * |
327 | as_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 | |
343 | uint16_t |
344 | as_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. |
354 | uint16_t |
355 | as_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 | |
402 | int |
403 | as_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 | |
423 | int |
424 | as_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 | |
484 | as_set * |
485 | as_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 | |
505 | as_set * |
506 | as_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 | |
525 | as_set * |
526 | as_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 | |
532 | void |
533 | as_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 | |
562 | void |
563 | as_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 | |
584 | void |
585 | as_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 | |
604 | void |
605 | as_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 ... |
643 | void |
644 | as_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 | |
725 | static void |
726 | append_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 | |