1/*
2 * thr_info.c
3 *
4 * Copyright (C) 2008-2016 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#include "base/thr_info.h"
24
25#include <errno.h>
26#include <fcntl.h>
27#include <getopt.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <string.h>
31#include <ctype.h>
32#include <limits.h>
33#include <malloc.h>
34#include <mcheck.h>
35#include <sys/ioctl.h>
36#include <sys/resource.h>
37#include <time.h>
38#include <unistd.h>
39
40#include "aerospike/as_atomic.h"
41#include "citrusleaf/alloc.h"
42#include "citrusleaf/cf_queue.h"
43#include "citrusleaf/cf_vector.h"
44
45#include "cf_mutex.h"
46#include "cf_str.h"
47#include "cf_thread.h"
48#include "dns.h"
49#include "dynbuf.h"
50#include "fault.h"
51#include "shash.h"
52#include "socket.h"
53#include "xmem.h"
54
55#include "ai_obj.h"
56#include "ai_btree.h"
57
58#include "base/batch.h"
59#include "base/cfg.h"
60#include "base/datamodel.h"
61#include "base/features.h"
62#include "base/health.h"
63#include "base/index.h"
64#include "base/monitor.h"
65#include "base/nsup.h"
66#include "base/scan.h"
67#include "base/service.h"
68#include "base/thr_info_port.h"
69#include "base/thr_sindex.h"
70#include "base/thr_tsvc.h"
71#include "base/transaction.h"
72#include "base/secondary_index.h"
73#include "base/security.h"
74#include "base/smd.h"
75#include "base/stats.h"
76#include "base/truncate.h"
77#include "base/udf_cask.h"
78#include "base/xdr_config.h"
79#include "base/xdr_serverside.h"
80#include "fabric/exchange.h"
81#include "fabric/fabric.h"
82#include "fabric/hb.h"
83#include "fabric/hlc.h"
84#include "fabric/migrate.h"
85#include "fabric/partition.h"
86#include "fabric/partition_balance.h"
87#include "fabric/roster.h"
88#include "fabric/service_list.h"
89#include "fabric/skew_monitor.h"
90#include "storage/storage.h"
91#include "transaction/proxy.h"
92#include "transaction/rw_request_hash.h"
93
94#define STR_NS "ns"
95#define STR_SET "set"
96#define STR_INDEXNAME "indexname"
97#define STR_NUMBIN "numbins"
98#define STR_INDEXDATA "indexdata"
99#define STR_TYPE_NUMERIC "numeric"
100#define STR_TYPE_STRING "string"
101#define STR_ITYPE "indextype"
102#define STR_ITYPE_DEFAULT "DEFAULT"
103#define STR_ITYPE_LIST "LIST"
104#define STR_ITYPE_MAPKEYS "MAPKEYS"
105#define STR_ITYPE_MAPVALUES "MAPVALUES"
106#define STR_BINTYPE "bintype"
107
108void info_set_num_info_threads(uint32_t n_threads);
109int info_get_objects(char *name, cf_dyn_buf *db);
110int info_get_tree_sets(char *name, char *subtree, cf_dyn_buf *db);
111int info_get_tree_bins(char *name, char *subtree, cf_dyn_buf *db);
112int info_get_tree_sindexes(char *name, char *subtree, cf_dyn_buf *db);
113int info_get_tree_statistics(char *name, char *subtree, cf_dyn_buf *db);
114void as_storage_show_wblock_stats(as_namespace *ns);
115void as_storage_summarize_wblock_stats(as_namespace *ns);
116
117
118as_stats g_stats = { 0 }; // separate .c file not worth it
119
120uint64_t g_start_sec; // start time of the server
121
122static cf_queue *g_info_work_q = 0;
123
124//
125// The dynamic list has a name, and a function to call
126//
127
128typedef struct info_static_s {
129 struct info_static_s *next;
130 bool def; // default, but default is a reserved word
131 char *name;
132 char *value;
133 size_t value_sz;
134} info_static;
135
136
137typedef struct info_dynamic_s {
138 struct info_dynamic_s *next;
139 bool def; // default, but that's a reserved word
140 char *name;
141 as_info_get_value_fn value_fn;
142} info_dynamic;
143
144typedef struct info_command_s {
145 struct info_command_s *next;
146 char *name;
147 as_info_command_fn command_fn;
148 as_sec_perm required_perm; // required security permission
149} info_command;
150
151typedef struct info_tree_s {
152 struct info_tree_s *next;
153 char *name;
154 as_info_get_tree_fn tree_fn;
155} info_tree;
156
157
158#define EOL '\n' // incoming commands are separated by EOL
159#define SEP '\t'
160#define TREE_SEP '/'
161
162#define INFO_COMMAND_SINDEX_FAILCODE(num, message) \
163 if (db) { \
164 cf_dyn_buf_append_string(db, "FAIL:"); \
165 cf_dyn_buf_append_int(db, num); \
166 cf_dyn_buf_append_string(db, ": "); \
167 cf_dyn_buf_append_string(db, message); \
168 }
169
170
171void
172info_get_aggregated_namespace_stats(cf_dyn_buf *db)
173{
174 uint64_t total_objects = 0;
175 uint64_t total_tombstones = 0;
176
177 for (uint32_t i = 0; i < g_config.n_namespaces; i++) {
178 as_namespace *ns = g_config.namespaces[i];
179
180 total_objects += ns->n_objects;
181 total_tombstones += ns->n_tombstones;
182 }
183
184 info_append_uint64(db, "objects", total_objects);
185 info_append_uint64(db, "tombstones", total_tombstones);
186}
187
188// TODO: This function should move elsewhere.
189static inline uint64_t
190get_cpu_ns(void)
191{
192 struct timespec ts;
193 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
194 return (ts.tv_sec * 1000 * 1000 * 1000) + ts.tv_nsec;
195}
196
197// TODO: This should move elsewhere.
198static uint32_t g_process_cpu_pct = 0;
199
200// TODO: This function should move elsewhere.
201// Called only from the ticker thread.
202uint32_t
203process_cpu(void)
204{
205 static uint64_t prev = 0;
206 static uint64_t prev_cpu = 0;
207
208 uint64_t now = cf_getns();
209 uint64_t now_cpu = get_cpu_ns();
210
211 if (prev != 0) {
212 uint64_t delta = now - prev;
213 uint64_t delta_cpu = now_cpu - prev_cpu;
214
215 g_process_cpu_pct = (uint32_t)(delta_cpu * 100 / delta);
216 }
217
218 prev = now;
219 prev_cpu = now_cpu;
220
221 return g_process_cpu_pct;
222}
223
224// TODO: This should move elsewhere.
225static uint32_t g_user_cpu_pct = 0;
226static uint32_t g_kernel_cpu_pct = 0;
227
228// TODO: This function should move elsewhere.
229// Called only from the ticker thread.
230void
231sys_cpu_info(uint32_t* user_pct, uint32_t* kernel_pct)
232{
233 FILE* fh = fopen("/proc/stat", "r");
234
235 if (fh == NULL) {
236 cf_crash(AS_INFO, "failed to open /proc/stat: %d", errno);
237 }
238
239 uint64_t user;
240 uint64_t nice;
241 uint64_t kernel;
242 uint64_t idle;
243
244 if (fscanf(fh, "cpu %lu %lu %lu %lu", &user, &nice, &kernel, &idle) != 4) {
245 cf_crash(AS_INFO, "can't parse /proc/stat");
246 }
247
248 fclose(fh);
249
250 static uint64_t prev_user = 0;
251 static uint64_t prev_nice = 0;
252 static uint64_t prev_kernel = 0;
253 static uint64_t prev_idle = 0;
254
255 if (prev_user != 0) {
256 uint32_t delta_user = (uint32_t)(user - prev_user);
257 uint32_t delta_nice = (uint32_t)(nice - prev_nice);
258 uint32_t delta_kernel = (uint32_t)(kernel - prev_kernel);
259 uint32_t delta_idle = (uint32_t)(idle - prev_idle);
260
261 uint32_t total = delta_user + delta_nice + delta_kernel + delta_idle;
262 uint32_t n_cpus = cf_topo_count_cpus();
263
264 g_user_cpu_pct = (delta_user + delta_nice) * 100 * n_cpus / total;
265 g_kernel_cpu_pct = delta_kernel * 100 * n_cpus / total;
266 }
267
268 prev_user = user;
269 prev_nice = nice;
270 prev_kernel = kernel;
271 prev_idle = idle;
272
273 if (user_pct != NULL) {
274 *user_pct = g_user_cpu_pct;
275 }
276
277 if (kernel_pct != NULL) {
278 *kernel_pct = g_kernel_cpu_pct;
279 }
280}
281
282// TODO: This function should move elsewhere.
283void
284sys_mem_info(uint64_t* free_mem, uint32_t* free_pct)
285{
286 if (free_mem != NULL) {
287 *free_mem = 0;
288 }
289
290 if (free_pct != NULL) {
291 *free_pct = 0;
292 }
293
294 int32_t fd = open("/proc/meminfo", O_RDONLY, 0);
295
296 if (fd < 0) {
297 cf_warning(AS_INFO, "failed to open /proc/meminfo: %d", errno);
298 return;
299 }
300
301 char buf[4096] = { 0 };
302 size_t limit = sizeof(buf);
303 size_t total = 0;
304
305 while (total < limit) {
306 ssize_t len = read(fd, buf + total, limit - total);
307
308 if (len < 0) {
309 cf_warning(AS_INFO, "couldn't read /proc/meminfo: %d", errno);
310 close(fd);
311 return;
312 }
313
314 if (len == 0) {
315 break; // EOF
316 }
317
318 total += (size_t)len;
319 }
320
321 close(fd);
322
323 if (total == limit) {
324 cf_warning(AS_INFO, "/proc/meminfo exceeds %zu bytes", limit);
325 return;
326 }
327
328 uint64_t mem_total = 0;
329 uint64_t active = 0;
330 uint64_t inactive = 0;
331 uint64_t cached = 0;
332 uint64_t buffers = 0;
333 uint64_t shmem = 0;
334
335 char* cur = buf;
336 char* save_ptr = NULL;
337
338 // We split each line into two fields separated by ':'. strtoul() will
339 // safely ignore the spaces and 'kB' (if present).
340 while (true) {
341 char* name_tok = strtok_r(cur, ":", &save_ptr);
342
343 if (name_tok == NULL) {
344 break; // no more lines
345 }
346
347 cur = NULL; // all except first name_tok use NULL
348
349 char* value_tok = strtok_r(NULL, "\r\n", &save_ptr);
350
351 if (value_tok == NULL) {
352 cf_warning(AS_INFO, "/proc/meminfo line missing value token");
353 return;
354 }
355
356 if (strcmp(name_tok, "MemTotal") == 0) {
357 mem_total = strtoul(value_tok, NULL, 0);
358 }
359 else if (strcmp(name_tok, "Active") == 0) {
360 active = strtoul(value_tok, NULL, 0);
361 }
362 else if (strcmp(name_tok, "Inactive") == 0) {
363 inactive = strtoul(value_tok, NULL, 0);
364 }
365 else if (strcmp(name_tok, "Cached") == 0) {
366 cached = strtoul(value_tok, NULL, 0);
367 }
368 else if (strcmp(name_tok, "Buffers") == 0) {
369 buffers = strtoul(value_tok, NULL, 0);
370 }
371 else if (strcmp(name_tok, "Shmem") == 0) {
372 shmem = strtoul(value_tok, NULL, 0);
373 }
374 }
375
376 // Add the cached memory and buffers, which are effectively available if and
377 // when needed. Caution: subtract the shared memory, which is included in
378 // the cached memory, but is not available.
379 uint64_t avail = mem_total - active - inactive + cached + buffers - shmem;
380
381 if (free_mem != NULL) {
382 *free_mem = avail * 1024;
383 }
384
385 if (free_pct != NULL) {
386 *free_pct = mem_total == 0 ? 0 : (avail * 100) / mem_total;
387 }
388}
389
390
391int
392info_get_stats(char *name, cf_dyn_buf *db)
393{
394 uint64_t now_sec = cf_get_seconds();
395
396 as_exchange_cluster_info(db);
397 info_append_bool(db, "cluster_integrity", as_clustering_has_integrity()); // not in ticker
398 info_append_bool(db, "cluster_is_member", ! as_clustering_is_orphan()); // not in ticker
399 as_hb_info_duplicates_get(db); // not in ticker
400 info_append_uint32(db, "cluster_clock_skew_stop_writes_sec", clock_skew_stop_writes_sec()); // not in ticker
401 info_append_uint64(db, "cluster_clock_skew_ms", as_skew_monitor_skew());
402 as_skew_monitor_info(db);
403
404 info_append_uint64(db, "uptime", now_sec - g_start_sec); // not in ticker
405
406 uint32_t user_pct = as_load_uint32(&g_user_cpu_pct);
407 uint32_t kernel_pct = as_load_uint32(&g_kernel_cpu_pct);
408
409 info_append_uint32(db, "system_total_cpu_pct", user_pct + kernel_pct);
410 info_append_uint32(db, "system_user_cpu_pct", user_pct);
411 info_append_uint32(db, "system_kernel_cpu_pct", kernel_pct);
412
413 uint32_t free_pct;
414
415 sys_mem_info(NULL, &free_pct);
416 info_append_int(db, "system_free_mem_pct", free_pct);
417
418 info_append_uint32(db, "process_cpu_pct", g_process_cpu_pct);
419
420 size_t allocated_kbytes;
421 size_t active_kbytes;
422 size_t mapped_kbytes;
423 double efficiency_pct;
424 uint32_t site_count;
425
426 cf_alloc_heap_stats(&allocated_kbytes, &active_kbytes, &mapped_kbytes, &efficiency_pct,
427 &site_count);
428 info_append_uint64(db, "heap_allocated_kbytes", allocated_kbytes);
429 info_append_uint64(db, "heap_active_kbytes", active_kbytes);
430 info_append_uint64(db, "heap_mapped_kbytes", mapped_kbytes);
431 info_append_int(db, "heap_efficiency_pct", (int)(efficiency_pct + 0.5));
432 info_append_uint32(db, "heap_site_count", site_count);
433
434 info_get_aggregated_namespace_stats(db);
435
436 info_append_int(db, "info_queue", as_info_queue_get_size());
437 info_append_uint32(db, "rw_in_progress", rw_request_hash_count());
438 info_append_uint32(db, "proxy_in_progress", as_proxy_hash_count());
439 info_append_int(db, "tree_gc_queue", as_index_tree_gc_queue_size());
440
441 info_append_uint64(db, "client_connections", g_stats.proto_connections_opened - g_stats.proto_connections_closed);
442 info_append_uint64(db, "heartbeat_connections", g_stats.heartbeat_connections_opened - g_stats.heartbeat_connections_closed);
443 info_append_uint64(db, "fabric_connections", g_stats.fabric_connections_opened - g_stats.fabric_connections_closed);
444
445 info_append_uint64(db, "heartbeat_received_self", g_stats.heartbeat_received_self);
446 info_append_uint64(db, "heartbeat_received_foreign", g_stats.heartbeat_received_foreign);
447
448 info_append_uint64(db, "reaped_fds", g_stats.reaper_count); // not in ticker
449
450 info_append_uint64(db, "info_complete", g_stats.info_complete); // not in ticker
451
452 info_append_uint64(db, "demarshal_error", g_stats.n_demarshal_error);
453 info_append_uint64(db, "early_tsvc_client_error", g_stats.n_tsvc_client_error);
454 info_append_uint64(db, "early_tsvc_from_proxy_error", g_stats.n_tsvc_from_proxy_error);
455 info_append_uint64(db, "early_tsvc_batch_sub_error", g_stats.n_tsvc_batch_sub_error);
456 info_append_uint64(db, "early_tsvc_from_proxy_batch_sub_error", g_stats.n_tsvc_from_proxy_batch_sub_error);
457 info_append_uint64(db, "early_tsvc_udf_sub_error", g_stats.n_tsvc_udf_sub_error);
458 info_append_uint64(db, "early_tsvc_ops_sub_error", g_stats.n_tsvc_ops_sub_error);
459
460 info_append_uint64(db, "batch_index_initiate", g_stats.batch_index_initiate); // not in ticker
461
462 cf_dyn_buf_append_string(db, "batch_index_queue=");
463 as_batch_queues_info(db); // not in ticker
464 cf_dyn_buf_append_char(db, ';');
465
466 info_append_uint64(db, "batch_index_complete", g_stats.batch_index_complete);
467 info_append_uint64(db, "batch_index_error", g_stats.batch_index_errors);
468 info_append_uint64(db, "batch_index_timeout", g_stats.batch_index_timeout);
469 info_append_uint64(db, "batch_index_delay", g_stats.batch_index_delay); // not in ticker
470
471 // Everything below is not in ticker...
472
473 info_append_int(db, "batch_index_unused_buffers", as_batch_unused_buffers());
474 info_append_uint64(db, "batch_index_huge_buffers", g_stats.batch_index_huge_buffers);
475 info_append_uint64(db, "batch_index_created_buffers", g_stats.batch_index_created_buffers);
476 info_append_uint64(db, "batch_index_destroyed_buffers", g_stats.batch_index_destroyed_buffers);
477
478 info_append_int(db, "scans_active", as_scan_get_active_job_count());
479
480 info_append_uint32(db, "query_short_running", g_query_short_running);
481 info_append_uint32(db, "query_long_running", g_query_long_running);
482
483 info_append_uint64(db, "sindex_ucgarbage_found", g_stats.query_false_positives);
484 info_append_uint64(db, "sindex_gc_retries", g_stats.sindex_gc_retries);
485 info_append_uint64(db, "sindex_gc_list_creation_time", g_stats.sindex_gc_list_creation_time);
486 info_append_uint64(db, "sindex_gc_list_deletion_time", g_stats.sindex_gc_list_deletion_time);
487 info_append_uint64(db, "sindex_gc_objects_validated", g_stats.sindex_gc_objects_validated);
488 info_append_uint64(db, "sindex_gc_garbage_found", g_stats.sindex_gc_garbage_found);
489 info_append_uint64(db, "sindex_gc_garbage_cleaned", g_stats.sindex_gc_garbage_cleaned);
490
491 char paxos_principal[16 + 1];
492 sprintf(paxos_principal, "%lX", as_exchange_principal());
493 info_append_string(db, "paxos_principal", paxos_principal);
494
495 info_append_uint64(db, "time_since_rebalance", now_sec - g_rebalance_sec); // not in ticker
496
497 info_append_bool(db, "migrate_allowed", as_partition_balance_are_migrations_allowed());
498 info_append_uint64(db, "migrate_partitions_remaining", as_partition_balance_remaining_migrations());
499
500 info_append_uint64(db, "fabric_bulk_send_rate", g_stats.fabric_bulk_s_rate);
501 info_append_uint64(db, "fabric_bulk_recv_rate", g_stats.fabric_bulk_r_rate);
502 info_append_uint64(db, "fabric_ctrl_send_rate", g_stats.fabric_ctrl_s_rate);
503 info_append_uint64(db, "fabric_ctrl_recv_rate", g_stats.fabric_ctrl_r_rate);
504 info_append_uint64(db, "fabric_meta_send_rate", g_stats.fabric_meta_s_rate);
505 info_append_uint64(db, "fabric_meta_recv_rate", g_stats.fabric_meta_r_rate);
506 info_append_uint64(db, "fabric_rw_send_rate", g_stats.fabric_rw_s_rate);
507 info_append_uint64(db, "fabric_rw_recv_rate", g_stats.fabric_rw_r_rate);
508
509 as_xdr_get_stats(db);
510
511 cf_dyn_buf_chomp(db);
512
513 return 0;
514}
515
516void
517info_get_printable_cluster_name(char *cluster_name)
518{
519 as_config_cluster_name_get(cluster_name);
520 if (cluster_name[0] == '\0'){
521 strcpy(cluster_name, "null");
522 }
523}
524
525int
526info_get_cluster_name(char *name, cf_dyn_buf *db)
527{
528 char cluster_name[AS_CLUSTER_NAME_SZ];
529 info_get_printable_cluster_name(cluster_name);
530 cf_dyn_buf_append_string(db, cluster_name);
531
532 return 0;
533}
534
535int
536info_get_features(char *name, cf_dyn_buf *db)
537{
538 cf_dyn_buf_append_string(db, as_features_info());
539
540 return 0;
541}
542
543static cf_ip_port
544bind_to_port(cf_serv_cfg *cfg, cf_sock_owner owner)
545{
546 for (uint32_t i = 0; i < cfg->n_cfgs; ++i) {
547 if (cfg->cfgs[i].owner == owner) {
548 return cfg->cfgs[i].port;
549 }
550 }
551
552 return 0;
553}
554
555char *
556as_info_bind_to_string(const cf_serv_cfg *cfg, cf_sock_owner owner)
557{
558 cf_dyn_buf_define_size(db, 2500);
559 uint32_t count = 0;
560
561 for (uint32_t i = 0; i < cfg->n_cfgs; ++i) {
562 if (cfg->cfgs[i].owner != owner) {
563 continue;
564 }
565
566 if (count > 0) {
567 cf_dyn_buf_append_char(&db, ',');
568 }
569
570 cf_dyn_buf_append_string(&db, cf_ip_addr_print(&cfg->cfgs[i].addr));
571 ++count;
572 }
573
574 char *string = cf_dyn_buf_strdup(&db);
575 cf_dyn_buf_free(&db);
576 return string != NULL ? string : cf_strdup("null");
577}
578
579static char *
580access_to_string(cf_addr_list *addrs)
581{
582 cf_dyn_buf_define_size(db, 2500);
583
584 for (uint32_t i = 0; i < addrs->n_addrs; ++i) {
585 if (i > 0) {
586 cf_dyn_buf_append_char(&db, ',');
587 }
588
589 cf_dyn_buf_append_string(&db, addrs->addrs[i]);
590 }
591
592 char *string = cf_dyn_buf_strdup(&db);
593 cf_dyn_buf_free(&db);
594 return string != NULL ? string : cf_strdup("null");
595}
596
597int
598info_get_endpoints(char *name, cf_dyn_buf *db)
599{
600 cf_ip_port port = bind_to_port(&g_service_bind, CF_SOCK_OWNER_SERVICE);
601 info_append_int(db, "service.port", port);
602
603 char *string = as_info_bind_to_string(&g_service_bind, CF_SOCK_OWNER_SERVICE);
604 info_append_string(db, "service.addresses", string);
605 cf_free(string);
606
607 info_append_int(db, "service.access-port", g_access.service.port);
608
609 string = access_to_string(&g_access.service.addrs);
610 info_append_string(db, "service.access-addresses", string);
611 cf_free(string);
612
613 info_append_int(db, "service.alternate-access-port", g_access.alt_service.port);
614
615 string = access_to_string(&g_access.alt_service.addrs);
616 info_append_string(db, "service.alternate-access-addresses", string);
617 cf_free(string);
618
619 port = bind_to_port(&g_service_bind, CF_SOCK_OWNER_SERVICE_TLS);
620 info_append_int(db, "service.tls-port", port);
621
622 string = as_info_bind_to_string(&g_service_bind, CF_SOCK_OWNER_SERVICE_TLS);
623 info_append_string(db, "service.tls-addresses", string);
624 cf_free(string);
625
626 info_append_int(db, "service.tls-access-port", g_access.tls_service.port);
627
628 string = access_to_string(&g_access.tls_service.addrs);
629 info_append_string(db, "service.tls-access-addresses", string);
630 cf_free(string);
631
632 info_append_int(db, "service.tls-alternate-access-port", g_access.alt_tls_service.port);
633
634 string = access_to_string(&g_access.alt_tls_service.addrs);
635 info_append_string(db, "service.tls-alternate-access-addresses", string);
636 cf_free(string);
637
638 as_hb_info_endpoints_get(db);
639
640 port = bind_to_port(&g_fabric_bind, CF_SOCK_OWNER_FABRIC);
641 info_append_int(db, "fabric.port", port);
642
643 string = as_info_bind_to_string(&g_fabric_bind, CF_SOCK_OWNER_FABRIC);
644 info_append_string(db, "fabric.addresses", string);
645 cf_free(string);
646
647 port = bind_to_port(&g_fabric_bind, CF_SOCK_OWNER_FABRIC_TLS);
648 info_append_int(db, "fabric.tls-port", port);
649
650 string = as_info_bind_to_string(&g_fabric_bind, CF_SOCK_OWNER_FABRIC_TLS);
651 info_append_string(db, "fabric.tls-addresses", string);
652 cf_free(string);
653
654 as_fabric_info_peer_endpoints_get(db);
655
656 info_append_int(db, "info.port", g_info_port);
657
658 string = as_info_bind_to_string(&g_info_bind, CF_SOCK_OWNER_INFO);
659 info_append_string(db, "info.addresses", string);
660 cf_free(string);
661
662 cf_dyn_buf_chomp(db);
663 return(0);
664}
665
666int
667info_get_partition_generation(char *name, cf_dyn_buf *db)
668{
669 cf_dyn_buf_append_int(db, (int)g_partition_generation);
670
671 return(0);
672}
673
674int
675info_get_partition_info(char *name, cf_dyn_buf *db)
676{
677 as_partition_getinfo_str(db);
678
679 return(0);
680}
681
682int
683info_get_rack_ids(char *name, cf_dyn_buf *db)
684{
685 if (as_info_error_enterprise_only()) {
686 cf_dyn_buf_append_string(db, "ERROR::enterprise-only");
687 return 0;
688 }
689
690 as_partition_balance_effective_rack_ids(db);
691
692 return 0;
693}
694
695int
696info_get_rebalance_generation(char *name, cf_dyn_buf *db)
697{
698 cf_dyn_buf_append_uint64(db, g_rebalance_generation);
699
700 return 0;
701}
702
703int
704info_get_replicas_master(char *name, cf_dyn_buf *db)
705{
706 as_partition_get_replicas_master_str(db);
707
708 return(0);
709}
710
711int
712info_get_replicas_all(char *name, cf_dyn_buf *db)
713{
714 as_partition_get_replicas_all_str(db, false);
715
716 return(0);
717}
718
719int
720info_get_replicas(char *name, cf_dyn_buf *db)
721{
722 as_partition_get_replicas_all_str(db, true);
723
724 return(0);
725}
726
727//
728// COMMANDS
729//
730
731int
732info_command_cluster_stable(char *name, char *params, cf_dyn_buf *db)
733{
734 // Command format:
735 // "cluster-stable:[size=<target-size>];[ignore-migrations=<bool>];[namespace=<namespace-name>]"
736
737 uint64_t begin_cluster_key = as_exchange_cluster_key();
738
739 if (! as_partition_balance_are_migrations_allowed()) {
740 cf_dyn_buf_append_string(db, "ERROR::unstable-cluster");
741 return 0;
742 }
743
744 char size_str[4] = { 0 }; // max cluster size is 128
745 int size_str_len = (int)sizeof(size_str);
746 int rv = as_info_parameter_get(params, "size", size_str, &size_str_len);
747
748 if (rv == -2) {
749 cf_warning(AS_INFO, "size parameter value too long");
750 cf_dyn_buf_append_string(db, "ERROR::bad-size");
751 return 0;
752 }
753
754 if (rv == 0) {
755 uint32_t target_size;
756
757 if (cf_str_atoi_u32(size_str, &target_size) != 0) {
758 cf_warning(AS_INFO, "non-integer size parameter");
759 cf_dyn_buf_append_string(db, "ERROR::bad-size");
760 return 0;
761 }
762
763 if (target_size != as_exchange_cluster_size()) {
764 cf_dyn_buf_append_string(db, "ERROR::cluster-not-specified-size");
765 return 0;
766 }
767 }
768
769 bool ignore_migrations = false;
770
771 char ignore_migrations_str[6] = { 0 };
772 int ignore_migrations_str_len = (int)sizeof(ignore_migrations_str);
773
774 rv = as_info_parameter_get(params, "ignore-migrations",
775 ignore_migrations_str, &ignore_migrations_str_len);
776
777 if (rv == -2) {
778 cf_warning(AS_INFO, "ignore-migrations value too long");
779 cf_dyn_buf_append_string(db, "ERROR::bad-ignore-migrations");
780 return 0;
781 }
782
783 if (rv == 0) {
784 if (strcmp(ignore_migrations_str, "true") == 0 ||
785 strcmp(ignore_migrations_str, "yes") == 0) {
786 ignore_migrations = true;
787 }
788 else if (strcmp(ignore_migrations_str, "false") == 0 ||
789 strcmp(ignore_migrations_str, "no") == 0) {
790 ignore_migrations = false;
791 }
792 else {
793 cf_warning(AS_INFO, "ignore-migrations value invalid");
794 cf_dyn_buf_append_string(db, "ERROR::bad-ignore-migrations");
795 return 0;
796 }
797 }
798
799 if (! ignore_migrations) {
800 char ns_name[AS_ID_NAMESPACE_SZ] = { 0 };
801 int ns_name_len = (int)sizeof(ns_name);
802
803 rv = as_info_parameter_get(params, "namespace", ns_name, &ns_name_len);
804
805 if (rv == -2) {
806 cf_warning(AS_INFO, "namespace parameter value too long");
807 cf_dyn_buf_append_string(db, "ERROR::bad-namespace");
808 return 0;
809 }
810
811 if (rv == -1) {
812 // Ensure migrations are complete for all namespaces.
813
814 if (as_partition_balance_remaining_migrations() != 0) {
815 cf_dyn_buf_append_string(db, "ERROR::unstable-cluster");
816 return 0;
817 }
818 }
819 else {
820 // Ensure migrations are complete for the requested namespace only.
821 as_namespace *ns = as_namespace_get_byname(ns_name);
822
823 if (! ns) {
824 cf_warning(AS_INFO, "unknown namespace %s", ns_name);
825 cf_dyn_buf_append_string(db, "ERROR::unknown-namespace");
826 return 0;
827 }
828
829 if (ns->migrate_tx_partitions_remaining +
830 ns->migrate_rx_partitions_remaining +
831 ns->n_unavailable_partitions +
832 ns->n_dead_partitions != 0) {
833 cf_dyn_buf_append_string(db, "ERROR::unstable-cluster");
834 return 0;
835 }
836 }
837 }
838
839 if (begin_cluster_key != as_exchange_cluster_key()) {
840 // Verify that the cluster didn't change while during the collection.
841 cf_dyn_buf_append_string(db, "ERROR::unstable-cluster");
842 }
843
844 cf_dyn_buf_append_uint64_x(db, begin_cluster_key);
845
846 return 0;
847}
848
849int
850info_command_get_sl(char *name, char *params, cf_dyn_buf *db)
851{
852 // Command Format: "get-sl:"
853
854 as_exchange_info_get_succession(db);
855
856 return 0;
857}
858
859int
860info_command_tip(char *name, char *params, cf_dyn_buf *db)
861{
862 cf_debug(AS_INFO, "tip command received: params %s", params);
863
864 char host_str[DNS_NAME_MAX_SIZE];
865 int host_str_len = sizeof(host_str);
866
867 char port_str[50];
868 int port_str_len = sizeof(port_str);
869 int rv = -1;
870
871 char tls_str[50];
872 int tls_str_len = sizeof(tls_str);
873
874 /*
875 * Command Format: "tip:host=<IPAddr>;port=<PortNum>[;tls=<Bool>]"
876 *
877 * where <IPAddr> is an IP address and <PortNum> is a valid TCP port number.
878 */
879
880 if (0 != as_info_parameter_get(params, "host", host_str, &host_str_len)) {
881 cf_warning(AS_INFO, "tip command: no host, must add a host parameter - maximum %d characters", DNS_NAME_MAX_LEN);
882 goto Exit;
883 }
884
885 if (0 != as_info_parameter_get(params, "port", port_str, &port_str_len)) {
886 cf_warning(AS_INFO, "tip command: no port, must have port");
887 goto Exit;
888 }
889
890 if (0 != as_info_parameter_get(params, "tls", tls_str, &tls_str_len)) {
891 strcpy(tls_str, "false");
892 }
893
894 int port = 0;
895 if (0 != cf_str_atoi(port_str, &port)) {
896 cf_warning(AS_INFO, "tip command: port must be an integer in: %s", port_str);
897 goto Exit;
898 }
899
900 bool tls;
901 if (strcmp(tls_str, "true") == 0) {
902 tls = true;
903 }
904 else if (strcmp(tls_str, "false") == 0) {
905 tls = false;
906 }
907 else {
908 cf_warning(AS_INFO, "The \"%s:\" command argument \"tls\" value must be one of {\"true\", \"false\"}, not \"%s\"", name, tls_str);
909 goto Exit;
910 }
911
912 rv = as_hb_mesh_tip(host_str, port, tls);
913
914Exit:
915 if (0 == rv) {
916 cf_dyn_buf_append_string(db, "ok");
917 } else {
918 cf_dyn_buf_append_string(db, "error");
919 }
920
921 return(0);
922}
923
924/*
925 * Command Format: "tip-clear:{host-port-list=<hpl>}"
926 *
927 * where <hpl> is either "all" or else a comma-separated list of items of the form: <HostIPAddr>:<PortNum>
928 */
929int32_t
930info_command_tip_clear(char* name, char* params, cf_dyn_buf* db)
931{
932 cf_info(AS_INFO, "tip clear command received: params %s", params);
933
934 // Command Format: "tip-clear:{host-port-list=<hpl>}" [the
935 // "host-port-list" argument is optional]
936 // where <hpl> is either "all" or else a comma-separated list of items
937 // of the form: <HostIPv4Addr>:<PortNum> or [<HostIPv6Addr>]:<PortNum>
938
939 char host_port_list[3000];
940 int host_port_list_len = sizeof(host_port_list);
941 host_port_list[0] = '\0';
942 bool success = true;
943 uint32_t cleared = 0, not_found = 0;
944
945 if (as_info_parameter_get(params, "host-port-list", host_port_list,
946 &host_port_list_len) == 0) {
947 if (0 != strcmp(host_port_list, "all")) {
948 char* save_ptr = NULL;
949 int port = -1;
950 char* host_port =
951 strtok_r(host_port_list, ",", &save_ptr);
952
953 while (host_port != NULL) {
954 char* host_port_delim = ":";
955 if (*host_port == '[') {
956 // Parse IPv6 address differently.
957 host_port++;
958 host_port_delim = "]";
959 }
960
961 char* host_port_save_ptr = NULL;
962 char* host =
963 strtok_r(host_port, host_port_delim, &host_port_save_ptr);
964
965 if (host == NULL) {
966 cf_warning(AS_INFO, "tip clear command: invalid host:port string: %s", host_port);
967 success = false;
968 break;
969 }
970
971 char* port_str =
972 strtok_r(NULL, host_port_delim, &host_port_save_ptr);
973
974 if (port_str != NULL && *port_str == ':') {
975 // IPv6 case
976 port_str++;
977 }
978 if (port_str == NULL ||
979 0 != cf_str_atoi(port_str, &port)) {
980 cf_warning(AS_INFO, "tip clear command: port must be an integer in: %s", port_str);
981 success = false;
982 break;
983 }
984
985 if (as_hb_mesh_tip_clear(host, port) == -1) {
986 success = false;
987 not_found++;
988 cf_warning(AS_INFO, "seed node %s:%d does not exist", host, port);
989 } else {
990 cleared++;
991 }
992
993 host_port = strtok_r(NULL, ",", &save_ptr);
994 }
995 } else {
996 if (as_hb_mesh_tip_clear_all(&cleared)) {
997 success = false;
998 }
999 }
1000 } else {
1001 success = false;
1002 }
1003
1004 if (success) {
1005 cf_info(AS_INFO, "tip clear command executed: cleared %"PRIu32", params %s", cleared, params);
1006 cf_dyn_buf_append_string(db, "ok");
1007 } else {
1008 cf_info(AS_INFO, "tip clear command failed: cleared %"PRIu32", params %s", cleared, params);
1009 char error_msg[1024];
1010 sprintf(error_msg, "error: %"PRIu32" cleared, %"PRIu32" not found", cleared, not_found);
1011 cf_dyn_buf_append_string(db, error_msg);
1012 }
1013
1014 return (0);
1015}
1016
1017int
1018info_command_show_devices(char *name, char *params, cf_dyn_buf *db)
1019{
1020 char ns_str[512];
1021 int ns_len = sizeof(ns_str);
1022
1023 if (0 != as_info_parameter_get(params, "namespace", ns_str, &ns_len)) {
1024 cf_info(AS_INFO, "show-devices requires namespace parameter");
1025 cf_dyn_buf_append_string(db, "error");
1026 return(0);
1027 }
1028
1029 as_namespace *ns = as_namespace_get_byname(ns_str);
1030 if (!ns) {
1031 cf_info(AS_INFO, "show-devices: namespace %s not found", ns_str);
1032 cf_dyn_buf_append_string(db, "error");
1033 return(0);
1034 }
1035 as_storage_show_wblock_stats(ns);
1036
1037 cf_dyn_buf_append_string(db, "ok");
1038
1039 return(0);
1040}
1041
1042int
1043info_command_dump_cluster(char *name, char *params, cf_dyn_buf *db)
1044{
1045 bool verbose = false;
1046 char param_str[100];
1047 int param_str_len = sizeof(param_str);
1048
1049 /*
1050 * Command Format: "dump-cluster:{verbose=<opt>}" [the "verbose" argument is optional]
1051 *
1052 * where <opt> is one of: {"true" | "false"} and defaults to "false".
1053 */
1054 param_str[0] = '\0';
1055 if (!as_info_parameter_get(params, "verbose", param_str, &param_str_len)) {
1056 if (!strncmp(param_str, "true", 5)) {
1057 verbose = true;
1058 } else if (!strncmp(param_str, "false", 6)) {
1059 verbose = false;
1060 } else {
1061 cf_warning(AS_INFO, "The \"%s:\" command argument \"verbose\" value must be one of {\"true\", \"false\"}, not \"%s\"", name, param_str);
1062 cf_dyn_buf_append_string(db, "error");
1063 return 0;
1064 }
1065 }
1066 as_clustering_dump(verbose);
1067 as_exchange_dump(verbose);
1068 cf_dyn_buf_append_string(db, "ok");
1069 return(0);
1070}
1071
1072int
1073info_command_dump_fabric(char *name, char *params, cf_dyn_buf *db)
1074{
1075 bool verbose = false;
1076 char param_str[100];
1077 int param_str_len = sizeof(param_str);
1078
1079 /*
1080 * Command Format: "dump-fabric:{verbose=<opt>}" [the "verbose" argument is optional]
1081 *
1082 * where <opt> is one of: {"true" | "false"} and defaults to "false".
1083 */
1084 param_str[0] = '\0';
1085 if (!as_info_parameter_get(params, "verbose", param_str, &param_str_len)) {
1086 if (!strncmp(param_str, "true", 5)) {
1087 verbose = true;
1088 } else if (!strncmp(param_str, "false", 6)) {
1089 verbose = false;
1090 } else {
1091 cf_warning(AS_INFO, "The \"%s:\" command argument \"verbose\" value must be one of {\"true\", \"false\"}, not \"%s\"", name, param_str);
1092 cf_dyn_buf_append_string(db, "error");
1093 return 0;
1094 }
1095 }
1096 as_fabric_dump(verbose);
1097 cf_dyn_buf_append_string(db, "ok");
1098 return(0);
1099}
1100
1101int
1102info_command_dump_hb(char *name, char *params, cf_dyn_buf *db)
1103{
1104 bool verbose = false;
1105 char param_str[100];
1106 int param_str_len = sizeof(param_str);
1107
1108 /*
1109 * Command Format: "dump-hb:{verbose=<opt>}" [the "verbose" argument is optional]
1110 *
1111 * where <opt> is one of: {"true" | "false"} and defaults to "false".
1112 */
1113 param_str[0] = '\0';
1114 if (!as_info_parameter_get(params, "verbose", param_str, &param_str_len)) {
1115 if (!strncmp(param_str, "true", 5)) {
1116 verbose = true;
1117 } else if (!strncmp(param_str, "false", 6)) {
1118 verbose = false;
1119 } else {
1120 cf_warning(AS_INFO, "The \"%s:\" command argument \"verbose\" value must be one of {\"true\", \"false\"}, not \"%s\"", name, param_str);
1121 cf_dyn_buf_append_string(db, "error");
1122 return 0;
1123 }
1124 }
1125 as_hb_dump(verbose);
1126 cf_dyn_buf_append_string(db, "ok");
1127 return(0);
1128}
1129
1130int
1131info_command_dump_hlc(char *name, char *params, cf_dyn_buf *db)
1132{
1133 bool verbose = false;
1134 char param_str[100];
1135 int param_str_len = sizeof(param_str);
1136
1137 /*
1138 * Command Format: "dump-hlc:{verbose=<opt>}" [the "verbose" argument is optional]
1139 *
1140 * where <opt> is one of: {"true" | "false"} and defaults to "false".
1141 */
1142 param_str[0] = '\0';
1143 if (!as_info_parameter_get(params, "verbose", param_str, &param_str_len)) {
1144 if (!strncmp(param_str, "true", 5)) {
1145 verbose = true;
1146 } else if (!strncmp(param_str, "false", 6)) {
1147 verbose = false;
1148 } else {
1149 cf_warning(AS_INFO, "The \"%s:\" command argument \"verbose\" value must be one of {\"true\", \"false\"}, not \"%s\"", name, param_str);
1150 cf_dyn_buf_append_string(db, "error");
1151 return 0;
1152 }
1153 }
1154 as_hlc_dump(verbose);
1155 cf_dyn_buf_append_string(db, "ok");
1156 return(0);
1157}
1158
1159
1160int
1161info_command_dump_migrates(char *name, char *params, cf_dyn_buf *db)
1162{
1163 bool verbose = false;
1164 char param_str[100];
1165 int param_str_len = sizeof(param_str);
1166
1167 /*
1168 * Command Format: "dump-migrates:{verbose=<opt>}" [the "verbose" argument is optional]
1169 *
1170 * where <opt> is one of: {"true" | "false"} and defaults to "false".
1171 */
1172 param_str[0] = '\0';
1173 if (!as_info_parameter_get(params, "verbose", param_str, &param_str_len)) {
1174 if (!strncmp(param_str, "true", 5)) {
1175 verbose = true;
1176 } else if (!strncmp(param_str, "false", 6)) {
1177 verbose = false;
1178 } else {
1179 cf_warning(AS_INFO, "The \"%s:\" command argument \"verbose\" value must be one of {\"true\", \"false\"}, not \"%s\"", name, param_str);
1180 cf_dyn_buf_append_string(db, "error");
1181 return 0;
1182 }
1183 }
1184 as_migrate_dump(verbose);
1185 cf_dyn_buf_append_string(db, "ok");
1186 return(0);
1187}
1188
1189int
1190info_command_dump_msgs(char *name, char *params, cf_dyn_buf *db)
1191{
1192 bool once = true;
1193 char param_str[100];
1194 int param_str_len = sizeof(param_str);
1195
1196 /*
1197 * Command Format: "dump-msgs:{mode=<mode>}" [the "mode" argument is optional]
1198 *
1199 * where <mode> is one of: {"on" | "off" | "once"} and defaults to "once".
1200 */
1201 param_str[0] = '\0';
1202 if (!as_info_parameter_get(params, "mode", param_str, &param_str_len)) {
1203 if (!strncmp(param_str, "on", 3)) {
1204 g_config.fabric_dump_msgs = true;
1205 } else if (!strncmp(param_str, "off", 4)) {
1206 g_config.fabric_dump_msgs = false;
1207 once = false;
1208 } else if (!strncmp(param_str, "once", 5)) {
1209 once = true;
1210 } else {
1211 cf_warning(AS_INFO, "The \"%s:\" command argument \"mode\" value must be one of {\"on\", \"off\", \"once\"}, not \"%s\"", name, param_str);
1212 cf_dyn_buf_append_string(db, "error");
1213 return 0;
1214 }
1215 }
1216
1217 if (once) {
1218 as_fabric_msg_queue_dump();
1219 }
1220
1221 cf_dyn_buf_append_string(db, "ok");
1222 return(0);
1223}
1224
1225int
1226info_command_dump_wb_summary(char *name, char *params, cf_dyn_buf *db)
1227{
1228 as_namespace *ns;
1229 char param_str[100];
1230 int param_str_len = sizeof(param_str);
1231
1232 /*
1233 * Command Format: "dump-wb-summary:ns=<Namespace>"
1234 *
1235 * where <Namespace> is the name of an existing namespace.
1236 */
1237 param_str[0] = '\0';
1238 if (!as_info_parameter_get(params, "ns", param_str, &param_str_len)) {
1239 if (!(ns = as_namespace_get_byname(param_str))) {
1240 cf_warning(AS_INFO, "The \"%s:\" command argument \"ns\" value must be the name of an existing namespace, not \"%s\"", name, param_str);
1241 cf_dyn_buf_append_string(db, "error");
1242 return(0);
1243 }
1244 } else {
1245 cf_warning(AS_INFO, "The \"%s:\" command requires an argument of the form \"ns=<Namespace>\"", name);
1246 cf_dyn_buf_append_string(db, "error");
1247 return 0;
1248 }
1249
1250 as_storage_summarize_wblock_stats(ns);
1251
1252 cf_dyn_buf_append_string(db, "ok");
1253
1254 return(0);
1255}
1256
1257int
1258info_command_dump_rw_request_hash(char *name, char *params, cf_dyn_buf *db)
1259{
1260 rw_request_hash_dump();
1261 cf_dyn_buf_append_string(db, "ok");
1262 return(0);
1263}
1264
1265int
1266info_command_physical_devices(char *name, char *params, cf_dyn_buf *db)
1267{
1268 // Command format: "physical-devices:path=<path>"
1269 //
1270 // <path> can specify a device partition, file path, mount directory, etc.
1271 // ... anything backed by one or more physical devices.
1272
1273 char path_str[1024] = { 0 };
1274 int path_str_len = (int)sizeof(path_str);
1275 int rv = as_info_parameter_get(params, "path", path_str, &path_str_len);
1276
1277 if (rv == -2) {
1278 cf_warning(AS_INFO, "path too long");
1279 cf_dyn_buf_append_string(db, "ERROR::bad-path");
1280 return 0;
1281 }
1282
1283 // For now path is mandatory.
1284 if (rv == -1) {
1285 cf_warning(AS_INFO, "path not specified");
1286 cf_dyn_buf_append_string(db, "ERROR::no-path");
1287 return 0;
1288 }
1289
1290 cf_storage_device_info *device_info = cf_storage_get_device_info(path_str);
1291
1292 if (device_info == NULL) {
1293 cf_warning(AS_INFO, "can't get device info for %s", path_str);
1294 cf_dyn_buf_append_string(db, "ERROR::no-device-info");
1295 return 0;
1296 }
1297
1298 for (uint32_t i = 0; i < device_info->n_phys; i++) {
1299 cf_dyn_buf_append_string(db, "physical-device=");
1300 cf_dyn_buf_append_string(db, device_info->phys[i].dev_path);
1301 cf_dyn_buf_append_char(db, ':');
1302 cf_dyn_buf_append_string(db, "age=");
1303 cf_dyn_buf_append_int(db, device_info->phys[i].nvme_age);
1304
1305 cf_dyn_buf_append_char(db, ';');
1306 }
1307
1308 cf_dyn_buf_chomp(db);
1309
1310 return 0;
1311}
1312
1313int
1314info_command_quiesce(char *name, char *params, cf_dyn_buf *db)
1315{
1316 // Command format: "quiesce:"
1317
1318 if (as_info_error_enterprise_only()) {
1319 cf_dyn_buf_append_string(db, "ERROR::enterprise-only");
1320 return 0;
1321 }
1322
1323 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
1324 g_config.namespaces[ns_ix]->pending_quiesce = true;
1325 }
1326
1327 cf_dyn_buf_append_string(db, "ok");
1328
1329 cf_info(AS_INFO, "quiesced this node");
1330
1331 return 0;
1332}
1333
1334int
1335info_command_quiesce_undo(char *name, char *params, cf_dyn_buf *db)
1336{
1337 // Command format: "quiesce-undo:"
1338
1339 if (as_info_error_enterprise_only()) {
1340 cf_dyn_buf_append_string(db, "ERROR::enterprise-only");
1341 return 0;
1342 }
1343
1344 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
1345 g_config.namespaces[ns_ix]->pending_quiesce = false;
1346 }
1347
1348 cf_dyn_buf_append_string(db, "ok");
1349
1350 cf_info(AS_INFO, "un-quiesced this node");
1351
1352 return 0;
1353}
1354
1355typedef struct rack_node_s {
1356 uint32_t rack_id;
1357 cf_node node;
1358} rack_node;
1359
1360// A comparison_fn_t used with qsort() - yields ascending rack-id order.
1361static inline int
1362compare_rack_nodes(const void* pa, const void* pb)
1363{
1364 uint32_t a = ((const rack_node*)pa)->rack_id;
1365 uint32_t b = ((const rack_node*)pb)->rack_id;
1366
1367 return a > b ? 1 : (a == b ? 0 : -1);
1368}
1369
1370void
1371namespace_rack_info(as_namespace *ns, cf_dyn_buf *db, uint32_t *rack_ids,
1372 uint32_t n_nodes, cf_node node_seq[], const char *tag)
1373{
1374 if (n_nodes == 0) {
1375 return;
1376 }
1377
1378 rack_node rack_nodes[n_nodes];
1379
1380 for (uint32_t n = 0; n < n_nodes; n++) {
1381 rack_nodes[n].rack_id = rack_ids[n];
1382 rack_nodes[n].node = node_seq[n];
1383 }
1384
1385 qsort(rack_nodes, n_nodes, sizeof(rack_node), compare_rack_nodes);
1386
1387 uint32_t cur_id = rack_nodes[0].rack_id;
1388
1389 cf_dyn_buf_append_string(db, tag);
1390 cf_dyn_buf_append_uint32(db, cur_id);
1391 cf_dyn_buf_append_char(db, '=');
1392 cf_dyn_buf_append_uint64_x(db, rack_nodes[0].node);
1393
1394 for (uint32_t n = 1; n < n_nodes; n++) {
1395 if (rack_nodes[n].rack_id == cur_id) {
1396 cf_dyn_buf_append_char(db, ',');
1397 cf_dyn_buf_append_uint64_x(db, rack_nodes[n].node);
1398 continue;
1399 }
1400
1401 cur_id = rack_nodes[n].rack_id;
1402
1403 cf_dyn_buf_append_char(db, ':');
1404 cf_dyn_buf_append_string(db, tag);
1405 cf_dyn_buf_append_uint32(db, cur_id);
1406 cf_dyn_buf_append_char(db, '=');
1407 cf_dyn_buf_append_uint64_x(db, rack_nodes[n].node);
1408 }
1409}
1410
1411int
1412info_command_racks(char *name, char *params, cf_dyn_buf *db)
1413{
1414 // Command format: "racks:{namespace=<namespace-name>}"
1415
1416 if (as_info_error_enterprise_only()) {
1417 cf_dyn_buf_append_string(db, "ERROR::enterprise-only");
1418 return 0;
1419 }
1420
1421 char param_str[AS_ID_NAMESPACE_SZ] = { 0 };
1422 int param_str_len = (int)sizeof(param_str);
1423 int rv = as_info_parameter_get(params, "namespace", param_str,
1424 &param_str_len);
1425
1426 if (rv == -2) {
1427 cf_warning(AS_INFO, "namespace parameter value too long");
1428 cf_dyn_buf_append_string(db, "ERROR::bad-namespace");
1429 return 0;
1430 }
1431
1432 if (rv == 0) {
1433 as_namespace *ns = as_namespace_get_byname(param_str);
1434
1435 if (! ns) {
1436 cf_warning(AS_INFO, "unknown namespace %s", param_str);
1437 cf_dyn_buf_append_string(db, "ERROR::unknown-namespace");
1438 return 0;
1439 }
1440
1441 as_exchange_info_lock();
1442
1443 namespace_rack_info(ns, db, ns->rack_ids, ns->cluster_size,
1444 ns->succession, "rack_");
1445
1446 if (ns->roster_count != 0) {
1447 cf_dyn_buf_append_char(db, ':');
1448 namespace_rack_info(ns, db, ns->roster_rack_ids, ns->roster_count,
1449 ns->roster, "roster_rack_");
1450 }
1451
1452 as_exchange_info_unlock();
1453
1454 return 0;
1455 }
1456
1457 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
1458 as_namespace *ns = g_config.namespaces[ns_ix];
1459
1460 cf_dyn_buf_append_string(db, "ns=");
1461 cf_dyn_buf_append_string(db, ns->name);
1462 cf_dyn_buf_append_char(db, ':');
1463
1464 as_exchange_info_lock();
1465
1466 namespace_rack_info(ns, db, ns->rack_ids, ns->cluster_size,
1467 ns->succession, "rack_");
1468
1469 if (ns->roster_count != 0) {
1470 cf_dyn_buf_append_char(db, ':');
1471 namespace_rack_info(ns, db, ns->roster_rack_ids, ns->roster_count,
1472 ns->roster, "roster_rack_");
1473 }
1474
1475 as_exchange_info_unlock();
1476
1477 cf_dyn_buf_append_char(db, ';');
1478 }
1479
1480 cf_dyn_buf_chomp(db);
1481
1482 return 0;
1483}
1484
1485int
1486info_command_recluster(char *name, char *params, cf_dyn_buf *db)
1487{
1488 // Command format: "recluster:"
1489
1490 int rv = as_clustering_cluster_reform();
1491
1492 // TODO - resolve error condition further?
1493 cf_dyn_buf_append_string(db,
1494 rv == 0 ? "ok" : (rv == 1 ? "ignored-by-non-principal" : "ERROR"));
1495
1496 return 0;
1497}
1498
1499int
1500info_command_jem_stats(char *name, char *params, cf_dyn_buf *db)
1501{
1502 cf_debug(AS_INFO, "jem_stats command received: params %s", params);
1503
1504 /*
1505 * Command Format: "jem-stats:{file=<string>;options=<string>;sites=<string>}" [the "file", "options", and "sites" arguments are optional]
1506 *
1507 * Logs the JEMalloc statistics to the console or an optionally-specified file pathname.
1508 * Options may be a string containing any of the characters "gmablh", as defined by jemalloc(3) man page.
1509 * The "sites" parameter optionally specifies a file to dump memory accounting information to.
1510 * [Note: Any options are only used if an output file is specified.]
1511 */
1512
1513 char param_str[100];
1514 int param_str_len = sizeof(param_str);
1515 char *file = NULL, *options = NULL, *sites = NULL;
1516
1517 param_str[0] = '\0';
1518 if (!as_info_parameter_get(params, "file", param_str, &param_str_len)) {
1519 file = cf_strdup(param_str);
1520 }
1521
1522 param_str[0] = '\0';
1523 param_str_len = sizeof(param_str);
1524 if (!as_info_parameter_get(params, "options", param_str, &param_str_len)) {
1525 options = cf_strdup(param_str);
1526 }
1527
1528 param_str[0] = '\0';
1529 param_str_len = sizeof(param_str);
1530 if (!as_info_parameter_get(params, "sites", param_str, &param_str_len)) {
1531 sites = cf_strdup(param_str);
1532 }
1533
1534 cf_alloc_log_stats(file, options);
1535
1536 if (file) {
1537 cf_free(file);
1538 }
1539
1540 if (options) {
1541 cf_free(options);
1542 }
1543
1544 if (sites) {
1545 cf_alloc_log_site_infos(sites);
1546 cf_free(sites);
1547 }
1548
1549 cf_dyn_buf_append_string(db, "ok");
1550 return 0;
1551}
1552
1553/*
1554 * Print out Secondary Index info.
1555 */
1556int
1557info_command_dump_si(char *name, char *params, cf_dyn_buf *db)
1558{
1559 cf_debug(AS_INFO, "dump-si command received: params %s", params);
1560
1561 char param_str[100];
1562 int param_str_len = sizeof(param_str);
1563 char *nsname = NULL, *indexname = NULL, *filename = NULL;
1564 bool verbose = false;
1565
1566 /*
1567 * Command Format: "dump-si:ns=<string>;indexname=<string>;filename=<string>;{verbose=<opt>}" [the "file" and "verbose" arguments are optional]
1568 *
1569 * where <opt> is one of: {"true" | "false"} and defaults to "false".
1570 */
1571 param_str[0] = '\0';
1572 if (!as_info_parameter_get(params, "ns", param_str, &param_str_len)) {
1573 nsname = cf_strdup(param_str);
1574 } else {
1575 cf_warning(AS_INFO, "The \"%s:\" command requires an \"ns\" parameter", name);
1576 cf_dyn_buf_append_string(db, "error");
1577 goto cleanup;
1578 }
1579
1580 param_str[0] = '\0';
1581 param_str_len = sizeof(param_str);
1582 if (!as_info_parameter_get(params, "indexname", param_str, &param_str_len)) {
1583 indexname = cf_strdup(param_str);
1584 } else {
1585 cf_warning(AS_INFO, "The \"%s:\" command requires a \"indexname\" parameter", name);
1586 cf_dyn_buf_append_string(db, "error");
1587 goto cleanup;
1588 }
1589
1590 param_str[0] = '\0';
1591 param_str_len = sizeof(param_str);
1592 if (!as_info_parameter_get(params, "file", param_str, &param_str_len)) {
1593 filename = cf_strdup(param_str);
1594 } else {
1595 cf_warning(AS_INFO, "The \"%s:\" command requires a \"filename\" parameter", name);
1596 cf_dyn_buf_append_string(db, "error");
1597 goto cleanup;
1598 }
1599
1600
1601 param_str[0] = '\0';
1602 if (!as_info_parameter_get(params, "verbose", param_str, &param_str_len)) {
1603 if (!strncmp(param_str, "true", 5)) {
1604 verbose = true;
1605 } else if (!strncmp(param_str, "false", 6)) {
1606 verbose = false;
1607 } else {
1608 cf_warning(AS_INFO, "The \"%s:\" command argument \"verbose\" value must be one of {\"true\", \"false\"}, not \"%s\"", name, param_str);
1609 cf_dyn_buf_append_string(db, "error");
1610 goto cleanup;
1611 }
1612 }
1613
1614 as_sindex_dump(nsname, indexname, filename, verbose);
1615 cf_dyn_buf_append_string(db, "ok");
1616
1617
1618 cleanup:
1619 if (nsname) {
1620 cf_free(nsname);
1621 }
1622
1623 if (indexname) {
1624 cf_free(indexname);
1625 }
1626
1627 if (filename) {
1628 cf_free(filename);
1629 }
1630
1631 return 0;
1632}
1633
1634/*
1635 * Print out clock skew information.
1636 */
1637int
1638info_command_dump_skew(char *name, char *params, cf_dyn_buf *db)
1639{
1640 cf_debug(AS_INFO, "dump-skew command received: params %s", params);
1641
1642 /*
1643 * Command Format: "dump-skew:"
1644 */
1645 as_skew_monitor_dump();
1646 cf_dyn_buf_append_string(db, "ok");
1647 return 0;
1648}
1649
1650int
1651info_command_mon_cmd(char *name, char *params, cf_dyn_buf *db)
1652{
1653 cf_debug(AS_INFO, "add-module command received: params %s", params);
1654
1655 /*
1656 * Command Format: "jobs:[module=<string>;cmd=<command>;<parameters>]"
1657 * asinfo -v 'jobs' -> list all jobs
1658 * asinfo -v 'jobs:module=query' -> list all jobs for query module
1659 * asinfo -v 'jobs:module=query;cmd=kill-job;trid=<trid>'
1660 * asinfo -v 'jobs:module=query;cmd=set-priority;trid=<trid>;value=<val>'
1661 *
1662 * where <module> is one of following:
1663 * - query
1664 * - scan
1665 */
1666
1667 char cmd[13];
1668 char module[21];
1669 char job_id[24];
1670 char val_str[11];
1671 int cmd_len = sizeof(cmd);
1672 int module_len = sizeof(module);
1673 int job_id_len = sizeof(job_id);
1674 int val_len = sizeof(val_str);
1675 uint64_t trid = 0;
1676 uint32_t value = 0;
1677
1678 cmd[0] = '\0';
1679 module[0] = '\0';
1680 job_id[0] = '\0';
1681 val_str[0] = '\0';
1682
1683 // Read the parameters: module cmd trid value
1684 int rv = as_info_parameter_get(params, "module", module, &module_len);
1685 if (rv == -1) {
1686 as_mon_info_cmd(NULL, NULL, 0, 0, db);
1687 return 0;
1688 }
1689 else if (rv == -2) {
1690 cf_dyn_buf_append_string(db, "ERROR:");
1691 cf_dyn_buf_append_int(db, AS_ERR_PARAMETER);
1692 cf_dyn_buf_append_string(db, ":\"module\" parameter too long (> ");
1693 cf_dyn_buf_append_int(db, module_len-1);
1694 cf_dyn_buf_append_string(db, " chars)");
1695 return 0;
1696 }
1697
1698 rv = as_info_parameter_get(params, "cmd", cmd, &cmd_len);
1699 if (rv == -1) {
1700 as_mon_info_cmd(module, NULL, 0, 0, db);
1701 return 0;
1702 }
1703 else if (rv == -2) {
1704 cf_dyn_buf_append_string(db, "ERROR:");
1705 cf_dyn_buf_append_int(db, AS_ERR_PARAMETER);
1706 cf_dyn_buf_append_string(db, ":\"cmd\" parameter too long (> ");
1707 cf_dyn_buf_append_int(db, cmd_len-1);
1708 cf_dyn_buf_append_string(db, " chars)");
1709 return 0;
1710 }
1711
1712 rv = as_info_parameter_get(params, "trid", job_id, &job_id_len);
1713 if (rv == 0) {
1714 trid = strtoull(job_id, NULL, 10);
1715 }
1716 else if (rv == -1) {
1717 cf_dyn_buf_append_string(db, "ERROR:");
1718 cf_dyn_buf_append_int(db, AS_ERR_PARAMETER);
1719 cf_dyn_buf_append_string(db, ":no \"trid\" parameter specified");
1720 return 0;
1721 }
1722 else if (rv == -2) {
1723 cf_dyn_buf_append_string(db, "ERROR:");
1724 cf_dyn_buf_append_int(db, AS_ERR_PARAMETER);
1725 cf_dyn_buf_append_string(db, ":\"trid\" parameter too long (> ");
1726 cf_dyn_buf_append_int(db, job_id_len-1);
1727 cf_dyn_buf_append_string(db, " chars)");
1728 return 0;
1729 }
1730
1731 rv = as_info_parameter_get(params, "value", val_str, &val_len);
1732 if (rv == 0) {
1733 value = strtoul(val_str, NULL, 10);
1734 }
1735 else if (rv == -2) {
1736 cf_dyn_buf_append_string(db, "ERROR:");
1737 cf_dyn_buf_append_int(db, AS_ERR_PARAMETER);
1738 cf_dyn_buf_append_string(db, ":\"value\" parameter too long (> ");
1739 cf_dyn_buf_append_int(db, val_len-1);
1740 cf_dyn_buf_append_string(db, " chars)");
1741 return 0;
1742 }
1743
1744 cf_info(AS_INFO, "%s %s %lu %u", module, cmd, trid, value);
1745 as_mon_info_cmd(module, cmd, trid, value, db);
1746 return 0;
1747}
1748
1749
1750static const char *
1751debug_allocations_string(void)
1752{
1753 switch (g_config.debug_allocations) {
1754 case CF_ALLOC_DEBUG_NONE:
1755 return "none";
1756
1757 case CF_ALLOC_DEBUG_TRANSIENT:
1758 return "transient";
1759
1760 case CF_ALLOC_DEBUG_PERSISTENT:
1761 return "persistent";
1762
1763 case CF_ALLOC_DEBUG_ALL:
1764 return "all";
1765
1766 default:
1767 cf_crash(CF_ALLOC, "invalid CF_ALLOC_DEBUG_* value");
1768 return NULL;
1769 }
1770}
1771
1772static const char *
1773auto_pin_string(void)
1774{
1775 switch (g_config.auto_pin) {
1776 case CF_TOPO_AUTO_PIN_NONE:
1777 return "none";
1778
1779 case CF_TOPO_AUTO_PIN_CPU:
1780 return "cpu";
1781
1782 case CF_TOPO_AUTO_PIN_NUMA:
1783 return "numa";
1784
1785 case CF_TOPO_AUTO_PIN_ADQ:
1786 return "adq";
1787
1788 default:
1789 cf_crash(CF_ALLOC, "invalid CF_TOPO_AUTO_* value");
1790 return NULL;
1791 }
1792}
1793
1794void
1795info_service_config_get(cf_dyn_buf *db)
1796{
1797 // Note - no user, group.
1798 info_append_uint32(db, "paxos-single-replica-limit", g_config.paxos_single_replica_limit);
1799 info_append_string_safe(db, "pidfile", g_config.pidfile);
1800 info_append_uint32(db, "proto-fd-max", g_config.n_proto_fd_max);
1801
1802 info_append_bool(db, "advertise-ipv6", cf_socket_advertises_ipv6());
1803 info_append_string(db, "auto-pin", auto_pin_string());
1804 info_append_uint32(db, "batch-index-threads", g_config.n_batch_index_threads);
1805 info_append_uint32(db, "batch-max-buffers-per-queue", g_config.batch_max_buffers_per_queue);
1806 info_append_uint32(db, "batch-max-requests", g_config.batch_max_requests);
1807 info_append_uint32(db, "batch-max-unused-buffers", g_config.batch_max_unused_buffers);
1808
1809 char cluster_name[AS_CLUSTER_NAME_SZ];
1810 info_get_printable_cluster_name(cluster_name);
1811 info_append_string(db, "cluster-name", cluster_name);
1812
1813 info_append_bool(db, "enable-benchmarks-fabric", g_config.fabric_benchmarks_enabled);
1814 info_append_bool(db, "enable-benchmarks-svc", g_config.svc_benchmarks_enabled);
1815 info_append_bool(db, "enable-health-check", g_config.health_check_enabled);
1816 info_append_bool(db, "enable-hist-info", g_config.info_hist_enabled);
1817 info_append_string(db, "feature-key-file", g_config.feature_key_file);
1818 info_append_uint32(db, "hist-track-back", g_config.hist_track_back);
1819 info_append_uint32(db, "hist-track-slice", g_config.hist_track_slice);
1820 info_append_string_safe(db, "hist-track-thresholds", g_config.hist_track_thresholds);
1821 info_append_uint32(db, "info-threads", g_config.n_info_threads);
1822 info_append_bool(db, "keep-caps-ssd-health", g_config.keep_caps_ssd_health);
1823 info_append_bool(db, "log-local-time", cf_fault_is_using_local_time());
1824 info_append_bool(db, "log-millis", cf_fault_is_logging_millis());
1825 info_append_uint32(db, "migrate-fill-delay", g_config.migrate_fill_delay);
1826 info_append_uint32(db, "migrate-max-num-incoming", g_config.migrate_max_num_incoming);
1827 info_append_uint32(db, "migrate-threads", g_config.n_migrate_threads);
1828 info_append_uint32(db, "min-cluster-size", g_config.clustering_config.cluster_size_min);
1829 info_append_uint64_x(db, "node-id", g_config.self_node); // may be configured or auto-generated
1830 info_append_string_safe(db, "node-id-interface", g_config.node_id_interface);
1831 info_append_int(db, "proto-fd-idle-ms", g_config.proto_fd_idle_ms);
1832 info_append_int(db, "proto-slow-netio-sleep-ms", g_config.proto_slow_netio_sleep_ms); // dynamic only
1833 info_append_uint32(db, "query-batch-size", g_config.query_bsize);
1834 info_append_uint32(db, "query-buf-size", g_config.query_buf_size); // dynamic only
1835 info_append_uint32(db, "query-bufpool-size", g_config.query_bufpool_size);
1836 info_append_bool(db, "query-in-transaction-thread", g_config.query_in_transaction_thr);
1837 info_append_uint32(db, "query-long-q-max-size", g_config.query_long_q_max_size);
1838 info_append_bool(db, "query-microbenchmark", g_config.query_enable_histogram); // dynamic only
1839 info_append_bool(db, "query-pre-reserve-partitions", g_config.partitions_pre_reserved);
1840 info_append_uint32(db, "query-priority", g_config.query_priority);
1841 info_append_uint64(db, "query-priority-sleep-us", g_config.query_sleep_us);
1842 info_append_uint64(db, "query-rec-count-bound", g_config.query_rec_count_bound);
1843 info_append_bool(db, "query-req-in-query-thread", g_config.query_req_in_query_thread);
1844 info_append_uint32(db, "query-req-max-inflight", g_config.query_req_max_inflight);
1845 info_append_uint32(db, "query-short-q-max-size", g_config.query_short_q_max_size);
1846 info_append_uint32(db, "query-threads", g_config.query_threads);
1847 info_append_uint32(db, "query-threshold", g_config.query_threshold);
1848 info_append_uint64(db, "query-untracked-time-ms", g_config.query_untracked_time_ms);
1849 info_append_uint32(db, "query-worker-threads", g_config.query_worker_threads);
1850 info_append_bool(db, "run-as-daemon", g_config.run_as_daemon);
1851 info_append_uint32(db, "scan-max-done", g_config.scan_max_done);
1852 info_append_uint32(db, "scan-threads-limit", g_config.n_scan_threads_limit);
1853 info_append_uint32(db, "service-threads", g_config.n_service_threads);
1854 info_append_uint32(db, "sindex-builder-threads", g_config.sindex_builder_threads);
1855 info_append_uint32(db, "sindex-gc-max-rate", g_config.sindex_gc_max_rate);
1856 info_append_uint32(db, "sindex-gc-period", g_config.sindex_gc_period);
1857 info_append_uint32(db, "ticker-interval", g_config.ticker_interval);
1858 info_append_int(db, "transaction-max-ms", (int)(g_config.transaction_max_ns / 1000000));
1859 info_append_uint32(db, "transaction-retry-ms", g_config.transaction_retry_ms);
1860 info_append_string_safe(db, "work-directory", g_config.work_directory);
1861
1862 info_append_string(db, "debug-allocations", debug_allocations_string());
1863 info_append_bool(db, "fabric-dump-msgs", g_config.fabric_dump_msgs);
1864 info_append_bool(db, "indent-allocations", g_config.indent_allocations);
1865}
1866
1867static void
1868append_addrs(cf_dyn_buf *db, const char *name, const cf_addr_list *list)
1869{
1870 for (uint32_t i = 0; i < list->n_addrs; ++i) {
1871 info_append_string(db, name, list->addrs[i]);
1872 }
1873}
1874
1875void
1876info_network_config_get(cf_dyn_buf *db)
1877{
1878 // Service:
1879
1880 info_append_int(db, "service.port", g_config.service.bind_port);
1881 append_addrs(db, "service.address", &g_config.service.bind);
1882 info_append_int(db, "service.access-port", g_config.service.std_port);
1883 append_addrs(db, "service.access-address", &g_config.service.std);
1884 info_append_int(db, "service.alternate-access-port", g_config.service.alt_port);
1885 append_addrs(db, "service.alternate-access-address", &g_config.service.alt);
1886
1887 info_append_int(db, "service.tls-port", g_config.tls_service.bind_port);
1888 append_addrs(db, "service.tls-address", &g_config.tls_service.bind);
1889 info_append_int(db, "service.tls-access-port", g_config.tls_service.std_port);
1890 append_addrs(db, "service.tls-access-address", &g_config.tls_service.std);
1891 info_append_int(db, "service.tls-alternate-access-port", g_config.tls_service.alt_port);
1892 append_addrs(db, "service.tls-alternate-access-address", &g_config.tls_service.alt);
1893 info_append_string_safe(db, "service.tls-name", g_config.tls_service.tls_our_name);
1894
1895 for (uint32_t i = 0; i < g_config.tls_service.n_tls_peer_names; ++i) {
1896 info_append_string(db, "service.tls-authenticate-client",
1897 g_config.tls_service.tls_peer_names[i]);
1898 }
1899
1900 // Heartbeat:
1901
1902 as_hb_info_config_get(db);
1903
1904 // Fabric:
1905
1906 append_addrs(db, "fabric.address", &g_config.fabric.bind);
1907 info_append_int(db, "fabric.port", g_config.fabric.bind_port);
1908 append_addrs(db, "fabric.tls-address", &g_config.tls_fabric.bind);
1909 info_append_int(db, "fabric.tls-port", g_config.tls_fabric.bind_port);
1910 info_append_string_safe(db, "fabric.tls-name", g_config.tls_fabric.tls_our_name);
1911 info_append_int(db, "fabric.channel-bulk-fds", g_config.n_fabric_channel_fds[AS_FABRIC_CHANNEL_BULK]);
1912 info_append_int(db, "fabric.channel-bulk-recv-threads", g_config.n_fabric_channel_recv_threads[AS_FABRIC_CHANNEL_BULK]);
1913 info_append_int(db, "fabric.channel-ctrl-fds", g_config.n_fabric_channel_fds[AS_FABRIC_CHANNEL_CTRL]);
1914 info_append_int(db, "fabric.channel-ctrl-recv-threads", g_config.n_fabric_channel_recv_threads[AS_FABRIC_CHANNEL_CTRL]);
1915 info_append_int(db, "fabric.channel-meta-fds", g_config.n_fabric_channel_fds[AS_FABRIC_CHANNEL_META]);
1916 info_append_int(db, "fabric.channel-meta-recv-threads", g_config.n_fabric_channel_recv_threads[AS_FABRIC_CHANNEL_META]);
1917 info_append_int(db, "fabric.channel-rw-fds", g_config.n_fabric_channel_fds[AS_FABRIC_CHANNEL_RW]);
1918 info_append_int(db, "fabric.channel-rw-recv-threads", g_config.n_fabric_channel_recv_threads[AS_FABRIC_CHANNEL_RW]);
1919 info_append_bool(db, "fabric.keepalive-enabled", g_config.fabric_keepalive_enabled);
1920 info_append_int(db, "fabric.keepalive-intvl", g_config.fabric_keepalive_intvl);
1921 info_append_int(db, "fabric.keepalive-probes", g_config.fabric_keepalive_probes);
1922 info_append_int(db, "fabric.keepalive-time", g_config.fabric_keepalive_time);
1923 info_append_int(db, "fabric.latency-max-ms", g_config.fabric_latency_max_ms);
1924 info_append_int(db, "fabric.recv-rearm-threshold", g_config.fabric_recv_rearm_threshold);
1925 info_append_int(db, "fabric.send-threads", g_config.n_fabric_send_threads);
1926
1927 // Info:
1928
1929 append_addrs(db, "info.address", &g_config.info.bind);
1930 info_append_int(db, "info.port", g_config.info.bind_port);
1931
1932 // TLS:
1933
1934 for (uint32_t i = 0; i < g_config.n_tls_specs; ++i) {
1935 cf_tls_spec *spec = g_config.tls_specs + i;
1936 char key[100];
1937
1938 snprintf(key, sizeof(key), "tls[%u].name", i);
1939 info_append_string_safe(db, key, spec->name);
1940
1941 snprintf(key, sizeof(key), "tls[%u].ca-file", i);
1942 info_append_string_safe(db, key, spec->ca_file);
1943
1944 snprintf(key, sizeof(key), "tls[%u].ca-path", i);
1945 info_append_string_safe(db, key, spec->ca_path);
1946
1947 snprintf(key, sizeof(key), "tls[%u].cert-blacklist", i);
1948 info_append_string_safe(db, key, spec->cert_blacklist);
1949
1950 snprintf(key, sizeof(key), "tls[%u].cert-file", i);
1951 info_append_string_safe(db, key, spec->cert_file);
1952
1953 snprintf(key, sizeof(key), "tls[%u].cipher-suite", i);
1954 info_append_string_safe(db, key, spec->cipher_suite);
1955
1956 snprintf(key, sizeof(key), "tls[%u].key-file", i);
1957 info_append_string_safe(db, key, spec->key_file);
1958
1959 snprintf(key, sizeof(key), "tls[%u].key-file-password", i);
1960 info_append_string_safe(db, key, spec->key_file_password);
1961
1962 snprintf(key, sizeof(key), "tls[%u].protocols", i);
1963 info_append_string_safe(db, key, spec->protocols);
1964 }
1965}
1966
1967
1968void
1969info_namespace_config_get(char* context, cf_dyn_buf *db)
1970{
1971 as_namespace *ns = as_namespace_get_byname(context);
1972
1973 if (! ns) {
1974 cf_dyn_buf_append_string(db, "namespace not found;"); // TODO - start with "error"?
1975 return;
1976 }
1977
1978 info_append_uint32(db, "replication-factor", ns->cfg_replication_factor);
1979 info_append_uint64(db, "memory-size", ns->memory_size);
1980 info_append_uint32(db, "default-ttl", ns->default_ttl);
1981
1982 info_append_bool(db, "enable-xdr", ns->enable_xdr);
1983 info_append_bool(db, "sets-enable-xdr", ns->sets_enable_xdr);
1984 info_append_bool(db, "ns-forward-xdr-writes", ns->ns_forward_xdr_writes);
1985 info_append_bool(db, "allow-nonxdr-writes", ns->ns_allow_nonxdr_writes);
1986 info_append_bool(db, "allow-xdr-writes", ns->ns_allow_xdr_writes);
1987
1988 // Not true config, but act as config overrides:
1989 cf_hist_track_get_settings(ns->read_hist, db);
1990 cf_hist_track_get_settings(ns->query_hist, db);
1991 cf_hist_track_get_settings(ns->udf_hist, db);
1992 cf_hist_track_get_settings(ns->write_hist, db);
1993
1994 info_append_uint32(db, "background-scan-max-rps", ns->background_scan_max_rps);
1995
1996 if (ns->conflict_resolution_policy == AS_NAMESPACE_CONFLICT_RESOLUTION_POLICY_GENERATION) {
1997 info_append_string(db, "conflict-resolution-policy", "generation");
1998 }
1999 else if (ns->conflict_resolution_policy == AS_NAMESPACE_CONFLICT_RESOLUTION_POLICY_LAST_UPDATE_TIME) {
2000 info_append_string(db, "conflict-resolution-policy", "last-update-time");
2001 }
2002 else {
2003 info_append_string(db, "conflict-resolution-policy", "undefined");
2004 }
2005
2006 info_append_bool(db, "data-in-index", ns->data_in_index);
2007 info_append_bool(db, "disable-cold-start-eviction", ns->cold_start_eviction_disabled);
2008 info_append_bool(db, "disable-write-dup-res", ns->write_dup_res_disabled);
2009 info_append_bool(db, "disallow-null-setname", ns->disallow_null_setname);
2010 info_append_bool(db, "enable-benchmarks-batch-sub", ns->batch_sub_benchmarks_enabled);
2011 info_append_bool(db, "enable-benchmarks-read", ns->read_benchmarks_enabled);
2012 info_append_bool(db, "enable-benchmarks-udf", ns->udf_benchmarks_enabled);
2013 info_append_bool(db, "enable-benchmarks-udf-sub", ns->udf_sub_benchmarks_enabled);
2014 info_append_bool(db, "enable-benchmarks-write", ns->write_benchmarks_enabled);
2015 info_append_bool(db, "enable-hist-proxy", ns->proxy_hist_enabled);
2016 info_append_uint32(db, "evict-hist-buckets", ns->evict_hist_buckets);
2017 info_append_uint32(db, "evict-tenths-pct", ns->evict_tenths_pct);
2018 info_append_uint32(db, "high-water-disk-pct", ns->hwm_disk_pct);
2019 info_append_uint32(db, "high-water-memory-pct", ns->hwm_memory_pct);
2020 info_append_uint64(db, "index-stage-size", ns->index_stage_size);
2021
2022 info_append_string(db, "index-type",
2023 ns->xmem_type == CF_XMEM_TYPE_UNDEFINED ? "undefined" :
2024 (ns->xmem_type == CF_XMEM_TYPE_SHMEM ? "shmem" :
2025 (ns->xmem_type == CF_XMEM_TYPE_PMEM ? "pmem" :
2026 (ns->xmem_type == CF_XMEM_TYPE_FLASH ? "flash" :
2027 "illegal"))));
2028
2029 info_append_uint32(db, "migrate-order", ns->migrate_order);
2030 info_append_uint32(db, "migrate-retransmit-ms", ns->migrate_retransmit_ms);
2031 info_append_uint32(db, "migrate-sleep", ns->migrate_sleep);
2032 info_append_uint32(db, "nsup-hist-period", ns->nsup_hist_period);
2033 info_append_uint32(db, "nsup-period", ns->nsup_period);
2034 info_append_uint32(db, "nsup-threads", ns->n_nsup_threads);
2035 info_append_uint32(db, "partition-tree-sprigs", ns->tree_shared.n_sprigs);
2036 info_append_bool(db, "prefer-uniform-balance", ns->cfg_prefer_uniform_balance);
2037 info_append_uint32(db, "rack-id", ns->rack_id);
2038 info_append_string(db, "read-consistency-level-override", NS_READ_CONSISTENCY_LEVEL_NAME());
2039 info_append_bool(db, "single-bin", ns->single_bin);
2040 info_append_uint32(db, "single-scan-threads", ns->n_single_scan_threads);
2041 info_append_uint32(db, "stop-writes-pct", ns->stop_writes_pct);
2042 info_append_bool(db, "strong-consistency", ns->cp);
2043 info_append_bool(db, "strong-consistency-allow-expunge", ns->cp_allow_drops);
2044 info_append_uint32(db, "tomb-raider-eligible-age", ns->tomb_raider_eligible_age);
2045 info_append_uint32(db, "tomb-raider-period", ns->tomb_raider_period);
2046 info_append_uint32(db, "transaction-pending-limit", ns->transaction_pending_limit);
2047 info_append_uint32(db, "truncate-threads", ns->n_truncate_threads);
2048 info_append_string(db, "write-commit-level-override", NS_WRITE_COMMIT_LEVEL_NAME());
2049
2050 for (uint32_t i = 0; i < ns->n_xmem_mounts; i++) {
2051 info_append_indexed_string(db, "index-type.mount", i, NULL, ns->xmem_mounts[i]);
2052 }
2053
2054 if (as_namespace_index_persisted(ns)) {
2055 info_append_uint32(db, "index-type.mounts-high-water-pct", ns->mounts_hwm_pct);
2056 info_append_uint64(db, "index-type.mounts-size-limit", ns->mounts_size_limit);
2057 }
2058
2059 info_append_string(db, "storage-engine",
2060 (ns->storage_type == AS_STORAGE_ENGINE_MEMORY ? "memory" :
2061 (ns->storage_type == AS_STORAGE_ENGINE_SSD ? "device" : "illegal")));
2062
2063 if (ns->storage_type == AS_STORAGE_ENGINE_SSD) {
2064 uint32_t n = as_namespace_device_count(ns);
2065 const char* tag = ns->n_storage_devices != 0 ?
2066 "storage-engine.device" : "storage-engine.file";
2067
2068 for (uint32_t i = 0; i < n; i++) {
2069 info_append_indexed_string(db, tag, i, NULL, ns->storage_devices[i]);
2070
2071 if (ns->n_storage_shadows != 0) {
2072 info_append_indexed_string(db, tag, i, "shadow", ns->storage_shadows[i]);
2073 }
2074 }
2075
2076 info_append_uint64(db, "storage-engine.filesize", ns->storage_filesize);
2077 info_append_string_safe(db, "storage-engine.scheduler-mode", ns->storage_scheduler_mode);
2078 info_append_uint32(db, "storage-engine.write-block-size", ns->storage_write_block_size);
2079 info_append_bool(db, "storage-engine.data-in-memory", ns->storage_data_in_memory);
2080 info_append_bool(db, "storage-engine.cold-start-empty", ns->storage_cold_start_empty);
2081 info_append_bool(db, "storage-engine.commit-to-device", ns->storage_commit_to_device);
2082 info_append_uint32(db, "storage-engine.commit-min-size", ns->storage_commit_min_size);
2083 info_append_string(db, "storage-engine.compression", NS_COMPRESSION());
2084 info_append_uint32(db, "storage-engine.compression-level", NS_COMPRESSION_LEVEL());
2085 info_append_uint32(db, "storage-engine.defrag-lwm-pct", ns->storage_defrag_lwm_pct);
2086 info_append_uint32(db, "storage-engine.defrag-queue-min", ns->storage_defrag_queue_min);
2087 info_append_uint32(db, "storage-engine.defrag-sleep", ns->storage_defrag_sleep);
2088 info_append_int(db, "storage-engine.defrag-startup-minimum", ns->storage_defrag_startup_minimum);
2089 info_append_bool(db, "storage-engine.direct-files", ns->storage_direct_files);
2090 info_append_bool(db, "storage-engine.disable-odsync", ns->storage_disable_odsync);
2091 info_append_bool(db, "storage-engine.enable-benchmarks-storage", ns->storage_benchmarks_enabled);
2092
2093 if (ns->storage_encryption_key_file != NULL) {
2094 info_append_string(db, "storage-engine.encryption",
2095 ns->storage_encryption == AS_ENCRYPTION_AES_128 ? "aes-128" :
2096 (ns->storage_encryption == AS_ENCRYPTION_AES_256 ? "aes-256" :
2097 "illegal"));
2098 }
2099
2100 info_append_string_safe(db, "storage-engine.encryption-key-file", ns->storage_encryption_key_file);
2101 info_append_uint64(db, "storage-engine.flush-max-ms", ns->storage_flush_max_us / 1000);
2102 info_append_uint64(db, "storage-engine.max-write-cache", ns->storage_max_write_cache);
2103 info_append_uint32(db, "storage-engine.min-avail-pct", ns->storage_min_avail_pct);
2104 info_append_uint32(db, "storage-engine.post-write-queue", ns->storage_post_write_queue);
2105 info_append_bool(db, "storage-engine.read-page-cache", ns->storage_read_page_cache);
2106 info_append_bool(db, "storage-engine.serialize-tomb-raider", ns->storage_serialize_tomb_raider);
2107 info_append_uint32(db, "storage-engine.tomb-raider-sleep", ns->storage_tomb_raider_sleep);
2108 }
2109
2110 info_append_uint32(db, "sindex.num-partitions", ns->sindex_num_partitions);
2111
2112 info_append_bool(db, "geo2dsphere-within.strict", ns->geo2dsphere_within_strict);
2113 info_append_uint32(db, "geo2dsphere-within.min-level", (uint32_t)ns->geo2dsphere_within_min_level);
2114 info_append_uint32(db, "geo2dsphere-within.max-level", (uint32_t)ns->geo2dsphere_within_max_level);
2115 info_append_uint32(db, "geo2dsphere-within.max-cells", (uint32_t)ns->geo2dsphere_within_max_cells);
2116 info_append_uint32(db, "geo2dsphere-within.level-mod", (uint32_t)ns->geo2dsphere_within_level_mod);
2117 info_append_uint32(db, "geo2dsphere-within.earth-radius-meters", ns->geo2dsphere_within_earth_radius_meters);
2118}
2119
2120
2121// TODO - security API?
2122void
2123info_security_config_get(cf_dyn_buf *db)
2124{
2125 info_append_bool(db, "enable-ldap", g_config.sec_cfg.ldap_enabled);
2126 info_append_bool(db, "enable-security", g_config.sec_cfg.security_enabled);
2127 info_append_uint32(db, "ldap-login-threads", g_config.sec_cfg.n_ldap_login_threads);
2128 info_append_uint32(db, "privilege-refresh-period", g_config.sec_cfg.privilege_refresh_period);
2129
2130 info_append_bool(db, "ldap.disable-tls", g_config.sec_cfg.ldap_tls_disabled);
2131 info_append_uint32(db, "ldap.polling-period", g_config.sec_cfg.ldap_polling_period);
2132 info_append_string_safe(db, "ldap.query-base-dn", g_config.sec_cfg.ldap_query_base_dn);
2133 info_append_string_safe(db, "ldap.query-user-dn", g_config.sec_cfg.ldap_query_user_dn);
2134 info_append_string_safe(db, "ldap.query-user-password-file", g_config.sec_cfg.ldap_query_user_password_file);
2135 info_append_string_safe(db, "ldap.role-query-base-dn", g_config.sec_cfg.ldap_role_query_base_dn);
2136
2137 for (int i = 0; i < MAX_ROLE_QUERY_PATTERNS; i++) {
2138 if (! g_config.sec_cfg.ldap_role_query_patterns[i]) {
2139 break;
2140 }
2141
2142 info_append_string(db, "ldap.role-query-pattern", g_config.sec_cfg.ldap_role_query_patterns[i]);
2143 }
2144
2145 info_append_bool(db, "ldap.role-query-search-ou", g_config.sec_cfg.ldap_role_query_search_ou);
2146 info_append_string_safe(db, "ldap.server", g_config.sec_cfg.ldap_server);
2147 info_append_uint32(db, "ldap.session-ttl", g_config.sec_cfg.ldap_session_ttl);
2148 info_append_string_safe(db, "ldap.tls-ca-file", g_config.sec_cfg.ldap_tls_ca_file);
2149
2150 info_append_string_safe(db, "ldap.token-hash-method",
2151 (g_config.sec_cfg.ldap_token_hash_method == AS_LDAP_EVP_SHA_256 ? "sha-256" :
2152 (g_config.sec_cfg.ldap_token_hash_method == AS_LDAP_EVP_SHA_256 ? "sha-512" : "illegal")));
2153
2154 info_append_string_safe(db, "ldap.user-dn-pattern", g_config.sec_cfg.ldap_user_dn_pattern);
2155 info_append_string_safe(db, "ldap.user-query-pattern", g_config.sec_cfg.ldap_user_query_pattern);
2156
2157 info_append_uint32(db, "report-authentication-sinks", g_config.sec_cfg.report.authentication);
2158 info_append_uint32(db, "report-data-op-sinks", g_config.sec_cfg.report.data_op);
2159 info_append_uint32(db, "report-sys-admin-sinks", g_config.sec_cfg.report.sys_admin);
2160 info_append_uint32(db, "report-user-admin-sinks", g_config.sec_cfg.report.user_admin);
2161 info_append_uint32(db, "report-violation-sinks", g_config.sec_cfg.report.violation);
2162 info_append_int(db, "syslog-local", g_config.sec_cfg.syslog_local);
2163}
2164
2165
2166void
2167info_command_config_get_with_params(char *name, char *params, cf_dyn_buf *db)
2168{
2169 char context[1024];
2170 int context_len = sizeof(context);
2171
2172 if (as_info_parameter_get(params, "context", context, &context_len) != 0) {
2173 cf_dyn_buf_append_string(db, "Error: Invalid get-config parameter;");
2174 return;
2175 }
2176
2177 if (strcmp(context, "service") == 0) {
2178 info_service_config_get(db);
2179 }
2180 else if (strcmp(context, "network") == 0) {
2181 info_network_config_get(db);
2182 }
2183 else if (strcmp(context, "namespace") == 0) {
2184 context_len = sizeof(context);
2185
2186 if (as_info_parameter_get(params, "id", context, &context_len) != 0) {
2187 cf_dyn_buf_append_string(db, "Error:invalid id;");
2188 return;
2189 }
2190
2191 info_namespace_config_get(context, db);
2192 }
2193 else if (strcmp(context, "security") == 0) {
2194 info_security_config_get(db);
2195 }
2196 else if (strcmp(context, "xdr") == 0) {
2197 as_xdr_get_config(db);
2198 }
2199 else {
2200 cf_dyn_buf_append_string(db, "Error:Invalid context;");
2201 }
2202}
2203
2204
2205int
2206info_command_config_get(char *name, char *params, cf_dyn_buf *db)
2207{
2208 cf_debug(AS_INFO, "config-get command received: params %s", params);
2209
2210 if (params && *params != 0) {
2211 info_command_config_get_with_params(name, params, db);
2212 cf_dyn_buf_chomp(db);
2213 return 0;
2214 }
2215
2216 // We come here when context is not mentioned.
2217 // In that case we want to print everything.
2218 info_service_config_get(db);
2219 info_network_config_get(db);
2220 info_security_config_get(db);
2221 as_xdr_get_config(db);
2222
2223 cf_dyn_buf_chomp(db);
2224
2225 return 0;
2226}
2227
2228
2229//
2230// config-set:context=service;variable=value;
2231// config-set:context=network;variable=heartbeat.value;
2232// config-set:context=namespace;id=test;variable=value;
2233//
2234int
2235info_command_config_set_threadsafe(char *name, char *params, cf_dyn_buf *db)
2236{
2237 cf_debug(AS_INFO, "config-set command received: params %s", params);
2238
2239 char context[1024];
2240 int context_len = sizeof(context);
2241 int val;
2242 char bool_val[2][6] = {"false", "true"};
2243
2244 if (0 != as_info_parameter_get(params, "context", context, &context_len))
2245 goto Error;
2246 if (strcmp(context, "service") == 0) {
2247 context_len = sizeof(context);
2248 if (0 == as_info_parameter_get(params, "advertise-ipv6", context, &context_len)) {
2249 if (strcmp(context, "true") == 0 || strcmp(context, "yes") == 0) {
2250 cf_socket_set_advertise_ipv6(true);
2251 }
2252 else if (strcmp(context, "false") == 0 || strcmp(context, "no") == 0) {
2253 cf_socket_set_advertise_ipv6(false);
2254 }
2255 else {
2256 goto Error;
2257 }
2258 }
2259 else if (0 == as_info_parameter_get(params, "service-threads", context, &context_len)) {
2260 if (0 != cf_str_atoi(context, &val)) {
2261 goto Error;
2262 }
2263 if (val < 1 || val > MAX_SERVICE_THREADS) {
2264 cf_warning(AS_INFO, "service-threads must be between 1 and %u", MAX_SERVICE_THREADS);
2265 goto Error;
2266 }
2267 uint16_t n_cpus = cf_topo_count_cpus();
2268 if (g_config.auto_pin != CF_TOPO_AUTO_PIN_NONE && val % n_cpus != 0) {
2269 cf_warning(AS_INFO, "with auto-pin, service-threads must be a multiple of the number of CPUs (%hu)", n_cpus);
2270 goto Error;
2271 }
2272 cf_info(AS_INFO, "Changing value of service-threads from %u to %d ", g_config.n_service_threads, val);
2273 as_service_set_threads((uint32_t)val);
2274 }
2275 else if (0 == as_info_parameter_get(params, "transaction-retry-ms", context, &context_len)) {
2276 if (0 != cf_str_atoi(context, &val))
2277 goto Error;
2278 if (val == 0)
2279 goto Error;
2280 cf_info(AS_INFO, "Changing value of transaction-retry-ms from %d to %d ", g_config.transaction_retry_ms, val);
2281 g_config.transaction_retry_ms = val;
2282 }
2283 else if (0 == as_info_parameter_get(params, "transaction-max-ms", context, &context_len)) {
2284 if (0 != cf_str_atoi(context, &val))
2285 goto Error;
2286 cf_info(AS_INFO, "Changing value of transaction-max-ms from %"PRIu64" to %d ", (g_config.transaction_max_ns / 1000000), val);
2287 g_config.transaction_max_ns = (uint64_t)val * 1000000;
2288 }
2289 else if (0 == as_info_parameter_get(params, "ticker-interval", context, &context_len)) {
2290 if (0 != cf_str_atoi(context, &val))
2291 goto Error;
2292 cf_info(AS_INFO, "Changing value of ticker-interval from %d to %d ", g_config.ticker_interval, val);
2293 g_config.ticker_interval = val;
2294 }
2295 else if (0 == as_info_parameter_get(params, "scan-max-done", context, &context_len)) {
2296 if (0 != cf_str_atoi(context, &val))
2297 goto Error;
2298 if (val < 0 || val > 1000) {
2299 goto Error;
2300 }
2301 cf_info(AS_INFO, "Changing value of scan-max-done from %d to %d ", g_config.scan_max_done, val);
2302 g_config.scan_max_done = val;
2303 as_scan_limit_finished_jobs();
2304 }
2305 else if (0 == as_info_parameter_get(params, "scan-threads-limit", context, &context_len)) {
2306 if (0 != cf_str_atoi(context, &val) || val < 1 || val > 1024) {
2307 goto Error;
2308 }
2309 cf_info(AS_INFO, "Changing value of scan-threads-limit from %u to %d ", g_config.n_scan_threads_limit, val);
2310 g_config.n_scan_threads_limit = (uint32_t)val;
2311 }
2312 else if (0 == as_info_parameter_get(params, "batch-index-threads", context, &context_len)) {
2313 if (0 != cf_str_atoi(context, &val))
2314 goto Error;
2315 if (0 != as_batch_threads_resize(val))
2316 goto Error;
2317 }
2318 else if (0 == as_info_parameter_get(params, "batch-max-requests", context, &context_len)) {
2319 if (0 != cf_str_atoi(context, &val))
2320 goto Error;
2321 cf_info(AS_INFO, "Changing value of batch-max-requests from %d to %d ", g_config.batch_max_requests, val);
2322 g_config.batch_max_requests = val;
2323 }
2324 else if (0 == as_info_parameter_get(params, "batch-max-buffers-per-queue", context, &context_len)) {
2325 if (0 != cf_str_atoi(context, &val))
2326 goto Error;
2327 cf_info(AS_INFO, "Changing value of batch-max-buffers-per-queue from %d to %d ", g_config.batch_max_buffers_per_queue, val);
2328 g_config.batch_max_buffers_per_queue = val;
2329 }
2330 else if (0 == as_info_parameter_get(params, "batch-max-unused-buffers", context, &context_len)) {
2331 if (0 != cf_str_atoi(context, &val))
2332 goto Error;
2333 cf_info(AS_INFO, "Changing value of batch-max-unused-buffers from %d to %d ", g_config.batch_max_unused_buffers, val);
2334 g_config.batch_max_unused_buffers = val;
2335 }
2336 else if (0 == as_info_parameter_get(params, "proto-fd-max", context, &context_len)) {
2337 if (cf_str_atoi(context, &val) != 0 || val < MIN_PROTO_FD_MAX) {
2338 cf_warning(AS_INFO, "invalid proto-fd-max %d", val);
2339 goto Error;
2340 }
2341 cf_info(AS_INFO, "Changing value of proto-fd-max from %u to %d ", g_config.n_proto_fd_max, val);
2342 g_config.n_proto_fd_max = (uint32_t)val;
2343 }
2344 else if (0 == as_info_parameter_get(params, "proto-fd-idle-ms", context, &context_len)) {
2345 if (0 != cf_str_atoi(context, &val))
2346 goto Error;
2347 cf_info(AS_INFO, "Changing value of proto-fd-idle-ms from %d to %d ", g_config.proto_fd_idle_ms, val);
2348 g_config.proto_fd_idle_ms = val;
2349 }
2350 else if (0 == as_info_parameter_get(params, "proto-slow-netio-sleep-ms", context, &context_len)) {
2351 if (0 != cf_str_atoi(context, &val))
2352 goto Error;
2353 cf_info(AS_INFO, "Changing value of proto-slow-netio-sleep-ms from %d to %d ", g_config.proto_slow_netio_sleep_ms, val);
2354 g_config.proto_slow_netio_sleep_ms = val;
2355 }
2356 else if (0 == as_info_parameter_get( params, "cluster-name", context, &context_len)){
2357 if (!as_config_cluster_name_set(context)) {
2358 goto Error;
2359 }
2360 cf_info(AS_INFO, "Changing value of cluster-name to '%s'", context);
2361 }
2362 else if (0 == as_info_parameter_get(params, "info-threads", context, &context_len)) {
2363 if (0 != cf_str_atoi(context, &val)) {
2364 goto Error;
2365 }
2366 if (val < 1 || val > MAX_INFO_THREADS) {
2367 cf_warning(AS_INFO, "info-threads %d must be between 1 and %u", val, MAX_INFO_THREADS);
2368 goto Error;
2369 }
2370 cf_info(AS_INFO, "Changing value of info-threads from %u to %d ", g_config.n_info_threads, val);
2371 info_set_num_info_threads((uint32_t)val);
2372 }
2373 else if (0 == as_info_parameter_get(params, "migrate-fill-delay", context, &context_len)) {
2374 if (as_config_error_enterprise_only()) {
2375 cf_warning(AS_INFO, "migrate-fill-delay is enterprise-only");
2376 goto Error;
2377 }
2378 uint32_t val;
2379 if (0 != cf_str_atoi_seconds(context, &val)) {
2380 goto Error;
2381 }
2382 cf_info(AS_INFO, "Changing value of migrate-fill-delay from %u to %u ", g_config.migrate_fill_delay, val);
2383 g_config.migrate_fill_delay = val;
2384 }
2385 else if (0 == as_info_parameter_get(params, "migrate-max-num-incoming", context, &context_len)) {
2386 if (0 != cf_str_atoi(context, &val)) {
2387 goto Error;
2388 }
2389 if ((uint32_t)val > AS_MIGRATE_LIMIT_MAX_NUM_INCOMING) {
2390 cf_warning(AS_INFO, "migrate-max-num-incoming %d must be >= 0 and <= %u", val, AS_MIGRATE_LIMIT_MAX_NUM_INCOMING);
2391 goto Error;
2392 }
2393 cf_info(AS_INFO, "Changing value of migrate-max-num-incoming from %u to %d ", g_config.migrate_max_num_incoming, val);
2394 g_config.migrate_max_num_incoming = (uint32_t)val;
2395 }
2396 else if (0 == as_info_parameter_get(params, "migrate-threads", context, &context_len)) {
2397 if (0 != cf_str_atoi(context, &val)) {
2398 goto Error;
2399 }
2400 if ((uint32_t)val > MAX_NUM_MIGRATE_XMIT_THREADS) {
2401 cf_warning(AS_INFO, "migrate-threads %d must be >= 0 and <= %u", val, MAX_NUM_MIGRATE_XMIT_THREADS);
2402 goto Error;
2403 }
2404 cf_info(AS_INFO, "Changing value of migrate-threads from %u to %d ", g_config.n_migrate_threads, val);
2405 as_migrate_set_num_xmit_threads(val);
2406 }
2407 else if (0 == as_info_parameter_get(params, "min-cluster-size", context, &context_len)) {
2408 if (0 != cf_str_atoi(context, &val) || (0 > val) || (as_clustering_cluster_size_min_set(val) < 0))
2409 goto Error;
2410 }
2411 else if (0 == as_info_parameter_get(params, "query-buf-size", context, &context_len)) {
2412 uint64_t val = atoll(context);
2413 cf_debug(AS_INFO, "query-buf-size = %"PRIu64"", val);
2414 if (val < 1024) {
2415 goto Error;
2416 }
2417 cf_info(AS_INFO, "Changing value of query-buf-size from %"PRIu64" to %"PRIu64"", g_config.query_buf_size, val);
2418 g_config.query_buf_size = val;
2419 }
2420 else if (0 == as_info_parameter_get(params, "query-threshold", context, &context_len)) {
2421 uint64_t val = atoll(context);
2422 cf_debug(AS_INFO, "query-threshold = %"PRIu64"", val);
2423 if ((int64_t)val <= 0) {
2424 goto Error;
2425 }
2426 cf_info(AS_INFO, "Changing value of query-threshold from %u to %"PRIu64, g_config.query_threshold, val);
2427 g_config.query_threshold = val;
2428 }
2429 else if (0 == as_info_parameter_get(params, "query-untracked-time-ms", context, &context_len)) {
2430 uint64_t val = atoll(context);
2431 cf_debug(AS_INFO, "query-untracked-time = %"PRIu64" milli seconds", val);
2432 if ((int64_t)val < 0) {
2433 goto Error;
2434 }
2435 cf_info(AS_INFO, "Changing value of query-untracked-time from %"PRIu64" milli seconds to %"PRIu64" milli seconds",
2436 g_config.query_untracked_time_ms, val);
2437 g_config.query_untracked_time_ms = val;
2438 }
2439 else if (0 == as_info_parameter_get(params, "query-rec-count-bound", context, &context_len)) {
2440 uint64_t val = atoll(context);
2441 cf_debug(AS_INFO, "query-rec-count-bound = %"PRIu64"", val);
2442 if ((int64_t)val <= 0) {
2443 goto Error;
2444 }
2445 cf_info(AS_INFO, "Changing value of query-rec-count-bound from %"PRIu64" to %"PRIu64" ", g_config.query_rec_count_bound, val);
2446 g_config.query_rec_count_bound = val;
2447 }
2448 else if (0 == as_info_parameter_get(params, "sindex-builder-threads", context, &context_len)) {
2449 int val = 0;
2450 if (0 != cf_str_atoi(context, &val) || (val > MAX_SINDEX_BUILDER_THREADS)) {
2451 cf_warning(AS_INFO, "sindex-builder-threads: value must be <= %d, not %s", MAX_SINDEX_BUILDER_THREADS, context);
2452 goto Error;
2453 }
2454 cf_info(AS_INFO, "Changing value of sindex-builder-threads from %u to %d", g_config.sindex_builder_threads, val);
2455 g_config.sindex_builder_threads = (uint32_t)val;
2456 as_sbld_resize_thread_pool(g_config.sindex_builder_threads);
2457 }
2458 else if (0 == as_info_parameter_get(params, "sindex-gc-max-rate", context, &context_len)) {
2459 if (0 != cf_str_atoi(context, &val))
2460 goto Error;
2461 cf_info(AS_INFO, "Changing value of sindex-gc-max-rate from %d to %d ", g_config.sindex_gc_max_rate, val);
2462 g_config.sindex_gc_max_rate = (uint32_t)val;
2463 }
2464 else if (0 == as_info_parameter_get(params, "sindex-gc-period", context, &context_len)) {
2465 if (0 != cf_str_atoi(context, &val))
2466 goto Error;
2467 cf_info(AS_INFO, "Changing value of sindex-gc-period from %d to %d ", g_config.sindex_gc_period, val);
2468 g_config.sindex_gc_period = (uint32_t)val;
2469 }
2470 else if (0 == as_info_parameter_get(params, "query-threads", context, &context_len)) {
2471 uint64_t val = atoll(context);
2472 cf_info(AS_INFO, "query-threads = %"PRIu64, val);
2473 if (val == 0) {
2474 cf_warning(AS_INFO, "query-threads should be a number %s", context);
2475 goto Error;
2476 }
2477 int old_val = g_config.query_threads;
2478 int new_val = 0;
2479 if (as_query_reinit(val, &new_val) != AS_QUERY_OK) {
2480 cf_warning(AS_INFO, "Config not changed.");
2481 goto Error;
2482 }
2483
2484 cf_info(AS_INFO, "Changing value of query-threads from %d to %d",
2485 old_val, new_val);
2486 }
2487 else if (0 == as_info_parameter_get(params, "query-worker-threads", context, &context_len)) {
2488 uint64_t val = atoll(context);
2489 cf_info(AS_INFO, "query-worker-threads = %"PRIu64, val);
2490 if (val == 0) {
2491 cf_warning(AS_INFO, "query-worker-threads should be a number %s", context);
2492 goto Error;
2493 }
2494 int old_val = g_config.query_threads;
2495 int new_val = 0;
2496 if (as_query_worker_reinit(val, &new_val) != AS_QUERY_OK) {
2497 cf_warning(AS_INFO, "Config not changed.");
2498 goto Error;
2499 }
2500 cf_info(AS_INFO, "Changing value of query-worker-threads from %d to %d",
2501 old_val, new_val);
2502 }
2503 else if (0 == as_info_parameter_get(params, "query-priority", context, &context_len)) {
2504 uint64_t val = atoll(context);
2505 cf_info(AS_INFO, "query_priority = %"PRIu64, val);
2506 if (val == 0) {
2507 cf_warning(AS_INFO, "query_priority should be a number %s", context);
2508 goto Error;
2509 }
2510 cf_info(AS_INFO, "Changing value of query-priority from %d to %"PRIu64, g_config.query_priority, val);
2511 g_config.query_priority = val;
2512 }
2513 else if (0 == as_info_parameter_get(params, "query-priority-sleep-us", context, &context_len)) {
2514 uint64_t val = atoll(context);
2515 if(val == 0) {
2516 cf_warning(AS_INFO, "query_sleep should be a number %s", context);
2517 goto Error;
2518 }
2519 cf_info(AS_INFO, "Changing value of query-sleep from %"PRIu64" uSec to %"PRIu64" uSec ", g_config.query_sleep_us, val);
2520 g_config.query_sleep_us = val;
2521 }
2522 else if (0 == as_info_parameter_get(params, "query-batch-size", context, &context_len)) {
2523 uint64_t val = atoll(context);
2524 cf_info(AS_INFO, "query-batch-size = %"PRIu64, val);
2525 if((int)val <= 0) {
2526 cf_warning(AS_INFO, "query-batch-size should be a positive number");
2527 goto Error;
2528 }
2529 cf_info(AS_INFO, "Changing value of query-batch-size from %d to %"PRIu64, g_config.query_bsize, val);
2530 g_config.query_bsize = val;
2531 }
2532 else if (0 == as_info_parameter_get(params, "query-req-max-inflight", context, &context_len)) {
2533 uint64_t val = atoll(context);
2534 cf_info(AS_INFO, "query-req-max-inflight = %"PRIu64, val);
2535 if((int)val <= 0) {
2536 cf_warning(AS_INFO, "query-req-max-inflight should be a positive number");
2537 goto Error;
2538 }
2539 cf_info(AS_INFO, "Changing value of query-req-max-inflight from %d to %"PRIu64, g_config.query_req_max_inflight, val);
2540 g_config.query_req_max_inflight = val;
2541 }
2542 else if (0 == as_info_parameter_get(params, "query-bufpool-size", context, &context_len)) {
2543 uint64_t val = atoll(context);
2544 cf_info(AS_INFO, "query-bufpool-size = %"PRIu64, val);
2545 if((int)val <= 0) {
2546 cf_warning(AS_INFO, "query-bufpool-size should be a positive number");
2547 goto Error;
2548 }
2549 cf_info(AS_INFO, "Changing value of query-bufpool-size from %d to %"PRIu64, g_config.query_bufpool_size, val);
2550 g_config.query_bufpool_size = val;
2551 }
2552 else if (0 == as_info_parameter_get(params, "query-in-transaction-thread", context, &context_len)) {
2553 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
2554 cf_info(AS_INFO, "Changing value of query-in-transaction-thread from %s to %s", bool_val[g_config.query_in_transaction_thr], context);
2555 g_config.query_in_transaction_thr = true;
2556 }
2557 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
2558 cf_info(AS_INFO, "Changing value of query-in-transaction-thread from %s to %s", bool_val[g_config.query_in_transaction_thr], context);
2559 g_config.query_in_transaction_thr = false;
2560 }
2561 else
2562 goto Error;
2563 }
2564 else if (0 == as_info_parameter_get(params, "query-req-in-query-thread", context, &context_len)) {
2565 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
2566 cf_info(AS_INFO, "Changing value of query-req-in-query-thread from %s to %s", bool_val[g_config.query_req_in_query_thread], context);
2567 g_config.query_req_in_query_thread = true;
2568
2569 }
2570 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
2571 cf_info(AS_INFO, "Changing value of query-req-in-query-thread from %s to %s", bool_val[g_config.query_req_in_query_thread], context);
2572 g_config.query_req_in_query_thread = false;
2573 }
2574 else
2575 goto Error;
2576 }
2577 else if (0 == as_info_parameter_get(params, "query-short-q-max-size", context, &context_len)) {
2578 uint64_t val = atoll(context);
2579 cf_info(AS_INFO, "query-short-q-max-size = %"PRIu64, val);
2580 if((int)val <= 0) {
2581 cf_warning(AS_INFO, "query-short-q-max-size should be a positive number");
2582 goto Error;
2583 }
2584 cf_info(AS_INFO, "Changing value of query-short-q-max-size from %d to %"PRIu64, g_config.query_short_q_max_size, val);
2585 g_config.query_short_q_max_size = val;
2586 }
2587 else if (0 == as_info_parameter_get(params, "query-long-q-max-size", context, &context_len)) {
2588 uint64_t val = atoll(context);
2589 cf_info(AS_INFO, "query-long-q-max-size = %"PRIu64, val);
2590 if((int)val <= 0) {
2591 cf_warning(AS_INFO, "query-long-q-max-size should be a positive number");
2592 goto Error;
2593 }
2594 cf_info(AS_INFO, "Changing value of query-longq-max-size from %d to %"PRIu64, g_config.query_long_q_max_size, val);
2595 g_config.query_long_q_max_size = val;
2596 }
2597 else if (0 == as_info_parameter_get(params, "enable-benchmarks-fabric", context, &context_len)) {
2598 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
2599 cf_info(AS_INFO, "Changing value of enable-benchmarks-fabric to %s", context);
2600 g_config.fabric_benchmarks_enabled = true;
2601 }
2602 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
2603 cf_info(AS_INFO, "Changing value of enable-benchmarks-fabric to %s", context);
2604 g_config.fabric_benchmarks_enabled = false;
2605 histogram_clear(g_stats.fabric_send_init_hists[AS_FABRIC_CHANNEL_BULK]);
2606 histogram_clear(g_stats.fabric_send_fragment_hists[AS_FABRIC_CHANNEL_BULK]);
2607 histogram_clear(g_stats.fabric_recv_fragment_hists[AS_FABRIC_CHANNEL_BULK]);
2608 histogram_clear(g_stats.fabric_recv_cb_hists[AS_FABRIC_CHANNEL_BULK]);
2609 histogram_clear(g_stats.fabric_send_init_hists[AS_FABRIC_CHANNEL_CTRL]);
2610 histogram_clear(g_stats.fabric_send_fragment_hists[AS_FABRIC_CHANNEL_CTRL]);
2611 histogram_clear(g_stats.fabric_recv_fragment_hists[AS_FABRIC_CHANNEL_CTRL]);
2612 histogram_clear(g_stats.fabric_recv_cb_hists[AS_FABRIC_CHANNEL_CTRL]);
2613 histogram_clear(g_stats.fabric_send_init_hists[AS_FABRIC_CHANNEL_META]);
2614 histogram_clear(g_stats.fabric_send_fragment_hists[AS_FABRIC_CHANNEL_META]);
2615 histogram_clear(g_stats.fabric_recv_fragment_hists[AS_FABRIC_CHANNEL_META]);
2616 histogram_clear(g_stats.fabric_recv_cb_hists[AS_FABRIC_CHANNEL_META]);
2617 histogram_clear(g_stats.fabric_send_init_hists[AS_FABRIC_CHANNEL_RW]);
2618 histogram_clear(g_stats.fabric_send_fragment_hists[AS_FABRIC_CHANNEL_RW]);
2619 histogram_clear(g_stats.fabric_recv_fragment_hists[AS_FABRIC_CHANNEL_RW]);
2620 histogram_clear(g_stats.fabric_recv_cb_hists[AS_FABRIC_CHANNEL_RW]);
2621 }
2622 else {
2623 goto Error;
2624 }
2625 }
2626 else if (0 == as_info_parameter_get(params, "enable-benchmarks-svc", context, &context_len)) {
2627 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
2628 cf_info(AS_INFO, "Changing value of enable-benchmarks-svc to %s", context);
2629 g_config.svc_benchmarks_enabled = true;
2630 }
2631 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
2632 cf_info(AS_INFO, "Changing value of enable-benchmarks-svc to %s", context);
2633 g_config.svc_benchmarks_enabled = false;
2634 histogram_clear(g_stats.svc_demarshal_hist);
2635 histogram_clear(g_stats.svc_queue_hist);
2636 }
2637 else {
2638 goto Error;
2639 }
2640 }
2641 else if (0 == as_info_parameter_get(params, "enable-health-check", context, &context_len)) {
2642 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
2643 cf_info(AS_INFO, "Changing value of enable-health-check to %s", context);
2644 g_config.health_check_enabled = true;
2645 }
2646 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
2647 cf_info(AS_INFO, "Changing value of enable-health-check to %s", context);
2648 g_config.health_check_enabled = false;
2649 }
2650 else {
2651 goto Error;
2652 }
2653 }
2654 else if (0 == as_info_parameter_get(params, "enable-hist-info", context, &context_len)) {
2655 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
2656 cf_info(AS_INFO, "Changing value of enable-hist-info to %s", context);
2657 g_config.info_hist_enabled = true;
2658 }
2659 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
2660 cf_info(AS_INFO, "Changing value of enable-hist-info to %s", context);
2661 g_config.info_hist_enabled = false;
2662 histogram_clear(g_stats.info_hist);
2663 }
2664 else {
2665 goto Error;
2666 }
2667 }
2668 else if (0 == as_info_parameter_get(params, "query-microbenchmark", context, &context_len)) {
2669 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
2670 cf_info(AS_INFO, "Changing value of query-enable-histogram to %s", context);
2671 g_config.query_enable_histogram = true;
2672 }
2673 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
2674 cf_info(AS_INFO, "Changing value of query-enable-histogram to %s", context);
2675 g_config.query_enable_histogram = false;
2676 }
2677 else {
2678 goto Error;
2679 }
2680 }
2681 else if (0 == as_info_parameter_get(params, "query-pre-reserve-partitions", context, &context_len)) {
2682 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
2683 cf_info(AS_INFO, "Changing value of query-pre-reserve-partitions to %s", context);
2684 g_config.partitions_pre_reserved = true;
2685 }
2686 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
2687 cf_info(AS_INFO, "Changing value of query-pre-reserve-partitions to %s", context);
2688 g_config.partitions_pre_reserved = false;
2689 }
2690 else {
2691 goto Error;
2692 }
2693 }
2694 else {
2695 goto Error;
2696 }
2697 }
2698 else if (strcmp(context, "network") == 0) {
2699 context_len = sizeof(context);
2700 if (0 == as_info_parameter_get(params, "heartbeat.interval", context, &context_len)) {
2701 if (0 != cf_str_atoi(context, &val))
2702 goto Error;
2703 if (as_hb_tx_interval_set(val) != 0) {
2704 goto Error;
2705 }
2706 }
2707 else if (0 == as_info_parameter_get(params, "heartbeat.timeout", context, &context_len)) {
2708 if (0 != cf_str_atoi(context, &val))
2709 goto Error;
2710 if (as_hb_max_intervals_missed_set(val) != 0){
2711 goto Error;
2712 }
2713 }
2714 else if (0 == as_info_parameter_get(params, "heartbeat.mtu", context, &context_len)) {
2715 if (0 != cf_str_atoi(context, &val))
2716 goto Error;
2717 as_hb_override_mtu_set(val);
2718 }
2719 else if (0 == as_info_parameter_get(params, "heartbeat.protocol", context, &context_len)) {
2720 as_hb_protocol protocol = (!strcmp(context, "v3") ? AS_HB_PROTOCOL_V3 :
2721 (!strcmp(context, "reset") ? AS_HB_PROTOCOL_RESET :
2722 (!strcmp(context, "none") ? AS_HB_PROTOCOL_NONE :
2723 AS_HB_PROTOCOL_UNDEF)));
2724 if (AS_HB_PROTOCOL_UNDEF == protocol) {
2725 cf_warning(AS_INFO, "heartbeat protocol version %s not supported", context);
2726 goto Error;
2727 }
2728 cf_info(AS_INFO, "Changing value of heartbeat protocol version to %s", context);
2729 if (0 > as_hb_protocol_set(protocol))
2730 goto Error;
2731 }
2732 else if (0 == as_info_parameter_get(params, "fabric.channel-bulk-recv-threads", context, &context_len)) {
2733 if (0 != cf_str_atoi(context, &val)) {
2734 goto Error;
2735 }
2736 if (val < 1 || val > MAX_FABRIC_CHANNEL_THREADS) {
2737 cf_warning(AS_INFO, "fabric.channel-bulk-recv-threads must be between 1 and %u", MAX_FABRIC_CHANNEL_THREADS);
2738 goto Error;
2739 }
2740 cf_info(AS_FABRIC, "changing fabric.channel-bulk-recv-threads from %u to %d", g_config.n_fabric_channel_recv_threads[AS_FABRIC_CHANNEL_BULK], val);
2741 as_fabric_set_recv_threads(AS_FABRIC_CHANNEL_BULK, val);
2742 }
2743 else if (0 == as_info_parameter_get(params, "fabric.channel-ctrl-recv-threads", context, &context_len)) {
2744 if (0 != cf_str_atoi(context, &val)) {
2745 goto Error;
2746 }
2747 if (val < 1 || val > MAX_FABRIC_CHANNEL_THREADS) {
2748 cf_warning(AS_INFO, "fabric.channel-ctrl-recv-threads must be between 1 and %u", MAX_FABRIC_CHANNEL_THREADS);
2749 goto Error;
2750 }
2751 cf_info(AS_FABRIC, "changing fabric.channel-ctrl-recv-threads from %u to %d", g_config.n_fabric_channel_recv_threads[AS_FABRIC_CHANNEL_CTRL], val);
2752 as_fabric_set_recv_threads(AS_FABRIC_CHANNEL_CTRL, val);
2753 }
2754 else if (0 == as_info_parameter_get(params, "fabric.channel-meta-recv-threads", context, &context_len)) {
2755 if (0 != cf_str_atoi(context, &val)) {
2756 goto Error;
2757 }
2758 if (val < 1 || val > MAX_FABRIC_CHANNEL_THREADS) {
2759 cf_warning(AS_INFO, "fabric.channel-meta-recv-threads must be between 1 and %u", MAX_FABRIC_CHANNEL_THREADS);
2760 goto Error;
2761 }
2762 cf_info(AS_FABRIC, "changing fabric.channel-meta-recv-threads from %u to %d", g_config.n_fabric_channel_recv_threads[AS_FABRIC_CHANNEL_META], val);
2763 as_fabric_set_recv_threads(AS_FABRIC_CHANNEL_META, val);
2764 }
2765 else if (0 == as_info_parameter_get(params, "fabric.channel-rw-recv-threads", context, &context_len)) {
2766 if (0 != cf_str_atoi(context, &val)) {
2767 goto Error;
2768 }
2769 if (val < 1 || val > MAX_FABRIC_CHANNEL_THREADS) {
2770 cf_warning(AS_INFO, "fabric.channel-rw-recv-threads must be between 1 and %u", MAX_FABRIC_CHANNEL_THREADS);
2771 goto Error;
2772 }
2773 cf_info(AS_FABRIC, "changing fabric.channel-rw-recv-threads from %u to %d", g_config.n_fabric_channel_recv_threads[AS_FABRIC_CHANNEL_RW], val);
2774 as_fabric_set_recv_threads(AS_FABRIC_CHANNEL_RW, val);
2775 }
2776 else if (0 == as_info_parameter_get(params, "fabric.recv-rearm-threshold", context, &context_len)) {
2777 if (0 != cf_str_atoi(context, &val)) {
2778 goto Error;
2779 }
2780
2781 if (val < 0 || val > 1024 * 1024) {
2782 goto Error;
2783 }
2784
2785 g_config.fabric_recv_rearm_threshold = (uint32_t)val;
2786 }
2787 else
2788 goto Error;
2789 }
2790 else if (strcmp(context, "namespace") == 0) {
2791 context_len = sizeof(context);
2792 if (0 != as_info_parameter_get(params, "id", context, &context_len))
2793 goto Error;
2794 as_namespace *ns = as_namespace_get_byname(context);
2795 if (!ns)
2796 goto Error;
2797
2798 context_len = sizeof(context);
2799 // configure namespace/set related parameters:
2800 if (0 == as_info_parameter_get(params, "set", context, &context_len)) {
2801 if (context_len == 0 || context_len >= AS_SET_NAME_MAX_SIZE) {
2802 cf_warning(AS_INFO, "illegal length %d for set name %s",
2803 context_len, context);
2804 goto Error;
2805 }
2806
2807 char set_name[AS_SET_NAME_MAX_SIZE];
2808 size_t set_name_len = (size_t)context_len;
2809
2810 strcpy(set_name, context);
2811
2812 // Ideally, set operations should not be part of configs. But,
2813 // set-delete is exception for historical reasons. Do an early check
2814 // and bail out if set doesn't exist.
2815 uint16_t set_id = as_namespace_get_set_id(ns, set_name);
2816 if (set_id == INVALID_SET_ID) {
2817 context_len = sizeof(context);
2818 if (0 == as_info_parameter_get(params, "set-delete", context,
2819 &context_len)) {
2820 cf_warning(AS_INFO, "set-delete failed because set %s doesn't exist in ns %s",
2821 set_name, ns->name);
2822 goto Error;
2823 }
2824 }
2825
2826 // configurations should create set if it doesn't exist.
2827 // checks if there is a vmap set with the same name and if so returns
2828 // a ptr to it. if not, it creates an set structure, initializes it
2829 // and returns a ptr to it.
2830 as_set *p_set = NULL;
2831 if (as_namespace_get_create_set_w_len(ns, set_name, set_name_len,
2832 &p_set, NULL) != 0) {
2833 goto Error;
2834 }
2835
2836 context_len = sizeof(context);
2837 if (0 == as_info_parameter_get(params, "set-enable-xdr", context, &context_len)) {
2838 // TODO - make sure context is null-terminated.
2839 if ((strncmp(context, "true", 4) == 0) || (strncmp(context, "yes", 3) == 0)) {
2840 cf_info(AS_INFO, "Changing value of set-enable-xdr of ns %s set %s to %s", ns->name, p_set->name, context);
2841 cf_atomic32_set(&p_set->enable_xdr, AS_SET_ENABLE_XDR_TRUE);
2842 }
2843 else if ((strncmp(context, "false", 5) == 0) || (strncmp(context, "no", 2) == 0)) {
2844 cf_info(AS_INFO, "Changing value of set-enable-xdr of ns %s set %s to %s", ns->name, p_set->name, context);
2845 cf_atomic32_set(&p_set->enable_xdr, AS_SET_ENABLE_XDR_FALSE);
2846 }
2847 else if (strncmp(context, "use-default", 11) == 0) {
2848 cf_info(AS_INFO, "Changing value of set-enable-xdr of ns %s set %s to %s", ns->name, p_set->name, context);
2849 cf_atomic32_set(&p_set->enable_xdr, AS_SET_ENABLE_XDR_DEFAULT);
2850 }
2851 else {
2852 goto Error;
2853 }
2854 }
2855 else if (0 == as_info_parameter_get(params, "set-disable-eviction", context, &context_len)) {
2856 if ((strncmp(context, "true", 4) == 0) || (strncmp(context, "yes", 3) == 0)) {
2857 cf_info(AS_INFO, "Changing value of set-disable-eviction of ns %s set %s to %s", ns->name, p_set->name, context);
2858 DISABLE_SET_EVICTION(p_set, true);
2859 }
2860 else if ((strncmp(context, "false", 5) == 0) || (strncmp(context, "no", 2) == 0)) {
2861 cf_info(AS_INFO, "Changing value of set-disable-eviction of ns %s set %s to %s", ns->name, p_set->name, context);
2862 DISABLE_SET_EVICTION(p_set, false);
2863 }
2864 else {
2865 goto Error;
2866 }
2867 }
2868 else if (0 == as_info_parameter_get(params, "set-stop-writes-count", context, &context_len)) {
2869 uint64_t val = atoll(context);
2870 cf_info(AS_INFO, "Changing value of set-stop-writes-count of ns %s set %s to %lu", ns->name, p_set->name, val);
2871 cf_atomic64_set(&p_set->stop_writes_count, val);
2872 }
2873 else {
2874 goto Error;
2875 }
2876 }
2877 else if (0 == as_info_parameter_get(params, "memory-size", context, &context_len)) {
2878 uint64_t val;
2879
2880 if (0 != cf_str_atoi_u64(context, &val)) {
2881 goto Error;
2882 }
2883 cf_debug(AS_INFO, "memory-size = %"PRIu64"", val);
2884 if (val > ns->memory_size)
2885 ns->memory_size = val;
2886 if (val < (ns->memory_size / 2L)) { // protect so someone does not reduce memory to below 1/2 current value
2887 goto Error;
2888 }
2889 cf_info(AS_INFO, "Changing value of memory-size of ns %s from %"PRIu64" to %"PRIu64, ns->name, ns->memory_size, val);
2890 ns->memory_size = val;
2891 }
2892 else if (0 == as_info_parameter_get(params, "high-water-disk-pct", context, &context_len)) {
2893 if (0 != cf_str_atoi(context, &val) || val < 0 || val > 100) {
2894 goto Error;
2895 }
2896 cf_info(AS_INFO, "Changing value of high-water-disk-pct of ns %s from %u to %d ", ns->name, ns->hwm_disk_pct, val);
2897 ns->hwm_disk_pct = (uint32_t)val;
2898 }
2899 else if (0 == as_info_parameter_get(params, "high-water-memory-pct", context, &context_len)) {
2900 if (0 != cf_str_atoi(context, &val) || val < 0 || val > 100) {
2901 goto Error;
2902 }
2903 cf_info(AS_INFO, "Changing value of high-water-memory-pct memory of ns %s from %u to %d ", ns->name, ns->hwm_memory_pct, val);
2904 ns->hwm_memory_pct = (uint32_t)val;
2905 }
2906 else if (0 == as_info_parameter_get(params, "evict-tenths-pct", context, &context_len)) {
2907 cf_info(AS_INFO, "Changing value of evict-tenths-pct memory of ns %s from %d to %d ", ns->name, ns->evict_tenths_pct, atoi(context));
2908 ns->evict_tenths_pct = atoi(context);
2909 }
2910 else if (0 == as_info_parameter_get(params, "evict-hist-buckets", context, &context_len)) {
2911 if (0 != cf_str_atoi(context, &val) || val < 100 || val > 10000000) {
2912 goto Error;
2913 }
2914 cf_info(AS_INFO, "Changing value of evict-hist-buckets of ns %s from %u to %d ", ns->name, ns->evict_hist_buckets, val);
2915 ns->evict_hist_buckets = (uint32_t)val;
2916 }
2917 else if (0 == as_info_parameter_get(params, "background-scan-max-rps", context, &context_len)) {
2918 if (0 != cf_str_atoi(context, &val) || val < 1 || val > 1000000) {
2919 goto Error;
2920 }
2921 cf_info(AS_INFO, "Changing value of background-scan-max-rps of ns %s from %u to %d ", ns->name, ns->background_scan_max_rps, val);
2922 ns->background_scan_max_rps = (uint32_t)val;
2923 }
2924 else if (0 == as_info_parameter_get(params, "single-scan-threads", context, &context_len)) {
2925 if (0 != cf_str_atoi(context, &val) || val < 1 || val > 128) {
2926 goto Error;
2927 }
2928 cf_info(AS_INFO, "Changing value of single-scan-threads of ns %s from %u to %d ", ns->name, ns->n_single_scan_threads, val);
2929 ns->n_single_scan_threads = (uint32_t)val;
2930 }
2931 else if (0 == as_info_parameter_get(params, "stop-writes-pct", context, &context_len)) {
2932 if (0 != cf_str_atoi(context, &val) || val < 0 || val > 100) {
2933 goto Error;
2934 }
2935 cf_info(AS_INFO, "Changing value of stop-writes-pct memory of ns %s from %u to %d ", ns->name, ns->stop_writes_pct, val);
2936 ns->stop_writes_pct = (uint32_t)val;
2937 }
2938 else if (0 == as_info_parameter_get(params, "default-ttl", context, &context_len)) {
2939 uint32_t val;
2940 if (cf_str_atoi_seconds(context, &val) != 0) {
2941 cf_warning(AS_INFO, "default-ttl must be an unsigned number with time unit (s, m, h, or d)");
2942 goto Error;
2943 }
2944 if (val > MAX_ALLOWED_TTL) {
2945 cf_warning(AS_INFO, "default-ttl must be <= %u seconds", MAX_ALLOWED_TTL);
2946 goto Error;
2947 }
2948 cf_info(AS_INFO, "Changing value of default-ttl memory of ns %s from %u to %u", ns->name, ns->default_ttl, val);
2949 ns->default_ttl = val;
2950 }
2951 else if (0 == as_info_parameter_get(params, "migrate-order", context, &context_len)) {
2952 if (0 != cf_str_atoi(context, &val) || val < 1 || val > 10) {
2953 goto Error;
2954 }
2955 cf_info(AS_INFO, "Changing value of migrate-order of ns %s from %u to %d", ns->name, ns->migrate_order, val);
2956 ns->migrate_order = (uint32_t)val;
2957 }
2958 else if (0 == as_info_parameter_get(params, "migrate-retransmit-ms", context, &context_len)) {
2959 if (0 != cf_str_atoi(context, &val)) {
2960 goto Error;
2961 }
2962 cf_info(AS_INFO, "Changing value of migrate-retransmit-ms of ns %s from %u to %d", ns->name, ns->migrate_retransmit_ms, val);
2963 ns->migrate_retransmit_ms = (uint32_t)val;
2964 }
2965 else if (0 == as_info_parameter_get(params, "migrate-sleep", context, &context_len)) {
2966 if (0 != cf_str_atoi(context, &val)) {
2967 goto Error;
2968 }
2969 cf_info(AS_INFO, "Changing value of migrate-sleep of ns %s from %u to %d", ns->name, ns->migrate_sleep, val);
2970 ns->migrate_sleep = (uint32_t)val;
2971 }
2972 else if (0 == as_info_parameter_get(params, "nsup-hist-period", context, &context_len)) {
2973 if (0 != cf_str_atoi(context, &val)) {
2974 goto Error;
2975 }
2976 cf_info(AS_INFO, "Changing value of nsup-hist-period of ns %s from %u to %d", ns->name, ns->nsup_hist_period, val);
2977 ns->nsup_hist_period = (uint32_t)val;
2978 }
2979 else if (0 == as_info_parameter_get(params, "nsup-period", context, &context_len)) {
2980 if (0 != cf_str_atoi(context, &val)) {
2981 goto Error;
2982 }
2983 cf_info(AS_INFO, "Changing value of nsup-period of ns %s from %u to %d", ns->name, ns->nsup_period, val);
2984 ns->nsup_period = (uint32_t)val;
2985 }
2986 else if (0 == as_info_parameter_get(params, "nsup-threads", context, &context_len)) {
2987 if (0 != cf_str_atoi(context, &val) || val < 1 || val > 128) {
2988 goto Error;
2989 }
2990 cf_info(AS_INFO, "Changing value of nsup-threads of ns %s from %u to %d", ns->name, ns->n_nsup_threads, val);
2991 ns->n_nsup_threads = (uint32_t)val;
2992 }
2993 else if (0 == as_info_parameter_get(params, "tomb-raider-eligible-age", context, &context_len)) {
2994 if (as_config_error_enterprise_only()) {
2995 cf_warning(AS_INFO, "tomb-raider-eligible-age is enterprise-only");
2996 goto Error;
2997 }
2998 uint32_t val;
2999 if (cf_str_atoi_seconds(context, &val) != 0) {
3000 cf_warning(AS_INFO, "tomb-raider-eligible-age must be an unsigned number with time unit (s, m, h, or d)");
3001 goto Error;
3002 }
3003 cf_info(AS_INFO, "Changing value of tomb-raider-eligible-age of ns %s from %u to %u", ns->name, ns->tomb_raider_eligible_age, val);
3004 ns->tomb_raider_eligible_age = val;
3005 }
3006 else if (0 == as_info_parameter_get(params, "tomb-raider-period", context, &context_len)) {
3007 if (as_config_error_enterprise_only()) {
3008 cf_warning(AS_INFO, "tomb-raider-period is enterprise-only");
3009 goto Error;
3010 }
3011 uint32_t val;
3012 if (cf_str_atoi_seconds(context, &val) != 0) {
3013 cf_warning(AS_INFO, "tomb-raider-period must be an unsigned number with time unit (s, m, h, or d)");
3014 goto Error;
3015 }
3016 cf_info(AS_INFO, "Changing value of tomb-raider-period of ns %s from %u to %u", ns->name, ns->tomb_raider_period, val);
3017 ns->tomb_raider_period = val;
3018 }
3019 else if (0 == as_info_parameter_get(params, "tomb-raider-sleep", context, &context_len)) {
3020 if (as_config_error_enterprise_only()) {
3021 cf_warning(AS_INFO, "tomb-raider-sleep is enterprise-only");
3022 goto Error;
3023 }
3024 if (0 != cf_str_atoi(context, &val)) {
3025 goto Error;
3026 }
3027 cf_info(AS_INFO, "Changing value of tomb-raider-sleep of ns %s from %u to %d", ns->name, ns->storage_tomb_raider_sleep, val);
3028 ns->storage_tomb_raider_sleep = (uint32_t)val;
3029 }
3030 else if (0 == as_info_parameter_get(params, "transaction-pending-limit", context, &context_len)) {
3031 if (0 != cf_str_atoi(context, &val)) {
3032 goto Error;
3033 }
3034 cf_info(AS_INFO, "Changing value of transaction-pending-limit of ns %s from %d to %d ", ns->name, ns->transaction_pending_limit, val);
3035 ns->transaction_pending_limit = val;
3036 }
3037 else if (0 == as_info_parameter_get(params, "truncate-threads", context, &context_len)) {
3038 if (0 != cf_str_atoi(context, &val)) {
3039 goto Error;
3040 }
3041 if (val > MAX_TRUNCATE_THREADS || val < 1) {
3042 cf_warning(AS_INFO, "truncate-threads %d must be >= 1 and <= %u", val, MAX_TRUNCATE_THREADS);
3043 goto Error;
3044 }
3045 cf_info(AS_INFO, "Changing value of truncate-threads of ns %s from %u to %d ", ns->name, ns->n_truncate_threads, val);
3046 ns->n_truncate_threads = (uint32_t)val;
3047 }
3048 else if (0 == as_info_parameter_get(params, "rack-id", context, &context_len)) {
3049 if (as_config_error_enterprise_only()) {
3050 cf_warning(AS_INFO, "rack-id is enterprise-only");
3051 goto Error;
3052 }
3053 if (0 != cf_str_atoi(context, &val)) {
3054 goto Error;
3055 }
3056 if ((uint32_t)val > MAX_RACK_ID) {
3057 cf_warning(AS_INFO, "rack-id %d must be >= 0 and <= %u", val, MAX_RACK_ID);
3058 goto Error;
3059 }
3060 cf_info(AS_INFO, "Changing value of rack-id of ns %s from %u to %d", ns->name, ns->rack_id, val);
3061 ns->rack_id = (uint32_t)val;
3062 }
3063 else if (0 == as_info_parameter_get(params, "conflict-resolution-policy", context, &context_len)) {
3064 if (ns->cp) {
3065 cf_warning(AS_INFO, "{%s} 'conflict-resolution-policy' is not applicable with 'strong-consistency'", ns->name);
3066 goto Error;
3067 }
3068 if (strncmp(context, "generation", 10) == 0) {
3069 cf_info(AS_INFO, "Changing value of conflict-resolution-policy of ns %s from %d to %s", ns->name, ns->conflict_resolution_policy, context);
3070 ns->conflict_resolution_policy = AS_NAMESPACE_CONFLICT_RESOLUTION_POLICY_GENERATION;
3071 }
3072 else if (strncmp(context, "last-update-time", 16) == 0) {
3073 cf_info(AS_INFO, "Changing value of conflict-resolution-policy of ns %s from %d to %s", ns->name, ns->conflict_resolution_policy, context);
3074 ns->conflict_resolution_policy = AS_NAMESPACE_CONFLICT_RESOLUTION_POLICY_LAST_UPDATE_TIME;
3075 }
3076 else {
3077 goto Error;
3078 }
3079 }
3080 else if (0 == as_info_parameter_get(params, "mounts-high-water-pct", context, &context_len)) {
3081 if (! as_namespace_index_persisted(ns)) {
3082 cf_warning(AS_INFO, "mounts-high-water-pct is not relevant for this index-type");
3083 goto Error;
3084 }
3085
3086 if (0 != cf_str_atoi(context, &val) || val < 0 || val > 100) {
3087 goto Error;
3088 }
3089
3090 cf_info(AS_INFO, "Changing value of mounts-high-water-pct of ns %s from %u to %d ", ns->name, ns->mounts_hwm_pct, val);
3091 ns->mounts_hwm_pct = (uint32_t)val;
3092 }
3093 else if (0 == as_info_parameter_get(params, "mounts-size-limit", context, &context_len)) {
3094 if (! as_namespace_index_persisted(ns)) {
3095 cf_warning(AS_INFO, "mounts-size-limit is not relevant for this index-type");
3096 goto Error;
3097 }
3098
3099 uint64_t val;
3100 uint64_t min = (ns->xmem_type == CF_XMEM_TYPE_FLASH ? 4 : 1) * 1024UL * 1024UL *1024UL;
3101
3102 if (0 != cf_str_atoi_u64(context, &val) || val < min) {
3103 goto Error;
3104 }
3105
3106 cf_info(AS_INFO, "Changing value of mounts-size-limit of ns %s from %"PRIu64" to %"PRIu64, ns->name, ns->mounts_size_limit, val);
3107 ns->mounts_size_limit = val;
3108 }
3109 else if (0 == as_info_parameter_get(params, "compression", context, &context_len)) {
3110 if (as_config_error_enterprise_only()) {
3111 cf_warning(AS_INFO, "compression is enterprise-only");
3112 goto Error;
3113 }
3114 if (as_config_error_enterprise_feature_only("compression")) {
3115 cf_warning(AS_INFO, "{%s} feature key does not allow compression", ns->name);
3116 goto Error;
3117 }
3118 const char* orig = NS_COMPRESSION();
3119 if (strcmp(context, "none") == 0) {
3120 ns->storage_compression = AS_COMPRESSION_NONE;
3121 }
3122 else if (strcmp(context, "lz4") == 0) {
3123 ns->storage_compression = AS_COMPRESSION_LZ4;
3124 }
3125 else if (strcmp(context, "snappy") == 0) {
3126 ns->storage_compression = AS_COMPRESSION_SNAPPY;
3127 }
3128 else if (strcmp(context, "zstd") == 0) {
3129 ns->storage_compression = AS_COMPRESSION_ZSTD;
3130 }
3131 else {
3132 goto Error;
3133 }
3134 cf_info(AS_INFO, "Changing value of compression of ns %s from %s to %s", ns->name, orig, context);
3135 }
3136 else if (0 == as_info_parameter_get(params, "compression-level", context, &context_len)) {
3137 if (as_config_error_enterprise_only()) {
3138 cf_warning(AS_INFO, "compression-level is enterprise-only");
3139 goto Error;
3140 }
3141 if (0 != cf_str_atoi(context, &val) || val < 1 || val > 9) {
3142 goto Error;
3143 }
3144 cf_info(AS_INFO, "Changing value of compression-level of ns %s from %u to %d", ns->name, ns->storage_compression_level, val);
3145 ns->storage_compression_level = (uint32_t)val;
3146 }
3147 else if (0 == as_info_parameter_get(params, "defrag-lwm-pct", context, &context_len)) {
3148 if (0 != cf_str_atoi(context, &val)) {
3149 goto Error;
3150 }
3151 cf_info(AS_INFO, "Changing value of defrag-lwm-pct of ns %s from %d to %d ", ns->name, ns->storage_defrag_lwm_pct, val);
3152
3153 uint32_t old_val = ns->storage_defrag_lwm_pct;
3154
3155 ns->storage_defrag_lwm_pct = val;
3156 ns->defrag_lwm_size = (ns->storage_write_block_size * ns->storage_defrag_lwm_pct) / 100;
3157
3158 if (ns->storage_defrag_lwm_pct > old_val) {
3159 as_storage_defrag_sweep(ns);
3160 }
3161 }
3162 else if (0 == as_info_parameter_get(params, "defrag-queue-min", context, &context_len)) {
3163 if (0 != cf_str_atoi(context, &val)) {
3164 goto Error;
3165 }
3166 cf_info(AS_INFO, "Changing value of defrag-queue-min of ns %s from %u to %d", ns->name, ns->storage_defrag_queue_min, val);
3167 ns->storage_defrag_queue_min = (uint32_t)val;
3168 }
3169 else if (0 == as_info_parameter_get(params, "defrag-sleep", context, &context_len)) {
3170 if (0 != cf_str_atoi(context, &val)) {
3171 goto Error;
3172 }
3173 cf_info(AS_INFO, "Changing value of defrag-sleep of ns %s from %u to %d", ns->name, ns->storage_defrag_sleep, val);
3174 ns->storage_defrag_sleep = (uint32_t)val;
3175 }
3176 else if (0 == as_info_parameter_get(params, "flush-max-ms", context, &context_len)) {
3177 if (0 != cf_str_atoi(context, &val)) {
3178 goto Error;
3179 }
3180 cf_info(AS_INFO, "Changing value of flush-max-ms of ns %s from %lu to %d", ns->name, ns->storage_flush_max_us / 1000, val);
3181 ns->storage_flush_max_us = (uint64_t)val * 1000;
3182 }
3183 else if (0 == as_info_parameter_get(params, "enable-xdr", context, &context_len)) {
3184 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3185 cf_info(AS_INFO, "Changing value of enable-xdr of ns %s from %s to %s", ns->name, bool_val[ns->enable_xdr], context);
3186 ns->enable_xdr = true;
3187 }
3188 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3189 cf_info(AS_INFO, "Changing value of enable-xdr of ns %s from %s to %s", ns->name, bool_val[ns->enable_xdr], context);
3190 ns->enable_xdr = false;
3191 }
3192 else {
3193 goto Error;
3194 }
3195 }
3196 else if (0 == as_info_parameter_get(params, "sets-enable-xdr", context, &context_len)) {
3197 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3198 cf_info(AS_INFO, "Changing value of sets-enable-xdr of ns %s from %s to %s", ns->name, bool_val[ns->sets_enable_xdr], context);
3199 ns->sets_enable_xdr = true;
3200 }
3201 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3202 cf_info(AS_INFO, "Changing value of sets-enable-xdr of ns %s from %s to %s", ns->name, bool_val[ns->sets_enable_xdr], context);
3203 ns->sets_enable_xdr = false;
3204 }
3205 else {
3206 goto Error;
3207 }
3208 }
3209 else if (0 == as_info_parameter_get(params, "ns-forward-xdr-writes", context, &context_len)) {
3210 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3211 cf_info(AS_INFO, "Changing value of ns-forward-xdr-writes of ns %s from %s to %s", ns->name, bool_val[ns->ns_forward_xdr_writes], context);
3212 ns->ns_forward_xdr_writes = true;
3213 }
3214 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3215 cf_info(AS_INFO, "Changing value of ns-forward-xdr-writes of ns %s from %s to %s", ns->name, bool_val[ns->ns_forward_xdr_writes], context);
3216 ns->ns_forward_xdr_writes = false;
3217 }
3218 else {
3219 goto Error;
3220 }
3221 }
3222 else if (0 == as_info_parameter_get(params, "allow-nonxdr-writes", context, &context_len)) {
3223 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3224 cf_info(AS_INFO, "Changing value of allow-nonxdr-writes of ns %s from %s to %s", ns->name, bool_val[ns->ns_allow_nonxdr_writes], context);
3225 ns->ns_allow_nonxdr_writes = true;
3226 }
3227 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3228 cf_info(AS_INFO, "Changing value of allow-nonxdr-writes of ns %s from %s to %s", ns->name, bool_val[ns->ns_allow_nonxdr_writes], context);
3229 ns->ns_allow_nonxdr_writes = false;
3230 }
3231 else {
3232 goto Error;
3233 }
3234 }
3235 else if (0 == as_info_parameter_get(params, "allow-xdr-writes", context, &context_len)) {
3236 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3237 cf_info(AS_INFO, "Changing value of allow-xdr-writes of ns %s from %s to %s", ns->name, bool_val[ns->ns_allow_xdr_writes], context);
3238 ns->ns_allow_xdr_writes = true;
3239 }
3240 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3241 cf_info(AS_INFO, "Changing value of allow-xdr-writes of ns %s from %s to %s", ns->name, bool_val[ns->ns_allow_xdr_writes], context);
3242 ns->ns_allow_xdr_writes = false;
3243 }
3244 else {
3245 goto Error;
3246 }
3247 }
3248 else if (0 == as_info_parameter_get(params, "strong-consistency-allow-expunge", context, &context_len)) {
3249 if (! ns->cp) {
3250 cf_warning(AS_INFO, "{%s} 'strong-consistency-allow-expunge' is only applicable with 'strong-consistency'", ns->name);
3251 goto Error;
3252 }
3253 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3254 cf_info(AS_INFO, "Changing value of strong-consistency-allow-expunge of ns %s from %s to %s", ns->name, bool_val[ns->cp_allow_drops], context);
3255 ns->cp_allow_drops = true;
3256 }
3257 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3258 cf_info(AS_INFO, "Changing value of strong-consistency-allow-expunge of ns %s from %s to %s", ns->name, bool_val[ns->cp_allow_drops], context);
3259 ns->cp_allow_drops = false;
3260 }
3261 else {
3262 goto Error;
3263 }
3264 }
3265 else if (0 == as_info_parameter_get(params, "disable-write-dup-res", context, &context_len)) {
3266 if (ns->cp) {
3267 cf_warning(AS_INFO, "{%s} 'disable-write-dup-res' is not applicable with 'strong-consistency'", ns->name);
3268 goto Error;
3269 }
3270 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3271 cf_info(AS_INFO, "Changing value of disable-write-dup-res of ns %s from %s to %s", ns->name, bool_val[ns->write_dup_res_disabled], context);
3272 ns->write_dup_res_disabled = true;
3273 }
3274 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3275 cf_info(AS_INFO, "Changing value of disable-write-dup-res of ns %s from %s to %s", ns->name, bool_val[ns->write_dup_res_disabled], context);
3276 ns->write_dup_res_disabled = false;
3277 }
3278 else {
3279 goto Error;
3280 }
3281 }
3282 else if (0 == as_info_parameter_get(params, "disallow-null-setname", context, &context_len)) {
3283 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3284 cf_info(AS_INFO, "Changing value of disallow-null-setname of ns %s from %s to %s", ns->name, bool_val[ns->disallow_null_setname], context);
3285 ns->disallow_null_setname = true;
3286 }
3287 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3288 cf_info(AS_INFO, "Changing value of disallow-null-setname of ns %s from %s to %s", ns->name, bool_val[ns->disallow_null_setname], context);
3289 ns->disallow_null_setname = false;
3290 }
3291 else {
3292 goto Error;
3293 }
3294 }
3295 else if (0 == as_info_parameter_get(params, "enable-benchmarks-batch-sub", context, &context_len)) {
3296 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3297 cf_info(AS_INFO, "Changing value of enable-benchmarks-batch-sub of ns %s from %s to %s", ns->name, bool_val[ns->batch_sub_benchmarks_enabled], context);
3298 ns->batch_sub_benchmarks_enabled = true;
3299 }
3300 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3301 cf_info(AS_INFO, "Changing value of enable-benchmarks-batch-sub of ns %s from %s to %s", ns->name, bool_val[ns->batch_sub_benchmarks_enabled], context);
3302 ns->batch_sub_benchmarks_enabled = false;
3303 histogram_clear(ns->batch_sub_start_hist);
3304 histogram_clear(ns->batch_sub_restart_hist);
3305 histogram_clear(ns->batch_sub_dup_res_hist);
3306 histogram_clear(ns->batch_sub_repl_ping_hist);
3307 histogram_clear(ns->batch_sub_read_local_hist);
3308 histogram_clear(ns->batch_sub_response_hist);
3309 }
3310 else {
3311 goto Error;
3312 }
3313 }
3314 else if (0 == as_info_parameter_get(params, "enable-benchmarks-ops-sub", context, &context_len)) {
3315 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3316 cf_info(AS_INFO, "Changing value of enable-benchmarks-ops-sub of ns %s from %s to %s", ns->name, bool_val[ns->ops_sub_benchmarks_enabled], context);
3317 ns->ops_sub_benchmarks_enabled = true;
3318 }
3319 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3320 cf_info(AS_INFO, "Changing value of enable-benchmarks-ops-sub of ns %s from %s to %s", ns->name, bool_val[ns->ops_sub_benchmarks_enabled], context);
3321 ns->ops_sub_benchmarks_enabled = false;
3322 histogram_clear(ns->ops_sub_start_hist);
3323 histogram_clear(ns->ops_sub_restart_hist);
3324 histogram_clear(ns->ops_sub_dup_res_hist);
3325 histogram_clear(ns->ops_sub_master_hist);
3326 histogram_clear(ns->ops_sub_repl_write_hist);
3327 histogram_clear(ns->ops_sub_response_hist);
3328 }
3329 else {
3330 goto Error;
3331 }
3332 }
3333 else if (0 == as_info_parameter_get(params, "enable-benchmarks-read", context, &context_len)) {
3334 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3335 cf_info(AS_INFO, "Changing value of enable-benchmarks-read of ns %s from %s to %s", ns->name, bool_val[ns->read_benchmarks_enabled], context);
3336 ns->read_benchmarks_enabled = true;
3337 }
3338 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3339 cf_info(AS_INFO, "Changing value of enable-benchmarks-read of ns %s from %s to %s", ns->name, bool_val[ns->read_benchmarks_enabled], context);
3340 ns->read_benchmarks_enabled = false;
3341 histogram_clear(ns->read_start_hist);
3342 histogram_clear(ns->read_restart_hist);
3343 histogram_clear(ns->read_dup_res_hist);
3344 histogram_clear(ns->read_repl_ping_hist);
3345 histogram_clear(ns->read_local_hist);
3346 histogram_clear(ns->read_response_hist);
3347 }
3348 else {
3349 goto Error;
3350 }
3351 }
3352 else if (0 == as_info_parameter_get(params, "enable-benchmarks-storage", context, &context_len)) {
3353 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3354 cf_info(AS_INFO, "Changing value of enable-benchmarks-storage of ns %s from %s to %s", ns->name, bool_val[ns->storage_benchmarks_enabled], context);
3355 ns->storage_benchmarks_enabled = true;
3356 }
3357 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3358 cf_info(AS_INFO, "Changing value of enable-benchmarks-storage of ns %s from %s to %s", ns->name, bool_val[ns->storage_benchmarks_enabled], context);
3359 ns->storage_benchmarks_enabled = false;
3360 as_storage_histogram_clear_all(ns);
3361 }
3362 else {
3363 goto Error;
3364 }
3365 }
3366 else if (0 == as_info_parameter_get(params, "enable-benchmarks-udf", context, &context_len)) {
3367 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3368 cf_info(AS_INFO, "Changing value of enable-benchmarks-udf of ns %s from %s to %s", ns->name, bool_val[ns->udf_benchmarks_enabled], context);
3369 ns->udf_benchmarks_enabled = true;
3370 }
3371 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3372 cf_info(AS_INFO, "Changing value of enable-benchmarks-udf of ns %s from %s to %s", ns->name, bool_val[ns->udf_benchmarks_enabled], context);
3373 ns->udf_benchmarks_enabled = false;
3374 histogram_clear(ns->udf_start_hist);
3375 histogram_clear(ns->udf_restart_hist);
3376 histogram_clear(ns->udf_dup_res_hist);
3377 histogram_clear(ns->udf_master_hist);
3378 histogram_clear(ns->udf_repl_write_hist);
3379 histogram_clear(ns->udf_response_hist);
3380 }
3381 else {
3382 goto Error;
3383 }
3384 }
3385 else if (0 == as_info_parameter_get(params, "enable-benchmarks-udf-sub", context, &context_len)) {
3386 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3387 cf_info(AS_INFO, "Changing value of enable-benchmarks-udf-sub of ns %s from %s to %s", ns->name, bool_val[ns->udf_sub_benchmarks_enabled], context);
3388 ns->udf_sub_benchmarks_enabled = true;
3389 }
3390 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3391 cf_info(AS_INFO, "Changing value of enable-benchmarks-udf-sub of ns %s from %s to %s", ns->name, bool_val[ns->udf_sub_benchmarks_enabled], context);
3392 ns->udf_sub_benchmarks_enabled = false;
3393 histogram_clear(ns->udf_sub_start_hist);
3394 histogram_clear(ns->udf_sub_restart_hist);
3395 histogram_clear(ns->udf_sub_dup_res_hist);
3396 histogram_clear(ns->udf_sub_master_hist);
3397 histogram_clear(ns->udf_sub_repl_write_hist);
3398 histogram_clear(ns->udf_sub_response_hist);
3399 }
3400 else {
3401 goto Error;
3402 }
3403 }
3404 else if (0 == as_info_parameter_get(params, "enable-benchmarks-write", context, &context_len)) {
3405 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3406 cf_info(AS_INFO, "Changing value of enable-benchmarks-write of ns %s from %s to %s", ns->name, bool_val[ns->write_benchmarks_enabled], context);
3407 ns->write_benchmarks_enabled = true;
3408 }
3409 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3410 cf_info(AS_INFO, "Changing value of enable-benchmarks-write of ns %s from %s to %s", ns->name, bool_val[ns->write_benchmarks_enabled], context);
3411 ns->write_benchmarks_enabled = false;
3412 histogram_clear(ns->write_start_hist);
3413 histogram_clear(ns->write_restart_hist);
3414 histogram_clear(ns->write_dup_res_hist);
3415 histogram_clear(ns->write_master_hist);
3416 histogram_clear(ns->write_repl_write_hist);
3417 histogram_clear(ns->write_response_hist);
3418 }
3419 else {
3420 goto Error;
3421 }
3422 }
3423 else if (0 == as_info_parameter_get(params, "enable-hist-proxy", context, &context_len)) {
3424 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3425 cf_info(AS_INFO, "Changing value of enable-hist-proxy of ns %s from %s to %s", ns->name, bool_val[ns->proxy_hist_enabled], context);
3426 ns->proxy_hist_enabled = true;
3427 }
3428 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3429 cf_info(AS_INFO, "Changing value of enable-hist-proxy of ns %s from %s to %s", ns->name, bool_val[ns->proxy_hist_enabled], context);
3430 ns->proxy_hist_enabled = false;
3431 histogram_clear(ns->proxy_hist);
3432 }
3433 else {
3434 goto Error;
3435 }
3436 }
3437 else if (0 == as_info_parameter_get(params, "read-page-cache", context, &context_len)) {
3438 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3439 cf_info(AS_INFO, "Changing value of read-page-cache of ns %s from %s to %s", ns->name, bool_val[ns->storage_read_page_cache], context);
3440 ns->storage_read_page_cache = true;
3441 }
3442 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3443 cf_info(AS_INFO, "Changing value of read-page-cache of ns %s from %s to %s", ns->name, bool_val[ns->storage_read_page_cache], context);
3444 ns->storage_read_page_cache = false;
3445 }
3446 else {
3447 goto Error;
3448 }
3449 }
3450 else if (0 == as_info_parameter_get(params, "max-write-cache", context, &context_len)) {
3451 uint64_t val_u64;
3452
3453 if (0 != cf_str_atoi_u64(context, &val_u64)) {
3454 goto Error;
3455 }
3456 if (val_u64 < (1024 * 1024 * 4)) { // TODO - why enforce this? And here, but not cfg.c?
3457 cf_warning(AS_INFO, "can't set max-write-cache less than 4M");
3458 goto Error;
3459 }
3460 cf_info(AS_INFO, "Changing value of max-write-cache of ns %s from %lu to %lu ", ns->name, ns->storage_max_write_cache, val_u64);
3461 ns->storage_max_write_cache = val_u64;
3462 ns->storage_max_write_q = (int)(ns->storage_max_write_cache / ns->storage_write_block_size);
3463 }
3464 else if (0 == as_info_parameter_get(params, "min-avail-pct", context, &context_len)) {
3465 ns->storage_min_avail_pct = atoi(context);
3466 cf_info(AS_INFO, "Changing value of min-avail-pct of ns %s from %u to %u ", ns->name, ns->storage_min_avail_pct, atoi(context));
3467 }
3468 else if (0 == as_info_parameter_get(params, "post-write-queue", context, &context_len)) {
3469 if (ns->storage_data_in_memory) {
3470 cf_warning(AS_INFO, "ns %s, can't set post-write-queue if data-in-memory", ns->name);
3471 goto Error;
3472 }
3473 if (0 != cf_str_atoi(context, &val)) {
3474 cf_warning(AS_INFO, "ns %s, post-write-queue %s is not a number", ns->name, context);
3475 goto Error;
3476 }
3477 if ((uint32_t)val > (8 * 1024)) {
3478 cf_warning(AS_INFO, "ns %s, post-write-queue %u must be < 8K", ns->name, val);
3479 goto Error;
3480 }
3481 cf_info(AS_INFO, "Changing value of post-write-queue of ns %s from %d to %d ", ns->name, ns->storage_post_write_queue, val);
3482 cf_atomic32_set(&ns->storage_post_write_queue, (uint32_t)val);
3483 }
3484 else if (0 == as_info_parameter_get(params, "read-consistency-level-override", context, &context_len)) {
3485 if (ns->cp) {
3486 cf_warning(AS_INFO, "{%s} 'read-consistency-level-override' is not applicable with 'strong-consistency'", ns->name);
3487 goto Error;
3488 }
3489 char *original_value = NS_READ_CONSISTENCY_LEVEL_NAME();
3490 if (strcmp(context, "all") == 0) {
3491 ns->read_consistency_level = AS_READ_CONSISTENCY_LEVEL_ALL;
3492 }
3493 else if (strcmp(context, "off") == 0) {
3494 ns->read_consistency_level = AS_READ_CONSISTENCY_LEVEL_PROTO;
3495 }
3496 else if (strcmp(context, "one") == 0) {
3497 ns->read_consistency_level = AS_READ_CONSISTENCY_LEVEL_ONE;
3498 }
3499 else {
3500 goto Error;
3501 }
3502 if (strcmp(original_value, context)) {
3503 cf_info(AS_INFO, "Changing value of read-consistency-level-override of ns %s from %s to %s", ns->name, original_value, context);
3504 }
3505 }
3506 else if (0 == as_info_parameter_get(params, "write-commit-level-override", context, &context_len)) {
3507 if (ns->cp) {
3508 cf_warning(AS_INFO, "{%s} 'write-commit-level-override' is not applicable with 'strong-consistency'", ns->name);
3509 goto Error;
3510 }
3511 char *original_value = NS_WRITE_COMMIT_LEVEL_NAME();
3512 if (strcmp(context, "all") == 0) {
3513 ns->write_commit_level = AS_WRITE_COMMIT_LEVEL_ALL;
3514 }
3515 else if (strcmp(context, "master") == 0) {
3516 ns->write_commit_level = AS_WRITE_COMMIT_LEVEL_MASTER;
3517 }
3518 else if (strcmp(context, "off") == 0) {
3519 ns->write_commit_level = AS_WRITE_COMMIT_LEVEL_PROTO;
3520 }
3521 else {
3522 goto Error;
3523 }
3524 if (strcmp(original_value, context)) {
3525 cf_info(AS_INFO, "Changing value of write-commit-level-override of ns %s from %s to %s", ns->name, original_value, context);
3526 }
3527 }
3528 else if (0 == as_info_parameter_get(params, "geo2dsphere-within-min-level", context, &context_len)) {
3529 if (0 != cf_str_atoi(context, &val)) {
3530 cf_warning(AS_INFO, "ns %s, geo2dsphere-within-min-level %s is not a number", ns->name, context);
3531 goto Error;
3532 }
3533 if (val < 0 || val > MAX_REGION_LEVELS) {
3534 cf_warning(AS_INFO, "ns %s, geo2dsphere-within-min-level %d must be between %u and %u",
3535 ns->name, val, 0, MAX_REGION_LEVELS);
3536 goto Error;
3537 }
3538 cf_info(AS_INFO, "Changing value of geo2dsphere-within-min-level of ns %s from %u to %d ",
3539 ns->name, ns->geo2dsphere_within_min_level, val);
3540 ns->geo2dsphere_within_min_level = val;
3541 }
3542 else if (0 == as_info_parameter_get(params, "geo2dsphere-within-max-level", context, &context_len)) {
3543 if (0 != cf_str_atoi(context, &val)) {
3544 cf_warning(AS_INFO, "ns %s, geo2dsphere-within-max-level %s is not a number", ns->name, context);
3545 goto Error;
3546 }
3547 if (val < 0 || val > MAX_REGION_LEVELS) {
3548 cf_warning(AS_INFO, "ns %s, geo2dsphere-within-max-level %d must be between %u and %u",
3549 ns->name, val, 0, MAX_REGION_LEVELS);
3550 goto Error;
3551 }
3552 cf_info(AS_INFO, "Changing value of geo2dsphere-within-max-level of ns %s from %u to %d ",
3553 ns->name, ns->geo2dsphere_within_max_level, val);
3554 ns->geo2dsphere_within_max_level = val;
3555 }
3556 else if (0 == as_info_parameter_get(params, "geo2dsphere-within-max-cells", context, &context_len)) {
3557 if (0 != cf_str_atoi(context, &val)) {
3558 cf_warning(AS_INFO, "ns %s, geo2dsphere-within-max-cells %s is not a number", ns->name, context);
3559 goto Error;
3560 }
3561 if (val < 1 || val > MAX_REGION_CELLS) {
3562 cf_warning(AS_INFO, "ns %s, geo2dsphere-within-max-cells %d must be between %u and %u",
3563 ns->name, val, 1, MAX_REGION_CELLS);
3564 goto Error;
3565 }
3566 cf_info(AS_INFO, "Changing value of geo2dsphere-within-max-cells of ns %s from %u to %d ",
3567 ns->name, ns->geo2dsphere_within_max_cells, val);
3568 ns->geo2dsphere_within_max_cells = val;
3569 }
3570 else if (0 == as_info_parameter_get(params, "prefer-uniform-balance", context, &context_len)) {
3571 if (as_config_error_enterprise_only()) {
3572 cf_warning(AS_INFO, "prefer-uniform-balance is enterprise-only");
3573 goto Error;
3574 }
3575 if (strncmp(context, "true", 4) == 0 || strncmp(context, "yes", 3) == 0) {
3576 cf_info(AS_INFO, "Changing value of prefer-uniform-balance of ns %s from %s to %s", ns->name, bool_val[ns->cfg_prefer_uniform_balance], context);
3577 ns->cfg_prefer_uniform_balance = true;
3578 }
3579 else if (strncmp(context, "false", 5) == 0 || strncmp(context, "no", 2) == 0) {
3580 cf_info(AS_INFO, "Changing value of prefer-uniform-balance of ns %s from %s to %s", ns->name, bool_val[ns->cfg_prefer_uniform_balance], context);
3581 ns->cfg_prefer_uniform_balance = false;
3582 }
3583 else {
3584 goto Error;
3585 }
3586 }
3587 else {
3588 if (as_xdr_set_config_ns(ns->name, params) == false) {
3589 goto Error;
3590 }
3591 }
3592 } // end of namespace stanza
3593 else if (strcmp(context, "security") == 0) {
3594 context_len = sizeof(context);
3595 if (0 == as_info_parameter_get(params, "privilege-refresh-period", context, &context_len)) {
3596 if (0 != cf_str_atoi(context, &val) || val < PRIVILEGE_REFRESH_PERIOD_MIN || val > PRIVILEGE_REFRESH_PERIOD_MAX) {
3597 cf_warning(AS_INFO, "privilege-refresh-period must be an unsigned integer between %u and %u",
3598 PRIVILEGE_REFRESH_PERIOD_MIN, PRIVILEGE_REFRESH_PERIOD_MAX);
3599 goto Error;
3600 }
3601 cf_info(AS_INFO, "Changing value of privilege-refresh-period from %u to %d", g_config.sec_cfg.privilege_refresh_period, val);
3602 g_config.sec_cfg.privilege_refresh_period = (uint32_t)val;
3603 }
3604 else if (0 == as_info_parameter_get(params, "ldap.polling-period", context, &context_len)) {
3605 if (0 != cf_str_atoi(context, &val) || val < LDAP_POLLING_PERIOD_MIN || val > LDAP_POLLING_PERIOD_MAX) {
3606 cf_warning(AS_INFO, "ldap.polling-period must be an unsigned integer between %u and %u",
3607 LDAP_POLLING_PERIOD_MIN, LDAP_POLLING_PERIOD_MAX);
3608 goto Error;
3609 }
3610 cf_info(AS_INFO, "Changing value of ldap.pollling-period from %u to %d", g_config.sec_cfg.ldap_polling_period, val);
3611 g_config.sec_cfg.ldap_polling_period = (uint32_t)val;
3612 }
3613 else if (0 == as_info_parameter_get(params, "ldap.session-ttl", context, &context_len)) {
3614 if (0 != cf_str_atoi(context, &val) || val < LDAP_SESSION_TTL_MIN || val > LDAP_SESSION_TTL_MAX) {
3615 cf_warning(AS_INFO, "ldap.session-ttl must be an unsigned integer between %u and %u",
3616 LDAP_SESSION_TTL_MIN, LDAP_SESSION_TTL_MAX);
3617 goto Error;
3618 }
3619 cf_info(AS_INFO, "Changing value of ldap.session-ttl from %u to %d", g_config.sec_cfg.ldap_session_ttl, val);
3620 g_config.sec_cfg.ldap_session_ttl = (uint32_t)val;
3621 }
3622 else {
3623 goto Error;
3624 }
3625 }
3626 else if (strcmp(context, "xdr") == 0) {
3627 if (as_xdr_set_config(params) == false) {
3628 goto Error;
3629 }
3630 }
3631 else
3632 goto Error;
3633
3634 cf_info(AS_INFO, "config-set command completed: params %s",params);
3635 cf_dyn_buf_append_string(db, "ok");
3636 return(0);
3637
3638Error:
3639 cf_dyn_buf_append_string(db, "error");
3640 return(0);
3641}
3642
3643// Protect all set-config commands from concurrency issues.
3644static cf_mutex g_set_cfg_lock = CF_MUTEX_INIT;
3645
3646int
3647info_command_config_set(char *name, char *params, cf_dyn_buf *db)
3648{
3649 cf_mutex_lock(&g_set_cfg_lock);
3650
3651 int result = info_command_config_set_threadsafe(name, params, db);
3652
3653 cf_mutex_unlock(&g_set_cfg_lock);
3654
3655 return result;
3656}
3657
3658//
3659// log-set:log=id;context=foo;level=bar
3660// ie:
3661// log-set:log=0;context=rw;level=debug
3662
3663
3664int
3665info_command_log_set(char *name, char *params, cf_dyn_buf *db)
3666{
3667 cf_debug(AS_INFO, "log-set command received: params %s", params);
3668
3669 char id_str[50];
3670 int id_str_len = sizeof(id_str);
3671 int id = -1;
3672 bool found_id = true;
3673 cf_fault_sink *s = 0;
3674
3675 if (0 != as_info_parameter_get(params, "id", id_str, &id_str_len)) {
3676 if (0 != as_info_parameter_get(params, "log", id_str, &id_str_len)) {
3677 cf_debug(AS_INFO, "log set command: no log id to be set - doing all");
3678 found_id = false;
3679 }
3680 }
3681 if (found_id == true) {
3682 if (0 != cf_str_atoi(id_str, &id) ) {
3683 cf_info(AS_INFO, "log set command: id must be an integer, is: %s", id_str);
3684 cf_dyn_buf_append_string(db, "error-id-not-integer");
3685 return(0);
3686 }
3687 s = cf_fault_sink_get_id(id);
3688 if (!s) {
3689 cf_info(AS_INFO, "log set command: sink id %d invalid", id);
3690 cf_dyn_buf_append_string(db, "error-bad-id");
3691 return(0);
3692 }
3693 }
3694
3695 // now, loop through all context strings. If we find a known context string,
3696 // do the set
3697 for (int c_id = 0; c_id < CF_FAULT_CONTEXT_UNDEF; c_id++) {
3698
3699 char level_str[50];
3700 int level_str_len = sizeof(level_str);
3701 char *context = cf_fault_context_strings[c_id];
3702 if (0 != as_info_parameter_get(params, context, level_str, &level_str_len)) {
3703 continue;
3704 }
3705 for (uint32_t i = 0; level_str[i]; i++) level_str[i] = toupper(level_str[i]);
3706
3707 if (0 != cf_fault_sink_addcontext(s, context, level_str)) {
3708 cf_info(AS_INFO, "log set command: addcontext failed: context %s level %s", context, level_str);
3709 cf_dyn_buf_append_string(db, "error-invalid-context-or-level");
3710 return(0);
3711 }
3712 }
3713
3714 cf_info(AS_INFO, "log-set command executed: params %s", params);
3715
3716 cf_dyn_buf_append_string(db, "ok");
3717
3718 return(0);
3719}
3720
3721
3722// latency:hist=reads;back=180;duration=60;slice=10;
3723// throughput:hist=reads;back=180;duration=60;slice=10;
3724// hist-track-start:hist=reads;back=43200;slice=30;thresholds=1,4,16,64;
3725// hist-track-stop:hist=reads;
3726//
3727// hist - optional histogram name - if none, command applies to all cf_hist_track objects
3728//
3729// for start command:
3730// back - total time span in seconds over which to cache data
3731// slice - period in seconds at which to cache histogram data
3732// thresholds - comma-separated bucket (ms) values to track, must be powers of 2. e.g:
3733// 1,4,16,64
3734// defaults are:
3735// - config value for back - mandatory, serves as flag for tracking
3736// - config value if it exists for slice, otherwise 10 seconds
3737// - config value if it exists for thresholds, otherwise internal defaults (1,8,64)
3738//
3739// for query commands:
3740// back - start search this many seconds before now, default: minimum to get last slice
3741// using back=0 will get cached data from oldest cached data
3742// duration - seconds (forward) from start to search, default 0: everything to present
3743// slice - intervals (in seconds) to analyze, default 0: everything as one slice
3744//
3745// e.g. query:
3746// latency:hist=reads;back=180;duration=60;slice=10;
3747// output (CF_HIST_TRACK_FMT_PACKED format) is:
3748// requested value latency:hist=reads;back=180;duration=60;slice=10
3749// value is reads:23:26:24-GMT,ops/sec,>1ms,>8ms,>64ms;23:26:34,30618.2,0.05,0.00,0.00;
3750// 23:26:44,31942.1,0.02,0.00,0.00;23:26:54,30966.9,0.01,0.00,0.00;23:27:04,30380.4,0.01,0.00,0.00;
3751// 23:27:14,37833.6,0.01,0.00,0.00;23:27:24,38502.7,0.01,0.00,0.00;23:27:34,39191.4,0.02,0.00,0.00;
3752//
3753// explanation:
3754// 23:26:24-GMT - timestamp of histogram starting first slice
3755// ops/sec,>1ms,>8ms,>64ms - labels for the columns: throughput, and which thresholds
3756// 23:26:34,30618.2,0.05,0.00,0.00; - timestamp of histogram ending slice, throughput, latencies
3757
3758int
3759info_command_hist_track(char *name, char *params, cf_dyn_buf *db)
3760{
3761 cf_debug(AS_INFO, "hist track %s command received: params %s", name, params);
3762
3763 char value_str[50];
3764 int value_str_len = sizeof(value_str);
3765 cf_hist_track* hist_p = NULL;
3766
3767 if (0 != as_info_parameter_get(params, "hist", value_str, &value_str_len)) {
3768 cf_debug(AS_INFO, "hist track %s command: no histogram specified - doing all", name);
3769 }
3770 else {
3771 if (*value_str == '{') {
3772 char* ns_name = value_str + 1;
3773 char* ns_name_end = strchr(ns_name, '}');
3774 as_namespace* ns = as_namespace_get_bybuf((uint8_t*)ns_name, ns_name_end - ns_name);
3775
3776 if (! ns) {
3777 cf_info(AS_INFO, "hist track %s command: unrecognized histogram: %s", name, value_str);
3778 cf_dyn_buf_append_string(db, "error-bad-hist-name");
3779 return 0;
3780 }
3781
3782 char* hist_name = ns_name_end + 1;
3783
3784 if (*hist_name++ != '-') {
3785 cf_info(AS_INFO, "hist track %s command: unrecognized histogram: %s", name, value_str);
3786 cf_dyn_buf_append_string(db, "error-bad-hist-name");
3787 return 0;
3788 }
3789
3790 if (0 == strcmp(hist_name, "read")) {
3791 hist_p = ns->read_hist;
3792 }
3793 else if (0 == strcmp(hist_name, "write")) {
3794 hist_p = ns->write_hist;
3795 }
3796 else if (0 == strcmp(hist_name, "udf")) {
3797 hist_p = ns->udf_hist;
3798 }
3799 else if (0 == strcmp(hist_name, "query")) {
3800 hist_p = ns->query_hist;
3801 }
3802 else {
3803 cf_info(AS_INFO, "hist track %s command: unrecognized histogram: %s", name, value_str);
3804 cf_dyn_buf_append_string(db, "error-bad-hist-name");
3805 return 0;
3806 }
3807 }
3808 else {
3809 cf_info(AS_INFO, "hist track %s command: unrecognized histogram: %s", name, value_str);
3810 cf_dyn_buf_append_string(db, "error-bad-hist-name");
3811 return 0;
3812 }
3813 }
3814
3815 if (0 == strcmp(name, "hist-track-stop")) {
3816 if (hist_p) {
3817 cf_hist_track_stop(hist_p);
3818 }
3819 else {
3820 for (uint32_t i = 0; i < g_config.n_namespaces; i++) {
3821 as_namespace* ns = g_config.namespaces[i];
3822
3823 cf_hist_track_stop(ns->read_hist);
3824 cf_hist_track_stop(ns->write_hist);
3825 cf_hist_track_stop(ns->udf_hist);
3826 cf_hist_track_stop(ns->query_hist);
3827 }
3828 }
3829
3830 cf_dyn_buf_append_string(db, "ok");
3831
3832 return 0;
3833 }
3834
3835 bool start_cmd = 0 == strcmp(name, "hist-track-start");
3836
3837 // Note - default query params will get the most recent saved slice.
3838 uint32_t back_sec = start_cmd ? g_config.hist_track_back : (g_config.hist_track_slice * 2) - 1;
3839 uint32_t slice_sec = start_cmd ? g_config.hist_track_slice : 0;
3840 int i;
3841
3842 value_str_len = sizeof(value_str);
3843
3844 if (0 == as_info_parameter_get(params, "back", value_str, &value_str_len)) {
3845 if (0 == cf_str_atoi(value_str, &i)) {
3846 back_sec = i >= 0 ? (uint32_t)i : (uint32_t)-i;
3847 }
3848 else {
3849 cf_info(AS_INFO, "hist track %s command: back is not a number, using default", name);
3850 }
3851 }
3852
3853 value_str_len = sizeof(value_str);
3854
3855 if (0 == as_info_parameter_get(params, "slice", value_str, &value_str_len)) {
3856 if (0 == cf_str_atoi(value_str, &i)) {
3857 slice_sec = i >= 0 ? (uint32_t)i : (uint32_t)-i;
3858 }
3859 else {
3860 cf_info(AS_INFO, "hist track %s command: slice is not a number, using default", name);
3861 }
3862 }
3863
3864 if (start_cmd) {
3865 char* thresholds = g_config.hist_track_thresholds;
3866
3867 value_str_len = sizeof(value_str);
3868
3869 if (0 == as_info_parameter_get(params, "thresholds", value_str, &value_str_len)) {
3870 thresholds = value_str;
3871 }
3872
3873 cf_debug(AS_INFO, "hist track start command: back %u, slice %u, thresholds %s",
3874 back_sec, slice_sec, thresholds ? thresholds : "null");
3875
3876 if (hist_p) {
3877 if (cf_hist_track_start(hist_p, back_sec, slice_sec, thresholds)) {
3878 cf_dyn_buf_append_string(db, "ok");
3879 }
3880 else {
3881 cf_dyn_buf_append_string(db, "error-bad-start-params");
3882 }
3883 }
3884 else {
3885 for (uint32_t i = 0; i < g_config.n_namespaces; i++) {
3886 as_namespace* ns = g_config.namespaces[i];
3887
3888 if ( ! (cf_hist_track_start(ns->read_hist, back_sec, slice_sec, thresholds) &&
3889 cf_hist_track_start(ns->write_hist, back_sec, slice_sec, thresholds) &&
3890 cf_hist_track_start(ns->udf_hist, back_sec, slice_sec, thresholds) &&
3891 cf_hist_track_start(ns->query_hist, back_sec, slice_sec, thresholds))) {
3892
3893 cf_dyn_buf_append_string(db, "error-bad-start-params");
3894 return 0;
3895 }
3896 }
3897
3898 cf_dyn_buf_append_string(db, "ok");
3899 }
3900
3901 return 0;
3902 }
3903
3904 // From here on it's latency or throughput...
3905
3906 uint32_t duration_sec = 0;
3907
3908 value_str_len = sizeof(value_str);
3909
3910 if (0 == as_info_parameter_get(params, "duration", value_str, &value_str_len)) {
3911 if (0 == cf_str_atoi(value_str, &i)) {
3912 duration_sec = i >= 0 ? (uint32_t)i : (uint32_t)-i;
3913 }
3914 else {
3915 cf_info(AS_INFO, "hist track %s command: duration is not a number, using default", name);
3916 }
3917 }
3918
3919 bool throughput_only = 0 == strcmp(name, "throughput");
3920
3921 cf_debug(AS_INFO, "hist track %s command: back %u, duration %u, slice %u",
3922 name, back_sec, duration_sec, slice_sec);
3923
3924 if (hist_p) {
3925 cf_hist_track_get_info(hist_p, back_sec, duration_sec, slice_sec, throughput_only, CF_HIST_TRACK_FMT_PACKED, db);
3926 }
3927 else {
3928 for (uint32_t i = 0; i < g_config.n_namespaces; i++) {
3929 as_namespace* ns = g_config.namespaces[i];
3930
3931 cf_hist_track_get_info(ns->read_hist, back_sec, duration_sec, slice_sec, throughput_only, CF_HIST_TRACK_FMT_PACKED, db);
3932 cf_hist_track_get_info(ns->write_hist, back_sec, duration_sec, slice_sec, throughput_only, CF_HIST_TRACK_FMT_PACKED, db);
3933 cf_hist_track_get_info(ns->udf_hist, back_sec, duration_sec, slice_sec, throughput_only, CF_HIST_TRACK_FMT_PACKED, db);
3934 cf_hist_track_get_info(ns->query_hist, back_sec, duration_sec, slice_sec, throughput_only, CF_HIST_TRACK_FMT_PACKED, db);
3935 }
3936 }
3937
3938 cf_dyn_buf_chomp(db);
3939
3940 return 0;
3941}
3942
3943// TODO - separate all these CP-related info commands.
3944
3945// Format is:
3946//
3947// revive:{namespace=<ns-name>}
3948//
3949int
3950info_command_revive(char *name, char *params, cf_dyn_buf *db)
3951{
3952 if (as_info_error_enterprise_only()) {
3953 cf_dyn_buf_append_string(db, "ERROR::enterprise-only");
3954 return 0;
3955 }
3956
3957 char ns_name[AS_ID_NAMESPACE_SZ] = { 0 };
3958 int ns_name_len = (int)sizeof(ns_name);
3959 int rv = as_info_parameter_get(params, "namespace", ns_name, &ns_name_len);
3960
3961 if (rv == -2) {
3962 cf_warning(AS_INFO, "revive: namespace parameter value too long");
3963 cf_dyn_buf_append_string(db, "ERROR::bad-namespace");
3964 return 0;
3965 }
3966
3967 if (rv == 0) {
3968 as_namespace *ns = as_namespace_get_byname(ns_name);
3969
3970 if (! ns) {
3971 cf_warning(AS_INFO, "revive: unknown namespace %s", ns_name);
3972 cf_dyn_buf_append_string(db, "ERROR::unknown-namespace");
3973 return 0;
3974 }
3975
3976 if (! as_partition_balance_revive(ns)) {
3977 cf_warning(AS_INFO, "revive: failed - recluster in progress");
3978 cf_dyn_buf_append_string(db, "ERROR::failed-revive");
3979 return 0;
3980 }
3981
3982 cf_info(AS_INFO, "revive: complete - issue 'recluster:' command");
3983 cf_dyn_buf_append_string(db, "ok");
3984 return 0;
3985 }
3986
3987 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
3988 as_namespace *ns = g_config.namespaces[ns_ix];
3989
3990 if (! as_partition_balance_revive(ns)) {
3991 cf_warning(AS_INFO, "revive: failed - recluster in progress");
3992 cf_dyn_buf_append_string(db, "ERROR::failed-revive");
3993 return 0;
3994 }
3995 }
3996
3997 cf_info(AS_INFO, "revive: complete - issue 'recluster:' command");
3998 cf_dyn_buf_append_string(db, "ok");
3999 return 0;
4000}
4001
4002void
4003namespace_roster_info(as_namespace *ns, cf_dyn_buf *db)
4004{
4005 as_exchange_info_lock();
4006
4007 cf_dyn_buf_append_string(db, "roster=");
4008
4009 if (ns->roster_count == 0) {
4010 cf_dyn_buf_append_string(db, "null");
4011 }
4012 else {
4013 for (uint32_t n = 0; n < ns->roster_count; n++) {
4014 cf_dyn_buf_append_uint64_x(db, ns->roster[n]);
4015
4016 if (ns->roster_rack_ids[n] != 0) {
4017 cf_dyn_buf_append_char(db, ROSTER_ID_PAIR_SEPARATOR);
4018 cf_dyn_buf_append_uint32(db, ns->roster_rack_ids[n]);
4019 }
4020
4021 cf_dyn_buf_append_char(db, ',');
4022 }
4023
4024 cf_dyn_buf_chomp(db);
4025 }
4026
4027 cf_dyn_buf_append_char(db, ':');
4028
4029 cf_dyn_buf_append_string(db, "pending_roster=");
4030
4031 if (ns->smd_roster_count == 0) {
4032 cf_dyn_buf_append_string(db, "null");
4033 }
4034 else {
4035 for (uint32_t n = 0; n < ns->smd_roster_count; n++) {
4036 cf_dyn_buf_append_uint64_x(db, ns->smd_roster[n]);
4037
4038 if (ns->smd_roster_rack_ids[n] != 0) {
4039 cf_dyn_buf_append_char(db, ROSTER_ID_PAIR_SEPARATOR);
4040 cf_dyn_buf_append_uint32(db, ns->smd_roster_rack_ids[n]);
4041 }
4042
4043 cf_dyn_buf_append_char(db, ',');
4044 }
4045
4046 cf_dyn_buf_chomp(db);
4047 }
4048
4049 cf_dyn_buf_append_char(db, ':');
4050
4051 cf_dyn_buf_append_string(db, "observed_nodes=");
4052
4053 if (ns->observed_cluster_size == 0) {
4054 cf_dyn_buf_append_string(db, "null");
4055 }
4056 else {
4057 for (uint32_t n = 0; n < ns->observed_cluster_size; n++) {
4058 cf_dyn_buf_append_uint64_x(db, ns->observed_succession[n]);
4059
4060 if (ns->rack_ids[n] != 0) {
4061 cf_dyn_buf_append_char(db, ROSTER_ID_PAIR_SEPARATOR);
4062 cf_dyn_buf_append_uint32(db, ns->rack_ids[n]);
4063 }
4064
4065 cf_dyn_buf_append_char(db, ',');
4066 }
4067
4068 cf_dyn_buf_chomp(db);
4069 }
4070
4071 as_exchange_info_unlock();
4072}
4073
4074// Format is:
4075//
4076// roster:{namespace=<ns-name>}
4077//
4078int
4079info_command_roster(char *name, char *params, cf_dyn_buf *db)
4080{
4081 if (as_info_error_enterprise_only()) {
4082 cf_dyn_buf_append_string(db, "ERROR::enterprise-only");
4083 return 0;
4084 }
4085
4086 char ns_name[AS_ID_NAMESPACE_SZ] = { 0 };
4087 int ns_name_len = (int)sizeof(ns_name);
4088 int rv = as_info_parameter_get(params, "namespace", ns_name, &ns_name_len);
4089
4090 if (rv == -2) {
4091 cf_warning(AS_INFO, "namespace parameter value too long");
4092 cf_dyn_buf_append_string(db, "ERROR::bad-namespace");
4093 return 0;
4094 }
4095
4096 if (rv == 0) {
4097 as_namespace *ns = as_namespace_get_byname(ns_name);
4098
4099 if (! ns) {
4100 cf_warning(AS_INFO, "unknown namespace %s", ns_name);
4101 cf_dyn_buf_append_string(db, "ERROR::unknown-namespace");
4102 return 0;
4103 }
4104
4105 namespace_roster_info(ns, db);
4106
4107 return 0;
4108 }
4109
4110 for (uint32_t ns_ix = 0; ns_ix < g_config.n_namespaces; ns_ix++) {
4111 as_namespace *ns = g_config.namespaces[ns_ix];
4112
4113 cf_dyn_buf_append_string(db, "ns=");
4114 cf_dyn_buf_append_string(db, ns->name);
4115 cf_dyn_buf_append_char(db, ':');
4116
4117 namespace_roster_info(ns, db);
4118
4119 cf_dyn_buf_append_char(db, ';');
4120 }
4121
4122 cf_dyn_buf_chomp(db);
4123
4124 return 0;
4125}
4126
4127// Format is:
4128//
4129// roster-set:namespace=<ns-name>;nodes=<nodes-string>
4130//
4131// where <nodes-string> is comma-separated list of node-id:rack-id pairs, and
4132// the :rack-id may be absent, indicating a rack-id of 0.
4133//
4134int
4135info_command_roster_set(char *name, char *params, cf_dyn_buf *db)
4136{
4137 if (as_info_error_enterprise_only()) {
4138 cf_dyn_buf_append_string(db, "ERROR::enterprise-only");
4139 return 0;
4140 }
4141
4142 // Get the namespace name.
4143
4144 char ns_name[AS_ID_NAMESPACE_SZ];
4145 int ns_name_len = (int)sizeof(ns_name);
4146 int ns_rv = as_info_parameter_get(params, "namespace", ns_name, &ns_name_len);
4147
4148 if (ns_rv != 0 || ns_name_len == 0) {
4149 cf_warning(AS_INFO, "roster-set command: missing or invalid namespace name in command");
4150 cf_dyn_buf_append_string(db, "ERROR::namespace-name");
4151 return 0;
4152 }
4153
4154 // Get the nodes list.
4155
4156 char nodes[AS_CLUSTER_SZ * ROSTER_STRING_ELE_LEN];
4157 int nodes_len = (int)sizeof(nodes);
4158 int nodes_rv = as_info_parameter_get(params, "nodes", nodes, &nodes_len);
4159
4160 if (nodes_rv == -2 || (nodes_rv == 0 && nodes_len == 0)) {
4161 cf_warning(AS_INFO, "roster-set command: invalid nodes in command");
4162 cf_dyn_buf_append_string(db, "ERROR::nodes");
4163 return 0;
4164 }
4165
4166 // Issue the roster-set command.
4167
4168 bool ok = as_roster_set_nodes_cmd(ns_name, nodes);
4169
4170 cf_dyn_buf_append_string(db, ok ? "ok" : "ERROR::roster-set");
4171
4172 return 0;
4173}
4174
4175// Format is:
4176//
4177// truncate-namespace:namespace=<ns-name>[;lut=<UTC-nanosec-string>]
4178//
4179// ... where no lut value means use this server's current time.
4180//
4181int
4182info_command_truncate_namespace(char *name, char *params, cf_dyn_buf *db)
4183{
4184 // Get the namespace name.
4185
4186 char ns_name[AS_ID_NAMESPACE_SZ];
4187 int ns_name_len = (int)sizeof(ns_name);
4188 int ns_rv = as_info_parameter_get(params, "namespace", ns_name, &ns_name_len);
4189
4190 if (ns_rv != 0 || ns_name_len == 0) {
4191 cf_warning(AS_INFO, "truncate-namespace command: missing or invalid namespace name in command");
4192 cf_dyn_buf_append_string(db, "ERROR::namespace-name");
4193 return 0;
4194 }
4195
4196 // Check for a set-name, for safety. (Did user intend 'truncate'?)
4197
4198 char set_name[1]; // just checking for existence
4199 int set_name_len = (int)sizeof(set_name);
4200 int set_rv = as_info_parameter_get(params, "set", set_name, &set_name_len);
4201
4202 if (set_rv != -1) {
4203 cf_warning(AS_INFO, "truncate-namespace command: unexpected set name in command");
4204 cf_dyn_buf_append_string(db, "ERROR::unexpected-set-name");
4205 return 0;
4206 }
4207
4208 // Get the threshold last-update-time, if there is one.
4209
4210 char lut_str[24]; // allow decimal, hex or octal in C constant format
4211 int lut_str_len = (int)sizeof(lut_str);
4212 int lut_rv = as_info_parameter_get(params, "lut", lut_str, &lut_str_len);
4213
4214 if (lut_rv == -2 || (lut_rv == 0 && lut_str_len == 0)) {
4215 cf_warning(AS_INFO, "truncate-namespace command: invalid last-update-time in command");
4216 cf_dyn_buf_append_string(db, "ERROR::last-update-time");
4217 return 0;
4218 }
4219
4220 // Issue the truncate command.
4221
4222 bool ok = as_truncate_cmd(ns_name, NULL, lut_rv == 0 ? lut_str : NULL);
4223
4224 cf_dyn_buf_append_string(db, ok ? "ok" : "ERROR::truncate");
4225
4226 return 0;
4227}
4228
4229// Format is:
4230//
4231// truncate-namespace-undo:namespace=<ns-name>
4232//
4233int
4234info_command_truncate_namespace_undo(char *name, char *params, cf_dyn_buf *db)
4235{
4236 // Get the namespace name.
4237
4238 char ns_name[AS_ID_NAMESPACE_SZ];
4239 int ns_name_len = (int)sizeof(ns_name);
4240 int ns_rv = as_info_parameter_get(params, "namespace", ns_name, &ns_name_len);
4241
4242 if (ns_rv != 0 || ns_name_len == 0) {
4243 cf_warning(AS_INFO, "truncate-namespace-undo command: missing or invalid namespace name in command");
4244 cf_dyn_buf_append_string(db, "ERROR::namespace-name");
4245 return 0;
4246 }
4247
4248 // Check for a set-name, for safety. (Did user intend 'truncate-undo'?)
4249
4250 char set_name[1]; // just checking for existence
4251 int set_name_len = (int)sizeof(set_name);
4252 int set_rv = as_info_parameter_get(params, "set", set_name, &set_name_len);
4253
4254 if (set_rv != -1) {
4255 cf_warning(AS_INFO, "truncate-namespace-undo command: unexpected set name in command");
4256 cf_dyn_buf_append_string(db, "ERROR::unexpected-set-name");
4257 return 0;
4258 }
4259
4260 // Issue the truncate-undo command.
4261
4262 bool ok = as_truncate_undo_cmd(ns_name, NULL);
4263
4264 cf_dyn_buf_append_string(db, ok ? "ok" : "ERROR::truncate-undo");
4265
4266 return 0;
4267}
4268
4269// Format is:
4270//
4271// truncate:namespace=<ns-name>;set=<set-name>[;lut=<UTC-nanosec-string>]
4272//
4273// ... where no lut value means use this server's current time.
4274//
4275int
4276info_command_truncate(char *name, char *params, cf_dyn_buf *db)
4277{
4278 // Get the namespace name.
4279
4280 char ns_name[AS_ID_NAMESPACE_SZ];
4281 int ns_name_len = (int)sizeof(ns_name);
4282 int ns_rv = as_info_parameter_get(params, "namespace", ns_name, &ns_name_len);
4283
4284 if (ns_rv != 0 || ns_name_len == 0) {
4285 cf_warning(AS_INFO, "truncate command: missing or invalid namespace name in command");
4286 cf_dyn_buf_append_string(db, "ERROR::namespace-name");
4287 return 0;
4288 }
4289
4290 // Get the set-name.
4291
4292 char set_name[AS_SET_NAME_MAX_SIZE];
4293 int set_name_len = (int)sizeof(set_name);
4294 int set_rv = as_info_parameter_get(params, "set", set_name, &set_name_len);
4295
4296 if (set_rv != 0 || set_name_len == 0) {
4297 cf_warning(AS_INFO, "truncate command: missing or invalid set name in command");
4298 cf_dyn_buf_append_string(db, "ERROR::set-name");
4299 return 0;
4300 }
4301
4302 // Get the threshold last-update-time, if there is one.
4303
4304 char lut_str[24]; // allow decimal, hex or octal in C constant format
4305 int lut_str_len = (int)sizeof(lut_str);
4306 int lut_rv = as_info_parameter_get(params, "lut", lut_str, &lut_str_len);
4307
4308 if (lut_rv == -2 || (lut_rv == 0 && lut_str_len == 0)) {
4309 cf_warning(AS_INFO, "truncate command: invalid last-update-time in command");
4310 cf_dyn_buf_append_string(db, "ERROR::last-update-time");
4311 return 0;
4312 }
4313
4314 // Issue the truncate command.
4315
4316 bool ok = as_truncate_cmd(ns_name, set_name, lut_rv == 0 ? lut_str : NULL);
4317
4318 cf_dyn_buf_append_string(db, ok ? "ok" : "ERROR::truncate");
4319
4320 return 0;
4321}
4322
4323// Format is:
4324//
4325// truncate-undo:namespace=<ns-name>;set=<set-name>
4326//
4327int
4328info_command_truncate_undo(char *name, char *params, cf_dyn_buf *db)
4329{
4330 // Get the namespace name.
4331
4332 char ns_name[AS_ID_NAMESPACE_SZ];
4333 int ns_name_len = (int)sizeof(ns_name);
4334 int ns_rv = as_info_parameter_get(params, "namespace", ns_name, &ns_name_len);
4335
4336 if (ns_rv != 0 || ns_name_len == 0) {
4337 cf_warning(AS_INFO, "truncate-undo command: missing or invalid namespace name in command");
4338 cf_dyn_buf_append_string(db, "ERROR::namespace-name");
4339 return 0;
4340 }
4341
4342 // Get the set-name.
4343
4344 char set_name[AS_SET_NAME_MAX_SIZE];
4345 int set_name_len = (int)sizeof(set_name);
4346 int set_rv = as_info_parameter_get(params, "set", set_name, &set_name_len);
4347
4348 if (set_rv != 0 || set_name_len == 0) {
4349 cf_warning(AS_INFO, "truncate-undo command: missing or invalid set name in command");
4350 cf_dyn_buf_append_string(db, "ERROR::set-name");
4351 return 0;
4352 }
4353
4354 // Issue the truncate-undo command.
4355
4356 bool ok = as_truncate_undo_cmd(ns_name, set_name);
4357
4358 cf_dyn_buf_append_string(db, ok ? "ok" : "ERROR::truncate-undo");
4359
4360 return 0;
4361}
4362
4363// Format is:
4364//
4365// eviction-reset:namespace=<ns-name>[;ttl=<seconds-from-now>]
4366//
4367// ... where no ttl means delete the SMD evict-void-time.
4368//
4369int
4370info_command_eviction_reset(char *name, char *params, cf_dyn_buf *db)
4371{
4372 // Get the namespace name.
4373
4374 char ns_name[AS_ID_NAMESPACE_SZ];
4375 int ns_name_len = (int)sizeof(ns_name);
4376 int ns_rv = as_info_parameter_get(params, "namespace", ns_name, &ns_name_len);
4377
4378 if (ns_rv != 0 || ns_name_len == 0) {
4379 cf_warning(AS_INFO, "eviction-reset command: missing or invalid namespace name in command");
4380 cf_dyn_buf_append_string(db, "ERROR::namespace-name");
4381 return 0;
4382 }
4383
4384 // Get the TTL if there is one.
4385
4386 char ttl_str[12]; // allow decimal, hex or octal in C constant format
4387 int ttl_str_len = (int)sizeof(ttl_str);
4388 int ttl_rv = as_info_parameter_get(params, "ttl", ttl_str, &ttl_str_len);
4389
4390 if (ttl_rv == -2 || (ttl_rv == 0 && ttl_str_len == 0)) {
4391 cf_warning(AS_INFO, "eviction-reset command: invalid ttl in command");
4392 cf_dyn_buf_append_string(db, "ERROR::ttl");
4393 return 0;
4394 }
4395
4396 // Issue the eviction-reset command.
4397
4398 bool ok = as_nsup_eviction_reset_cmd(ns_name, ttl_rv == 0 ? ttl_str : NULL);
4399
4400 cf_dyn_buf_append_string(db, ok ? "ok" : "ERROR::eviction-reset");
4401
4402 return 0;
4403}
4404
4405//
4406// Log a message to the server.
4407// Limited to 2048 characters.
4408//
4409// Format:
4410// log-message:message=<MESSAGE>[;who=<WHO>]
4411//
4412// Example:
4413// log-message:message=Example Log Message;who=Aerospike User
4414//
4415int
4416info_command_log_message(char *name, char *params, cf_dyn_buf *db)
4417{
4418 char who[128];
4419 int who_len = sizeof(who);
4420 if (0 != as_info_parameter_get(params, "who", who, &who_len)) {
4421 strcpy(who, "unknown");
4422 }
4423
4424 char message[2048];
4425 int message_len = sizeof(message);
4426 if (0 == as_info_parameter_get(params, "message", message, &message_len)) {
4427 cf_info(AS_INFO, "%s: %s", who, message);
4428 }
4429
4430 return 0;
4431}
4432
4433// Generic info system functions
4434// These functions act when an INFO message comes in over the PROTO pipe
4435// collects the static and dynamic portions, puts it in a 'dyn buf',
4436// and sends a reply
4437//
4438
4439// Error strings for security check results.
4440static void
4441append_sec_err_str(cf_dyn_buf *db, uint32_t result, as_sec_perm cmd_perm) {
4442 switch (result) {
4443 case AS_SEC_ERR_NOT_AUTHENTICATED:
4444 cf_dyn_buf_append_string(db, "ERROR:");
4445 cf_dyn_buf_append_uint32(db, result);
4446 cf_dyn_buf_append_string(db, ":not authenticated");
4447 return;
4448 case AS_SEC_ERR_ROLE_VIOLATION:
4449 switch (cmd_perm) {
4450 case PERM_INDEX_MANAGE:
4451 INFO_COMMAND_SINDEX_FAILCODE(result, "role violation");
4452 return;
4453 case PERM_UDF_MANAGE:
4454 cf_dyn_buf_append_string(db, "error=role_violation");
4455 return;
4456 default:
4457 break;
4458 }
4459 cf_dyn_buf_append_string(db, "ERROR:");
4460 cf_dyn_buf_append_uint32(db, result);
4461 cf_dyn_buf_append_string(db, ":role violation");
4462 return;
4463 default:
4464 cf_dyn_buf_append_string(db, "ERROR:");
4465 cf_dyn_buf_append_uint32(db, result);
4466 cf_dyn_buf_append_string(db, ":unexpected security error");
4467 return;
4468 }
4469}
4470
4471static cf_mutex g_info_lock = CF_MUTEX_INIT;
4472info_static *static_head = 0;
4473info_dynamic *dynamic_head = 0;
4474info_tree *tree_head = 0;
4475info_command *command_head = 0;
4476//
4477// Pull up all elements in both list into the buffers
4478// (efficient enough if you're looking for lots of things)
4479// But only gets 'default' values
4480//
4481
4482int
4483info_all(const as_file_handle* fd_h, cf_dyn_buf *db)
4484{
4485 uint8_t auth_result = as_security_check(fd_h, PERM_NONE);
4486
4487 if (auth_result != AS_OK) {
4488 as_security_log(fd_h, auth_result, PERM_NONE, "info-all request", NULL);
4489 append_sec_err_str(db, auth_result, PERM_NONE);
4490 cf_dyn_buf_append_char(db, EOL);
4491 return 0;
4492 }
4493
4494 info_static *s = static_head;
4495 while (s) {
4496 if (s->def == true) {
4497 cf_dyn_buf_append_string( db, s->name);
4498 cf_dyn_buf_append_char( db, SEP );
4499 cf_dyn_buf_append_buf( db, (uint8_t *) s->value, s->value_sz);
4500 cf_dyn_buf_append_char( db, EOL );
4501 }
4502 s = s->next;
4503 }
4504
4505 info_dynamic *d = dynamic_head;
4506 while (d) {
4507 if (d->def == true) {
4508 cf_dyn_buf_append_string( db, d->name);
4509 cf_dyn_buf_append_char(db, SEP );
4510 d->value_fn(d->name, db);
4511 cf_dyn_buf_append_char(db, EOL);
4512 }
4513 d = d->next;
4514 }
4515
4516 return(0);
4517}
4518
4519//
4520// Parse the input buffer. It contains a list of keys that should be spit back.
4521// Do the parse, call the necessary function collecting the information in question
4522// Filling the dynbuf
4523
4524int
4525info_some(char *buf, char *buf_lim, const as_file_handle* fd_h, cf_dyn_buf *db)
4526{
4527 uint8_t auth_result = as_security_check(fd_h, PERM_NONE);
4528
4529 if (auth_result != AS_OK) {
4530 // TODO - log null-terminated buf as detail?
4531 as_security_log(fd_h, auth_result, PERM_NONE, "info request", NULL);
4532 append_sec_err_str(db, auth_result, PERM_NONE);
4533 cf_dyn_buf_append_char(db, EOL);
4534 return 0;
4535 }
4536
4537 // For each incoming name
4538 char *c = buf;
4539 char *tok = c;
4540
4541 while (c < buf_lim) {
4542
4543 if ( *c == EOL ) {
4544 *c = 0;
4545 char *name = tok;
4546 bool handled = false;
4547
4548 // search the static queue first always
4549 info_static *s = static_head;
4550 while (s) {
4551 if (strcmp(s->name, name) == 0) {
4552 // return exact command string received from client
4553 cf_dyn_buf_append_string( db, name);
4554 cf_dyn_buf_append_char( db, SEP );
4555 cf_dyn_buf_append_buf( db, (uint8_t *) s->value, s->value_sz);
4556 cf_dyn_buf_append_char( db, EOL );
4557 handled = true;
4558 break;
4559 }
4560 s = s->next;
4561 }
4562
4563 // didn't find in static, try dynamic
4564 if (!handled) {
4565 info_dynamic *d = dynamic_head;
4566 while (d) {
4567 if (strcmp(d->name, name) == 0) {
4568 // return exact command string received from client
4569 cf_dyn_buf_append_string( db, d->name);
4570 cf_dyn_buf_append_char(db, SEP );
4571 d->value_fn(d->name, db);
4572 cf_dyn_buf_append_char(db, EOL);
4573 handled = true;
4574 break;
4575 }
4576 d = d->next;
4577 }
4578 }
4579
4580 // search the tree
4581 if (!handled) {
4582
4583 // see if there's a '/',
4584 char *branch = strchr( name, TREE_SEP);
4585 if (branch) {
4586 *branch = 0;
4587 branch++;
4588
4589 info_tree *t = tree_head;
4590 while (t) {
4591 if (strcmp(t->name, name) == 0) {
4592 // return exact command string received from client
4593 cf_dyn_buf_append_string( db, t->name);
4594 cf_dyn_buf_append_char( db, TREE_SEP);
4595 cf_dyn_buf_append_string( db, branch);
4596 cf_dyn_buf_append_char(db, SEP );
4597 t->tree_fn(t->name, branch, db);
4598 cf_dyn_buf_append_char(db, EOL);
4599 break;
4600 }
4601 t = t->next;
4602 }
4603 }
4604 }
4605
4606 tok = c + 1;
4607 }
4608 // commands have parameters
4609 else if ( *c == ':' ) {
4610 *c = 0;
4611 char *name = tok;
4612
4613 // parse parameters
4614 tok = c + 1;
4615 // make sure c doesn't go beyond buf_lim
4616 while (*c != EOL && c < buf_lim-1) c++;
4617 if (*c != EOL) {
4618 cf_warning(AS_INFO, "Info '%s' parameter not terminated with '\\n'.", name);
4619 break;
4620 }
4621 *c = 0;
4622 char *param = tok;
4623
4624 // search the command list
4625 info_command *cmd = command_head;
4626 while (cmd) {
4627 if (strcmp(cmd->name, name) == 0) {
4628 // return exact command string received from client
4629 cf_dyn_buf_append_string( db, name);
4630 cf_dyn_buf_append_char( db, ':');
4631 cf_dyn_buf_append_string( db, param);
4632 cf_dyn_buf_append_char( db, SEP );
4633
4634 uint8_t result = as_security_check(fd_h, cmd->required_perm);
4635
4636 as_security_log(fd_h, result, cmd->required_perm, name, param);
4637
4638 if (result == AS_OK) {
4639 cmd->command_fn(cmd->name, param, db);
4640 }
4641 else {
4642 append_sec_err_str(db, result, cmd->required_perm);
4643 }
4644
4645 cf_dyn_buf_append_char( db, EOL );
4646 break;
4647 }
4648 cmd = cmd->next;
4649 }
4650
4651 if (!cmd) {
4652 cf_info(AS_INFO, "received command %s, not registered", name);
4653 }
4654
4655 tok = c + 1;
4656 }
4657
4658 c++;
4659
4660 }
4661 return(0);
4662}
4663
4664int
4665as_info_buffer(uint8_t *req_buf, size_t req_buf_len, cf_dyn_buf *rsp)
4666{
4667 // Either we'e doing all, or doing some
4668 if (req_buf_len == 0) {
4669 info_all(NULL, rsp);
4670 }
4671 else {
4672 info_some((char *)req_buf, (char *)(req_buf + req_buf_len), NULL, rsp);
4673 }
4674
4675 return(0);
4676}
4677
4678//
4679// Worker threads!
4680// these actually do the work. There is a lot of network activity,
4681// writes and such, don't want to clog up the main queue
4682//
4683
4684void *
4685thr_info_fn(void *unused)
4686{
4687 for ( ; ; ) {
4688
4689 as_info_transaction it;
4690
4691 if (0 != cf_queue_pop(g_info_work_q, &it, CF_QUEUE_FOREVER)) {
4692 cf_crash(AS_TSVC, "unable to pop from info work queue");
4693 }
4694
4695 if (it.fd_h == NULL) {
4696 break; // termination signal
4697 }
4698
4699 as_file_handle *fd_h = it.fd_h;
4700 as_proto *pr = it.proto;
4701
4702 // Allocate an output buffer sufficiently large to avoid ever resizing
4703 cf_dyn_buf_define_size(db, 128 * 1024);
4704 // write space for the header
4705 uint64_t h = 0;
4706 cf_dyn_buf_append_buf(&db, (uint8_t *) &h, sizeof(h));
4707
4708 // Either we'e doing all, or doing some
4709 if (pr->sz == 0) {
4710 info_all(fd_h, &db);
4711 }
4712 else {
4713 info_some((char *)pr->body, (char *)pr->body + pr->sz, fd_h, &db);
4714 }
4715
4716 // write the proto header in the space we pre-wrote
4717 db.buf[0] = 2;
4718 db.buf[1] = 1;
4719 uint64_t sz = db.used_sz - 8;
4720 db.buf[4] = (sz >> 24) & 0xff;
4721 db.buf[5] = (sz >> 16) & 0xff;
4722 db.buf[6] = (sz >> 8) & 0xff;
4723 db.buf[7] = sz & 0xff;
4724
4725 // write the data buffer
4726 if (cf_socket_send_all(&fd_h->sock, db.buf, db.used_sz,
4727 MSG_NOSIGNAL, CF_SOCKET_TIMEOUT) < 0) {
4728 cf_info(AS_INFO, "error sending to %s - fd %d sz %zu %s",
4729 fd_h->client, CSFD(&fd_h->sock), db.used_sz,
4730 cf_strerror(errno));
4731 as_end_of_transaction_force_close(fd_h);
4732 fd_h = NULL;
4733 }
4734
4735 cf_dyn_buf_free(&db);
4736
4737 cf_free(pr);
4738
4739 if (fd_h) {
4740 as_end_of_transaction_ok(fd_h);
4741 fd_h = NULL;
4742 }
4743
4744 G_HIST_INSERT_DATA_POINT(info_hist, it.start_time);
4745 cf_atomic64_incr(&g_stats.info_complete);
4746 }
4747
4748 return NULL;
4749}
4750
4751//
4752// received an info request from a file descriptor
4753// Called by the thr_tsvc when an info message is seen
4754// calls functions info_all or info_some to collect the response
4755// calls write to send the response back
4756//
4757// Proto will be freed by the caller
4758//
4759
4760void
4761as_info(as_info_transaction *it)
4762{
4763 cf_queue_push(g_info_work_q, it);
4764}
4765
4766// Called via info command. Caller has sanity-checked n_threads.
4767void
4768info_set_num_info_threads(uint32_t n_threads)
4769{
4770 if (g_config.n_info_threads > n_threads) {
4771 // Decrease the number of info threads to n_threads.
4772 while (g_config.n_info_threads > n_threads) {
4773 as_info_transaction death_msg = { 0 };
4774
4775 // Send terminator (NULL message).
4776 as_info(&death_msg);
4777 g_config.n_info_threads--;
4778 }
4779 }
4780 else {
4781 // Increase the number of info threads to n_threads.
4782 while (g_config.n_info_threads < n_threads) {
4783 cf_thread_create_detached(thr_info_fn, NULL);
4784 g_config.n_info_threads++;
4785 }
4786 }
4787}
4788
4789// Return the number of pending Info requests in the queue.
4790int
4791as_info_queue_get_size()
4792{
4793 return cf_queue_sz(g_info_work_q);
4794}
4795
4796// Registers a dynamic name-value calculator.
4797// the get_value_fn will be called if a request comes in for this name.
4798// only does the registration!
4799// def means it's part of the default results - will get invoked for a blank info command (asinfo -v "")
4800
4801
4802int
4803as_info_set_dynamic(const char *name, as_info_get_value_fn gv_fn, bool def)
4804{
4805 int rv = -1;
4806 cf_mutex_lock(&g_info_lock);
4807
4808 info_dynamic *e = dynamic_head;
4809 while (e) {
4810 if (strcmp(name, e->name) == 0) {
4811 e->value_fn = gv_fn;
4812 break;
4813 }
4814
4815 e = e->next;
4816 }
4817
4818 if (!e) {
4819 e = cf_malloc(sizeof(info_dynamic));
4820 e->def = def;
4821 e->name = cf_strdup(name);
4822 e->value_fn = gv_fn;
4823 e->next = dynamic_head;
4824 dynamic_head = e;
4825 }
4826 rv = 0;
4827
4828 cf_mutex_unlock(&g_info_lock);
4829 return(rv);
4830}
4831
4832
4833// Registers a tree-based name-value calculator.
4834// the get_value_fn will be called if a request comes in for this name.
4835// only does the registration!
4836
4837
4838int
4839as_info_set_tree(char *name, as_info_get_tree_fn gv_fn)
4840{
4841 int rv = -1;
4842 cf_mutex_lock(&g_info_lock);
4843
4844 info_tree *e = tree_head;
4845 while (e) {
4846 if (strcmp(name, e->name) == 0) {
4847 e->tree_fn = gv_fn;
4848 break;
4849 }
4850
4851 e = e->next;
4852 }
4853
4854 if (!e) {
4855 e = cf_malloc(sizeof(info_tree));
4856 e->name = cf_strdup(name);
4857 e->tree_fn = gv_fn;
4858 e->next = tree_head;
4859 tree_head = e;
4860 }
4861 rv = 0;
4862
4863 cf_mutex_unlock(&g_info_lock);
4864 return(rv);
4865}
4866
4867
4868// Registers a command handler
4869// the get_value_fn will be called if a request comes in for this name, and
4870// parameters will be passed in
4871// This function only does the registration!
4872
4873int
4874as_info_set_command(const char *name, as_info_command_fn command_fn, as_sec_perm required_perm)
4875{
4876 int rv = -1;
4877 cf_mutex_lock(&g_info_lock);
4878
4879 info_command *e = command_head;
4880 while (e) {
4881 if (strcmp(name, e->name) == 0) {
4882 e->command_fn = command_fn;
4883 break;
4884 }
4885
4886 e = e->next;
4887 }
4888
4889 if (!e) {
4890 e = cf_malloc(sizeof(info_command));
4891 e->name = cf_strdup(name);
4892 e->command_fn = command_fn;
4893 e->required_perm = required_perm;
4894 e->next = command_head;
4895 command_head = e;
4896 }
4897 rv = 0;
4898
4899 cf_mutex_unlock(&g_info_lock);
4900 return(rv);
4901}
4902
4903
4904
4905//
4906// Sets a static name-value pair
4907// def means it's part of the default set - will get returned if nothing is passed
4908
4909int
4910as_info_set_buf(const char *name, const uint8_t *value, size_t value_sz, bool def)
4911{
4912 cf_mutex_lock(&g_info_lock);
4913
4914 // Delete case
4915 if (value_sz == 0 || value == 0) {
4916
4917 info_static *p = 0;
4918 info_static *e = static_head;
4919
4920 while (e) {
4921 if (strcmp(name, e->name) == 0) {
4922 if (p) {
4923 p->next = e->next;
4924 cf_free(e->name);
4925 cf_free(e->value);
4926 cf_free(e);
4927 }
4928 else {
4929 info_static *_t = static_head->next;
4930 cf_free(e->name);
4931 cf_free(e->value);
4932 cf_free(static_head);
4933 static_head = _t;
4934 }
4935 break;
4936 }
4937 p = e;
4938 e = e->next;
4939 }
4940 }
4941 // insert case
4942 else {
4943
4944 info_static *e = static_head;
4945
4946 // search for old value and overwrite
4947 while(e) {
4948 if (strcmp(name, e->name) == 0) {
4949 cf_free(e->value);
4950 e->value = cf_malloc(value_sz);
4951 memcpy(e->value, value, value_sz);
4952 e->value_sz = value_sz;
4953 break;
4954 }
4955 e = e->next;
4956 }
4957
4958 // not found, insert fresh
4959 if (e == 0) {
4960 info_static *_t = cf_malloc(sizeof(info_static));
4961 _t->next = static_head;
4962 _t->def = def;
4963 _t->name = cf_strdup(name);
4964 _t->value = cf_malloc(value_sz);
4965 memcpy(_t->value, value, value_sz);
4966 _t->value_sz = value_sz;
4967 static_head = _t;
4968 }
4969 }
4970
4971 cf_mutex_unlock(&g_info_lock);
4972 return(0);
4973
4974}
4975
4976//
4977// A helper function. Commands have the form:
4978// cmd:param=value;param=value
4979//
4980// The main parser gives us the entire parameter string
4981// so use this function to scan through and get the particular parameter value
4982// you're looking for
4983//
4984// The 'param_string' is the param passed by the command parser into a command
4985//
4986// @return 0 : success
4987// -1 : parameter not found
4988// -2 : parameter found but value is too long
4989//
4990
4991int
4992as_info_parameter_get(char *param_str, char *param, char *value, int *value_len)
4993{
4994 cf_detail(AS_INFO, "parameter get: paramstr %s seeking param %s", param_str, param);
4995
4996 char *c = param_str;
4997 char *tok = param_str;
4998 int param_len = strlen(param);
4999
5000 while (*c) {
5001 if (*c == '=') {
5002 if ( ( param_len == c - tok) && (0 == memcmp(tok, param, param_len) ) ) {
5003 c++;
5004 tok = c;
5005 while ( *c != 0 && *c != ';') c++;
5006 if (*value_len <= c - tok) {
5007 // The found value is too long.
5008 return(-2);
5009 }
5010 *value_len = c - tok;
5011 memcpy(value, tok, *value_len);
5012 value[*value_len] = 0;
5013 return(0);
5014 }
5015 c++;
5016 }
5017 else if (*c == ';') {
5018 c++;
5019 tok = c;
5020 }
5021 else c++;
5022
5023 }
5024
5025 return(-1);
5026}
5027
5028int
5029as_info_set(const char *name, const char *value, bool def)
5030{
5031 return(as_info_set_buf(name, (const uint8_t *) value, strlen(value), def ) );
5032}
5033
5034//
5035// Iterate through the current namespace list and cons up a string
5036//
5037
5038int
5039info_get_namespaces(char *name, cf_dyn_buf *db)
5040{
5041 for (uint32_t i = 0; i < g_config.n_namespaces; i++) {
5042 cf_dyn_buf_append_string(db, g_config.namespaces[i]->name);
5043 cf_dyn_buf_append_char(db, ';');
5044 }
5045
5046 if (g_config.n_namespaces > 0) {
5047 cf_dyn_buf_chomp(db);
5048 }
5049
5050 return(0);
5051}
5052
5053int
5054info_get_health_outliers(char *name, cf_dyn_buf *db)
5055{
5056 as_health_get_outliers(db);
5057 return(0);
5058}
5059
5060int
5061info_get_health_stats(char *name, cf_dyn_buf *db)
5062{
5063 as_health_get_stats(db);
5064 return(0);
5065}
5066
5067int
5068info_get_logs(char *name, cf_dyn_buf *db)
5069{
5070 cf_fault_sink_strlist(db);
5071 return(0);
5072}
5073
5074int
5075info_get_objects(char *name, cf_dyn_buf *db)
5076{
5077 uint64_t objects = 0;
5078
5079 for (uint32_t i = 0; i < g_config.n_namespaces; i++) {
5080 objects += g_config.namespaces[i]->n_objects;
5081 }
5082
5083 cf_dyn_buf_append_uint64(db, objects);
5084 return(0);
5085}
5086
5087int
5088info_get_sets(char *name, cf_dyn_buf *db)
5089{
5090 return info_get_tree_sets(name, "", db);
5091}
5092
5093int
5094info_get_smd_info(char *name, cf_dyn_buf *db)
5095{
5096 as_smd_get_info(db);
5097
5098 return (0);
5099}
5100
5101int
5102info_get_bins(char *name, cf_dyn_buf *db)
5103{
5104 return info_get_tree_bins(name, "", db);
5105}
5106
5107int
5108info_get_config( char* name, cf_dyn_buf *db)
5109{
5110 return info_command_config_get(name, NULL, db);
5111}
5112
5113int
5114info_get_sindexes(char *name, cf_dyn_buf *db)
5115{
5116 return info_get_tree_sindexes(name, "", db);
5117}
5118
5119static int32_t
5120oldest_nvme_age(const char *path)
5121{
5122 cf_storage_device_info *info = cf_storage_get_device_info(path);
5123
5124 if (info == NULL) {
5125 return -1;
5126 }
5127
5128 int32_t oldest = -1;
5129
5130 for (int32_t i = 0; i < info->n_phys; ++i) {
5131 if (info->phys[i].nvme_age > oldest) {
5132 oldest = info->phys[i].nvme_age;
5133 }
5134 }
5135
5136 return oldest;
5137}
5138
5139static void
5140add_index_device_stats(as_namespace *ns, cf_dyn_buf *db)
5141{
5142 for (uint32_t i = 0; i < ns->n_xmem_mounts; i++) {
5143 info_append_indexed_int(db, "index-type.mount", i, "age",
5144 oldest_nvme_age(ns->xmem_mounts[i]));
5145 }
5146}
5147
5148static void
5149add_data_device_stats(as_namespace *ns, cf_dyn_buf *db)
5150{
5151 uint32_t n = as_namespace_device_count(ns);
5152 const char* tag = ns->n_storage_devices != 0 ?
5153 "storage-engine.device" : "storage-engine.file";
5154
5155 for (uint32_t i = 0; i < n; i++) {
5156 storage_device_stats stats;
5157 as_storage_device_stats(ns, i, &stats);
5158
5159 info_append_indexed_uint64(db, tag, i, "used_bytes", stats.used_sz);
5160 info_append_indexed_uint32(db, tag, i, "free_wblocks", stats.n_free_wblocks);
5161
5162 info_append_indexed_uint32(db, tag, i, "write_q", stats.write_q_sz);
5163 info_append_indexed_uint64(db, tag, i, "writes", stats.n_writes);
5164
5165 info_append_indexed_uint32(db, tag, i, "defrag_q", stats.defrag_q_sz);
5166 info_append_indexed_uint64(db, tag, i, "defrag_reads", stats.n_defrag_reads);
5167 info_append_indexed_uint64(db, tag, i, "defrag_writes", stats.n_defrag_writes);
5168
5169 info_append_indexed_uint32(db, tag, i, "shadow_write_q", stats.shadow_write_q_sz);
5170
5171 info_append_indexed_int(db, tag, i, "age",
5172 oldest_nvme_age(ns->storage_devices[i]));
5173 }
5174}
5175
5176void
5177info_get_namespace_info(as_namespace *ns, cf_dyn_buf *db)
5178{
5179 // Cluster size.
5180
5181 // Using ns_ prefix to avoid confusion with global cluster_size.
5182 info_append_uint32(db, "ns_cluster_size", ns->cluster_size);
5183
5184 // Using effective_ prefix to avoid confusion with configured value.
5185 info_append_uint32(db, "effective_replication_factor", ns->replication_factor);
5186
5187 // Object counts.
5188
5189 info_append_uint64(db, "objects", ns->n_objects);
5190 info_append_uint64(db, "tombstones", ns->n_tombstones);
5191
5192 repl_stats mp;
5193 as_partition_get_replica_stats(ns, &mp);
5194
5195 info_append_uint64(db, "master_objects", mp.n_master_objects);
5196 info_append_uint64(db, "master_tombstones", mp.n_master_tombstones);
5197 info_append_uint64(db, "prole_objects", mp.n_prole_objects);
5198 info_append_uint64(db, "prole_tombstones", mp.n_prole_tombstones);
5199 info_append_uint64(db, "non_replica_objects", mp.n_non_replica_objects);
5200 info_append_uint64(db, "non_replica_tombstones", mp.n_non_replica_tombstones);
5201
5202 // Consistency info.
5203
5204 info_append_uint32(db, "dead_partitions", ns->n_dead_partitions);
5205 info_append_uint32(db, "unavailable_partitions", ns->n_unavailable_partitions);
5206 info_append_bool(db, "clock_skew_stop_writes", ns->clock_skew_stop_writes);
5207
5208 // Expiration & eviction (nsup) stats.
5209
5210 info_append_bool(db, "stop_writes", ns->stop_writes);
5211 info_append_bool(db, "hwm_breached", ns->hwm_breached);
5212
5213 info_append_uint64(db, "current_time", as_record_void_time_get());
5214 info_append_uint64(db, "non_expirable_objects", ns->non_expirable_objects);
5215 info_append_uint64(db, "expired_objects", ns->n_expired_objects);
5216 info_append_uint64(db, "evicted_objects", ns->n_evicted_objects);
5217 info_append_int(db, "evict_ttl", ns->evict_ttl);
5218 info_append_uint32(db, "evict_void_time", ns->evict_void_time);
5219 info_append_uint32(db, "smd_evict_void_time", ns->smd_evict_void_time);
5220 info_append_uint32(db, "nsup_cycle_duration", ns->nsup_cycle_duration);
5221
5222 // Truncate stats.
5223
5224 info_append_uint64(db, "truncate_lut", ns->truncate.lut);
5225 info_append_uint64(db, "truncated_records", ns->truncate.n_records);
5226
5227 // Memory usage stats.
5228
5229 uint64_t index_used = (ns->n_tombstones + ns->n_objects) * sizeof(as_index);
5230
5231 uint64_t data_memory = ns->n_bytes_memory;
5232 uint64_t index_memory = as_namespace_index_persisted(ns) ? 0 : index_used;
5233 uint64_t sindex_memory = ns->n_bytes_sindex_memory;
5234 uint64_t used_memory = data_memory + index_memory + sindex_memory;
5235
5236 info_append_uint64(db, "memory_used_bytes", used_memory);
5237 info_append_uint64(db, "memory_used_data_bytes", data_memory);
5238 info_append_uint64(db, "memory_used_index_bytes", index_memory);
5239 info_append_uint64(db, "memory_used_sindex_bytes", sindex_memory);
5240
5241 uint64_t free_pct = ns->memory_size > used_memory ?
5242 ((ns->memory_size - used_memory) * 100L) / ns->memory_size : 0;
5243
5244 info_append_uint64(db, "memory_free_pct", free_pct);
5245
5246 // Persistent memory block keys' namespace ID (enterprise only).
5247 info_append_uint32(db, "xmem_id", ns->xmem_id);
5248
5249 // Remaining bin-name slots (yes, this can be negative).
5250 if (! ns->single_bin) {
5251 info_append_int(db, "available_bin_names", BIN_NAMES_QUOTA - (int)cf_vmapx_count(ns->p_bin_name_vmap));
5252 }
5253
5254 // Persistent index stats.
5255
5256 if (ns->xmem_type == CF_XMEM_TYPE_PMEM) {
5257 // If numa-pinned, not all configured mounts are used.
5258 if (as_config_is_numa_pinned()) {
5259 for (uint32_t i = 0; i < ns->n_xmem_mounts; i++) {
5260 if (cf_mount_is_local(ns->xmem_mounts[i])) {
5261 info_append_indexed_string(db, "local_mount", i, NULL,
5262 ns->xmem_mounts[i]);
5263 }
5264 }
5265 }
5266
5267 uint64_t used_pct = index_used * 100 / ns->mounts_size_limit;
5268
5269 info_append_uint64(db, "index_pmem_used_bytes", index_used);
5270 info_append_uint64(db, "index_pmem_used_pct", used_pct);
5271 }
5272 else if (ns->xmem_type == CF_XMEM_TYPE_FLASH) {
5273 uint64_t used_pct = index_used * 100 / ns->mounts_size_limit;
5274
5275 info_append_uint64(db, "index_flash_used_bytes", index_used);
5276 info_append_uint64(db, "index_flash_used_pct", used_pct);
5277
5278 add_index_device_stats(ns, db);
5279 }
5280
5281 // Persistent storage stats.
5282
5283 if (ns->storage_type == AS_STORAGE_ENGINE_SSD) {
5284 int available_pct = 0;
5285 uint64_t inuse_disk_bytes = 0;
5286 as_storage_stats(ns, &available_pct, &inuse_disk_bytes);
5287
5288 info_append_uint64(db, "device_total_bytes", ns->ssd_size);
5289 info_append_uint64(db, "device_used_bytes", inuse_disk_bytes);
5290
5291 free_pct = (ns->ssd_size != 0 && (ns->ssd_size > inuse_disk_bytes)) ?
5292 ((ns->ssd_size - inuse_disk_bytes) * 100L) / ns->ssd_size : 0;
5293
5294 info_append_uint64(db, "device_free_pct", free_pct);
5295 info_append_int(db, "device_available_pct", available_pct);
5296
5297 if (ns->storage_compression != AS_COMPRESSION_NONE) {
5298 double orig_sz = as_load_double(&ns->comp_avg_orig_sz);
5299 double ratio = orig_sz > 0.0 ? ns->comp_avg_comp_sz / orig_sz : 1.0;
5300
5301 info_append_format(db, "device_compression_ratio", "%.3f", ratio);
5302 }
5303
5304 if (! ns->storage_data_in_memory) {
5305 info_append_int(db, "cache_read_pct", (int)(ns->cache_read_pct + 0.5));
5306 }
5307
5308 add_data_device_stats(ns, db);
5309 }
5310
5311 // Partition balance state.
5312
5313 info_append_bool(db, "pending_quiesce", ns->pending_quiesce);
5314 info_append_bool(db, "effective_is_quiesced", ns->is_quiesced);
5315 info_append_uint64(db, "nodes_quiesced", ns->cluster_size - ns->active_size);
5316
5317 info_append_bool(db, "effective_prefer_uniform_balance", ns->prefer_uniform_balance);
5318
5319 // Migration stats.
5320
5321 info_append_uint64(db, "migrate_tx_partitions_imbalance", ns->migrate_tx_partitions_imbalance);
5322
5323 info_append_uint64(db, "migrate_tx_instances", ns->migrate_tx_instance_count);
5324 info_append_uint64(db, "migrate_rx_instances", ns->migrate_rx_instance_count);
5325
5326 info_append_uint64(db, "migrate_tx_partitions_active", ns->migrate_tx_partitions_active);
5327 info_append_uint64(db, "migrate_rx_partitions_active", ns->migrate_rx_partitions_active);
5328
5329 info_append_uint64(db, "migrate_tx_partitions_initial", ns->migrate_tx_partitions_initial);
5330 info_append_uint64(db, "migrate_tx_partitions_remaining", ns->migrate_tx_partitions_remaining);
5331 info_append_uint64(db, "migrate_tx_partitions_lead_remaining", ns->migrate_tx_partitions_lead_remaining);
5332
5333 info_append_uint64(db, "migrate_rx_partitions_initial", ns->migrate_rx_partitions_initial);
5334 info_append_uint64(db, "migrate_rx_partitions_remaining", ns->migrate_rx_partitions_remaining);
5335
5336 info_append_uint64(db, "migrate_records_skipped", ns->migrate_records_skipped);
5337 info_append_uint64(db, "migrate_records_transmitted", ns->migrate_records_transmitted);
5338 info_append_uint64(db, "migrate_record_retransmits", ns->migrate_record_retransmits);
5339 info_append_uint64(db, "migrate_record_receives", ns->migrate_record_receives);
5340
5341 info_append_uint64(db, "migrate_signals_active", ns->migrate_signals_active);
5342 info_append_uint64(db, "migrate_signals_remaining", ns->migrate_signals_remaining);
5343
5344 info_append_uint64(db, "appeals_tx_active", ns->appeals_tx_active);
5345 info_append_uint64(db, "appeals_rx_active", ns->appeals_rx_active);
5346
5347 info_append_uint64(db, "appeals_tx_remaining", ns->appeals_tx_remaining);
5348
5349 info_append_uint64(db, "appeals_records_exonerated", ns->appeals_records_exonerated);
5350
5351 // From-client transaction stats.
5352
5353 info_append_uint64(db, "client_tsvc_error", ns->n_client_tsvc_error);
5354 info_append_uint64(db, "client_tsvc_timeout", ns->n_client_tsvc_timeout);
5355
5356 info_append_uint64(db, "client_proxy_complete", ns->n_client_proxy_complete);
5357 info_append_uint64(db, "client_proxy_error", ns->n_client_proxy_error);
5358 info_append_uint64(db, "client_proxy_timeout", ns->n_client_proxy_timeout);
5359
5360 info_append_uint64(db, "client_read_success", ns->n_client_read_success);
5361 info_append_uint64(db, "client_read_error", ns->n_client_read_error);
5362 info_append_uint64(db, "client_read_timeout", ns->n_client_read_timeout);
5363 info_append_uint64(db, "client_read_not_found", ns->n_client_read_not_found);
5364 info_append_uint64(db, "client_read_filtered_out", ns->n_client_read_filtered_out);
5365
5366 info_append_uint64(db, "client_write_success", ns->n_client_write_success);
5367 info_append_uint64(db, "client_write_error", ns->n_client_write_error);
5368 info_append_uint64(db, "client_write_timeout", ns->n_client_write_timeout);
5369 info_append_uint64(db, "client_write_filtered_out", ns->n_client_write_filtered_out);
5370
5371 // Subset of n_client_write_... above, respectively.
5372 info_append_uint64(db, "xdr_client_write_success", ns->n_xdr_client_write_success);
5373 info_append_uint64(db, "xdr_client_write_error", ns->n_xdr_client_write_error);
5374 info_append_uint64(db, "xdr_client_write_timeout", ns->n_xdr_client_write_timeout);
5375
5376 info_append_uint64(db, "client_delete_success", ns->n_client_delete_success);
5377 info_append_uint64(db, "client_delete_error", ns->n_client_delete_error);
5378 info_append_uint64(db, "client_delete_timeout", ns->n_client_delete_timeout);
5379 info_append_uint64(db, "client_delete_not_found", ns->n_client_delete_not_found);
5380 info_append_uint64(db, "client_delete_filtered_out", ns->n_client_delete_filtered_out);
5381
5382 // Subset of n_client_delete_... above, respectively.
5383 info_append_uint64(db, "xdr_client_delete_success", ns->n_xdr_client_delete_success);
5384 info_append_uint64(db, "xdr_client_delete_error", ns->n_xdr_client_delete_error);
5385 info_append_uint64(db, "xdr_client_delete_timeout", ns->n_xdr_client_delete_timeout);
5386 info_append_uint64(db, "xdr_client_delete_not_found", ns->n_xdr_client_delete_not_found);
5387
5388 info_append_uint64(db, "client_udf_complete", ns->n_client_udf_complete);
5389 info_append_uint64(db, "client_udf_error", ns->n_client_udf_error);
5390 info_append_uint64(db, "client_udf_timeout", ns->n_client_udf_timeout);
5391 info_append_uint64(db, "client_udf_filtered_out", ns->n_client_udf_filtered_out);
5392
5393 info_append_uint64(db, "client_lang_read_success", ns->n_client_lang_read_success);
5394 info_append_uint64(db, "client_lang_write_success", ns->n_client_lang_write_success);
5395 info_append_uint64(db, "client_lang_delete_success", ns->n_client_lang_delete_success);
5396 info_append_uint64(db, "client_lang_error", ns->n_client_lang_error);
5397
5398 // From-proxy transaction stats.
5399
5400 info_append_uint64(db, "from_proxy_tsvc_error", ns->n_from_proxy_tsvc_error);
5401 info_append_uint64(db, "from_proxy_tsvc_timeout", ns->n_from_proxy_tsvc_timeout);
5402
5403 info_append_uint64(db, "from_proxy_read_success", ns->n_from_proxy_read_success);
5404 info_append_uint64(db, "from_proxy_read_error", ns->n_from_proxy_read_error);
5405 info_append_uint64(db, "from_proxy_read_timeout", ns->n_from_proxy_read_timeout);
5406 info_append_uint64(db, "from_proxy_read_not_found", ns->n_from_proxy_read_not_found);
5407 info_append_uint64(db, "from_proxy_read_filtered_out", ns->n_from_proxy_read_filtered_out);
5408
5409 info_append_uint64(db, "from_proxy_write_success", ns->n_from_proxy_write_success);
5410 info_append_uint64(db, "from_proxy_write_error", ns->n_from_proxy_write_error);
5411 info_append_uint64(db, "from_proxy_write_timeout", ns->n_from_proxy_write_timeout);
5412 info_append_uint64(db, "from_proxy_write_filtered_out", ns->n_from_proxy_write_filtered_out);
5413
5414 // Subset of n_from_proxy_write_... above, respectively.
5415 info_append_uint64(db, "xdr_from_proxy_write_success", ns->n_xdr_from_proxy_write_success);
5416 info_append_uint64(db, "xdr_from_proxy_write_error", ns->n_xdr_from_proxy_write_error);
5417 info_append_uint64(db, "xdr_from_proxy_write_timeout", ns->n_xdr_from_proxy_write_timeout);
5418
5419 info_append_uint64(db, "from_proxy_delete_success", ns->n_from_proxy_delete_success);
5420 info_append_uint64(db, "from_proxy_delete_error", ns->n_from_proxy_delete_error);
5421 info_append_uint64(db, "from_proxy_delete_timeout", ns->n_from_proxy_delete_timeout);
5422 info_append_uint64(db, "from_proxy_delete_not_found", ns->n_from_proxy_delete_not_found);
5423 info_append_uint64(db, "from_proxy_delete_filtered_out", ns->n_from_proxy_delete_filtered_out);
5424
5425 // Subset of n_from_proxy_delete_... above, respectively.
5426 info_append_uint64(db, "xdr_from_proxy_delete_success", ns->n_xdr_from_proxy_delete_success);
5427 info_append_uint64(db, "xdr_from_proxy_delete_error", ns->n_xdr_from_proxy_delete_error);
5428 info_append_uint64(db, "xdr_from_proxy_delete_timeout", ns->n_xdr_from_proxy_delete_timeout);
5429 info_append_uint64(db, "xdr_from_proxy_delete_not_found", ns->n_xdr_from_proxy_delete_not_found);
5430
5431 info_append_uint64(db, "from_proxy_udf_complete", ns->n_from_proxy_udf_complete);
5432 info_append_uint64(db, "from_proxy_udf_error", ns->n_from_proxy_udf_error);
5433 info_append_uint64(db, "from_proxy_udf_timeout", ns->n_from_proxy_udf_timeout);
5434 info_append_uint64(db, "from_proxy_udf_filtered_out", ns->n_from_proxy_udf_filtered_out);
5435
5436 info_append_uint64(db, "from_proxy_lang_read_success", ns->n_from_proxy_lang_read_success);
5437 info_append_uint64(db, "from_proxy_lang_write_success", ns->n_from_proxy_lang_write_success);
5438 info_append_uint64(db, "from_proxy_lang_delete_success", ns->n_from_proxy_lang_delete_success);
5439 info_append_uint64(db, "from_proxy_lang_error", ns->n_from_proxy_lang_error);
5440
5441 // Batch sub-transaction stats.
5442
5443 info_append_uint64(db, "batch_sub_tsvc_error", ns->n_batch_sub_tsvc_error);
5444 info_append_uint64(db, "batch_sub_tsvc_timeout", ns->n_batch_sub_tsvc_timeout);
5445
5446 info_append_uint64(db, "batch_sub_proxy_complete", ns->n_batch_sub_proxy_complete);
5447 info_append_uint64(db, "batch_sub_proxy_error", ns->n_batch_sub_proxy_error);
5448 info_append_uint64(db, "batch_sub_proxy_timeout", ns->n_batch_sub_proxy_timeout);
5449
5450 info_append_uint64(db, "batch_sub_read_success", ns->n_batch_sub_read_success);
5451 info_append_uint64(db, "batch_sub_read_error", ns->n_batch_sub_read_error);
5452 info_append_uint64(db, "batch_sub_read_timeout", ns->n_batch_sub_read_timeout);
5453 info_append_uint64(db, "batch_sub_read_not_found", ns->n_batch_sub_read_not_found);
5454 info_append_uint64(db, "batch_sub_read_filtered_out", ns->n_batch_sub_read_filtered_out);
5455
5456 // From-proxy batch sub-transaction stats.
5457
5458 info_append_uint64(db, "from_proxy_batch_sub_tsvc_error", ns->n_from_proxy_batch_sub_tsvc_error);
5459 info_append_uint64(db, "from_proxy_batch_sub_tsvc_timeout", ns->n_from_proxy_batch_sub_tsvc_timeout);
5460
5461 info_append_uint64(db, "from_proxy_batch_sub_read_success", ns->n_from_proxy_batch_sub_read_success);
5462 info_append_uint64(db, "from_proxy_batch_sub_read_error", ns->n_from_proxy_batch_sub_read_error);
5463 info_append_uint64(db, "from_proxy_batch_sub_read_timeout", ns->n_from_proxy_batch_sub_read_timeout);
5464 info_append_uint64(db, "from_proxy_batch_sub_read_not_found", ns->n_from_proxy_batch_sub_read_not_found);
5465 info_append_uint64(db, "from_proxy_batch_sub_read_filtered_out", ns->n_from_proxy_batch_sub_read_filtered_out);
5466
5467 // Internal-UDF sub-transaction stats.
5468
5469 info_append_uint64(db, "udf_sub_tsvc_error", ns->n_udf_sub_tsvc_error);
5470 info_append_uint64(db, "udf_sub_tsvc_timeout", ns->n_udf_sub_tsvc_timeout);
5471
5472 info_append_uint64(db, "udf_sub_udf_complete", ns->n_udf_sub_udf_complete);
5473 info_append_uint64(db, "udf_sub_udf_error", ns->n_udf_sub_udf_error);
5474 info_append_uint64(db, "udf_sub_udf_timeout", ns->n_udf_sub_udf_timeout);
5475 info_append_uint64(db, "udf_sub_udf_filtered_out", ns->n_udf_sub_udf_filtered_out);
5476
5477 info_append_uint64(db, "udf_sub_lang_read_success", ns->n_udf_sub_lang_read_success);
5478 info_append_uint64(db, "udf_sub_lang_write_success", ns->n_udf_sub_lang_write_success);
5479 info_append_uint64(db, "udf_sub_lang_delete_success", ns->n_udf_sub_lang_delete_success);
5480 info_append_uint64(db, "udf_sub_lang_error", ns->n_udf_sub_lang_error);
5481
5482 // Internal-ops sub-transaction stats.
5483
5484 info_append_uint64(db, "ops_sub_tsvc_error", ns->n_ops_sub_tsvc_error);
5485 info_append_uint64(db, "ops_sub_tsvc_timeout", ns->n_ops_sub_tsvc_timeout);
5486
5487 info_append_uint64(db, "ops_sub_write_success", ns->n_ops_sub_write_success);
5488 info_append_uint64(db, "ops_sub_write_error", ns->n_ops_sub_write_error);
5489 info_append_uint64(db, "ops_sub_write_timeout", ns->n_ops_sub_write_timeout);
5490 info_append_uint64(db, "ops_sub_write_filtered_out", ns->n_ops_sub_write_filtered_out);
5491
5492 // Transaction retransmit stats - 'all' means both client & proxy origins.
5493
5494 info_append_uint64(db, "retransmit_all_read_dup_res", ns->n_retransmit_all_read_dup_res);
5495
5496 info_append_uint64(db, "retransmit_all_write_dup_res", ns->n_retransmit_all_write_dup_res);
5497 info_append_uint64(db, "retransmit_all_write_repl_write", ns->n_retransmit_all_write_repl_write);
5498
5499 info_append_uint64(db, "retransmit_all_delete_dup_res", ns->n_retransmit_all_delete_dup_res);
5500 info_append_uint64(db, "retransmit_all_delete_repl_write", ns->n_retransmit_all_delete_repl_write);
5501
5502 info_append_uint64(db, "retransmit_all_udf_dup_res", ns->n_retransmit_all_udf_dup_res);
5503 info_append_uint64(db, "retransmit_all_udf_repl_write", ns->n_retransmit_all_udf_repl_write);
5504
5505 info_append_uint64(db, "retransmit_all_batch_sub_dup_res", ns->n_retransmit_all_batch_sub_dup_res);
5506
5507 info_append_uint64(db, "retransmit_udf_sub_dup_res", ns->n_retransmit_udf_sub_dup_res);
5508 info_append_uint64(db, "retransmit_udf_sub_repl_write", ns->n_retransmit_udf_sub_repl_write);
5509
5510 info_append_uint64(db, "retransmit_ops_sub_dup_res", ns->n_retransmit_ops_sub_dup_res);
5511 info_append_uint64(db, "retransmit_ops_sub_repl_write", ns->n_retransmit_ops_sub_repl_write);
5512
5513 // Scan stats.
5514
5515 info_append_uint64(db, "scan_basic_complete", ns->n_scan_basic_complete);
5516 info_append_uint64(db, "scan_basic_error", ns->n_scan_basic_error);
5517 info_append_uint64(db, "scan_basic_abort", ns->n_scan_basic_abort);
5518
5519 info_append_uint64(db, "scan_aggr_complete", ns->n_scan_aggr_complete);
5520 info_append_uint64(db, "scan_aggr_error", ns->n_scan_aggr_error);
5521 info_append_uint64(db, "scan_aggr_abort", ns->n_scan_aggr_abort);
5522
5523 info_append_uint64(db, "scan_udf_bg_complete", ns->n_scan_udf_bg_complete);
5524 info_append_uint64(db, "scan_udf_bg_error", ns->n_scan_udf_bg_error);
5525 info_append_uint64(db, "scan_udf_bg_abort", ns->n_scan_udf_bg_abort);
5526
5527 info_append_uint64(db, "scan_ops_bg_complete", ns->n_scan_ops_bg_complete);
5528 info_append_uint64(db, "scan_ops_bg_error", ns->n_scan_ops_bg_error);
5529 info_append_uint64(db, "scan_ops_bg_abort", ns->n_scan_ops_bg_abort);
5530
5531 // Query stats.
5532
5533 uint64_t agg = ns->n_aggregation;
5534 uint64_t agg_success = ns->n_agg_success;
5535 uint64_t agg_err = ns->n_agg_errs;
5536 uint64_t agg_abort = ns->n_agg_abort;
5537 uint64_t agg_records = ns->agg_num_records;
5538
5539 uint64_t lkup = ns->n_lookup;
5540 uint64_t lkup_success = ns->n_lookup_success;
5541 uint64_t lkup_err = ns->n_lookup_errs;
5542 uint64_t lkup_abort = ns->n_lookup_abort;
5543 uint64_t lkup_records = ns->lookup_num_records;
5544
5545 info_append_uint64(db, "query_reqs", ns->query_reqs);
5546 info_append_uint64(db, "query_fail", ns->query_fail);
5547
5548 info_append_uint64(db, "query_short_queue_full", ns->query_short_queue_full);
5549 info_append_uint64(db, "query_long_queue_full", ns->query_long_queue_full);
5550 info_append_uint64(db, "query_short_reqs", ns->query_short_reqs);
5551 info_append_uint64(db, "query_long_reqs", ns->query_long_reqs);
5552
5553 info_append_uint64(db, "query_agg", agg);
5554 info_append_uint64(db, "query_agg_success", agg_success);
5555 info_append_uint64(db, "query_agg_error", agg_err);
5556 info_append_uint64(db, "query_agg_abort", agg_abort);
5557 info_append_uint64(db, "query_agg_avg_rec_count", agg ? agg_records / agg : 0);
5558
5559 info_append_uint64(db, "query_lookups", lkup);
5560 info_append_uint64(db, "query_lookup_success", lkup_success);
5561 info_append_uint64(db, "query_lookup_error", lkup_err);
5562 info_append_uint64(db, "query_lookup_abort", lkup_abort);
5563 info_append_uint64(db, "query_lookup_avg_rec_count", lkup ? lkup_records / lkup : 0);
5564
5565 info_append_uint64(db, "query_udf_bg_success", ns->n_query_udf_bg_success);
5566 info_append_uint64(db, "query_udf_bg_failure", ns->n_query_udf_bg_failure);
5567
5568 info_append_uint64(db, "query_ops_bg_success", ns->n_query_ops_bg_success);
5569 info_append_uint64(db, "query_ops_bg_failure", ns->n_query_ops_bg_failure);
5570
5571 // Geospatial query stats:
5572 info_append_uint64(db, "geo_region_query_reqs", ns->geo_region_query_count);
5573 info_append_uint64(db, "geo_region_query_cells", ns->geo_region_query_cells);
5574 info_append_uint64(db, "geo_region_query_points", ns->geo_region_query_points);
5575 info_append_uint64(db, "geo_region_query_falsepos", ns->geo_region_query_falsepos);
5576
5577 // Re-replication stats - relevant only for enterprise edition.
5578
5579 info_append_uint64(db, "re_repl_success", ns->n_re_repl_success);
5580 info_append_uint64(db, "re_repl_error", ns->n_re_repl_error);
5581 info_append_uint64(db, "re_repl_timeout", ns->n_re_repl_timeout);
5582
5583 // Special errors that deserve their own counters:
5584
5585 info_append_uint64(db, "fail_xdr_forbidden", ns->n_fail_xdr_forbidden);
5586 info_append_uint64(db, "fail_key_busy", ns->n_fail_key_busy);
5587 info_append_uint64(db, "fail_generation", ns->n_fail_generation);
5588 info_append_uint64(db, "fail_record_too_big", ns->n_fail_record_too_big);
5589
5590 // Special non-error counters:
5591
5592 info_append_uint64(db, "deleted_last_bin", ns->n_deleted_last_bin);
5593}
5594
5595//
5596// Iterate through the current namespace list and cons up a string
5597//
5598
5599int
5600info_get_tree_namespace(char *name, char *subtree, cf_dyn_buf *db)
5601{
5602 as_namespace *ns = as_namespace_get_byname(subtree);
5603
5604 if (! ns) {
5605 cf_dyn_buf_append_string(db, "type=unknown"); // TODO - better message?
5606 return 0;
5607 }
5608
5609 info_get_namespace_info(ns, db);
5610 info_namespace_config_get(ns->name, db);
5611
5612 cf_dyn_buf_chomp(db);
5613
5614 return 0;
5615}
5616
5617int
5618info_get_tree_sets(char *name, char *subtree, cf_dyn_buf *db)
5619{
5620 char *set_name = NULL;
5621 as_namespace *ns = NULL;
5622
5623 // if there is a subtree, get the namespace
5624 if (subtree && strlen(subtree) > 0) {
5625 // see if subtree has a sep as well
5626 set_name = strchr(subtree, TREE_SEP);
5627
5628 // pull out namespace, and namespace name...
5629 if (set_name) {
5630 int ns_name_len = (set_name - subtree);
5631 char ns_name[ns_name_len + 1];
5632 memcpy(ns_name, subtree, ns_name_len);
5633 ns_name[ns_name_len] = '\0';
5634 ns = as_namespace_get_byname(ns_name);
5635 set_name++; // currently points to the TREE_SEP, which is not what we want.
5636 }
5637 else {
5638 ns = as_namespace_get_byname(subtree);
5639 }
5640
5641 if (!ns) {
5642 cf_dyn_buf_append_string(db, "ns_type=unknown");
5643 return(0);
5644 }
5645 }
5646
5647 // format w/o namespace is ns1:set1:prop1=val1:prop2=val2:..propn=valn;ns1:set2...;ns2:set1...;
5648 if (!ns) {
5649 for (uint32_t i = 0; i < g_config.n_namespaces; i++) {
5650 as_namespace_get_set_info(g_config.namespaces[i], set_name, db);
5651 }
5652 }
5653 // format w namespace w/o set name is ns:set1:prop1=val1:prop2=val2...propn=valn;ns:set2...;
5654 // format w namespace & set name is prop1=val1:prop2=val2...propn=valn;
5655 else {
5656 as_namespace_get_set_info(ns, set_name, db);
5657 }
5658 return(0);
5659}
5660
5661int
5662info_get_tree_statistics(char *name, char *subtree, cf_dyn_buf *db)
5663{
5664 if (strcmp(subtree, "xdr") == 0) {
5665 as_xdr_get_stats(db);
5666 cf_dyn_buf_chomp(db);
5667 return 0;
5668 }
5669
5670 cf_dyn_buf_append_string(db, "error");
5671 return -1;
5672}
5673
5674int
5675info_get_tree_bins(char *name, char *subtree, cf_dyn_buf *db)
5676{
5677 as_namespace *ns = NULL;
5678
5679 // if there is a subtree, get the namespace
5680 if (subtree && strlen(subtree) > 0) {
5681 ns = as_namespace_get_byname(subtree);
5682
5683 if (!ns) {
5684 cf_dyn_buf_append_string(db, "ns_type=unknown");
5685 return 0;
5686 }
5687 }
5688
5689 // format w/o namespace is
5690 // ns:num-bin-names=val1,bin-names-quota=val2,name1,name2,...;ns:...
5691 if (!ns) {
5692 for (uint32_t i = 0; i < g_config.n_namespaces; i++) {
5693 as_namespace_get_bins_info(g_config.namespaces[i], db, true);
5694 }
5695 }
5696 // format w/namespace is
5697 // num-bin-names=val1,bin-names-quota=val2,name1,name2,...
5698 else {
5699 as_namespace_get_bins_info(ns, db, false);
5700 }
5701
5702 return 0;
5703}
5704
5705int
5706info_command_histogram(char *name, char *params, cf_dyn_buf *db)
5707{
5708 char value_str[128];
5709 int value_str_len = sizeof(value_str);
5710
5711 if (0 != as_info_parameter_get(params, "namespace", value_str, &value_str_len)) {
5712 cf_info(AS_INFO, "histogram %s command: no namespace specified", name);
5713 cf_dyn_buf_append_string(db, "error-no-namespace");
5714 return 0;
5715 }
5716
5717 as_namespace *ns = as_namespace_get_byname(value_str);
5718
5719 if (!ns) {
5720 cf_info(AS_INFO, "histogram %s command: unknown namespace: %s", name, value_str);
5721 cf_dyn_buf_append_string(db, "error-unknown-namespace");
5722 return 0;
5723 }
5724
5725 value_str_len = sizeof(value_str);
5726
5727 if (0 != as_info_parameter_get(params, "type", value_str, &value_str_len)) {
5728 cf_info(AS_INFO, "histogram %s command:", name);
5729 cf_dyn_buf_append_string(db, "error-no-histogram-specified");
5730
5731 return 0;
5732 }
5733
5734 // get optional set field
5735 char set_name_str[AS_SET_NAME_MAX_SIZE];
5736 int set_name_str_len = sizeof(set_name_str);
5737 set_name_str[0] = 0;
5738
5739 if (as_info_parameter_get(params, "set", set_name_str, &set_name_str_len) == -2) {
5740 cf_warning(AS_INFO, "set name too long");
5741 cf_dyn_buf_append_string(db, "ERROR::bad-set-name");
5742 return 0;
5743 }
5744
5745 as_namespace_get_hist_info(ns, set_name_str, value_str, db);
5746
5747 return 0;
5748}
5749
5750
5751int
5752info_get_tree_log(char *name, char *subtree, cf_dyn_buf *db)
5753{
5754 // see if subtree has a sep as well
5755 int sink_id;
5756 char *context = strchr(subtree, TREE_SEP);
5757 if (context) { // this means: log/id/context ,
5758 *context = 0;
5759 context++;
5760
5761 if (0 != cf_str_atoi(subtree, &sink_id)) return(-1);
5762
5763 cf_fault_sink_context_strlist(sink_id, context, db);
5764 }
5765 else { // this means just: log/id , so get all contexts
5766 if (0 != cf_str_atoi(subtree, &sink_id)) return(-1);
5767
5768 cf_fault_sink_context_all_strlist(sink_id, db);
5769 }
5770
5771 return(0);
5772}
5773
5774
5775int
5776info_get_tree_sindexes(char *name, char *subtree, cf_dyn_buf *db)
5777{
5778 char *index_name = NULL;
5779 as_namespace *ns = NULL;
5780
5781 // if there is a subtree, get the namespace
5782 if (subtree && strlen(subtree) > 0) {
5783 // see if subtree has a sep as well
5784 index_name = strchr(subtree, TREE_SEP);
5785
5786 // pull out namespace, and namespace name...
5787 if (index_name) {
5788 int ns_name_len = (index_name - subtree);
5789 char ns_name[ns_name_len + 1];
5790 memcpy(ns_name, subtree, ns_name_len);
5791 ns_name[ns_name_len] = '\0';
5792 ns = as_namespace_get_byname(ns_name);
5793 index_name++; // currently points to the TREE_SEP, which is not what we want.
5794 }
5795 else {
5796 ns = as_namespace_get_byname(subtree);
5797 }
5798
5799 if (!ns) {
5800 cf_dyn_buf_append_string(db, "ns_type=unknown");
5801 return(0);
5802 }
5803 }
5804
5805 // format w/o namespace is:
5806 // ns=ns1:set=set1:indexname=index1:prop1=val1:...:propn=valn;ns=ns1:set=set2:indexname=index2:...;ns=ns2:set=set1:...;
5807 if (!ns) {
5808 for (uint32_t i = 0; i < g_config.n_namespaces; i++) {
5809 as_sindex_list_str(g_config.namespaces[i], db);
5810 }
5811 }
5812 // format w namespace w/o index name is:
5813 // ns=ns1:set=set1:indexname=index1:prop1=val1:...:propn=valn;ns=ns1:set=set2:indexname=indexname2:...;
5814 else if (!index_name) {
5815 as_sindex_list_str(ns, db);
5816 }
5817 else {
5818 // format w namespace & index name is:
5819 // prop1=val1;prop2=val2;...;propn=valn
5820 int resp = as_sindex_stats_str(ns, index_name, db);
5821 if (resp) {
5822 cf_warning(AS_INFO, "Failed to get statistics for index %s: err = %d", index_name, resp);
5823 INFO_COMMAND_SINDEX_FAILCODE(
5824 as_sindex_err_to_clienterr(resp, __FILE__, __LINE__),
5825 as_sindex_err_str(resp));
5826 }
5827 }
5828 return(0);
5829}
5830
5831// SINDEX wire protocol examples:
5832// 1.) NUMERIC: sindex-create:ns=usermap;set=demo;indexname=um_age;indexdata=age,numeric
5833// 2.) STRING: sindex-create:ns=usermap;set=demo;indexname=um_state;indexdata=state,string
5834/*
5835 * Parameters:
5836 * params --- string passed to asinfo call
5837 * imd -- parses the params and fills this sindex struct.
5838 *
5839 * Returns
5840 * AS_SINDEX_OK if it successfully fills up imd
5841 * AS_SINDEX_ERR_PARAM otherwise
5842 * TODO REVIEW : send cmd as argument
5843 */
5844int
5845as_info_parse_params_to_sindex_imd(char* params, as_sindex_metadata *imd, cf_dyn_buf* db,
5846 bool is_create, bool *is_smd_op, char * OP)
5847{
5848 if (! imd) {
5849 cf_warning(AS_INFO, "%s : Failed. internal error.", OP);
5850 return AS_SINDEX_ERR_PARAM;
5851 }
5852
5853 char indexname_str[AS_ID_INAME_SZ];
5854 int indname_len = sizeof(indexname_str);
5855 int ret = as_info_parameter_get(params, STR_INDEXNAME, indexname_str,
5856 &indname_len);
5857 if ( ret == -1 ) {
5858 cf_warning(AS_INFO, "%s : Failed. Missing Index name.", OP);
5859 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Missing Index name");
5860 return AS_SINDEX_ERR_PARAM;
5861 }
5862 else if ( ret == -2 ) {
5863 cf_warning(AS_INFO, "%s : Failed. Index name longer than allowed %d.",
5864 OP, AS_ID_INAME_SZ-1);
5865 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Index name too long");
5866 return AS_SINDEX_ERR_PARAM;
5867 }
5868
5869 char cmd[512];
5870 sprintf(cmd, "%s %s", OP, indexname_str);
5871
5872 char ns_str[AS_ID_NAMESPACE_SZ];
5873 int ns_len = sizeof(ns_str);
5874 ret = as_info_parameter_get(params, STR_NS, ns_str, &ns_len);
5875 if ( ret == -1 ) {
5876 cf_warning(AS_INFO, "%s : Failed. Missing Namespace name.", cmd);
5877 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
5878 "Missing Namespace name");
5879 return AS_SINDEX_ERR_PARAM;
5880 }
5881 else if (ret == -2 ) {
5882 cf_warning(AS_INFO, "%s : Failed. Namespace name longer than allowed %d.",
5883 cmd, AS_ID_NAMESPACE_SZ - 1);
5884 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
5885 "Namespace name too long");
5886 return AS_SINDEX_ERR_PARAM;
5887 }
5888
5889 as_namespace *ns = as_namespace_get_byname(ns_str);
5890 if (! ns) {
5891 cf_warning(AS_INFO, "%s : Failed. Namespace '%s' not found %d",
5892 cmd, ns_str, ns_len);
5893 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Namespace Not Found");
5894 return AS_SINDEX_ERR_PARAM;
5895 }
5896 if (ns->single_bin) {
5897 cf_warning(AS_INFO, "%s : Failed. Secondary Index is not allowed on single bin "
5898 "namespace '%s'.", cmd, ns_str);
5899 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Single bin namespace");
5900 return AS_SINDEX_ERR_PARAM;
5901 }
5902
5903 char set_str[AS_SET_NAME_MAX_SIZE];
5904 int set_len = sizeof(set_str);
5905 if (imd->set) {
5906 cf_free(imd->set);
5907 imd->set = NULL;
5908 }
5909 ret = as_info_parameter_get(params, STR_SET, set_str, &set_len);
5910 if (!ret && set_len != 0) {
5911 if (as_namespace_get_create_set_w_len(ns, set_str, set_len, NULL, NULL)
5912 != 0) {
5913 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
5914 "Set name quota full");
5915 return AS_SINDEX_ERR_PARAM;
5916 }
5917 imd->set = cf_strdup(set_str);
5918 } else if (ret == -2) {
5919 cf_warning(AS_INFO, "%s : Failed. Setname longer than %d for index.",
5920 cmd, AS_SET_NAME_MAX_SIZE - 1);
5921 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Set name too long");
5922 return AS_SINDEX_ERR_PARAM;
5923 }
5924
5925 char cluster_op[6];
5926 int cluster_op_len = sizeof(cluster_op);
5927 if (as_info_parameter_get(params, "cluster_op", cluster_op, &cluster_op_len)
5928 != 0) {
5929 *is_smd_op = true;
5930 }
5931 else if (strcmp(cluster_op, "true") == 0) {
5932 *is_smd_op = true;
5933 }
5934 else if (strcmp(cluster_op, "false") == 0) {
5935 *is_smd_op = false;
5936 }
5937
5938 // Delete only need parsing till here
5939 if (!is_create) {
5940 imd->ns_name = cf_strdup(ns->name);
5941 imd->iname = cf_strdup(indexname_str);
5942 return 0;
5943 }
5944
5945 char indextype_str[AS_SINDEX_TYPE_STR_SIZE];
5946 int indtype_len = sizeof(indextype_str);
5947 ret = as_info_parameter_get(params, STR_ITYPE, indextype_str, &indtype_len);
5948 if (ret == -1) {
5949 // if not specified the index type is DEFAULT
5950 imd->itype = AS_SINDEX_ITYPE_DEFAULT;
5951 }
5952 else if (ret == -2) {
5953 cf_warning(AS_INFO, "%s : Failed. Indextype str longer than allowed %d.",
5954 cmd, AS_SINDEX_TYPE_STR_SIZE-1);
5955 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Indextype is too long");
5956 return AS_SINDEX_ERR_PARAM;
5957
5958 }
5959 else {
5960 if (strncasecmp(indextype_str, STR_ITYPE_DEFAULT, 7) == 0) {
5961 imd->itype = AS_SINDEX_ITYPE_DEFAULT;
5962 }
5963 else if (strncasecmp(indextype_str, STR_ITYPE_LIST, 4) == 0) {
5964 imd->itype = AS_SINDEX_ITYPE_LIST;
5965 }
5966 else if (strncasecmp(indextype_str, STR_ITYPE_MAPKEYS, 7) == 0) {
5967 imd->itype = AS_SINDEX_ITYPE_MAPKEYS;
5968 }
5969 else if (strncasecmp(indextype_str, STR_ITYPE_MAPVALUES, 9) == 0) {
5970 imd->itype = AS_SINDEX_ITYPE_MAPVALUES;
5971 }
5972 else {
5973 cf_warning(AS_INFO, "%s : Failed. Invalid indextype '%s'.", cmd,
5974 indextype_str);
5975 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
5976 "Invalid indextype. Should be one of [DEFAULT, LIST, MAPKEYS, MAPVALUES]");
5977 return AS_SINDEX_ERR_PARAM;
5978 }
5979 }
5980
5981 // Indexdata = binpath,keytype
5982 char indexdata_str[AS_SINDEXDATA_STR_SIZE];
5983 int indexdata_len = sizeof(indexdata_str);
5984 if (as_info_parameter_get(params, STR_INDEXDATA, indexdata_str,
5985 &indexdata_len)) {
5986 cf_warning(AS_INFO, "%s : Failed. Invalid indexdata '%s'.", cmd,
5987 indexdata_str);
5988 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Invalid indexdata");
5989 return AS_SINDEX_ERR_PARAM;
5990 }
5991
5992 cf_vector *str_v = cf_vector_create(sizeof(void *), 10, VECTOR_FLAG_INITZERO);
5993 cf_str_split(",", indexdata_str, str_v);
5994 if ((cf_vector_size(str_v)) > 2) {
5995 cf_warning(AS_INFO, "%s : Failed. >1 bins specified in indexdata.",
5996 cmd);
5997 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
5998 "Number of bins more than 1");
5999 cf_vector_destroy(str_v);
6000 return AS_SINDEX_ERR_PARAM;
6001 }
6002
6003 char *path_str = NULL;
6004 cf_vector_get(str_v, 0, &path_str);
6005 if (! path_str) {
6006 cf_warning(AS_INFO, "%s : Failed. Missing Bin Name.", cmd);
6007 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Missing Bin name");
6008 cf_vector_destroy(str_v);
6009 return AS_SINDEX_ERR_PARAM;
6010 }
6011
6012 if (as_sindex_extract_bin_path(imd, path_str)
6013 || ! imd->bname) {
6014 cf_warning(AS_INFO, "%s : Failed. Invalid Bin Path '%s'.", cmd, path_str);
6015 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Invalid Bin path");
6016 cf_vector_destroy(str_v);
6017 return AS_SINDEX_ERR_PARAM;
6018 }
6019
6020 if (imd->bname && strlen(imd->bname) >= AS_BIN_NAME_MAX_SZ) {
6021 cf_warning(AS_INFO, "%s : Failed. Bin Name longer than allowed %d",
6022 cmd, AS_BIN_NAME_MAX_SZ - 1);
6023 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Bin Name too long");
6024 cf_vector_destroy(str_v);
6025 return AS_SINDEX_ERR_PARAM;
6026 }
6027
6028 char *type_str = NULL;
6029 cf_vector_get(str_v, 1, &type_str);
6030 if (! type_str) {
6031 cf_warning(AS_INFO, "%s : Failed. Missing Bin type", cmd);
6032 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Missing Bin Type.");
6033 cf_vector_destroy(str_v);
6034 return AS_SINDEX_ERR_PARAM;
6035 }
6036
6037 as_sindex_ktype ktype = as_sindex_ktype_from_string(type_str);
6038 if (ktype == COL_TYPE_INVALID) {
6039 cf_warning(AS_INFO, "%s : Failed. Invalid Bin type '%s'.", cmd, type_str);
6040 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
6041 "Invalid Bin type. Supported types [Numeric, String, Geo2dsphere]");
6042 cf_vector_destroy(str_v);
6043 return AS_SINDEX_ERR_PARAM;
6044 }
6045 imd->sktype = ktype;
6046
6047
6048
6049 cf_vector_destroy(str_v);
6050
6051 if (is_create) {
6052 imd->ns_name = cf_strdup(ns->name);
6053 imd->iname = cf_strdup(indexname_str);
6054 }
6055 imd->path_str = cf_strdup(path_str);
6056 return AS_SINDEX_OK;
6057}
6058
6059int info_command_sindex_create(char *name, char *params, cf_dyn_buf *db)
6060{
6061 as_sindex_metadata imd;
6062 memset((void *)&imd, 0, sizeof(imd));
6063 bool is_smd_op = true;
6064
6065 // Check info-command params for correctness.
6066 int res = as_info_parse_params_to_sindex_imd(params, &imd, db, true, &is_smd_op, "SINDEX CREATE");
6067
6068 if (res != 0) {
6069 goto ERR;
6070 }
6071
6072 as_namespace *ns = as_namespace_get_byname(imd.ns_name);
6073 res = as_sindex_create_check_params(ns, &imd);
6074
6075 if (res == AS_SINDEX_ERR_FOUND) {
6076 cf_warning(AS_INFO, "SINDEX CREATE: Index already exists on namespace '%s', either with same name '%s' or same bin '%s' / type '%s' combination.",
6077 imd.ns_name, imd.iname, imd.bname,
6078 as_sindex_ktype_str(imd.sktype));
6079 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_SINDEX_FOUND,
6080 "Index with the same name already exists or this bin has already been indexed.");
6081 goto ERR;
6082 }
6083 else if (res == AS_SINDEX_ERR_MAXCOUNT) {
6084 cf_warning(AS_INFO, "SINDEX CREATE : More than %d index are not allowed per namespace.", AS_SINDEX_MAX);
6085 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_SINDEX_MAX_COUNT,
6086 "Reached maximum number of sindex allowed");
6087 goto ERR;
6088 }
6089
6090 if (is_smd_op == true)
6091 {
6092 cf_info(AS_INFO, "SINDEX CREATE : Request received for %s:%s via SMD", imd.ns_name, imd.iname);
6093
6094 char smd_key[SINDEX_SMD_KEY_SIZE];
6095
6096 as_sindex_imd_to_smd_key(&imd, smd_key);
6097
6098 if (! as_smd_set_blocking(AS_SMD_MODULE_SINDEX, smd_key, imd.iname, 0)) {
6099 cf_dyn_buf_append_string(db, "ERROR::timeout");
6100
6101 goto ERR;
6102 }
6103 }
6104 else if (is_smd_op == false) {
6105 cf_info(AS_INFO, "SINDEX CREATE : Request received for %s:%s via info", imd.ns_name, imd.iname);
6106 res = as_sindex_create(ns, &imd);
6107 if (0 != res) {
6108 cf_warning(AS_INFO, "SINDEX CREATE : Failed with error %s for index %s",
6109 as_sindex_err_str(res), imd.iname);
6110 INFO_COMMAND_SINDEX_FAILCODE(as_sindex_err_to_clienterr(res, __FILE__, __LINE__),
6111 as_sindex_err_str(res));
6112 goto ERR;
6113 }
6114 }
6115 cf_dyn_buf_append_string(db, "OK");
6116ERR:
6117 as_sindex_imd_free(&imd);
6118 return(0);
6119
6120}
6121
6122int info_command_sindex_delete(char *name, char *params, cf_dyn_buf *db) {
6123 as_sindex_metadata imd;
6124 memset((void *)&imd, 0, sizeof(imd));
6125 bool is_smd_op = true;
6126 int res = as_info_parse_params_to_sindex_imd(params, &imd, db, false, &is_smd_op, "SINDEX DROP");
6127
6128 if (res != 0) {
6129 goto ERR;
6130 }
6131
6132 as_namespace *ns = as_namespace_get_byname(imd.ns_name);
6133
6134 // Do not use as_sindex_exists_by_defn() here, it'll fail because bname is null.
6135 if (!as_sindex_delete_checker(ns, &imd)) {
6136 cf_warning(AS_INFO, "SINDEX DROP : Index %s:%s does not exist on the system",
6137 imd.ns_name, imd.iname);
6138 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_SINDEX_NOT_FOUND,
6139 "Index does not exist on the system.");
6140 goto ERR;
6141 }
6142
6143 if (is_smd_op == true)
6144 {
6145 cf_info(AS_INFO, "SINDEX DROP : Request received for %s:%s via SMD", imd.ns_name, imd.iname);
6146
6147 char smd_key[SINDEX_SMD_KEY_SIZE];
6148
6149 if (as_sindex_delete_imd_to_smd_key(ns, &imd, smd_key)) {
6150 if (! as_smd_delete_blocking(AS_SMD_MODULE_SINDEX, smd_key, 0)) {
6151 cf_dyn_buf_append_string(db, "ERROR::timeout");
6152
6153 goto ERR;
6154 }
6155 }
6156 else {
6157 res = AS_SINDEX_ERR_NOTFOUND;
6158 }
6159
6160 if (0 != res) {
6161 cf_warning(AS_INFO, "SINDEX DROP : Queuing the index %s metadata to SMD failed with error %s",
6162 imd.iname, as_sindex_err_str(res));
6163 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, as_sindex_err_str(res));
6164 goto ERR;
6165 }
6166 }
6167 else if(is_smd_op == false)
6168 {
6169 cf_info(AS_INFO, "SINDEX DROP : Request received for %s:%s via info", imd.ns_name, imd.iname);
6170 res = as_sindex_destroy(ns, &imd);
6171 if (0 != res) {
6172 cf_warning(AS_INFO, "SINDEX DROP : Failed with error %s for index %s",
6173 as_sindex_err_str(res), imd.iname);
6174 INFO_COMMAND_SINDEX_FAILCODE(as_sindex_err_to_clienterr(res, __FILE__, __LINE__),
6175 as_sindex_err_str(res));
6176 goto ERR;
6177 }
6178 }
6179
6180 cf_dyn_buf_append_string(db, "OK");
6181ERR:
6182 as_sindex_imd_free(&imd);
6183 return 0;
6184}
6185
6186int
6187as_info_parse_ns_iname(char* params, as_namespace ** ns, char ** iname, cf_dyn_buf* db, char * sindex_cmd)
6188{
6189 char ns_str[AS_ID_NAMESPACE_SZ];
6190 int ns_len = sizeof(ns_str);
6191 int ret = 0;
6192
6193 ret = as_info_parameter_get(params, "ns", ns_str, &ns_len);
6194 if (ret) {
6195 if (ret == -2) {
6196 cf_warning(AS_INFO, "%s : namespace name exceeds max length %d",
6197 sindex_cmd, AS_ID_NAMESPACE_SZ);
6198 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
6199 "Namespace name exceeds max length");
6200 }
6201 else {
6202 cf_warning(AS_INFO, "%s : invalid namespace %s", sindex_cmd, ns_str);
6203 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
6204 "Namespace Not Specified");
6205 }
6206 return -1;
6207 }
6208
6209 *ns = as_namespace_get_byname(ns_str);
6210 if (!*ns) {
6211 cf_warning(AS_INFO, "%s : namespace %s not found", sindex_cmd, ns_str);
6212 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Namespace Not Found");
6213 return -1;
6214 }
6215
6216 // get indexname
6217 char index_name_str[AS_ID_INAME_SZ];
6218 int index_len = sizeof(index_name_str);
6219 ret = as_info_parameter_get(params, "indexname", index_name_str, &index_len);
6220 if (ret) {
6221 if (ret == -2) {
6222 cf_warning(AS_INFO, "%s : indexname exceeds max length %d", sindex_cmd, AS_ID_INAME_SZ);
6223 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
6224 "Index Name exceeds max length");
6225 }
6226 else {
6227 cf_warning(AS_INFO, "%s : invalid indexname %s", sindex_cmd, index_name_str);
6228 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER,
6229 "Index Name Not Specified");
6230 }
6231 return -1;
6232 }
6233
6234 cf_info(AS_SINDEX, "%s : received request on index %s - namespace %s",
6235 sindex_cmd, index_name_str, ns_str);
6236
6237 *iname = cf_strdup(index_name_str);
6238
6239 return 0;
6240}
6241
6242int info_command_abort_scan(char *name, char *params, cf_dyn_buf *db) {
6243 char context[100];
6244 int context_len = sizeof(context);
6245 int rv = -1;
6246 if (0 == as_info_parameter_get(params, "id", context, &context_len)) {
6247 uint64_t trid;
6248 trid = strtoull(context, NULL, 10);
6249 if (trid != 0) {
6250 rv = as_scan_abort(trid);
6251 }
6252 }
6253
6254 if (rv != 0) {
6255 cf_dyn_buf_append_string(db, "ERROR:");
6256 cf_dyn_buf_append_int(db, AS_ERR_NOT_FOUND);
6257 cf_dyn_buf_append_string(db, ":Transaction Not Found");
6258 }
6259 else {
6260 cf_dyn_buf_append_string(db, "OK");
6261 }
6262
6263 return 0;
6264}
6265
6266int info_command_abort_all_scans(char *name, char *params, cf_dyn_buf *db) {
6267
6268 int n_scans_killed = as_scan_abort_all();
6269
6270 cf_dyn_buf_append_string(db, "OK - number of scans killed: ");
6271 cf_dyn_buf_append_int(db, n_scans_killed);
6272
6273 return 0;
6274}
6275
6276int info_command_query_kill(char *name, char *params, cf_dyn_buf *db) {
6277 char context[100];
6278 int context_len = sizeof(context);
6279 int rv = AS_QUERY_ERR;
6280 if (0 == as_info_parameter_get(params, "trid", context, &context_len)) {
6281 uint64_t trid;
6282 trid = strtoull(context, NULL, 10);
6283 if (trid != 0) {
6284 rv = as_query_kill(trid);
6285 }
6286 }
6287
6288 if (AS_QUERY_OK != rv) {
6289 cf_dyn_buf_append_string(db, "Transaction Not Found");
6290 }
6291 else {
6292 cf_dyn_buf_append_string(db, "Ok");
6293 }
6294
6295 return 0;
6296
6297
6298
6299}
6300int info_command_sindex_stat(char *name, char *params, cf_dyn_buf *db) {
6301 as_namespace *ns = NULL;
6302 char * iname = NULL;
6303
6304 if (as_info_parse_ns_iname(params, &ns, &iname, db, "SINDEX STAT")) {
6305 return 0;
6306 }
6307
6308 int resp = as_sindex_stats_str(ns, iname, db);
6309 if (resp) {
6310 cf_warning(AS_INFO, "SINDEX STAT : for index %s - ns %s failed with error %d",
6311 iname, ns->name, resp);
6312 INFO_COMMAND_SINDEX_FAILCODE(
6313 as_sindex_err_to_clienterr(resp, __FILE__, __LINE__),
6314 as_sindex_err_str(resp));
6315 }
6316
6317 if (iname) {
6318 cf_free(iname);
6319 }
6320 return(0);
6321}
6322
6323
6324// sindex-histogram:ns=test_D;indexname=indname;enable=true/false
6325int info_command_sindex_histogram(char *name, char *params, cf_dyn_buf *db)
6326{
6327 as_namespace * ns = NULL;
6328 char * iname = NULL;
6329 if (as_info_parse_ns_iname(params, &ns, &iname, db, "SINDEX HISTOGRAM")) {
6330 return 0;
6331 }
6332
6333 char op[10];
6334 int op_len = sizeof(op);
6335
6336 if (as_info_parameter_get(params, "enable", op, &op_len)) {
6337 cf_info(AS_INFO, "SINDEX HISTOGRAM : invalid OP");
6338 cf_dyn_buf_append_string(db, "Invalid Op");
6339 goto END;
6340 }
6341
6342 bool enable = false;
6343 if (!strncmp(op, "true", 5) && op_len != 5) {
6344 enable = true;
6345 }
6346 else if (!strncmp(op, "false", 6) && op_len != 6) {
6347 enable = false;
6348 }
6349 else {
6350 cf_info(AS_INFO, "SINDEX HISTOGRAM : invalid OP");
6351 cf_dyn_buf_append_string(db, "Invalid Op");
6352 goto END;
6353 }
6354
6355 int resp = as_sindex_histogram_enable(ns, iname, enable);
6356 if (resp) {
6357 cf_warning(AS_INFO, "SINDEX HISTOGRAM : for index %s - ns %s failed with error %d",
6358 iname, ns->name, resp);
6359 INFO_COMMAND_SINDEX_FAILCODE(
6360 as_sindex_err_to_clienterr(resp, __FILE__, __LINE__),
6361 as_sindex_err_str(resp));
6362 } else {
6363 cf_dyn_buf_append_string(db, "Ok");
6364 cf_info(AS_INFO, "SINDEX HISTOGRAM : for index %s - ns %s histogram is set as %s",
6365 iname, ns->name, op);
6366 }
6367
6368END:
6369 if (iname) {
6370 cf_free(iname);
6371 }
6372 return(0);
6373}
6374
6375int info_command_sindex_list(char *name, char *params, cf_dyn_buf *db) {
6376 bool listall = true;
6377 char ns_str[128];
6378 int ns_len = sizeof(ns_str);
6379 if (!as_info_parameter_get(params, "ns", ns_str, &ns_len)) {
6380 listall = false;
6381 }
6382
6383 if (listall) {
6384 bool found = false;
6385 for (int i = 0; i < g_config.n_namespaces; i++) {
6386 as_namespace *ns = g_config.namespaces[i];
6387 if (ns) {
6388 if (!as_sindex_list_str(ns, db)) {
6389 found = true;
6390 }
6391 else {
6392 cf_detail(AS_INFO, "No indexes for namespace %s", ns->name);
6393 }
6394 }
6395 }
6396
6397 if (found) {
6398 cf_dyn_buf_chomp(db);
6399 }
6400 else {
6401 cf_dyn_buf_append_string(db, "Empty");
6402 }
6403 }
6404 else {
6405 as_namespace *ns = as_namespace_get_byname(ns_str);
6406 if (!ns) {
6407 cf_warning(AS_INFO, "SINDEX LIST : ns %s not found", ns_str);
6408 INFO_COMMAND_SINDEX_FAILCODE(AS_ERR_PARAMETER, "Namespace Not Found");
6409 return 0;
6410 } else {
6411 if (as_sindex_list_str(ns, db)) {
6412 cf_info(AS_INFO, "ns not found");
6413 cf_dyn_buf_append_string(db, "Empty");
6414 }
6415 return 0;
6416 }
6417 }
6418 return(0);
6419}
6420
6421// Defined in "make_in/version.c" (auto-generated by the build system.)
6422extern const char aerospike_build_id[];
6423extern const char aerospike_build_time[];
6424extern const char aerospike_build_type[];
6425extern const char aerospike_build_os[];
6426extern const char aerospike_build_features[];
6427
6428int
6429as_info_init()
6430{
6431 // create worker threads
6432 g_info_work_q = cf_queue_create(sizeof(as_info_transaction), true);
6433
6434 char vstr[64];
6435 sprintf(vstr, "%s build %s", aerospike_build_type, aerospike_build_id);
6436
6437 char compatibility_id[20];
6438 cf_str_itoa(AS_EXCHANGE_COMPATIBILITY_ID, compatibility_id, 10);
6439
6440 // Set some basic values
6441 as_info_set("version", vstr, true); // Returns the edition and build number.
6442 as_info_set("build", aerospike_build_id, true); // Returns the build number for this server.
6443 as_info_set("build_os", aerospike_build_os, true); // Return the OS used to create this build.
6444 as_info_set("build_time", aerospike_build_time, true); // Return the creation time of this build.
6445 as_info_set("edition", aerospike_build_type, true); // Return the edition of this build.
6446 as_info_set("compatibility-id", compatibility_id, true); // Used for compatibility purposes.
6447 as_info_set("digests", "RIPEMD160", false); // Returns the hashing algorithm used by the server for key hashing.
6448 as_info_set("status", "ok", false); // Always returns ok, used to verify service port is open.
6449 as_info_set("STATUS", "OK", false); // Always returns OK, used to verify service port is open.
6450
6451 char istr[1024];
6452 cf_str_itoa(AS_PARTITIONS, istr, 10);
6453 as_info_set("partitions", istr, false); // Returns the number of partitions used to hash keys across.
6454
6455 cf_str_itoa_u64(g_config.self_node, istr, 16);
6456 as_info_set("node", istr, true); // Node ID. Unique 15 character hex string for each node based on the mac address and port.
6457 as_info_set("name", istr, false); // Alias to 'node'.
6458
6459 // Returns list of features supported by this server
6460 static char features[1024];
6461 strcat(features,
6462 "batch-index;blob-bits;"
6463 "cdt-list;cdt-map;cluster-stable;"
6464 "float;"
6465 "geo;"
6466 "peers;pipelining;"
6467 "relaxed-sc;replicas;replicas-all;replicas-master;"
6468 "truncate-namespace;"
6469 "udf");
6470 strcat(features, aerospike_build_features);
6471 as_info_set("features", features, true);
6472
6473 as_hb_mode hb_mode;
6474 as_hb_info_listen_addr_get(&hb_mode, istr, sizeof(istr));
6475 as_info_set(hb_mode == AS_HB_MODE_MESH ? "mesh" : "mcast", istr, false);
6476
6477 // Commands expected via asinfo/telnet. If it's not in this list, it's a
6478 // "client-only" command, e.g. for cluster management.
6479 as_info_set("help",
6480 "bins;build;build_os;build_time;"
6481 "cluster-name;config-get;config-set;"
6482 "digests;dump-cluster;dump-fabric;dump-hb;dump-hlc;dump-migrates;"
6483 "dump-msgs;dump-rw;dump-si;dump-skew;dump-wb-summary;"
6484 "eviction-reset;"
6485 "feature-key;"
6486 "get-config;get-sl;"
6487 "health-outliers;health-stats;hist-track-start;hist-track-stop;"
6488 "histogram;"
6489 "jem-stats;jobs;"
6490 "latency;log;log-set;log-message;logs;"
6491 "mcast;mesh;"
6492 "name;namespace;namespaces;node;"
6493 "physical-devices;"
6494 "quiesce;quiesce-undo;"
6495 "racks;recluster;revive;roster;roster-set;"
6496 "service;services;services-alumni;services-alumni-reset;set-config;"
6497 "set-log;sets;show-devices;sindex;sindex-create;"
6498 "sindex-delete;sindex-histogram;statistics;status;"
6499 "tip;tip-clear;truncate;truncate-namespace;truncate-namespace-undo;"
6500 "truncate-undo;"
6501 "version;",
6502 false);
6503
6504 // Set up some dynamic functions
6505 as_info_set_dynamic("alumni-clear-std", as_service_list_dynamic, false); // Supersedes "services-alumni" for non-TLS service.
6506 as_info_set_dynamic("alumni-tls-std", as_service_list_dynamic, false); // Supersedes "services-alumni" for TLS service.
6507 as_info_set_dynamic("bins", info_get_bins, false); // Returns bin usage information and used bin names.
6508 as_info_set_dynamic("cluster-name", info_get_cluster_name, false); // Returns cluster name.
6509 as_info_set_dynamic("endpoints", info_get_endpoints, false); // Returns the expanded bind / access address configuration.
6510 as_info_set_dynamic("feature-key", info_get_features, false); // Returns the contents of the feature key (except signature).
6511 as_info_set_dynamic("get-config", info_get_config, false); // Returns running config for specified context.
6512 as_info_set_dynamic("health-outliers", info_get_health_outliers, false); // Returns a list of outliers.
6513 as_info_set_dynamic("health-stats", info_get_health_stats, false); // Returns health stats.
6514 as_info_set_dynamic("logs", info_get_logs, false); // Returns a list of log file locations in use by this server.
6515 as_info_set_dynamic("namespaces", info_get_namespaces, false); // Returns a list of namespace defined on this server.
6516 as_info_set_dynamic("objects", info_get_objects, false); // Returns the number of objects stored on this server.
6517 as_info_set_dynamic("partition-generation", info_get_partition_generation, true); // Returns the current partition generation.
6518 as_info_set_dynamic("partition-info", info_get_partition_info, false); // Returns partition ownership information.
6519 as_info_set_dynamic("peers-clear-alt", as_service_list_dynamic, false); // Supersedes "services-alternate" for non-TLS, alternate addresses.
6520 as_info_set_dynamic("peers-clear-std", as_service_list_dynamic, false); // Supersedes "services" for non-TLS, standard addresses.
6521 as_info_set_dynamic("peers-generation", as_service_list_dynamic, false); // Returns the generation of the peers-*-* services lists.
6522 as_info_set_dynamic("peers-tls-alt", as_service_list_dynamic, false); // Supersedes "services-alternate" for TLS, alternate addresses.
6523 as_info_set_dynamic("peers-tls-std", as_service_list_dynamic, false); // Supersedes "services" for TLS, standard addresses.
6524 as_info_set_dynamic("rack-ids", info_get_rack_ids, false); // Effective rack-ids for all namespaces on this node.
6525 as_info_set_dynamic("rebalance-generation", info_get_rebalance_generation, false); // How many rebalances we've done.
6526 as_info_set_dynamic("replicas", info_get_replicas, false); // Same as replicas-all, but includes regime.
6527 as_info_set_dynamic("replicas-all", info_get_replicas_all, false); // Base 64 encoded binary representation of partitions this node is replica for.
6528 as_info_set_dynamic("replicas-master", info_get_replicas_master, false); // Base 64 encoded binary representation of partitions this node is master (replica) for.
6529 as_info_set_dynamic("service", as_service_list_dynamic, false); // IP address and server port for this node, expected to be a single.
6530 // address/port per node, may be multiple address if this node is configured.
6531 // to listen on multiple interfaces (typically not advised).
6532 as_info_set_dynamic("service-clear-alt", as_service_list_dynamic, false); // Supersedes "service". The alternate address and port for this node's non-TLS
6533 // client service.
6534 as_info_set_dynamic("service-clear-std", as_service_list_dynamic, false); // Supersedes "service". The address and port for this node's non-TLS client service.
6535 as_info_set_dynamic("service-tls-alt", as_service_list_dynamic, false); // Supersedes "service". The alternate address and port for this node's TLS
6536 // client service.
6537 as_info_set_dynamic("service-tls-std", as_service_list_dynamic, false); // Supersedes "service". The address and port for this node's TLS client service.
6538 as_info_set_dynamic("services", as_service_list_dynamic, true); // List of addresses of neighbor cluster nodes to advertise for Application to connect.
6539 as_info_set_dynamic("services-alternate", as_service_list_dynamic, false); // IP address mapping from internal to public ones
6540 as_info_set_dynamic("services-alumni", as_service_list_dynamic, true); // All neighbor addresses (services) this server has ever know about.
6541 as_info_set_dynamic("services-alumni-reset", as_service_list_dynamic, false); // Reset the services alumni to equal services.
6542 as_info_set_dynamic("sets", info_get_sets, false); // Returns set statistics for all or a particular set.
6543 as_info_set_dynamic("smd-info", info_get_smd_info, false); // Returns SMD state information.
6544 as_info_set_dynamic("statistics", info_get_stats, true); // Returns system health and usage stats for this server.
6545 as_info_set_dynamic("thread-traces", cf_thread_traces, false); // Returns backtraces for all threads.
6546
6547 // Tree-based names
6548 as_info_set_tree("bins", info_get_tree_bins); // Returns bin usage information and used bin names for all or a particular namespace.
6549 as_info_set_tree("log", info_get_tree_log); //
6550 as_info_set_tree("namespace", info_get_tree_namespace); // Returns health and usage stats for a particular namespace.
6551 as_info_set_tree("sets", info_get_tree_sets); // Returns set statistics for all or a particular set.
6552 as_info_set_tree("statistics", info_get_tree_statistics);
6553
6554 // Define commands
6555 as_info_set_command("cluster-stable", info_command_cluster_stable, PERM_NONE); // Returns cluster key if cluster is stable.
6556 as_info_set_command("config-get", info_command_config_get, PERM_NONE); // Returns running config for specified context.
6557 as_info_set_command("config-set", info_command_config_set, PERM_SET_CONFIG); // Set a configuration parameter at run time, configuration parameter must be dynamic.
6558 as_info_set_command("dump-cluster", info_command_dump_cluster, PERM_LOGGING_CTRL); // Print debug information about clustering and exchange to the log file.
6559 as_info_set_command("dump-fabric", info_command_dump_fabric, PERM_LOGGING_CTRL); // Print debug information about fabric to the log file.
6560 as_info_set_command("dump-hb", info_command_dump_hb, PERM_LOGGING_CTRL); // Print debug information about heartbeat state to the log file.
6561 as_info_set_command("dump-hlc", info_command_dump_hlc, PERM_LOGGING_CTRL); // Print debug information about Hybrid Logical Clock to the log file.
6562 as_info_set_command("dump-migrates", info_command_dump_migrates, PERM_LOGGING_CTRL); // Print debug information about migration.
6563 as_info_set_command("dump-msgs", info_command_dump_msgs, PERM_LOGGING_CTRL); // Print debug information about existing 'msg' objects and queues to the log file.
6564 as_info_set_command("dump-rw", info_command_dump_rw_request_hash, PERM_LOGGING_CTRL); // Print debug information about transaction hash table to the log file.
6565 as_info_set_command("dump-si", info_command_dump_si, PERM_LOGGING_CTRL); // Print information about a Secondary Index
6566 as_info_set_command("dump-skew", info_command_dump_skew, PERM_LOGGING_CTRL); // Print information about clock skew
6567 as_info_set_command("dump-wb-summary", info_command_dump_wb_summary, PERM_LOGGING_CTRL); // Print summary information about all Write Blocks (WB) on a device to the log file.
6568 as_info_set_command("eviction-reset", info_command_eviction_reset, PERM_TRUNCATE); // Delete or manually set SMD evict-void-time.
6569 as_info_set_command("get-config", info_command_config_get, PERM_NONE); // Returns running config for all or a particular context.
6570 as_info_set_command("get-sl", info_command_get_sl, PERM_NONE); // Get the Paxos succession list.
6571 as_info_set_command("hist-track-start", info_command_hist_track, PERM_SERVICE_CTRL); // Start or Restart histogram tracking.
6572 as_info_set_command("hist-track-stop", info_command_hist_track, PERM_SERVICE_CTRL); // Stop histogram tracking.
6573 as_info_set_command("histogram", info_command_histogram, PERM_NONE); // Returns a histogram snapshot for a particular histogram.
6574 as_info_set_command("jem-stats", info_command_jem_stats, PERM_LOGGING_CTRL); // Print JEMalloc statistics to the log file.
6575 as_info_set_command("latency", info_command_hist_track, PERM_NONE); // Returns latency and throughput information.
6576 as_info_set_command("log-message", info_command_log_message, PERM_LOGGING_CTRL); // Log a message.
6577 as_info_set_command("log-set", info_command_log_set, PERM_LOGGING_CTRL); // Set values in the log system.
6578 as_info_set_command("peers-clear-alt", as_service_list_command, PERM_NONE); // The delta update version of "peers-clear-alt".
6579 as_info_set_command("peers-clear-std", as_service_list_command, PERM_NONE); // The delta update version of "peers-clear-std".
6580 as_info_set_command("peers-tls-alt", as_service_list_command, PERM_NONE); // The delta update version of "peers-tls-alt".
6581 as_info_set_command("peers-tls-std", as_service_list_command, PERM_NONE); // The delta update version of "peers-tls-std".
6582 as_info_set_command("physical-devices", info_command_physical_devices, PERM_NONE); // Physical device information.
6583 as_info_set_command("quiesce", info_command_quiesce, PERM_SERVICE_CTRL); // Quiesce this node.
6584 as_info_set_command("quiesce-undo", info_command_quiesce_undo, PERM_SERVICE_CTRL); // Un-quiesce this node.
6585 as_info_set_command("racks", info_command_racks, PERM_NONE); // Rack-aware information.
6586 as_info_set_command("recluster", info_command_recluster, PERM_SERVICE_CTRL); // Force cluster to re-form.
6587 as_info_set_command("revive", info_command_revive, PERM_SERVICE_CTRL); // Mark "untrusted" partitions as "revived".
6588 as_info_set_command("roster", info_command_roster, PERM_NONE); // Roster information.
6589 as_info_set_command("roster-set", info_command_roster_set, PERM_SERVICE_CTRL); // Set the entire roster.
6590 as_info_set_command("set-config", info_command_config_set, PERM_SET_CONFIG); // Set config values.
6591 as_info_set_command("set-log", info_command_log_set, PERM_LOGGING_CTRL); // Set values in the log system.
6592 as_info_set_command("show-devices", info_command_show_devices, PERM_LOGGING_CTRL); // Print snapshot of wblocks to the log file.
6593 as_info_set_command("throughput", info_command_hist_track, PERM_NONE); // Returns throughput info.
6594 as_info_set_command("tip", info_command_tip, PERM_SERVICE_CTRL); // Add external IP to mesh-mode heartbeats.
6595 as_info_set_command("tip-clear", info_command_tip_clear, PERM_SERVICE_CTRL); // Clear tip list from mesh-mode heartbeats.
6596 as_info_set_command("truncate", info_command_truncate, PERM_TRUNCATE); // Truncate a set.
6597 as_info_set_command("truncate-namespace", info_command_truncate_namespace, PERM_TRUNCATE); // Truncate a namespace.
6598 as_info_set_command("truncate-namespace-undo", info_command_truncate_namespace_undo, PERM_TRUNCATE); // Undo a truncate-namespace command.
6599 as_info_set_command("truncate-undo", info_command_truncate_undo, PERM_TRUNCATE); // Undo a truncate (set) command.
6600 as_info_set_command("xdr-command", as_info_command_xdr, PERM_SERVICE_CTRL); // Command to XDR module.
6601
6602 // SINDEX
6603 as_info_set_dynamic("sindex", info_get_sindexes, false);
6604 as_info_set_tree("sindex", info_get_tree_sindexes);
6605 as_info_set_command("sindex-create", info_command_sindex_create, PERM_INDEX_MANAGE); // Create a secondary index.
6606 as_info_set_command("sindex-delete", info_command_sindex_delete, PERM_INDEX_MANAGE); // Delete a secondary index.
6607
6608 // UDF
6609 as_info_set_dynamic("udf-list", udf_cask_info_list, false);
6610 as_info_set_command("udf-put", udf_cask_info_put, PERM_UDF_MANAGE);
6611 as_info_set_command("udf-get", udf_cask_info_get, PERM_NONE);
6612 as_info_set_command("udf-remove", udf_cask_info_remove, PERM_UDF_MANAGE);
6613 as_info_set_command("udf-clear-cache", udf_cask_info_clear_cache, PERM_UDF_MANAGE);
6614
6615 // JOBS
6616 as_info_set_command("jobs", info_command_mon_cmd, PERM_JOB_MONITOR); // Manipulate the multi-key lookup monitoring infrastructure.
6617
6618 // Undocumented Secondary Index Command
6619 as_info_set_command("sindex-histogram", info_command_sindex_histogram, PERM_SERVICE_CTRL);
6620
6621 as_info_set_dynamic("query-list", as_query_list, false);
6622 as_info_set_command("query-kill", info_command_query_kill, PERM_QUERY_MANAGE);
6623 as_info_set_command("scan-abort", info_command_abort_scan, PERM_SCAN_MANAGE); // Abort a scan with a given id.
6624 as_info_set_command("scan-abort-all", info_command_abort_all_scans, PERM_SCAN_MANAGE); // Abort all scans.
6625 as_info_set_dynamic("scan-list", as_scan_list, false); // List info for all scan jobs.
6626 as_info_set_command("sindex-stat", info_command_sindex_stat, PERM_NONE);
6627 as_info_set_command("sindex-list", info_command_sindex_list, PERM_NONE);
6628 as_info_set_dynamic("sindex-builder-list", as_sbld_list, false); // List info for all secondary index builder jobs.
6629
6630 as_xdr_info_init();
6631 as_service_list_init();
6632
6633 for (uint32_t i = 0; i < g_config.n_info_threads; i++) {
6634 cf_thread_create_detached(thr_info_fn, NULL);
6635 }
6636
6637 return(0);
6638}
6639