mirror of
https://github.com/apple/foundationdb.git
synced 2025-06-02 19:25:52 +08:00
Previously with EaR we always enable authentication (e.g. we encrypt Redwood pages). The authentication is a form of checksum, so dedicated page checksum was not needed. This PR adds back xxhash page checksum when authentication is disabled. Also change the knob to default disable authentication.
571 lines
27 KiB
C++
571 lines
27 KiB
C++
/*
|
|
* Knobs.cpp
|
|
*
|
|
* This source file is part of the FoundationDB open source project
|
|
*
|
|
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "flow/EncryptUtils.h"
|
|
#include "flow/Error.h"
|
|
#include "flow/flow.h"
|
|
#include "flow/Knobs.h"
|
|
#include "flow/BooleanParam.h"
|
|
#include "flow/UnitTest.h"
|
|
|
|
#include <cmath>
|
|
#include <cinttypes>
|
|
|
|
FDB_BOOLEAN_PARAM(IsSimulated);
|
|
FDB_BOOLEAN_PARAM(Randomize);
|
|
|
|
FlowKnobs::FlowKnobs(Randomize randomize, IsSimulated isSimulated) {
|
|
initialize(randomize, isSimulated);
|
|
}
|
|
|
|
FlowKnobs bootstrapGlobalFlowKnobs(Randomize::False, IsSimulated::False);
|
|
FlowKnobs const* FLOW_KNOBS = &bootstrapGlobalFlowKnobs;
|
|
|
|
#define init(...) KNOB_FN(__VA_ARGS__, INIT_ATOMIC_KNOB, INIT_KNOB)(__VA_ARGS__)
|
|
|
|
// clang-format off
|
|
void FlowKnobs::initialize(Randomize randomize, IsSimulated isSimulated) {
|
|
init( AUTOMATIC_TRACE_DUMP, 1 );
|
|
init( PREVENT_FAST_SPIN_DELAY, .01 );
|
|
init( HOSTNAME_RESOLVE_INIT_INTERVAL, .05 );
|
|
init( HOSTNAME_RESOLVE_MAX_INTERVAL, 1.0 );
|
|
init( HOSTNAME_RECONNECT_INIT_INTERVAL, .05 );
|
|
init( HOSTNAME_RECONNECT_MAX_INTERVAL, 1.0 );
|
|
init( ENABLE_COORDINATOR_DNS_CACHE, false ); if( randomize && BUGGIFY ) ENABLE_COORDINATOR_DNS_CACHE = true;
|
|
init( CACHE_REFRESH_INTERVAL_WHEN_ALL_ALTERNATIVES_FAILED, 1.0 );
|
|
|
|
init( DELAY_JITTER_OFFSET, 0.9 );
|
|
init( DELAY_JITTER_RANGE, 0.2 );
|
|
init( BUSY_WAIT_THRESHOLD, 0 ); // 1e100 == never sleep
|
|
init( CLIENT_REQUEST_INTERVAL, 1.0 ); if( randomize && BUGGIFY ) CLIENT_REQUEST_INTERVAL = 2.0;
|
|
init( SERVER_REQUEST_INTERVAL, 1.0 ); if( randomize && BUGGIFY ) SERVER_REQUEST_INTERVAL = 2.0;
|
|
|
|
init( REACTOR_FLAGS, 0 );
|
|
|
|
init( DISABLE_ASSERTS, 0 );
|
|
init( QUEUE_MODEL_SMOOTHING_AMOUNT, 2.0 );
|
|
|
|
init( RUN_LOOP_PROFILING_INTERVAL, 0.125 ); // A value of 0 disables run loop profiling
|
|
init( SLOWTASK_PROFILING_LOG_INTERVAL, 0 ); // A value of 0 means use RUN_LOOP_PROFILING_INTERVAL
|
|
init( SLOWTASK_PROFILING_MAX_LOG_INTERVAL, 1.0 );
|
|
init( SLOWTASK_PROFILING_LOG_BACKOFF, 2.0 );
|
|
init( SLOWTASK_BLOCKED_INTERVAL, 60.0 );
|
|
init( SATURATION_PROFILING_LOG_INTERVAL, 0.5 ); // A value of 0 means use RUN_LOOP_PROFILING_INTERVAL
|
|
init( SATURATION_PROFILING_MAX_LOG_INTERVAL, 5.0 );
|
|
init( SATURATION_PROFILING_LOG_BACKOFF, 2.0 );
|
|
|
|
init( FAST_ALLOC_LOGGING_BYTES, 10e6 );
|
|
init( FAST_ALLOC_ALLOW_GUARD_PAGES, false );
|
|
init( HUGE_ARENA_LOGGING_BYTES, 100e6 );
|
|
init( HUGE_ARENA_LOGGING_INTERVAL, 5.0 );
|
|
|
|
init( MEMORY_USAGE_CHECK_INTERVAL, 1.0 );
|
|
|
|
// Chaos testing - enabled for simulation by default
|
|
init( ENABLE_CHAOS_FEATURES, isSimulated );
|
|
init( CHAOS_LOGGING_INTERVAL, 5.0 );
|
|
|
|
|
|
init( WRITE_TRACING_ENABLED, true ); if( randomize && BUGGIFY ) WRITE_TRACING_ENABLED = false;
|
|
init( TRACING_SAMPLE_RATE, 0.0 ); if (randomize && BUGGIFY) TRACING_SAMPLE_RATE = 0.01; // Fraction of distributed traces (not spans) to sample (0 means ignore all traces)
|
|
init( TRACING_UDP_LISTENER_ADDR, "127.0.0.1" ); // Only applicable if TracerType is set to a network option
|
|
init( TRACING_UDP_LISTENER_PORT, 8889 ); // Only applicable if TracerType is set to a network option
|
|
|
|
// Native metrics
|
|
init( METRICS_DATA_MODEL, "none"); if (randomize && BUGGIFY) METRICS_DATA_MODEL="otel";
|
|
init( METRICS_EMISSION_INTERVAL, 30.0 ); // The time (in seconds) between metric flushes
|
|
init( STATSD_UDP_EMISSION_ADDR, "127.0.0.1");
|
|
init( STATSD_UDP_EMISSION_PORT, 8125 );
|
|
init( OTEL_UDP_EMISSION_ADDR, "127.0.0.1");
|
|
init( OTEL_UDP_EMISSION_PORT, 8903 );
|
|
init( METRICS_EMIT_DDSKETCH, false ); // Determines if DDSketch buckets will get emitted
|
|
|
|
//connectionMonitor
|
|
init( CONNECTION_MONITOR_LOOP_TIME, isSimulated ? 0.75 : 1.0 ); if( randomize && BUGGIFY ) CONNECTION_MONITOR_LOOP_TIME = 6.0;
|
|
init( CONNECTION_MONITOR_TIMEOUT, isSimulated ? 1.50 : 2.0 ); if( randomize && BUGGIFY ) CONNECTION_MONITOR_TIMEOUT = 6.0;
|
|
init( CONNECTION_MONITOR_IDLE_TIMEOUT, 180.0 ); if( randomize && BUGGIFY ) CONNECTION_MONITOR_IDLE_TIMEOUT = 5.0;
|
|
init( CONNECTION_MONITOR_INCOMING_IDLE_MULTIPLIER, 1.2 );
|
|
init( CONNECTION_MONITOR_UNREFERENCED_CLOSE_DELAY, 2.0 );
|
|
|
|
//FlowTransport
|
|
init( CONNECTION_REJECTED_MESSAGE_DELAY, 1.0 );
|
|
init( CONNECTION_ID_TIMEOUT, 600.0 ); if( randomize && BUGGIFY ) CONNECTION_ID_TIMEOUT = 60.0;
|
|
init( CONNECTION_CLEANUP_DELAY, 100.0 );
|
|
init( INITIAL_RECONNECTION_TIME, 0.05 );
|
|
init( MAX_RECONNECTION_TIME, 0.5 );
|
|
init( RECONNECTION_TIME_GROWTH_RATE, 1.2 );
|
|
init( RECONNECTION_RESET_TIME, 5.0 );
|
|
init( ALWAYS_ACCEPT_DELAY, 15.0 );
|
|
init( ACCEPT_BATCH_SIZE, 10 );
|
|
init( TOO_MANY_CONNECTIONS_CLOSED_RESET_DELAY, 5.0 );
|
|
init( TOO_MANY_CONNECTIONS_CLOSED_TIMEOUT, 20.0 );
|
|
init( PEER_UNAVAILABLE_FOR_LONG_TIME_TIMEOUT, 3600.0 );
|
|
init( INCOMPATIBLE_PEER_DELAY_BEFORE_LOGGING, 5.0 );
|
|
init( PING_LOGGING_INTERVAL, 3.0 );
|
|
init( PING_SKETCH_ACCURACY, 0.1 );
|
|
|
|
init( TLS_CERT_REFRESH_DELAY_SECONDS, 12*60*60 );
|
|
init( TLS_SERVER_CONNECTION_THROTTLE_TIMEOUT, 9.0 );
|
|
init( TLS_CLIENT_CONNECTION_THROTTLE_TIMEOUT, 11.0 );
|
|
init( TLS_SERVER_CONNECTION_THROTTLE_ATTEMPTS, 1 );
|
|
init( TLS_CLIENT_CONNECTION_THROTTLE_ATTEMPTS, 1 );
|
|
init( TLS_CLIENT_HANDSHAKE_THREADS, 0 );
|
|
init( TLS_SERVER_HANDSHAKE_THREADS, 64 );
|
|
init( TLS_HANDSHAKE_THREAD_STACKSIZE, 64 * 1024 );
|
|
init( TLS_MALLOC_ARENA_MAX, 6 );
|
|
init( TLS_HANDSHAKE_LIMIT, 1000 );
|
|
|
|
init( NETWORK_TEST_CLIENT_COUNT, 30 );
|
|
init( NETWORK_TEST_REPLY_SIZE, 600e3 );
|
|
init( NETWORK_TEST_REQUEST_COUNT, 0 ); // 0 -> run forever
|
|
init( NETWORK_TEST_REQUEST_SIZE, 1 );
|
|
init( NETWORK_TEST_SCRIPT_MODE, false );
|
|
|
|
//Authorization
|
|
init( ALLOW_TOKENLESS_TENANT_ACCESS, false );
|
|
init( PUBLIC_KEY_FILE_MAX_SIZE, 1024 * 1024 );
|
|
init( PUBLIC_KEY_FILE_REFRESH_INTERVAL_SECONDS, 30 );
|
|
init( MAX_CACHED_EXPIRED_TOKENS, 1024 );
|
|
init( AUDIT_TIME_WINDOW, 5.0 );
|
|
|
|
//AsyncFileCached
|
|
init( PAGE_CACHE_4K, 2LL<<30 );
|
|
init( PAGE_CACHE_64K, 200LL<<20 );
|
|
init( SIM_PAGE_CACHE_4K, 1e8 );
|
|
init( SIM_PAGE_CACHE_64K, 1e7 );
|
|
init( BUGGIFY_SIM_PAGE_CACHE_4K, 1e6 );
|
|
init( BUGGIFY_SIM_PAGE_CACHE_64K, 1e6 );
|
|
init( MAX_EVICT_ATTEMPTS, 100 ); if( randomize && BUGGIFY ) MAX_EVICT_ATTEMPTS = 2;
|
|
init( CACHE_EVICTION_POLICY, "random" );
|
|
init( PAGE_CACHE_TRUNCATE_LOOKUP_FRACTION, 0.1 ); if( randomize && BUGGIFY ) PAGE_CACHE_TRUNCATE_LOOKUP_FRACTION = 0.0; else if( randomize && BUGGIFY ) PAGE_CACHE_TRUNCATE_LOOKUP_FRACTION = 1.0;
|
|
init( FLOW_CACHEDFILE_WRITE_IO_SIZE, 0 );
|
|
if ( randomize && BUGGIFY) {
|
|
// Choose 16KB to 64KB as I/O size
|
|
FLOW_CACHEDFILE_WRITE_IO_SIZE = deterministicRandom()->randomInt(16384, 65537);
|
|
}
|
|
|
|
//AsyncFileEIO
|
|
init( EIO_MAX_PARALLELISM, 4 );
|
|
init( EIO_USE_ODIRECT, 0 );
|
|
|
|
//AsyncFileEncrypted
|
|
init( ENCRYPTION_BLOCK_SIZE, 4096 );
|
|
init( MAX_DECRYPTED_BLOCKS, 10 );
|
|
|
|
//AsyncFileKAIO
|
|
init( MAX_OUTSTANDING, 64 );
|
|
init( MIN_SUBMIT, 10 );
|
|
init( SQLITE_DISK_METRIC_LOGGING_INTERVAL, 5.0 );
|
|
init( KAIO_LATENCY_LOGGING_INTERVAL, 30.0 );
|
|
init( KAIO_LATENCY_SKETCH_ACCURACY, 0.01 );
|
|
|
|
init( PAGE_WRITE_CHECKSUM_HISTORY, 0 ); if( randomize && BUGGIFY ) PAGE_WRITE_CHECKSUM_HISTORY = 10000000;
|
|
init( DISABLE_POSIX_KERNEL_AIO, 0 );
|
|
|
|
//AsyncFileNonDurable
|
|
init( NON_DURABLE_MAX_WRITE_DELAY, 2.0 ); if( randomize && BUGGIFY ) NON_DURABLE_MAX_WRITE_DELAY = 5.0;
|
|
init( MAX_PRIOR_MODIFICATION_DELAY, 1.0 ); if( randomize && BUGGIFY ) MAX_PRIOR_MODIFICATION_DELAY = 10.0;
|
|
|
|
//GenericActors
|
|
init( BUGGIFY_FLOW_LOCK_RELEASE_DELAY, 1.0 );
|
|
init( LOW_PRIORITY_DELAY_COUNT, 5 );
|
|
init( LOW_PRIORITY_MAX_DELAY, 5.0 );
|
|
|
|
// HTTP
|
|
init( HTTP_READ_SIZE, 128*1024 );
|
|
init( HTTP_SEND_SIZE, 32*1024 );
|
|
init( HTTP_VERBOSE_LEVEL, 0 );
|
|
init( HTTP_REQUEST_ID_HEADER, "" );
|
|
init( HTTP_RESPONSE_SKIP_VERIFY_CHECKSUM_FOR_PARTIAL_CONTENT, false );
|
|
|
|
//IAsyncFile
|
|
init( INCREMENTAL_DELETE_TRUNCATE_AMOUNT, 5e8 ); //500MB
|
|
init( INCREMENTAL_DELETE_INTERVAL, 1.0 ); //every 1 second
|
|
|
|
//Net2 and FlowTransport
|
|
init( MIN_COALESCE_DELAY, 10e-6 ); if( randomize && BUGGIFY ) MIN_COALESCE_DELAY = 0;
|
|
init( MAX_COALESCE_DELAY, 20e-6 ); if( randomize && BUGGIFY ) MAX_COALESCE_DELAY = 0;
|
|
init( SLOW_LOOP_CUTOFF, 15.0 / 1000.0 );
|
|
init( SLOW_LOOP_SAMPLING_RATE, 0.1 );
|
|
init( TSC_YIELD_TIME, 1000000 );
|
|
init( MIN_LOGGED_PRIORITY_BUSY_FRACTION, 0.05 );
|
|
init( CERT_FILE_MAX_SIZE, 5 * 1024 * 1024 );
|
|
init( READY_QUEUE_RESERVED_SIZE, 8192 );
|
|
init( TASKS_PER_REACTOR_CHECK, 100 );
|
|
|
|
//Network
|
|
init( PACKET_LIMIT, 100LL<<20 );
|
|
init( PACKET_WARNING, 2LL<<20 ); // 2MB packet warning quietly allows for 1MB system messages
|
|
init( TIME_OFFSET_LOGGING_INTERVAL, 60.0 );
|
|
init( MAX_PACKET_SEND_BYTES, 128 * 1024 );
|
|
init( MIN_PACKET_BUFFER_BYTES, 4 * 1024 );
|
|
init( MIN_PACKET_BUFFER_FREE_BYTES, 256 );
|
|
init( FLOW_TCP_NODELAY, 1 );
|
|
init( FLOW_TCP_QUICKACK, 0 );
|
|
|
|
//Sim2
|
|
init( MIN_OPEN_TIME, 0.0002 );
|
|
init( MAX_OPEN_TIME, 0.0012 );
|
|
init( SIM_DISK_IOPS, 5000 );
|
|
init( SIM_DISK_BANDWIDTH, 50000000 );
|
|
init( MIN_NETWORK_LATENCY, 100e-6 );
|
|
init( FAST_NETWORK_LATENCY, 800e-6 );
|
|
init( SLOW_NETWORK_LATENCY, 100e-3 );
|
|
init( MAX_CLOGGING_LATENCY, 0 ); if( randomize && BUGGIFY ) MAX_CLOGGING_LATENCY = 0.1 * deterministicRandom()->random01();
|
|
init( MAX_BUGGIFIED_DELAY, 0 ); if( randomize && BUGGIFY ) MAX_BUGGIFIED_DELAY = 0.2 * deterministicRandom()->random01();
|
|
init( MAX_RUNLOOP_SLEEP_DELAY, 0 );
|
|
init( SIM_CONNECT_ERROR_MODE, deterministicRandom()->randomInt(0,3) );
|
|
|
|
//Tracefiles
|
|
init( ZERO_LENGTH_FILE_PAD, 1 );
|
|
init( TRACE_FLUSH_INTERVAL, 0.25 );
|
|
init( TRACE_RETRY_OPEN_INTERVAL, 1.00 );
|
|
init( MIN_TRACE_SEVERITY, isSimulated ? 1 : 10, Atomic::NO ); // Related to the trace severity in Trace.h
|
|
init( MAX_TRACE_SUPPRESSIONS, 1e4 );
|
|
init( TRACE_DATETIME_ENABLED, true ); // trace time in human readable format (always real time)
|
|
init( TRACE_SYNC_ENABLED, 0 );
|
|
init( TRACE_EVENT_METRIC_UNITS_PER_SAMPLE, 500 );
|
|
init( TRACE_EVENT_THROTTLER_SAMPLE_EXPIRY, 1800.0 ); // 30 mins
|
|
init( TRACE_EVENT_THROTTLER_MSG_LIMIT, 20000 );
|
|
init( MAX_TRACE_FIELD_LENGTH, 495 ); // If the value of this is changed, the corresponding default in Trace.cpp should be changed as well
|
|
init( MAX_TRACE_EVENT_LENGTH, 4000 ); // If the value of this is changed, the corresponding default in Trace.cpp should be changed as well
|
|
init( ALLOCATION_TRACING_ENABLED, true );
|
|
init( SIM_SPEEDUP_AFTER_SECONDS, 450 );
|
|
init( MAX_TRACE_LINES, 1'000'000 );
|
|
init( CODE_COV_TRACE_EVENT_SEVERITY, 10 ); // Code coverage TraceEvent severity level
|
|
|
|
//TDMetrics
|
|
init( MAX_METRICS, 600 );
|
|
init( MAX_METRIC_SIZE, 2500, Atomic::NO );
|
|
init( MAX_METRIC_LEVEL, 25 );
|
|
init( METRIC_LEVEL_DIVISOR, log(4) );
|
|
init( METRIC_LIMIT_START_QUEUE_SIZE, 10 ); // The queue size at which to start restricting logging by disabling levels
|
|
init( METRIC_LIMIT_RESPONSE_FACTOR, 10 ); // The additional queue size at which to disable logging of another level (higher == less restrictive)
|
|
|
|
//Load Balancing
|
|
init( LOAD_BALANCE_ZONE_ID_LOCALITY_ENABLED, 0 );
|
|
init( LOAD_BALANCE_DC_ID_LOCALITY_ENABLED, 1 );
|
|
init( LOAD_BALANCE_MAX_BACKOFF, 5.0 );
|
|
init( LOAD_BALANCE_START_BACKOFF, 0.01 );
|
|
init( LOAD_BALANCE_BACKOFF_RATE, 2.0 );
|
|
init( MAX_LAGGING_REQUESTS_OUTSTANDING, 100000 );
|
|
init( INSTANT_SECOND_REQUEST_MULTIPLIER, 2.0 );
|
|
init( BASE_SECOND_REQUEST_TIME, 0.0005 );
|
|
init( SECOND_REQUEST_MULTIPLIER_GROWTH, 0.01 );
|
|
init( SECOND_REQUEST_MULTIPLIER_DECAY, 0.00025 );
|
|
init( SECOND_REQUEST_BUDGET_GROWTH, 0.05 );
|
|
init( SECOND_REQUEST_MAX_BUDGET, 100.0 );
|
|
init( ALTERNATIVES_FAILURE_RESET_TIME, 5.0 );
|
|
init( ALTERNATIVES_FAILURE_MIN_DELAY, 0.05 );
|
|
init( ALTERNATIVES_FAILURE_DELAY_RATIO, 0.2 );
|
|
init( ALTERNATIVES_FAILURE_MAX_DELAY, 1.0 );
|
|
init( ALTERNATIVES_FAILURE_SLOW_DELAY_RATIO, 0.04 );
|
|
init( ALTERNATIVES_FAILURE_SLOW_MAX_DELAY, 30.0 );
|
|
init( ALTERNATIVES_FAILURE_SKIP_DELAY, 1.0 );
|
|
init( FUTURE_VERSION_INITIAL_BACKOFF, 1.0 );
|
|
init( FUTURE_VERSION_MAX_BACKOFF, 8.0 );
|
|
init( FUTURE_VERSION_BACKOFF_GROWTH, 2.0 );
|
|
init( LOAD_BALANCE_MAX_BAD_OPTIONS, 1 ); //should be the same as MAX_MACHINES_FALLING_BEHIND
|
|
init( LOAD_BALANCE_PENALTY_IS_BAD, true );
|
|
init( BASIC_LOAD_BALANCE_UPDATE_RATE, 10.0 ); //should be longer than the rate we log network metrics
|
|
init( BASIC_LOAD_BALANCE_MAX_CHANGE, 0.10 );
|
|
init( BASIC_LOAD_BALANCE_MAX_PROB, 2.0 );
|
|
init( BASIC_LOAD_BALANCE_MIN_REQUESTS, 20 ); //do not adjust LB probabilities if the proxies are less than releasing less than 20 transactions per second
|
|
init( BASIC_LOAD_BALANCE_MIN_CPU, 0.05 ); //do not adjust LB probabilities if the proxies are less than 5% utilized
|
|
init( BASIC_LOAD_BALANCE_BUCKETS, 40 ); //proxies bin recent GRV requests into 40 time bins
|
|
init( BASIC_LOAD_BALANCE_COMPUTE_PRECISION, 10000 ); //determines how much of the LB usage is holding the CPU usage of the proxy
|
|
init( LOAD_BALANCE_TSS_TIMEOUT, 5.0 );
|
|
init( LOAD_BALANCE_TSS_MISMATCH_VERIFY_SS, true ); if( randomize && BUGGIFY ) LOAD_BALANCE_TSS_MISMATCH_VERIFY_SS = false; // Whether the client should validate the SS teams all agree on TSS mismatch
|
|
init( LOAD_BALANCE_TSS_MISMATCH_TRACE_FULL, false ); if( randomize && BUGGIFY ) LOAD_BALANCE_TSS_MISMATCH_TRACE_FULL = true; // If true, saves the full details of the mismatch in a trace event. If false, saves them in the DB and the trace event references the DB row.
|
|
init( TSS_LARGE_TRACE_SIZE, 50000 );
|
|
|
|
// Health Monitor
|
|
init( FAILURE_DETECTION_DELAY, 4.0 ); if( randomize && BUGGIFY ) FAILURE_DETECTION_DELAY = 1.0;
|
|
init( HEALTH_MONITOR_MARK_FAILED_UNSTABLE_CONNECTIONS, true );
|
|
init( HEALTH_MONITOR_CLIENT_REQUEST_INTERVAL_SECS, 30 );
|
|
init( HEALTH_MONITOR_CONNECTION_MAX_CLOSED, 5 );
|
|
|
|
// Encryption
|
|
init( ENCRYPT_CIPHER_KEY_CACHE_TTL, isSimulated ? 5 * 60 : 10 * 60 );
|
|
if ( randomize && BUGGIFY) { ENCRYPT_CIPHER_KEY_CACHE_TTL = deterministicRandom()->randomInt(2, 10) * 60; }
|
|
init( ENCRYPT_KEY_REFRESH_INTERVAL, isSimulated ? 60 : 8 * 60 );
|
|
if ( randomize && BUGGIFY) { ENCRYPT_KEY_REFRESH_INTERVAL = deterministicRandom()->randomInt(2, 10); }
|
|
init( TOKEN_CACHE_SIZE, 100 );
|
|
init( ENCRYPT_KEY_CACHE_LOGGING_INTERVAL, 5.0 );
|
|
init( ENCRYPT_KEY_CACHE_LOGGING_SKETCH_ACCURACY, 0.01 );
|
|
// Refer to EncryptUtil::EncryptAuthTokenAlgo for more details
|
|
init( ENCRYPT_HEADER_AUTH_TOKEN_ENABLED, false ); if ( randomize && BUGGIFY ) { ENCRYPT_HEADER_AUTH_TOKEN_ENABLED = !ENCRYPT_HEADER_AUTH_TOKEN_ENABLED; }
|
|
init( ENCRYPT_HEADER_AUTH_TOKEN_ALGO, 0 ); if ( randomize && ENCRYPT_HEADER_AUTH_TOKEN_ENABLED ) { ENCRYPT_HEADER_AUTH_TOKEN_ALGO = getRandomAuthTokenAlgo(); }
|
|
|
|
|
|
// REST Client
|
|
init( RESTCLIENT_MAX_CONNECTIONPOOL_SIZE, 10 );
|
|
init( RESTCLIENT_CONNECT_TRIES, 10 );
|
|
init( RESTCLIENT_CONNECT_TIMEOUT, 10 );
|
|
init( RESTCLIENT_MAX_CONNECTION_LIFE, 120 );
|
|
init( RESTCLIENT_REQUEST_TRIES, 10 );
|
|
init( RESTCLIENT_REQUEST_TIMEOUT_SEC, 120 );
|
|
}
|
|
// clang-format on
|
|
|
|
static std::string toLower(std::string const& name) {
|
|
std::string lower_name;
|
|
for (auto c = name.begin(); c != name.end(); ++c)
|
|
if (*c >= 'A' && *c <= 'Z')
|
|
lower_name += *c - 'A' + 'a';
|
|
else
|
|
lower_name += *c;
|
|
return lower_name;
|
|
}
|
|
|
|
// Converts the given string into a double. If any errors are
|
|
// encountered, it throws an invalid_option_value exception.
|
|
static double safe_stod(std::string const& str) {
|
|
size_t n;
|
|
double value = std::stod(str, &n);
|
|
if (n < str.size()) {
|
|
throw invalid_option_value();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
// Converts the given (possibly hexadecimal) string into an
|
|
// integer. If any errors are encountered, it throws an
|
|
// invalid_option_value exception.
|
|
static int safe_stoi(std::string const& str) {
|
|
size_t n;
|
|
int value = std::stoi(str, &n, 0);
|
|
if (n < str.size()) {
|
|
throw invalid_option_value();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
// Converts the given (possibly hexadecimal) string into a 64-bit
|
|
// integer. If any errors are encountered, it throws an
|
|
// invalid_option_value exception.
|
|
static int64_t safe_stoi64(std::string const& str) {
|
|
size_t n;
|
|
int64_t value = static_cast<int64_t>(std::stoll(str, &n, 0));
|
|
if (n < str.size()) {
|
|
throw invalid_option_value();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
// Converts the given string into a bool. "true" and "false" are case
|
|
// insenstively interpreted as true and false. Otherwise, any non-zero
|
|
// integer is true. If any errors are encountered, it throws an
|
|
// invalid_option_value exception.
|
|
static bool safe_stob(std::string const& str) {
|
|
if (toLower(str) == "true") {
|
|
return true;
|
|
} else if (toLower(str) == "false") {
|
|
return false;
|
|
} else {
|
|
return safe_stoi(str) != 0;
|
|
}
|
|
}
|
|
|
|
// Parses a string value into the appropriate type based upon the knob
|
|
// name. If any errors are encountered, it throws an
|
|
// invalid_option_value exception.
|
|
ParsedKnobValue Knobs::parseKnobValue(std::string const& knob, std::string const& value) const {
|
|
try {
|
|
if (double_knobs.count(knob)) {
|
|
return safe_stod(value);
|
|
} else if (bool_knobs.count(knob)) {
|
|
return safe_stob(value);
|
|
} else if (int64_knobs.count(knob)) {
|
|
return safe_stoi64(value);
|
|
} else if (int_knobs.count(knob)) {
|
|
return safe_stoi(value);
|
|
} else if (string_knobs.count(knob)) {
|
|
return value;
|
|
}
|
|
return NoKnobFound{};
|
|
} catch (...) {
|
|
throw invalid_option_value();
|
|
}
|
|
}
|
|
|
|
bool Knobs::setKnob(std::string const& knob, int value) {
|
|
if (!int_knobs.count(knob)) {
|
|
return false;
|
|
}
|
|
*int_knobs[knob].value = value;
|
|
explicitlySetKnobs.insert(toLower(knob));
|
|
return true;
|
|
}
|
|
|
|
bool Knobs::setKnob(std::string const& knob, int64_t value) {
|
|
if (!int64_knobs.count(knob)) {
|
|
return false;
|
|
}
|
|
*int64_knobs[knob].value = value;
|
|
explicitlySetKnobs.insert(toLower(knob));
|
|
return true;
|
|
}
|
|
|
|
bool Knobs::setKnob(std::string const& knob, bool value) {
|
|
if (!bool_knobs.count(knob)) {
|
|
return false;
|
|
}
|
|
*bool_knobs[knob].value = value;
|
|
explicitlySetKnobs.insert(toLower(knob));
|
|
return true;
|
|
}
|
|
|
|
bool Knobs::setKnob(std::string const& knob, double value) {
|
|
if (!double_knobs.count(knob)) {
|
|
return false;
|
|
}
|
|
*double_knobs[knob].value = value;
|
|
explicitlySetKnobs.insert(toLower(knob));
|
|
return true;
|
|
}
|
|
|
|
bool Knobs::setKnob(std::string const& knob, std::string const& value) {
|
|
if (!string_knobs.count(knob)) {
|
|
return false;
|
|
}
|
|
*string_knobs[knob].value = value;
|
|
explicitlySetKnobs.insert(toLower(knob));
|
|
return true;
|
|
}
|
|
|
|
ParsedKnobValue Knobs::getKnob(const std::string& name) const {
|
|
if (double_knobs.count(name) > 0) {
|
|
return ParsedKnobValue{ *double_knobs.at(name).value };
|
|
}
|
|
if (int64_knobs.count(name) > 0) {
|
|
return ParsedKnobValue{ *int64_knobs.at(name).value };
|
|
}
|
|
if (int_knobs.count(name) > 0) {
|
|
return ParsedKnobValue{ *int_knobs.at(name).value };
|
|
}
|
|
if (string_knobs.count(name) > 0) {
|
|
return ParsedKnobValue{ *string_knobs.at(name).value };
|
|
}
|
|
if (bool_knobs.count(name) > 0) {
|
|
return ParsedKnobValue{ *bool_knobs.at(name).value };
|
|
}
|
|
|
|
return ParsedKnobValue{ NoKnobFound() };
|
|
}
|
|
|
|
bool Knobs::isAtomic(std::string const& knob) const {
|
|
if (double_knobs.count(knob)) {
|
|
return double_knobs.find(knob)->second.atomic == Atomic::YES;
|
|
} else if (int64_knobs.count(knob)) {
|
|
return int64_knobs.find(knob)->second.atomic == Atomic::YES;
|
|
} else if (int_knobs.count(knob)) {
|
|
return int_knobs.find(knob)->second.atomic == Atomic::YES;
|
|
} else if (string_knobs.count(knob)) {
|
|
return string_knobs.find(knob)->second.atomic == Atomic::YES;
|
|
} else if (bool_knobs.count(knob)) {
|
|
return bool_knobs.find(knob)->second.atomic == Atomic::YES;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Knobs::initKnob(double& knob, double value, std::string const& name, Atomic atomic) {
|
|
if (!explicitlySetKnobs.count(toLower(name))) {
|
|
knob = value;
|
|
double_knobs[toLower(name)] = KnobValue<double>{ &knob, atomic };
|
|
}
|
|
}
|
|
|
|
void Knobs::initKnob(int64_t& knob, int64_t value, std::string const& name, Atomic atomic) {
|
|
if (!explicitlySetKnobs.count(toLower(name))) {
|
|
knob = value;
|
|
int64_knobs[toLower(name)] = KnobValue<int64_t>{ &knob, atomic };
|
|
}
|
|
}
|
|
|
|
void Knobs::initKnob(int& knob, int value, std::string const& name, Atomic atomic) {
|
|
if (!explicitlySetKnobs.count(toLower(name))) {
|
|
knob = value;
|
|
int_knobs[toLower(name)] = KnobValue<int>{ &knob, atomic };
|
|
}
|
|
}
|
|
|
|
void Knobs::initKnob(std::string& knob, const std::string& value, const std::string& name, Atomic atomic) {
|
|
if (!explicitlySetKnobs.count(toLower(name))) {
|
|
knob = value;
|
|
string_knobs[toLower(name)] = KnobValue<std::string>{ &knob, atomic };
|
|
}
|
|
}
|
|
|
|
void Knobs::initKnob(bool& knob, bool value, std::string const& name, Atomic atomic) {
|
|
if (!explicitlySetKnobs.count(toLower(name))) {
|
|
knob = value;
|
|
bool_knobs[toLower(name)] = KnobValue<bool>{ &knob, atomic };
|
|
}
|
|
}
|
|
|
|
void Knobs::trace() const {
|
|
for (auto& k : double_knobs)
|
|
TraceEvent("Knob")
|
|
.detail("Name", k.first.c_str())
|
|
.detail("Value", *k.second.value)
|
|
.detail("Atomic", k.second.atomic);
|
|
for (auto& k : int_knobs)
|
|
TraceEvent("Knob")
|
|
.detail("Name", k.first.c_str())
|
|
.detail("Value", *k.second.value)
|
|
.detail("Atomic", k.second.atomic);
|
|
for (auto& k : int64_knobs)
|
|
TraceEvent("Knob")
|
|
.detail("Name", k.first.c_str())
|
|
.detail("Value", *k.second.value)
|
|
.detail("Atomic", k.second.atomic);
|
|
for (auto& k : string_knobs)
|
|
TraceEvent("Knob")
|
|
.detail("Name", k.first.c_str())
|
|
.detail("Value", *k.second.value)
|
|
.detail("Atomic", k.second.atomic);
|
|
for (auto& k : bool_knobs)
|
|
TraceEvent("Knob")
|
|
.detail("Name", k.first.c_str())
|
|
.detail("Value", *k.second.value)
|
|
.detail("Atomic", k.second.atomic);
|
|
}
|
|
|
|
TEST_CASE("/flow/Knobs/ParseKnobValue") {
|
|
// Test the safe conversion functions.
|
|
ASSERT_EQ(safe_stod("4.0"), 4.0);
|
|
|
|
ASSERT_EQ(safe_stoi("4"), 4);
|
|
|
|
ASSERT_EQ(safe_stoi64("4"), (int64_t)4);
|
|
try {
|
|
[[maybe_unused]] int64_t value = safe_stoi64("4GiB");
|
|
UNREACHABLE();
|
|
} catch (Error& e) {
|
|
ASSERT_EQ(e.code(), error_code_invalid_option_value);
|
|
}
|
|
|
|
ASSERT_EQ(safe_stob("true"), true);
|
|
ASSERT_EQ(safe_stob("false"), false);
|
|
|
|
return Void();
|
|
}
|