2017-05-26 04:48:44 +08:00
/*
* fdbserver . actor . cpp
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013 - 2018 Apple Inc . and the FoundationDB project authors
2018-02-22 02:25:11 +08:00
*
2017-05-26 04:48:44 +08:00
* 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
2018-02-22 02:25:11 +08:00
*
2017-05-26 04:48:44 +08:00
* http : //www.apache.org/licenses/LICENSE-2.0
2018-02-22 02:25:11 +08:00
*
2017-05-26 04:48:44 +08:00
* 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 .
*/
2019-02-06 08:46:08 +08:00
// There's something in one of the files below that defines a macros
// a macro that makes boost interprocess break on Windows.
# define BOOST_DATE_TIME_NO_LIB
# include <boost/interprocess/managed_shared_memory.hpp>
2019-06-19 09:15:15 +08:00
# include <boost/algorithm/string.hpp>
2019-02-06 08:46:08 +08:00
2017-05-26 04:48:44 +08:00
# include "fdbrpc/simulator.h"
# include "flow/DeterministicRandom.h"
# include "fdbrpc/PerfMetric.h"
# include "flow/Platform.h"
# include "flow/SystemMonitor.h"
2019-02-18 07:41:16 +08:00
# include "fdbclient/NativeAPI.actor.h"
2017-05-26 04:48:44 +08:00
# include "fdbclient/SystemData.h"
2018-10-20 01:30:13 +08:00
# include "fdbserver/CoordinationInterface.h"
2019-02-18 11:13:26 +08:00
# include "fdbserver/WorkerInterface.actor.h"
2019-09-26 15:18:37 +08:00
# include "fdbclient/RestoreWorkerInterface.actor.h"
2018-10-20 01:30:13 +08:00
# include "fdbserver/ClusterRecruitmentInterface.h"
# include "fdbserver/ServerDBInfo.h"
2019-02-18 10:55:52 +08:00
# include "fdbserver/MoveKeys.actor.h"
2018-10-20 01:30:13 +08:00
# include "fdbserver/ConflictSet.h"
2019-03-06 02:29:37 +08:00
# include "fdbserver/DataDistribution.actor.h"
2018-10-20 01:30:13 +08:00
# include "fdbserver/NetworkTest.h"
# include "fdbserver/IKeyValueStore.h"
2018-10-23 08:57:09 +08:00
# include <algorithm>
2017-05-26 04:48:44 +08:00
# include <stdarg.h>
# include <stdio.h>
2018-04-20 18:16:28 +08:00
# include <fstream>
2018-10-20 01:30:13 +08:00
# include "fdbserver/pubsub.h"
# include "fdbserver/SimulatedCluster.h"
2019-02-18 11:25:16 +08:00
# include "fdbserver/TesterInterface.actor.h"
2019-02-18 11:18:30 +08:00
# include "fdbserver/workloads/workloads.actor.h"
2017-05-26 04:48:44 +08:00
# include <time.h>
2018-10-20 01:30:13 +08:00
# include "fdbserver/Status.h"
2017-05-26 04:48:44 +08:00
# include "fdbrpc/Net2FileSystem.h"
2019-05-07 14:32:57 +08:00
# include "fdbrpc/AsyncFileCached.actor.h"
2018-10-20 01:30:13 +08:00
# include "fdbserver/CoroFlow.h"
2020-03-05 12:14:47 +08:00
# include "flow/TLSConfig.actor.h"
2019-02-09 04:24:32 +08:00
# if defined(CMAKE_BUILD) || !defined(WIN32)
2019-02-07 10:16:54 +08:00
# include "versions.h"
2019-02-09 04:24:32 +08:00
# endif
2017-05-26 04:48:44 +08:00
2019-03-11 22:31:44 +08:00
# include "fdbmonitor/SimpleIni.h"
2017-05-26 04:48:44 +08:00
# ifdef __linux__
# include <execinfo.h>
# include <signal.h>
# ifdef ALLOC_INSTRUMENTATION
# include <cxxabi.h>
# endif
# endif
2019-02-07 11:27:38 +08:00
# ifdef WIN32
# define NOMINMAX
# define WIN32_LEAN_AND_MEAN
# include <Windows.h>
2017-05-26 04:48:44 +08:00
# endif
# include "flow/SimpleOpt.h"
2018-08-11 06:18:24 +08:00
# include "flow/actorcompiler.h" // This must be the last #include.
2017-05-26 04:48:44 +08:00
2020-01-29 09:53:41 +08:00
// clang-format off
2017-05-26 04:48:44 +08:00
enum {
2020-01-29 09:53:41 +08:00
OPT_CONNFILE , OPT_SEEDCONNFILE , OPT_SEEDCONNSTRING , OPT_ROLE , OPT_LISTEN , OPT_PUBLICADDR , OPT_DATAFOLDER , OPT_LOGFOLDER , OPT_PARENTPID , OPT_NEWCONSOLE ,
OPT_NOBOX , OPT_TESTFILE , OPT_RESTARTING , OPT_RESTORING , OPT_RANDOMSEED , OPT_KEY , OPT_MEMLIMIT , OPT_STORAGEMEMLIMIT , OPT_CACHEMEMLIMIT , OPT_MACHINEID ,
OPT_DCID , OPT_MACHINE_CLASS , OPT_BUGGIFY , OPT_VERSION , OPT_CRASHONERROR , OPT_HELP , OPT_NETWORKIMPL , OPT_NOBUFSTDOUT , OPT_BUFSTDOUTERR , OPT_TRACECLOCK ,
OPT_NUMTESTERS , OPT_DEVHELP , OPT_ROLLSIZE , OPT_MAXLOGS , OPT_MAXLOGSSIZE , OPT_KNOB , OPT_TESTSERVERS , OPT_TEST_ON_SERVERS , OPT_METRICSCONNFILE ,
OPT_METRICSPREFIX , OPT_LOGGROUP , OPT_LOCALITY , OPT_IO_TRUST_SECONDS , OPT_IO_TRUST_WARN_ONLY , OPT_FILESYSTEM , OPT_PROFILER_RSS_SIZE , OPT_KVFILE ,
OPT_TRACE_FORMAT , OPT_WHITELIST_BINPATH , OPT_BLOB_CREDENTIAL_FILE
2019-07-24 06:05:21 +08:00
} ;
2017-05-26 04:48:44 +08:00
CSimpleOpt : : SOption g_rgOptions [ ] = {
2019-01-30 00:43:57 +08:00
{ OPT_CONNFILE , " -C " , SO_REQ_SEP } ,
{ OPT_CONNFILE , " --cluster_file " , SO_REQ_SEP } ,
{ OPT_SEEDCONNFILE , " --seed_cluster_file " , SO_REQ_SEP } ,
{ OPT_SEEDCONNSTRING , " --seed_connection_string " , SO_REQ_SEP } ,
{ OPT_ROLE , " -r " , SO_REQ_SEP } ,
{ OPT_ROLE , " --role " , SO_REQ_SEP } ,
{ OPT_PUBLICADDR , " -p " , SO_REQ_SEP } ,
{ OPT_PUBLICADDR , " --public_address " , SO_REQ_SEP } ,
{ OPT_LISTEN , " -l " , SO_REQ_SEP } ,
{ OPT_LISTEN , " --listen_address " , SO_REQ_SEP } ,
2017-05-26 04:48:44 +08:00
# ifdef __linux__
{ OPT_FILESYSTEM , " --data_filesystem " , SO_REQ_SEP } ,
2019-04-06 07:06:30 +08:00
{ OPT_PROFILER_RSS_SIZE , " --rsssize " , SO_REQ_SEP } ,
2017-05-26 04:48:44 +08:00
# endif
2019-01-30 00:43:57 +08:00
{ OPT_DATAFOLDER , " -d " , SO_REQ_SEP } ,
{ OPT_DATAFOLDER , " --datadir " , SO_REQ_SEP } ,
{ OPT_LOGFOLDER , " -L " , SO_REQ_SEP } ,
{ OPT_LOGFOLDER , " --logdir " , SO_REQ_SEP } ,
{ OPT_ROLLSIZE , " -Rs " , SO_REQ_SEP } ,
{ OPT_ROLLSIZE , " --logsize " , SO_REQ_SEP } ,
{ OPT_MAXLOGS , " --maxlogs " , SO_REQ_SEP } ,
{ OPT_MAXLOGSSIZE , " --maxlogssize " , SO_REQ_SEP } ,
{ OPT_LOGGROUP , " --loggroup " , SO_REQ_SEP } ,
{ OPT_PARENTPID , " --parentpid " , SO_REQ_SEP } ,
2017-05-26 04:48:44 +08:00
# ifdef _WIN32
2019-01-30 00:43:57 +08:00
{ OPT_NEWCONSOLE , " -n " , SO_NONE } ,
{ OPT_NEWCONSOLE , " --newconsole " , SO_NONE } ,
{ OPT_NOBOX , " -q " , SO_NONE } ,
{ OPT_NOBOX , " --no_dialog " , SO_NONE } ,
2017-05-26 04:48:44 +08:00
# endif
2019-01-30 00:43:57 +08:00
{ OPT_KVFILE , " --kvfile " , SO_REQ_SEP } ,
{ OPT_TESTFILE , " -f " , SO_REQ_SEP } ,
{ OPT_TESTFILE , " --testfile " , SO_REQ_SEP } ,
{ OPT_RESTARTING , " -R " , SO_NONE } ,
{ OPT_RESTARTING , " --restarting " , SO_NONE } ,
{ OPT_RANDOMSEED , " -s " , SO_REQ_SEP } ,
{ OPT_RANDOMSEED , " --seed " , SO_REQ_SEP } ,
{ OPT_KEY , " -k " , SO_REQ_SEP } ,
{ OPT_KEY , " --key " , SO_REQ_SEP } ,
{ OPT_MEMLIMIT , " -m " , SO_REQ_SEP } ,
{ OPT_MEMLIMIT , " --memory " , SO_REQ_SEP } ,
{ OPT_STORAGEMEMLIMIT , " -M " , SO_REQ_SEP } ,
{ OPT_STORAGEMEMLIMIT , " --storage_memory " , SO_REQ_SEP } ,
2019-07-24 06:05:21 +08:00
{ OPT_CACHEMEMLIMIT , " --cache_memory " , SO_REQ_SEP } ,
2019-01-30 00:43:57 +08:00
{ OPT_MACHINEID , " -i " , SO_REQ_SEP } ,
{ OPT_MACHINEID , " --machine_id " , SO_REQ_SEP } ,
{ OPT_DCID , " -a " , SO_REQ_SEP } ,
{ OPT_DCID , " --datacenter_id " , SO_REQ_SEP } ,
{ OPT_MACHINE_CLASS , " -c " , SO_REQ_SEP } ,
{ OPT_MACHINE_CLASS , " --class " , SO_REQ_SEP } ,
{ OPT_BUGGIFY , " -b " , SO_REQ_SEP } ,
{ OPT_BUGGIFY , " --buggify " , SO_REQ_SEP } ,
{ OPT_VERSION , " -v " , SO_NONE } ,
{ OPT_VERSION , " --version " , SO_NONE } ,
{ OPT_CRASHONERROR , " --crash " , SO_NONE } ,
{ OPT_NETWORKIMPL , " -N " , SO_REQ_SEP } ,
{ OPT_NETWORKIMPL , " --network " , SO_REQ_SEP } ,
{ OPT_NOBUFSTDOUT , " --unbufferedout " , SO_NONE } ,
{ OPT_BUFSTDOUTERR , " --bufferedout " , SO_NONE } ,
{ OPT_TRACECLOCK , " --traceclock " , SO_REQ_SEP } ,
{ OPT_NUMTESTERS , " --num_testers " , SO_REQ_SEP } ,
{ OPT_HELP , " -? " , SO_NONE } ,
{ OPT_HELP , " -h " , SO_NONE } ,
{ OPT_HELP , " --help " , SO_NONE } ,
{ OPT_DEVHELP , " --dev-help " , SO_NONE } ,
{ OPT_KNOB , " --knob_ " , SO_REQ_SEP } ,
{ OPT_LOCALITY , " --locality_ " , SO_REQ_SEP } ,
{ OPT_TESTSERVERS , " --testservers " , SO_REQ_SEP } ,
{ OPT_TEST_ON_SERVERS , " --testonservers " , SO_NONE } ,
{ OPT_METRICSCONNFILE , " --metrics_cluster " , SO_REQ_SEP } ,
{ OPT_METRICSPREFIX , " --metrics_prefix " , SO_REQ_SEP } ,
{ OPT_IO_TRUST_SECONDS , " --io_trust_seconds " , SO_REQ_SEP } ,
{ OPT_IO_TRUST_WARN_ONLY , " --io_trust_warn_only " , SO_NONE } ,
{ OPT_TRACE_FORMAT , " --trace_format " , SO_REQ_SEP } ,
2019-04-13 04:23:02 +08:00
{ OPT_WHITELIST_BINPATH , " --whitelist_binpath " , SO_REQ_SEP } ,
2020-01-29 09:53:41 +08:00
{ OPT_BLOB_CREDENTIAL_FILE , " --blob_credential_file " , SO_REQ_SEP } ,
2017-05-26 04:48:44 +08:00
2018-06-27 03:08:32 +08:00
# ifndef TLS_DISABLED
2017-05-26 04:48:44 +08:00
TLS_OPTION_FLAGS
2018-06-21 00:21:23 +08:00
# endif
2017-05-26 04:48:44 +08:00
SO_END_OF_OPTIONS
} ;
2020-01-29 09:53:41 +08:00
// clang-format on
2017-05-26 04:48:44 +08:00
extern void dsltest ( ) ;
extern void pingtest ( ) ;
extern void copyTest ( ) ;
extern void versionedMapTest ( ) ;
extern void createTemplateDatabase ( ) ;
// FIXME: this really belongs in a header somewhere since it is actually used.
2019-02-27 10:04:03 +08:00
extern IPAddress determinePublicIPAutomatically ( ClusterConnectionString const & ccs ) ;
2017-05-26 04:48:44 +08:00
2019-11-16 04:26:51 +08:00
extern const char * getSourceVersion ( ) ;
2017-05-26 04:48:44 +08:00
extern void flushTraceFileVoid ( ) ;
extern bool noUnseed ;
extern const int MAX_CLUSTER_FILE_BYTES ;
# ifdef ALLOC_INSTRUMENTATION
extern uint8_t * g_extra_memory ;
# endif
bool enableFailures = true ;
# define test_assert(x) if (!(x)) { cout << "Test failed: " #x << endl; return false; }
vector < Standalone < VectorRef < DebugEntryRef > > > debugEntries ;
int64_t totalDebugEntriesSize = 0 ;
# if CENABLED(0, NOT_IN_CLEAN)
2020-04-08 06:56:44 +08:00
StringRef debugKey = LiteralStringRef ( " " ) ;
StringRef debugKey2 = LiteralStringRef ( " \xff \xff \xff \xff " ) ;
2017-05-26 04:48:44 +08:00
bool debugMutation ( const char * context , Version version , MutationRef const & mutation ) {
if ( ( mutation . type = = mutation . SetValue | | mutation . type = = mutation . AddValue | | mutation . type = = mutation . DebugKey ) & & ( mutation . param1 = = debugKey | | mutation . param1 = = debugKey2 ) )
2019-03-19 06:03:43 +08:00
; //TraceEvent("MutationTracking").detail("At", context).detail("Version", version).detail("MutationType", "SetValue").detail("Key", mutation.param1).detail("Value", mutation.param2);
2017-05-26 04:48:44 +08:00
else if ( ( mutation . type = = mutation . ClearRange | | mutation . type = = mutation . DebugKeyRange ) & & ( ( mutation . param1 < = debugKey & & mutation . param2 > debugKey ) | | ( mutation . param1 < = debugKey2 & & mutation . param2 > debugKey2 ) ) )
2019-03-19 06:03:43 +08:00
; //TraceEvent("MutationTracking").detail("At", context).detail("Version", version).detail("MutationType", "ClearRange").detail("KeyBegin", mutation.param1).detail("KeyEnd", mutation.param2);
2017-05-26 04:48:44 +08:00
else
return false ;
const char * type =
mutation . type = = MutationRef : : SetValue ? " SetValue " :
mutation . type = = MutationRef : : ClearRange ? " ClearRange " :
mutation . type = = MutationRef : : AddValue ? " AddValue " :
mutation . type = = MutationRef : : DebugKeyRange ? " DebugKeyRange " :
mutation . type = = MutationRef : : DebugKey ? " DebugKey " :
" UnknownMutation " ;
printf ( " DEBUGMUTATION: \t %.6f \t %s \t %s \t %lld \t %s \t %s \t %s \n " , now ( ) , g_network - > getLocalAddress ( ) . toString ( ) . c_str ( ) , context , version , type , printable ( mutation . param1 ) . c_str ( ) , printable ( mutation . param2 ) . c_str ( ) ) ;
return true ;
}
bool debugKeyRange ( const char * context , Version version , KeyRangeRef const & keys ) {
if ( keys . contains ( debugKey ) | | keys . contains ( debugKey2 ) ) {
debugMutation ( context , version , MutationRef ( MutationRef : : DebugKeyRange , keys . begin , keys . end ) ) ;
2019-03-19 06:03:43 +08:00
//TraceEvent("MutationTracking").detail("At", context).detail("Version", version).detail("KeyBegin", keys.begin).detail("KeyEnd", keys.end);
2017-05-26 04:48:44 +08:00
return true ;
} else
return false ;
}
# elif CENABLED(0, NOT_IN_CLEAN)
bool debugMutation ( const char * context , Version version , MutationRef const & mutation ) {
if ( ! debugEntries . size ( ) | | debugEntries . back ( ) . size ( ) > = 1000 ) {
if ( debugEntries . size ( ) ) totalDebugEntriesSize + = debugEntries . back ( ) . arena ( ) . getSize ( ) + sizeof ( debugEntries . back ( ) ) ;
debugEntries . push_back ( Standalone < VectorRef < DebugEntryRef > > ( ) ) ;
TraceEvent ( " DebugMutationBuffer " ) . detail ( " Bytes " , totalDebugEntriesSize ) ;
}
auto & v = debugEntries . back ( ) ;
v . push_back_deep ( v . arena ( ) , DebugEntryRef ( context , version , mutation ) ) ;
return false ; // No auxiliary logging
}
bool debugKeyRange ( const char * context , Version version , KeyRangeRef const & keys ) {
return debugMutation ( context , version , MutationRef ( MutationRef : : DebugKeyRange , keys . begin , keys . end ) ) ;
}
# else // Default implementation.
bool debugMutation ( const char * context , Version version , MutationRef const & mutation ) { return false ; }
bool debugKeyRange ( const char * context , Version version , KeyRangeRef const & keys ) { return false ; }
# endif
# ifdef _WIN32
# include <sddl.h>
// It is your
// responsibility to properly initialize the
// structure and to free the structure's
// lpSecurityDescriptor member when you have
// finished using it. To free the structure's
// lpSecurityDescriptor member, call the
// LocalFree function.
BOOL CreatePermissiveReadWriteDACL ( SECURITY_ATTRIBUTES * pSA )
{
UNSTOPPABLE_ASSERT ( pSA ! = NULL ) ;
TCHAR * szSD = TEXT ( " D: " ) // Discretionary ACL
TEXT ( " (A;OICI;GR;;;AU) " ) // Allow read/write/execute to authenticated users
TEXT ( " (A;OICI;GA;;;BA) " ) ; // Allow full control to administrators
return ConvertStringSecurityDescriptorToSecurityDescriptor (
szSD ,
SDDL_REVISION_1 ,
& ( pSA - > lpSecurityDescriptor ) ,
NULL ) ;
}
# endif
class WorldReadablePermissions {
public :
WorldReadablePermissions ( ) {
# ifdef _WIN32
sa . nLength = sizeof ( SECURITY_ATTRIBUTES ) ;
sa . bInheritHandle = FALSE ;
if ( ! CreatePermissiveReadWriteDACL ( & sa ) ) {
TraceEvent ( " Win32DACLCreationFail " ) . GetLastError ( ) ;
throw platform_error ( ) ;
}
permission . set_permissions ( & sa ) ;
# elif (defined(__linux__) || defined(__APPLE__))
// There is nothing to do here, since the default permissions are fine
# else
# error Port me!
# endif
}
virtual ~ WorldReadablePermissions ( ) {
# ifdef _WIN32
LocalFree ( sa . lpSecurityDescriptor ) ;
# elif (defined(__linux__) || defined(__APPLE__))
// There is nothing to do here, since the default permissions are fine
# else
# error Port me!
# endif
}
boost : : interprocess : : permissions permission ;
private :
WorldReadablePermissions ( const WorldReadablePermissions & rhs ) { }
# ifdef _WIN32
SECURITY_ATTRIBUTES sa ;
# endif
} ;
UID getSharedMemoryMachineId ( ) {
UID * machineId = NULL ;
int numTries = 0 ;
// Permissions object defaults to 0644 on *nix, but on windows defaults to allowing access to only the creator.
// On windows, this means that we have to create an elaborate workaround for DACLs
WorldReadablePermissions p ;
2019-03-22 06:23:22 +08:00
std : : string sharedMemoryIdentifier = " fdbserver_shared_memory_id " ;
2017-05-26 04:48:44 +08:00
loop {
try {
// "0" is the default parameter "addr"
2019-03-22 05:05:41 +08:00
boost : : interprocess : : managed_shared_memory segment ( boost : : interprocess : : open_or_create , sharedMemoryIdentifier . c_str ( ) , 1000 , 0 , p . permission ) ;
2019-05-11 05:01:52 +08:00
machineId = segment . find_or_construct < UID > ( " machineId " ) ( deterministicRandom ( ) - > randomUniqueID ( ) ) ;
2017-05-26 04:48:44 +08:00
if ( ! machineId )
criticalError ( FDB_EXIT_ERROR , " SharedMemoryError " , " Could not locate or create shared memory - 'machineId' " ) ;
return * machineId ;
}
2019-03-27 00:58:54 +08:00
catch ( boost : : interprocess : : interprocess_exception & ) {
2017-05-26 04:48:44 +08:00
try {
//If the shared memory already exists, open it read-only in case it was created by another user
2019-03-22 05:05:41 +08:00
boost : : interprocess : : managed_shared_memory segment ( boost : : interprocess : : open_read_only , sharedMemoryIdentifier . c_str ( ) ) ;
2017-05-26 04:48:44 +08:00
machineId = segment . find < UID > ( " machineId " ) . first ;
if ( ! machineId )
criticalError ( FDB_EXIT_ERROR , " SharedMemoryError " , " Could not locate shared memory - 'machineId' " ) ;
return * machineId ;
}
catch ( boost : : interprocess : : interprocess_exception & ex ) {
//Retry in case the shared memory was deleted in between the call to open_or_create and open_read_only
//Don't keep trying forever in case this is caused by some other problem
if ( + + numTries = = 10 )
criticalError ( FDB_EXIT_ERROR , " SharedMemoryError " , format ( " Could not open shared memory - %s " , ex . what ( ) ) . c_str ( ) ) ;
}
}
}
}
ACTOR void failAfter ( Future < Void > trigger , ISimulator : : ProcessInfo * m = g_simulator . getCurrentProcess ( ) ) {
2018-08-11 04:57:10 +08:00
wait ( trigger ) ;
2017-05-26 04:48:44 +08:00
if ( enableFailures ) {
printf ( " Killing machine: %s at %f \n " , m - > address . toString ( ) . c_str ( ) , now ( ) ) ;
g_simulator . killProcess ( m , ISimulator : : KillInstantly ) ;
}
}
void failAfter ( Future < Void > trigger , Endpoint e ) {
if ( g_network = = & g_simulator )
failAfter ( trigger , g_simulator . getProcess ( e ) ) ;
}
void testSerializationSpeed ( ) {
double tstart ;
double build = 0 , serialize = 0 , deserialize = 0 , copy = 0 , deallocate = 0 ;
double bytes = 0 ;
double testBegin = timer ( ) ;
for ( int a = 0 ; a < 10000 ; a + + ) {
{
tstart = timer ( ) ;
Arena batchArena ;
VectorRef < CommitTransactionRef > batch ;
batch . resize ( batchArena , 1000 ) ;
for ( int t = 0 ; t < batch . size ( ) ; t + + ) {
CommitTransactionRef & tr = batch [ t ] ;
tr . read_snapshot = 0 ;
for ( int i = 0 ; i < 2 ; i + + )
tr . mutations . push_back_deep ( batchArena ,
MutationRef ( MutationRef : : SetValue , LiteralStringRef ( " KeyABCDE " ) , LiteralStringRef ( " SomeValu " ) ) ) ;
tr . mutations . push_back_deep ( batchArena ,
MutationRef ( MutationRef : : ClearRange , LiteralStringRef ( " BeginKey " ) , LiteralStringRef ( " EndKeyAB " ) ) ) ;
}
build + = timer ( ) - tstart ;
tstart = timer ( ) ;
BinaryWriter wr ( IncludeVersion ( ) ) ;
wr < < batch ;
bytes + = wr . getLength ( ) ;
serialize + = timer ( ) - tstart ;
for ( int i = 0 ; i < 1 ; i + + ) {
tstart = timer ( ) ;
Arena arena ;
StringRef data ( arena , StringRef ( ( const uint8_t * ) wr . getData ( ) , wr . getLength ( ) ) ) ;
copy + = timer ( ) - tstart ;
tstart = timer ( ) ;
ArenaReader rd ( arena , data , IncludeVersion ( ) ) ;
VectorRef < CommitTransactionRef > batch2 ;
rd > > arena > > batch2 ;
deserialize + = timer ( ) - tstart ;
}
tstart = timer ( ) ;
}
deallocate + = timer ( ) - tstart ;
}
double elapsed = ( timer ( ) - testBegin ) ;
printf ( " Test speed: %0.1f MB/sec (%0.0f/sec) \n " , bytes / 1e6 / elapsed , 1000000 / elapsed ) ;
printf ( " Build: %0.1f MB/sec \n " , bytes / 1e6 / build ) ;
printf ( " Serialize: %0.1f MB/sec \n " , bytes / 1e6 / serialize ) ;
printf ( " Copy: %0.1f MB/sec \n " , bytes / 1e6 / copy ) ;
printf ( " Deserialize: %0.1f MB/sec \n " , bytes / 1e6 / deserialize ) ;
printf ( " Deallocate: %0.1f MB/sec \n " , bytes / 1e6 / deallocate ) ;
printf ( " Bytes: %0.1f MB \n " , bytes / 1e6 ) ;
printf ( " \n " ) ;
}
std : : string toHTML ( const StringRef & binaryString ) {
std : : string s ;
for ( int i = 0 ; i < binaryString . size ( ) ; i + + ) {
uint8_t c = binaryString [ i ] ;
if ( c = = ' < ' ) s + = " < " ;
else if ( c = = ' > ' ) s + = " > ; " ;
else if ( c = = ' & ' ) s + = " & ; " ;
else if ( c = = ' " ' ) s + = " " ; " ;
else if ( c = = ' ' ) s + = "   ; " ;
else if ( c > 32 & & c < 127 ) s + = c ;
else s + = format ( " <span class= \" binary \" >[%02x]</span> " , c ) ;
}
return s ;
}
ACTOR Future < Void > dumpDatabase ( Database cx , std : : string outputFilename , KeyRange range = allKeys ) {
try {
state Transaction tr ( cx ) ;
loop {
state FILE * output = fopen ( outputFilename . c_str ( ) , " wt " ) ;
try {
state KeySelectorRef iter = firstGreaterOrEqual ( range . begin ) ;
state Arena arena ;
fprintf ( output , " <html><head><style type= \" text/css \" >.binary {color:red}</style></head><body> \n " ) ;
Version ver = wait ( tr . getReadVersion ( ) ) ;
2019-05-05 01:52:02 +08:00
fprintf ( output , " <h3>Database version: % " PRId64 " </h3> " , ver ) ;
2017-05-26 04:48:44 +08:00
loop {
Standalone < RangeResultRef > results = wait (
tr . getRange ( iter , firstGreaterOrEqual ( range . end ) , 1000 ) ) ;
for ( int r = 0 ; r < results . size ( ) ; r + + ) {
std : : string key = toHTML ( results [ r ] . key ) , value = toHTML ( results [ r ] . value ) ;
fprintf ( output , " <p>%s <b>:=</b> %s</p> \n " , key . c_str ( ) , value . c_str ( ) ) ;
}
if ( results . size ( ) < 1000 ) break ;
iter = firstGreaterThan ( KeyRef ( arena , results [ results . size ( ) - 1 ] . key ) ) ;
}
fprintf ( output , " </body></html> " ) ;
fclose ( output ) ;
TraceEvent ( " DatabaseDumped " ) . detail ( " Filename " , outputFilename ) ;
return Void ( ) ;
} catch ( Error & e ) {
fclose ( output ) ;
2018-08-11 04:57:10 +08:00
wait ( tr . onError ( e ) ) ;
2017-05-26 04:48:44 +08:00
}
}
} catch ( Error & e ) {
2018-06-09 04:57:00 +08:00
TraceEvent ( SevError , " DumpDatabaseError " ) . error ( e ) . detail ( " Filename " , outputFilename ) ;
2017-05-26 04:48:44 +08:00
throw ;
}
}
void memoryTest ( ) ;
void skipListTest ( ) ;
Future < Void > startSystemMonitor ( std : : string dataFolder , Optional < Standalone < StringRef > > zoneId , Optional < Standalone < StringRef > > machineId ) {
initializeSystemMonitorMachineState ( SystemMonitorMachineState ( dataFolder , zoneId , machineId , g_network - > getLocalAddress ( ) . ip ) ) ;
systemMonitor ( ) ;
2019-06-25 17:47:35 +08:00
return recurring ( & systemMonitor , 5.0 , TaskPriority : : FlushTrace ) ;
2017-05-26 04:48:44 +08:00
}
void testIndexedSet ( ) ;
# ifdef _WIN32
void parentWatcher ( void * parentHandle ) {
HANDLE parent = ( HANDLE ) parentHandle ;
int signal = WaitForSingleObject ( parent , INFINITE ) ;
CloseHandle ( parentHandle ) ;
if ( signal = = WAIT_OBJECT_0 )
criticalError ( FDB_EXIT_SUCCESS , " ParentProcessExited " , " Parent process exited " ) ;
TraceEvent ( SevError , " ParentProcessWaitFailed " ) . detail ( " RetCode " , signal ) . GetLastError ( ) ;
}
2019-04-26 03:49:14 +08:00
# else
void * parentWatcher ( void * arg ) {
int * parent_pid = ( int * ) arg ;
while ( 1 ) {
sleep ( 1 ) ;
if ( getppid ( ) ! = * parent_pid )
criticalError ( FDB_EXIT_SUCCESS , " ParentProcessExited " , " Parent process exited " ) ;
}
}
2017-05-26 04:48:44 +08:00
# endif
static void printVersion ( ) {
printf ( " FoundationDB " FDB_VT_PACKAGE_NAME " (v " FDB_VT_VERSION " ) \n " ) ;
2019-11-16 04:26:51 +08:00
printf ( " source version %s \n " , getSourceVersion ( ) ) ;
2019-08-02 01:19:46 +08:00
printf ( " protocol % " PRIx64 " \n " , currentProtocolVersion . version ( ) ) ;
2017-05-26 04:48:44 +08:00
}
static void printHelpTeaser ( const char * name ) {
fprintf ( stderr , " Try `%s --help' for more information. \n " , name ) ;
}
static void printUsage ( const char * name , bool devhelp ) {
printf ( " FoundationDB " FDB_VT_PACKAGE_NAME " (v " FDB_VT_VERSION " ) \n " ) ;
printf ( " Usage: %s -p ADDRESS [OPTIONS] \n \n " , name ) ;
printf ( " -p ADDRESS, --public_address ADDRESS \n "
" Public address, specified as `IP_ADDRESS:PORT' or `auto:PORT'. \n " ) ;
printf ( " -l ADDRESS, --listen_address ADDRESS \n "
" Listen address, specified as `IP_ADDRESS:PORT' (defaults to \n " ) ;
printf ( " public address). \n " ) ;
printf ( " -C CONNFILE, --cluster_file CONNFILE \n "
" The path of a file containing the connection string for the \n "
" FoundationDB cluster. The default is first the value of the \n "
" FDB_CLUSTER_FILE environment variable, then `./fdb.cluster', \n "
" then `%s'. \n " , platform : : getDefaultClusterFilePath ( ) . c_str ( ) ) ;
printf ( " --seed_cluster_file SEEDCONNFILE \n "
" The path of a seed cluster file which will be used to connect \n "
" if the -C cluster file does not exist. If the server connects \n "
" successfully using the seed file, then it copies the file to \n "
" the -C file location. \n " ) ;
printf ( " --seed_connection_string SEEDCONNSTRING \n "
" The path of a seed connection string which will be used to connect \n "
" if the -C cluster file does not exist. If the server connects \n "
" successfully using the seed string, then it copies the string to \n "
" the -C file location. \n " ) ;
# ifdef __linux__
printf ( " --data_filesystem PATH \n "
" Turns on validation that all data files are written to a drive \n "
" mounted at the specified PATH. This checks that the device at PATH \n "
" is currently mounted and that any data files get written to the \n "
" same device. \n " ) ;
# endif
printf ( " -d PATH, --datadir PATH \n "
" Store data files in the given folder (must be unique for each \n " ) ;
printf ( " fdbserver instance on a given machine). \n " ) ;
printf ( " -L PATH, --logdir PATH \n "
" Store log files in the given folder (default is `.'). \n " ) ;
printf ( " --logsize SIZE Roll over to a new log file after the current log file \n "
" exceeds SIZE bytes. The default value is 10MiB. \n " ) ;
printf ( " --maxlogs SIZE, --maxlogssize SIZE \n "
" Delete the oldest log file when the total size of all log \n "
" files exceeds SIZE bytes. If set to 0, old log files will not \n "
" be deleted. The default value is 100MiB. \n " ) ;
2019-08-20 03:59:14 +08:00
printf ( " --loggroup LOG_GROUP \n "
" Sets the LogGroup field with the specified value for all \n "
" events in the trace output (defaults to `default'). \n " ) ;
2018-12-21 08:22:41 +08:00
printf ( " --trace_format FORMAT \n "
2019-07-31 07:11:09 +08:00
" Select the format of the log files. xml (the default) and json \n "
" are supported. \n " ) ;
2017-05-26 04:48:44 +08:00
printf ( " -i ID, --machine_id ID \n "
2019-07-31 07:11:09 +08:00
" Machine and zone identifier key (up to 16 hex characters). \n "
" Defaults to a random value shared by all fdbserver processes \n "
" on this machine. \n " ) ;
2017-05-26 04:48:44 +08:00
printf ( " -a ID, --datacenter_id ID \n "
" Data center identifier key (up to 16 hex characters). \n " ) ;
2019-07-31 05:34:27 +08:00
printf ( " --locality_LOCALITYKEY LOCALITYVALUE \n "
2019-07-31 07:11:09 +08:00
" Define a locality key. LOCALITYKEY is case-insensitive though \n "
" LOCALITYVALUE is not. \n " ) ;
2019-07-31 05:34:27 +08:00
printf ( " -m SIZE, --memory SIZE \n "
" Memory limit. The default value is 8GiB. When specified \n "
" without a unit, MiB is assumed. \n " ) ;
printf ( " -M SIZE, --storage_memory SIZE \n "
" Maximum amount of memory used for storage. The default \n "
" value is 1GiB. When specified without a unit, MB is \n "
" assumed. \n " ) ;
printf ( " --cache_memory SIZE \n "
" The amount of memory to use for caching disk pages. \n "
" The default value is 2GiB. When specified without a unit, \n "
" MiB is assumed. \n " ) ;
2017-05-26 04:48:44 +08:00
printf ( " -c CLASS, --class CLASS \n "
2018-03-27 04:24:34 +08:00
" Machine class (valid options are storage, transaction, \n "
" resolution, proxy, master, test, unset, stateless, log, router, \n "
" and cluster_controller). \n " ) ;
2018-06-27 03:08:32 +08:00
# ifndef TLS_DISABLED
2017-05-26 04:48:44 +08:00
printf ( TLS_HELP ) ;
2018-06-21 00:21:23 +08:00
# endif
2017-05-26 04:48:44 +08:00
printf ( " -v, --version Print version information and exit. \n " ) ;
printf ( " -h, -?, --help Display this help and exit. \n " ) ;
if ( devhelp ) {
printf ( " -r ROLE, --role ROLE \n "
" Server role (valid options are fdbd, test, multitest, \n " ) ;
2018-10-10 09:47:28 +08:00
printf ( " simulation, networktestclient, networktestserver, restore \n " ) ;
2017-05-27 08:43:28 +08:00
printf ( " consistencycheck, kvfileintegritycheck, kvfilegeneratesums). The default is `fdbd'. \n " ) ;
2017-05-26 04:48:44 +08:00
# ifdef _WIN32
printf ( " -n, --newconsole \n "
" Create a new console. \n " ) ;
printf ( " -q, --no_dialog \n "
" Disable error dialog on crash. \n " ) ;
printf ( " --parentpid PID \n " ) ;
printf ( " Specify a process after whose termination to exit. \n " ) ;
# endif
printf ( " -f TESTFILE, --testfile \n "
" Testfile to run, defaults to `tests/default.txt'. \n " ) ;
printf ( " -R, --restarting \n " ) ;
printf ( " Restart a previous simulation that was cleanly shut down. \n " ) ;
printf ( " -s SEED, --seed SEED \n "
" Random seed. \n " ) ;
printf ( " -k KEY, --key KEY Target key for search role. \n " ) ;
2017-06-02 03:07:30 +08:00
printf ( " --kvfile FILE Input file (SQLite database file) for use by the 'kvfilegeneratesums' and 'kvfileintegritycheck' roles. \n " ) ;
2017-05-26 04:48:44 +08:00
printf ( " -b [on,off], --buggify [on,off] \n "
" Sets Buggify system state, defaults to `off'. \n " ) ;
printf ( " --crash Crash on serious errors instead of continuing. \n " ) ;
printf ( " -N NETWORKIMPL, --network NETWORKIMPL \n "
" Select network implementation, `net2' (default), \n " ) ;
printf ( " `net2-threadpool'. \n " ) ;
printf ( " --unbufferedout \n " ) ;
printf ( " Do not buffer stdout and stderr. \n " ) ;
printf ( " --bufferedout \n " ) ;
printf ( " Buffer stdout and stderr. \n " ) ;
printf ( " --traceclock CLOCKIMPL \n " ) ;
printf ( " Select clock source for trace files, `now' (default) or \n " ) ;
printf ( " `realtime'. \n " ) ;
printf ( " --num_testers NUM \n " ) ;
printf ( " A multitester will wait for NUM testers before starting \n " ) ;
printf ( " (defaults to 1). \n " ) ;
2019-04-10 04:26:12 +08:00
# ifdef __linux__
printf ( " --rsssize SIZE \n "
" Turns on automatic heap profiling when RSS memory size exceeds \n "
" the given threshold. fdbserver needs to be compiled with \n "
" USE_GPERFTOOLS flag in order to use this feature. \n " ) ;
# endif
2017-05-26 04:48:44 +08:00
printf ( " --testservers ADDRESSES \n " ) ;
printf ( " The addresses of networktestservers \n " ) ;
printf ( " specified as ADDRESS:PORT,ADDRESS:PORT... \n " ) ;
printf ( " --testonservers \n " ) ;
printf ( " Testers are recruited on servers. \n " ) ;
printf ( " --metrics_cluster CONNFILE \n " ) ;
printf ( " The cluster file designating where this process will \n " ) ;
printf ( " store its metric data. By default metrics will be stored \n " ) ;
printf ( " in the same database the process is participating in. \n " ) ;
printf ( " --metrics_prefix PREFIX \n " ) ;
printf ( " The prefix where this process will store its metric data. \n " ) ;
printf ( " Must be specified if using a different database for metrics. \n " ) ;
printf ( " --knob_KNOBNAME KNOBVALUE \n " ) ;
printf ( " Changes a database knob. KNOBNAME should be lowercase. \n " ) ;
printf ( " --io_trust_seconds SECONDS \n " ) ;
printf ( " Sets the time in seconds that a read or write operation is allowed to take \n "
" before timing out with an error. If an operation times out, all future \n "
" operations on that file will fail with an error as well. Only has an effect \n "
" when using AsyncFileKAIO in Linux. \n " ) ;
printf ( " --io_trust_warn_only \n " ) ;
printf ( " Instead of failing when an I/O operation exceeds io_trust_seconds, just \n "
" log a warning to the trace log. Has no effect if io_trust_seconds is unspecified. \n " ) ;
} else {
printf ( " --dev-help Display developer-specific help and exit. \n " ) ;
}
printf ( " \n "
" SIZE parameters may use one of the multiplicative suffixes B=1, KB=10^3, \n "
" KiB=2^10, MB=10^6, MiB=2^20, GB=10^9, GiB=2^30, TB=10^12, or TiB=2^40. \n " ) ;
}
extern bool g_crashOnError ;
# if defined(ALLOC_INSTRUMENTATION) || defined(ALLOC_INSTRUMENTATION_STDOUT)
2019-10-09 06:50:47 +08:00
void * operator new ( std : : size_t size ) {
2017-05-26 04:48:44 +08:00
void * p = malloc ( size ) ;
if ( ! p )
throw std : : bad_alloc ( ) ;
recordAllocation ( p , size ) ;
return p ;
}
void operator delete ( void * ptr ) throw ( ) {
recordDeallocation ( ptr ) ;
free ( ptr ) ;
}
//scalar, nothrow new and it matching delete
void * operator new ( std : : size_t size , const std : : nothrow_t & ) throw ( ) {
void * p = malloc ( size ) ;
recordAllocation ( p , size ) ;
return p ;
}
void operator delete ( void * ptr , const std : : nothrow_t & ) throw ( ) {
recordDeallocation ( ptr ) ;
free ( ptr ) ;
}
//array throwing new and matching delete[]
2019-10-09 06:50:47 +08:00
void * operator new [ ] ( std : : size_t size ) {
2017-05-26 04:48:44 +08:00
void * p = malloc ( size ) ;
if ( ! p )
throw std : : bad_alloc ( ) ;
recordAllocation ( p , size ) ;
return p ;
}
void operator delete [ ] ( void * ptr ) throw ( ) {
recordDeallocation ( ptr ) ;
free ( ptr ) ;
}
//array, nothrow new and matching delete[]
void * operator new [ ] ( std : : size_t size , const std : : nothrow_t & ) throw ( ) {
void * p = malloc ( size ) ;
recordAllocation ( p , size ) ;
return p ;
}
void operator delete [ ] ( void * ptr , const std : : nothrow_t & ) throw ( ) {
recordDeallocation ( ptr ) ;
free ( ptr ) ;
}
# endif
2017-09-16 08:55:01 +08:00
Optional < bool > checkBuggifyOverride ( const char * testFile ) {
std : : ifstream ifs ;
ifs . open ( testFile , std : : ifstream : : in ) ;
if ( ! ifs . good ( ) )
return 0 ;
std : : string cline ;
while ( ifs . good ( ) ) {
getline ( ifs , cline ) ;
std : : string line = removeWhitespace ( std : : string ( cline ) ) ;
if ( ! line . size ( ) | | line . find ( ' ; ' ) = = 0 )
continue ;
size_t found = line . find ( ' = ' ) ;
if ( found = = std : : string : : npos )
// hmmm, not good
continue ;
std : : string attrib = removeWhitespace ( line . substr ( 0 , found ) ) ;
std : : string value = removeWhitespace ( line . substr ( found + 1 ) ) ;
if ( attrib = = " buggify " ) {
if ( ! strcmp ( value . c_str ( ) , " on " ) ) {
ifs . close ( ) ;
return true ;
} else if ( ! strcmp ( value . c_str ( ) , " off " ) ) {
ifs . close ( ) ;
return false ;
} else {
fprintf ( stderr , " ERROR: Unknown buggify override state `%s' \n " , value . c_str ( ) ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
}
}
ifs . close ( ) ;
return Optional < bool > ( ) ;
}
2018-10-23 08:57:09 +08:00
// Takes a vector of public and listen address strings given via command line, and returns vector of NetworkAddress objects.
std : : pair < NetworkAddressList , NetworkAddressList > buildNetworkAddresses ( const ClusterConnectionFile & connectionFile ,
2019-02-14 07:37:31 +08:00
const vector < std : : string > & publicAddressStrs ,
vector < std : : string > & listenAddressStrs ) {
if ( listenAddressStrs . size ( ) > 0 & & publicAddressStrs . size ( ) ! = listenAddressStrs . size ( ) ) {
fprintf ( stderr ,
" ERROR: Listen addresses (if provided) should be equal to the number of public addresses in order. \n " ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
listenAddressStrs . resize ( publicAddressStrs . size ( ) , " public " ) ;
if ( publicAddressStrs . size ( ) > 2 ) {
fprintf ( stderr , " ERROR: maximum 2 public/listen addresses are allowed \n " ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
2018-10-23 08:57:09 +08:00
NetworkAddressList publicNetworkAddresses ;
NetworkAddressList listenNetworkAddresses ;
2019-03-24 08:54:46 +08:00
auto & coordinators = connectionFile . getConnectionString ( ) . coordinators ( ) ;
2019-02-14 07:37:31 +08:00
ASSERT ( coordinators . size ( ) > 0 ) ;
2018-10-23 08:57:09 +08:00
for ( int ii = 0 ; ii < publicAddressStrs . size ( ) ; + + ii ) {
const std : : string & publicAddressStr = publicAddressStrs [ ii ] ;
bool autoPublicAddress = StringRef ( publicAddressStr ) . startsWith ( LiteralStringRef ( " auto: " ) ) ;
2019-03-24 08:54:46 +08:00
NetworkAddress currentPublicAddress ;
2018-10-23 08:57:09 +08:00
if ( autoPublicAddress ) {
try {
const NetworkAddress & parsedAddress = NetworkAddress : : parse ( " 0.0.0.0: " + publicAddressStr . substr ( 5 ) ) ;
2019-02-27 10:04:03 +08:00
const IPAddress publicIP = determinePublicIPAutomatically ( connectionFile . getConnectionString ( ) ) ;
2019-03-24 08:54:46 +08:00
currentPublicAddress = NetworkAddress ( publicIP , parsedAddress . port , true , parsedAddress . isTLS ( ) ) ;
2018-10-23 08:57:09 +08:00
} catch ( Error & e ) {
fprintf ( stderr , " ERROR: could not determine public address automatically from `%s': %s \n " , publicAddressStr . c_str ( ) , e . what ( ) ) ;
throw ;
}
} else {
try {
2019-03-24 08:54:46 +08:00
currentPublicAddress = NetworkAddress : : parse ( publicAddressStr ) ;
2018-10-23 08:57:09 +08:00
} catch ( Error & ) {
fprintf ( stderr , " ERROR: Could not parse network address `%s' (specify as IP_ADDRESS:PORT) \n " , publicAddressStr . c_str ( ) ) ;
throw ;
}
}
2019-03-24 08:54:46 +08:00
if ( ii = = 0 ) {
publicNetworkAddresses . address = currentPublicAddress ;
} else {
publicNetworkAddresses . secondaryAddress = currentPublicAddress ;
}
2019-02-27 13:03:34 +08:00
if ( ! currentPublicAddress . isValid ( ) ) {
2019-03-05 14:13:47 +08:00
fprintf ( stderr , " ERROR: %s is not a valid IP address \n " , currentPublicAddress . toString ( ) . c_str ( ) ) ;
2019-02-14 07:37:31 +08:00
flushAndExit ( FDB_EXIT_ERROR ) ;
}
2018-10-23 08:57:09 +08:00
const std : : string & listenAddressStr = listenAddressStrs [ ii ] ;
2019-03-24 08:54:46 +08:00
NetworkAddress currentListenAddress ;
2018-10-23 08:57:09 +08:00
if ( listenAddressStr = = " public " ) {
2019-03-24 08:54:46 +08:00
currentListenAddress = currentPublicAddress ;
2018-10-23 08:57:09 +08:00
} else {
try {
2019-03-24 08:54:46 +08:00
currentListenAddress = NetworkAddress : : parse ( listenAddressStr ) ;
2018-10-23 08:57:09 +08:00
} catch ( Error & ) {
fprintf ( stderr , " ERROR: Could not parse network address `%s' (specify as IP_ADDRESS:PORT) \n " , listenAddressStr . c_str ( ) ) ;
throw ;
}
2019-02-14 07:37:31 +08:00
2019-03-24 08:54:46 +08:00
if ( currentListenAddress . isTLS ( ) ! = currentPublicAddress . isTLS ( ) ) {
2019-02-14 07:37:31 +08:00
fprintf ( stderr ,
" ERROR: TLS state of listen address: %s is not equal to the TLS state of public address: %s. \n " ,
listenAddressStr . c_str ( ) , publicAddressStr . c_str ( ) ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
2018-10-23 08:57:09 +08:00
}
2019-03-24 08:54:46 +08:00
if ( ii = = 0 ) {
listenNetworkAddresses . address = currentListenAddress ;
} else {
listenNetworkAddresses . secondaryAddress = currentListenAddress ;
}
2019-02-27 13:03:34 +08:00
bool hasSameCoord =
std : : all_of ( coordinators . begin ( ) , coordinators . end ( ) , [ & ] ( const NetworkAddress & address ) {
if ( address . ip = = currentPublicAddress . ip & & address . port = = currentPublicAddress . port ) {
return address . isTLS ( ) = = currentPublicAddress . isTLS ( ) ;
}
return true ;
} ) ;
if ( ! hasSameCoord ) {
fprintf ( stderr , " ERROR: TLS state of public address %s does not match in coordinator list. \n " ,
publicAddressStr . c_str ( ) ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2018-10-23 08:57:09 +08:00
}
}
2019-03-24 08:54:46 +08:00
if ( publicNetworkAddresses . secondaryAddress . present ( ) & & publicNetworkAddresses . address . isTLS ( ) = = publicNetworkAddresses . secondaryAddress . get ( ) . isTLS ( ) ) {
2019-02-14 07:37:31 +08:00
fprintf ( stderr , " ERROR: only one public address of each TLS state is allowed. \n " ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2018-10-23 08:57:09 +08:00
}
return std : : make_pair ( publicNetworkAddresses , listenNetworkAddresses ) ;
}
2019-07-16 02:33:40 +08:00
// moves files from 'dirSrc' to 'dirToMove' if their name contains 'role'
2019-06-20 02:22:23 +08:00
void restoreRoleFilesHelper ( std : : string dirSrc , std : : string dirToMove , std : : string role ) {
std : : vector < std : : string > returnFiles = platform : : listFiles ( dirSrc , " " ) ;
for ( const auto & fileEntry : returnFiles ) {
if ( fileEntry ! = " fdb.cluster " & & fileEntry . find ( role ) ! = std : : string : : npos ) {
//rename files
TraceEvent ( " RenamingSnapFile " )
. detail ( " Oldname " , dirSrc + " / " + fileEntry )
. detail ( " Newname " , dirToMove + " / " + fileEntry ) ;
renameFile ( dirSrc + " / " + fileEntry , dirToMove + " / " + fileEntry ) ;
}
}
}
2019-08-06 08:08:42 +08:00
namespace {
enum Role {
2019-08-10 04:10:12 +08:00
ConsistencyCheck ,
CreateTemplateDatabase ,
DSLTest ,
2019-08-06 08:08:42 +08:00
FDBD ,
2019-08-10 04:10:12 +08:00
KVFileGenerateIOLogChecksums ,
KVFileIntegrityCheck ,
2019-08-06 08:08:42 +08:00
MultiTester ,
NetworkTestClient ,
NetworkTestServer ,
Restore ,
2019-08-10 04:10:12 +08:00
SearchMutations ,
Simulation ,
SkipListTest ,
Test ,
VersionedMapTest ,
2019-08-06 08:08:42 +08:00
} ;
struct CLIOptions {
std : : string commandLine ;
2019-08-10 04:09:59 +08:00
std : : string fileSystemPath , dataFolder , connFile , seedConnFile , seedConnString , logFolder = " . " , metricsConnFile ,
metricsPrefix ;
2019-08-06 08:08:42 +08:00
std : : string logGroup = " default " ;
2019-08-10 04:09:59 +08:00
uint64_t rollsize = TRACE_DEFAULT_ROLL_SIZE ;
uint64_t maxLogsSize = TRACE_DEFAULT_MAX_LOGS_SIZE ;
bool maxLogsSizeSet = false ;
int maxLogs = 0 ;
bool maxLogsSet = false ;
2019-08-06 08:08:42 +08:00
Role role = FDBD ;
uint32_t randomSeed = platform : : getRandomSeed ( ) ;
const char * testFile = " tests/default.txt " ;
std : : string kvFile ;
std : : string testServersStr ;
std : : string whitelistBinPaths ;
2019-08-10 04:09:59 +08:00
2019-08-06 08:08:42 +08:00
std : : vector < std : : string > publicAddressStrs , listenAddressStrs ;
2019-08-10 04:09:59 +08:00
NetworkAddressList publicAddresses , listenAddresses ;
2019-08-06 08:08:42 +08:00
const char * targetKey = NULL ;
uint64_t memLimit =
8LL < < 30 ; // Nice to maintain the same default value for memLimit and SERVER_KNOBS->SERVER_MEM_LIMIT and
// SERVER_KNOBS->COMMIT_BATCHES_MEM_BYTES_HARD_LIMIT
uint64_t storageMemLimit = 1LL < < 30 ;
bool buggifyEnabled = false , restarting = false ;
Optional < Standalone < StringRef > > zoneId ;
Optional < Standalone < StringRef > > dcId ;
ProcessClass processClass = ProcessClass ( ProcessClass : : UnsetClass , ProcessClass : : CommandLineSource ) ;
bool useNet2 = true ;
bool useThreadPool = false ;
std : : vector < std : : pair < std : : string , std : : string > > knobs ;
LocalityData localities ;
int minTesterCount = 1 ;
bool testOnServers = false ;
2020-03-07 10:22:46 +08:00
TLSConfig tlsConfig = TLSConfig ( TLSEndpointType : : SERVER ) ;
2019-08-06 08:08:42 +08:00
double fileIoTimeout = 0.0 ;
bool fileIoWarnOnly = false ;
uint64_t rsssize = - 1 ;
2020-01-29 09:53:41 +08:00
std : : vector < std : : string > blobCredentials ; // used for fast restore workers
const char * blobCredsFromENV = nullptr ;
2019-08-06 08:08:42 +08:00
Reference < ClusterConnectionFile > connectionFile ;
Standalone < StringRef > machineId ;
static CLIOptions parseArgs ( int argc , char * argv [ ] ) {
CLIOptions opts ;
opts . parseArgsInternal ( argc , argv ) ;
return opts ;
}
2017-05-26 04:48:44 +08:00
2019-08-06 08:08:42 +08:00
private :
CLIOptions ( ) = default ;
2018-06-21 00:21:23 +08:00
2019-08-06 08:08:42 +08:00
void parseArgsInternal ( int argc , char * argv [ ] ) {
for ( int a = 0 ; a < argc ; a + + ) {
2017-05-26 04:48:44 +08:00
if ( a ) commandLine + = ' ' ;
commandLine + = argv [ a ] ;
}
CSimpleOpt args ( argc , argv , g_rgOptions , SO_O_EXACT ) ;
2019-08-06 08:08:42 +08:00
if ( argc = = 1 ) {
2017-05-26 04:48:44 +08:00
printUsage ( argv [ 0 ] , false ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
while ( args . Next ( ) ) {
if ( args . LastError ( ) = = SO_ARG_INVALID_DATA ) {
fprintf ( stderr , " ERROR: invalid argument to option `%s' \n " , args . OptionText ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
if ( args . LastError ( ) = = SO_ARG_INVALID ) {
fprintf ( stderr , " ERROR: argument given for option `%s' \n " , args . OptionText ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
if ( args . LastError ( ) = = SO_ARG_MISSING ) {
fprintf ( stderr , " ERROR: missing argument for option `%s' \n " , args . OptionText ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
if ( args . LastError ( ) = = SO_OPT_INVALID ) {
fprintf ( stderr , " ERROR: unknown option: `%s' \n " , args . OptionText ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
if ( args . LastError ( ) ! = SO_SUCCESS ) {
fprintf ( stderr , " ERROR: error parsing options \n " ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
2019-08-06 08:08:42 +08:00
const char * sRole ;
2017-05-26 04:48:44 +08:00
Optional < uint64_t > ti ;
2019-06-19 09:15:15 +08:00
std : : string argStr ;
2019-06-21 14:03:49 +08:00
std : : vector < std : : string > tmpStrings ;
2017-05-26 04:48:44 +08:00
switch ( args . OptionId ( ) ) {
2019-08-06 08:08:42 +08:00
case OPT_HELP :
printUsage ( argv [ 0 ] , false ) ;
flushAndExit ( FDB_EXIT_SUCCESS ) ;
break ;
case OPT_DEVHELP :
printUsage ( argv [ 0 ] , true ) ;
flushAndExit ( FDB_EXIT_SUCCESS ) ;
break ;
case OPT_KNOB : {
std : : string syn = args . OptionSyntax ( ) ;
if ( ! StringRef ( syn ) . startsWith ( LiteralStringRef ( " --knob_ " ) ) ) {
fprintf ( stderr , " ERROR: unable to parse knob option '%s' \n " , syn . c_str ( ) ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
syn = syn . substr ( 7 ) ;
knobs . push_back ( std : : make_pair ( syn , args . OptionArg ( ) ) ) ;
break ;
}
case OPT_LOCALITY : {
std : : string syn = args . OptionSyntax ( ) ;
if ( ! StringRef ( syn ) . startsWith ( LiteralStringRef ( " --locality_ " ) ) ) {
fprintf ( stderr , " ERROR: unable to parse locality key '%s' \n " , syn . c_str ( ) ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2019-04-06 07:06:30 +08:00
}
2019-08-06 08:08:42 +08:00
syn = syn . substr ( 11 ) ;
std : : transform ( syn . begin ( ) , syn . end ( ) , syn . begin ( ) , : : tolower ) ;
localities . set ( Standalone < StringRef > ( syn ) , Standalone < StringRef > ( std : : string ( args . OptionArg ( ) ) ) ) ;
break ;
}
case OPT_VERSION :
printVersion ( ) ;
flushAndExit ( FDB_EXIT_SUCCESS ) ;
break ;
case OPT_NOBUFSTDOUT :
setvbuf ( stdout , NULL , _IONBF , 0 ) ;
setvbuf ( stderr , NULL , _IONBF , 0 ) ;
break ;
case OPT_BUFSTDOUTERR :
setvbuf ( stdout , NULL , _IOFBF , BUFSIZ ) ;
setvbuf ( stderr , NULL , _IOFBF , BUFSIZ ) ;
break ;
case OPT_ROLE :
sRole = args . OptionArg ( ) ;
if ( ! strcmp ( sRole , " fdbd " ) )
role = FDBD ;
else if ( ! strcmp ( sRole , " simulation " ) )
role = Simulation ;
else if ( ! strcmp ( sRole , " test " ) )
role = Test ;
else if ( ! strcmp ( sRole , " multitest " ) )
role = MultiTester ;
else if ( ! strcmp ( sRole , " skiplisttest " ) )
role = SkipListTest ;
else if ( ! strcmp ( sRole , " search " ) )
role = SearchMutations ;
else if ( ! strcmp ( sRole , " dsltest " ) )
role = DSLTest ;
else if ( ! strcmp ( sRole , " versionedmaptest " ) )
role = VersionedMapTest ;
else if ( ! strcmp ( sRole , " createtemplatedb " ) )
role = CreateTemplateDatabase ;
else if ( ! strcmp ( sRole , " networktestclient " ) )
role = NetworkTestClient ;
else if ( ! strcmp ( sRole , " networktestserver " ) )
role = NetworkTestServer ;
else if ( ! strcmp ( sRole , " restore " ) )
role = Restore ;
else if ( ! strcmp ( sRole , " kvfileintegritycheck " ) )
role = KVFileIntegrityCheck ;
else if ( ! strcmp ( sRole , " kvfilegeneratesums " ) )
role = KVFileGenerateIOLogChecksums ;
else if ( ! strcmp ( sRole , " consistencycheck " ) )
role = ConsistencyCheck ;
else {
fprintf ( stderr , " ERROR: Unknown role `%s' \n " , sRole ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
break ;
case OPT_PUBLICADDR :
argStr = args . OptionArg ( ) ;
boost : : split ( tmpStrings , argStr , [ ] ( char c ) { return c = = ' , ' ; } ) ;
publicAddressStrs . insert ( publicAddressStrs . end ( ) , tmpStrings . begin ( ) , tmpStrings . end ( ) ) ;
break ;
case OPT_LISTEN :
argStr = args . OptionArg ( ) ;
boost : : split ( tmpStrings , argStr , [ ] ( char c ) { return c = = ' , ' ; } ) ;
listenAddressStrs . insert ( listenAddressStrs . end ( ) , tmpStrings . begin ( ) , tmpStrings . end ( ) ) ;
break ;
case OPT_CONNFILE :
connFile = args . OptionArg ( ) ;
break ;
case OPT_LOGGROUP :
logGroup = args . OptionArg ( ) ;
break ;
case OPT_SEEDCONNFILE :
seedConnFile = args . OptionArg ( ) ;
break ;
case OPT_SEEDCONNSTRING :
seedConnString = args . OptionArg ( ) ;
break ;
# ifdef __linux__
case OPT_FILESYSTEM : {
fileSystemPath = args . OptionArg ( ) ;
break ;
}
case OPT_PROFILER_RSS_SIZE : {
const char * a = args . OptionArg ( ) ;
char * end ;
rsssize = strtoull ( a , & end , 10 ) ;
if ( * end ) {
fprintf ( stderr , " ERROR: Unrecognized memory size `%s' \n " , a ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
break ;
}
# endif
case OPT_DATAFOLDER :
dataFolder = args . OptionArg ( ) ;
break ;
case OPT_LOGFOLDER :
logFolder = args . OptionArg ( ) ;
break ;
case OPT_NETWORKIMPL : {
const char * a = args . OptionArg ( ) ;
if ( ! strcmp ( a , " net2 " ) )
useNet2 = true ;
else if ( ! strcmp ( a , " net2-threadpool " ) ) {
useNet2 = true ;
useThreadPool = true ;
} else {
fprintf ( stderr , " ERROR: Unknown network implementation `%s' \n " , a ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
break ;
}
case OPT_TRACECLOCK : {
const char * a = args . OptionArg ( ) ;
2020-01-17 10:37:47 +08:00
if ( ! strcmp ( a , " realtime " ) ) g_trace_clock . store ( TRACE_CLOCK_REALTIME ) ;
else if ( ! strcmp ( a , " now " ) ) g_trace_clock . store ( TRACE_CLOCK_NOW ) ;
2019-08-06 08:08:42 +08:00
else {
fprintf ( stderr , " ERROR: Unknown clock source `%s' \n " , a ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
break ;
}
case OPT_NUMTESTERS : {
const char * a = args . OptionArg ( ) ;
if ( ! sscanf ( a , " %d " , & minTesterCount ) ) {
fprintf ( stderr , " ERROR: Could not parse numtesters `%s' \n " , a ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
break ;
}
case OPT_ROLLSIZE : {
const char * a = args . OptionArg ( ) ;
ti = parse_with_suffix ( a ) ;
if ( ! ti . present ( ) ) {
fprintf ( stderr , " ERROR: Could not parse logsize `%s' \n " , a ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
rollsize = ti . get ( ) ;
break ;
}
case OPT_MAXLOGSSIZE : {
const char * a = args . OptionArg ( ) ;
ti = parse_with_suffix ( a ) ;
if ( ! ti . present ( ) ) {
fprintf ( stderr , " ERROR: Could not parse maxlogssize `%s' \n " , a ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
maxLogsSize = ti . get ( ) ;
maxLogsSizeSet = true ;
break ;
}
case OPT_MAXLOGS : {
const char * a = args . OptionArg ( ) ;
char * end ;
maxLogs = strtoull ( a , & end , 10 ) ;
if ( * end ) {
fprintf ( stderr , " ERROR: Unrecognized maximum number of logs `%s' \n " , a ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2019-04-26 03:49:14 +08:00
}
2019-08-06 08:08:42 +08:00
maxLogsSet = true ;
break ;
}
# ifdef _WIN32
case OPT_PARENTPID : {
auto pid_str = args . OptionArg ( ) ;
int parent_pid = atoi ( pid_str ) ;
auto pHandle = OpenProcess ( SYNCHRONIZE , FALSE , parent_pid ) ;
if ( ! pHandle ) {
TraceEvent ( " ParentProcessOpenError " ) . GetLastError ( ) ;
fprintf ( stderr , " Could not open parent process at pid %d (error %d) " , parent_pid , GetLastError ( ) ) ;
throw platform_error ( ) ;
}
startThread ( & parentWatcher , pHandle ) ;
break ;
}
case OPT_NEWCONSOLE :
FreeConsole ( ) ;
AllocConsole ( ) ;
freopen ( " CONIN$ " , " rb " , stdin ) ;
freopen ( " CONOUT$ " , " wb " , stdout ) ;
freopen ( " CONOUT$ " , " wb " , stderr ) ;
break ;
case OPT_NOBOX :
SetErrorMode ( SetErrorMode ( 0 ) | SEM_NOGPFAULTERRORBOX ) ;
break ;
# else
case OPT_PARENTPID : {
auto pid_str = args . OptionArg ( ) ;
int * parent_pid = new ( int ) ;
* parent_pid = atoi ( pid_str ) ;
startThread ( & parentWatcher , parent_pid ) ;
break ;
}
# endif
case OPT_TESTFILE :
testFile = args . OptionArg ( ) ;
break ;
case OPT_KVFILE :
kvFile = args . OptionArg ( ) ;
break ;
case OPT_RESTARTING :
restarting = true ;
break ;
case OPT_RANDOMSEED : {
char * end ;
randomSeed = ( uint32_t ) strtoul ( args . OptionArg ( ) , & end , 0 ) ;
if ( * end ) {
fprintf ( stderr , " ERROR: Could not parse random seed `%s' \n " , args . OptionArg ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
break ;
}
case OPT_MACHINEID : {
zoneId = std : : string ( args . OptionArg ( ) ) ;
break ;
}
case OPT_DCID : {
dcId = std : : string ( args . OptionArg ( ) ) ;
break ;
}
case OPT_MACHINE_CLASS :
sRole = args . OptionArg ( ) ;
processClass = ProcessClass ( sRole , ProcessClass : : CommandLineSource ) ;
if ( processClass = = ProcessClass : : InvalidClass ) {
fprintf ( stderr , " ERROR: Unknown machine class `%s' \n " , sRole ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
break ;
case OPT_KEY :
targetKey = args . OptionArg ( ) ;
break ;
case OPT_MEMLIMIT :
ti = parse_with_suffix ( args . OptionArg ( ) , " MiB " ) ;
if ( ! ti . present ( ) ) {
fprintf ( stderr , " ERROR: Could not parse memory limit from `%s' \n " , args . OptionArg ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
memLimit = ti . get ( ) ;
break ;
case OPT_STORAGEMEMLIMIT :
ti = parse_with_suffix ( args . OptionArg ( ) , " MB " ) ;
if ( ! ti . present ( ) ) {
fprintf ( stderr , " ERROR: Could not parse storage memory limit from `%s' \n " , args . OptionArg ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
storageMemLimit = ti . get ( ) ;
break ;
case OPT_CACHEMEMLIMIT :
ti = parse_with_suffix ( args . OptionArg ( ) , " MiB " ) ;
if ( ! ti . present ( ) ) {
fprintf ( stderr , " ERROR: Could not parse cache memory limit from `%s' \n " , args . OptionArg ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
// SOMEDAY: ideally we'd have some better way to express that a knob should be elevated to formal
// parameter
knobs . push_back ( std : : make_pair (
" page_cache_4k " ,
format ( " %ld " , ti . get ( ) / 4096 * 4096 ) ) ) ; // The cache holds 4K pages, so we can truncate this to the
// next smaller multiple of 4K.
break ;
case OPT_BUGGIFY :
if ( ! strcmp ( args . OptionArg ( ) , " on " ) )
buggifyEnabled = true ;
else if ( ! strcmp ( args . OptionArg ( ) , " off " ) )
buggifyEnabled = false ;
else {
fprintf ( stderr , " ERROR: Unknown buggify state `%s' \n " , args . OptionArg ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
break ;
case OPT_CRASHONERROR :
g_crashOnError = true ;
break ;
case OPT_TESTSERVERS :
testServersStr = args . OptionArg ( ) ;
break ;
case OPT_TEST_ON_SERVERS :
testOnServers = true ;
break ;
case OPT_METRICSCONNFILE :
metricsConnFile = args . OptionArg ( ) ;
break ;
case OPT_METRICSPREFIX :
metricsPrefix = args . OptionArg ( ) ;
break ;
case OPT_IO_TRUST_SECONDS : {
const char * a = args . OptionArg ( ) ;
if ( ! sscanf ( a , " %lf " , & fileIoTimeout ) ) {
fprintf ( stderr , " ERROR: Could not parse io_trust_seconds `%s' \n " , a ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
break ;
}
case OPT_IO_TRUST_WARN_ONLY :
fileIoWarnOnly = true ;
break ;
case OPT_TRACE_FORMAT :
if ( ! selectTraceFormatter ( args . OptionArg ( ) ) ) {
fprintf ( stderr , " WARNING: Unrecognized trace format `%s' \n " , args . OptionArg ( ) ) ;
}
break ;
case OPT_WHITELIST_BINPATH :
whitelistBinPaths = args . OptionArg ( ) ;
break ;
2020-01-29 09:53:41 +08:00
case OPT_BLOB_CREDENTIAL_FILE :
// Add blob credential following backup agent example
blobCredentials . push_back ( args . OptionArg ( ) ) ;
printf ( " blob credential file:%s \n " , blobCredentials . back ( ) . c_str ( ) ) ;
blobCredsFromENV = getenv ( " FDB_BLOB_CREDENTIALS " ) ;
if ( blobCredsFromENV ! = nullptr ) {
fprintf ( stderr , " [WARNING] Set blob credetial via env variable is not tested yet \n " ) ;
TraceEvent ( SevError , " FastRestoreGetBlobCredentialFile " )
. detail ( " Reason " , " Set blob credetial via env variable is not tested yet " ) ;
StringRef t ( ( uint8_t * ) blobCredsFromENV , strlen ( blobCredsFromENV ) ) ;
do {
StringRef file = t . eat ( " : " ) ;
if ( file . size ( ) ! = 0 ) {
blobCredentials . push_back ( file . toString ( ) ) ;
}
} while ( t . size ( ) ! = 0 ) ;
}
break ;
2018-06-27 03:08:32 +08:00
# ifndef TLS_DISABLED
2020-03-07 10:22:46 +08:00
case TLSConfig : : OPT_TLS_PLUGIN :
2019-08-06 08:08:42 +08:00
args . OptionArg ( ) ;
break ;
2020-03-07 10:22:46 +08:00
case TLSConfig : : OPT_TLS_CERTIFICATES :
tlsConfig . setCertificatePath ( args . OptionArg ( ) ) ;
2019-08-06 08:08:42 +08:00
break ;
2020-03-07 10:22:46 +08:00
case TLSConfig : : OPT_TLS_PASSWORD :
tlsConfig . setPassword ( args . OptionArg ( ) ) ;
2019-08-06 08:08:42 +08:00
break ;
2020-03-07 10:22:46 +08:00
case TLSConfig : : OPT_TLS_CA_FILE :
tlsConfig . setCAPath ( args . OptionArg ( ) ) ;
2019-08-06 08:08:42 +08:00
break ;
2020-03-07 10:22:46 +08:00
case TLSConfig : : OPT_TLS_KEY :
tlsConfig . setKeyPath ( args . OptionArg ( ) ) ;
2019-08-06 08:08:42 +08:00
break ;
2020-03-07 10:22:46 +08:00
case TLSConfig : : OPT_TLS_VERIFY_PEERS :
tlsConfig . addVerifyPeers ( args . OptionArg ( ) ) ;
2019-08-06 08:08:42 +08:00
break ;
2018-06-21 00:21:23 +08:00
# endif
2017-05-26 04:48:44 +08:00
}
}
if ( seedConnString . length ( ) & & seedConnFile . length ( ) ) {
2019-08-06 08:08:42 +08:00
fprintf ( stderr , " %s \n " ,
" --seed_cluster_file and --seed_connection_string may not both be specified at once. " ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
bool seedSpecified = seedConnFile . length ( ) | | seedConnString . length ( ) ;
2019-08-06 08:08:42 +08:00
if ( seedSpecified & & ! connFile . length ( ) ) {
fprintf ( stderr , " %s \n " ,
" If -seed_cluster_file or --seed_connection_string is specified, -C must be specified as well. " ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
if ( metricsConnFile = = connFile ) metricsConnFile = " " ;
2017-05-26 04:48:44 +08:00
2019-08-06 08:08:42 +08:00
if ( metricsConnFile ! = " " & & metricsPrefix = = " " ) {
2017-05-26 04:48:44 +08:00
fprintf ( stderr , " If a metrics cluster file is specified, a metrics prefix is required. \n " ) ;
2019-08-06 08:08:42 +08:00
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
bool autoPublicAddress =
std : : any_of ( publicAddressStrs . begin ( ) , publicAddressStrs . end ( ) ,
[ ] ( const std : : string & addr ) { return StringRef ( addr ) . startsWith ( LiteralStringRef ( " auto: " ) ) ; } ) ;
if ( ( role ! = Simulation & & role ! = CreateTemplateDatabase & & role ! = KVFileIntegrityCheck & &
role ! = KVFileGenerateIOLogChecksums ) | |
autoPublicAddress ) {
if ( seedSpecified & & ! fileExists ( connFile ) ) {
std : : string connectionString = seedConnString . length ( ) ? seedConnString : " " ;
ClusterConnectionString ccs ;
if ( seedConnFile . length ( ) ) {
2017-05-26 04:48:44 +08:00
try {
2019-08-06 08:08:42 +08:00
connectionString = readFileBytes ( seedConnFile , MAX_CLUSTER_FILE_BYTES ) ;
2017-05-26 04:48:44 +08:00
} catch ( Error & e ) {
2019-08-06 08:08:42 +08:00
fprintf ( stderr , " %s \n " ,
ClusterConnectionFile : : getErrorString ( std : : make_pair ( seedConnFile , false ) , e ) . c_str ( ) ) ;
2017-05-26 04:48:44 +08:00
throw ;
}
}
2019-08-06 08:08:42 +08:00
try {
ccs = ClusterConnectionString ( connectionString ) ;
} catch ( Error & e ) {
fprintf ( stderr , " %s \n " , ClusterConnectionString : : getErrorString ( connectionString , e ) . c_str ( ) ) ;
throw ;
}
connectionFile = Reference < ClusterConnectionFile > ( new ClusterConnectionFile ( connFile , ccs ) ) ;
} else {
std : : pair < std : : string , bool > resolvedClusterFile ;
try {
resolvedClusterFile = ClusterConnectionFile : : lookupClusterFileName ( connFile ) ;
connectionFile =
Reference < ClusterConnectionFile > ( new ClusterConnectionFile ( resolvedClusterFile . first ) ) ;
} catch ( Error & e ) {
fprintf ( stderr , " %s \n " , ClusterConnectionFile : : getErrorString ( resolvedClusterFile , e ) . c_str ( ) ) ;
throw ;
}
}
2017-05-26 04:48:44 +08:00
// failmon?
}
2018-10-23 08:57:09 +08:00
try {
if ( ! publicAddressStrs . empty ( ) ) {
2019-08-06 08:08:42 +08:00
std : : tie ( publicAddresses , listenAddresses ) =
buildNetworkAddresses ( * connectionFile , publicAddressStrs , listenAddressStrs ) ;
2017-05-26 04:48:44 +08:00
}
2018-10-23 08:57:09 +08:00
} catch ( Error & ) {
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
if ( role = = ConsistencyCheck ) {
if ( ! publicAddressStrs . empty ( ) ) {
2018-03-07 07:40:04 +08:00
fprintf ( stderr , " ERROR: Public address cannot be specified for consistency check processes \n " ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
auto publicIP = determinePublicIPAutomatically ( connectionFile - > getConnectionString ( ) ) ;
2019-03-24 08:54:46 +08:00
publicAddresses . address = NetworkAddress ( publicIP , : : getpid ( ) ) ;
2017-05-26 04:48:44 +08:00
}
2019-08-06 08:08:42 +08:00
if ( role = = Simulation ) {
Optional < bool > buggifyOverride = checkBuggifyOverride ( testFile ) ;
if ( buggifyOverride . present ( ) ) buggifyEnabled = buggifyOverride . get ( ) ;
}
if ( role = = SearchMutations & & ! targetKey ) {
fprintf ( stderr , " ERROR: please specify a target key \n " ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
2017-05-26 04:48:44 +08:00
2019-08-06 08:08:42 +08:00
if ( role = = NetworkTestClient & & ! testServersStr . size ( ) ) {
fprintf ( stderr , " ERROR: please specify --testservers \n " ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
2017-05-26 04:48:44 +08:00
2019-08-06 08:08:42 +08:00
// Interpret legacy "maxLogs" option in the most sensible and unsurprising way we can while eliminating its code
// path
if ( maxLogsSet ) {
if ( maxLogsSizeSet ) {
// This is the case where both options are set and we must deconflict.
auto maxLogsAsSize = maxLogs * rollsize ;
2017-05-26 04:48:44 +08:00
2019-08-06 08:08:42 +08:00
// If either was unlimited, then the safe option here is to take the larger one.
// This means that is one of the two options specified a limited amount of logging
// then the option that specified "unlimited" will be ignored.
if ( maxLogsSize = = 0 | | maxLogs = = 0 )
maxLogsSize = std : : max ( maxLogsSize , maxLogsAsSize ) ;
else
maxLogsSize = std : : min ( maxLogsSize , maxLogs * rollsize ) ;
} else {
maxLogsSize = maxLogs * rollsize ;
}
2017-09-16 08:55:01 +08:00
}
2019-08-06 08:08:42 +08:00
machineId = getSharedMemoryMachineId ( ) . toString ( ) ;
if ( ! localities . isPresent ( LocalityData : : keyZoneId ) )
localities . set ( LocalityData : : keyZoneId , zoneId . present ( ) ? zoneId : machineId ) ;
if ( ! localities . isPresent ( LocalityData : : keyMachineId ) )
localities . set ( LocalityData : : keyMachineId , zoneId . present ( ) ? zoneId : machineId ) ;
if ( ! localities . isPresent ( LocalityData : : keyDcId ) & & dcId . present ( ) ) localities . set ( LocalityData : : keyDcId , dcId ) ;
}
} ;
} // namespace
int main ( int argc , char * argv [ ] ) {
try {
platformInit ( ) ;
# ifdef ALLOC_INSTRUMENTATION
g_extra_memory = new uint8_t [ 1000000 ] ;
# endif
registerCrashHandler ( ) ;
// Set default of line buffering standard out and error
setvbuf ( stdout , NULL , _IOLBF , BUFSIZ ) ;
setvbuf ( stderr , NULL , _IOLBF , BUFSIZ ) ;
// Enables profiling on this thread (but does not start it)
registerThreadForProfiling ( ) ;
# ifdef _WIN32
// Windows needs a gentle nudge to format floats correctly
//_set_output_format(_TWO_DIGIT_EXPONENT);
# endif
const auto opts = CLIOptions : : parseArgs ( argc , argv ) ;
const auto role = opts . role ;
if ( role = = Simulation ) printf ( " Random seed is %u... \n " , opts . randomSeed ) ;
if ( opts . zoneId . present ( ) )
printf ( " ZoneId set to %s, dcId to %s \n " , printable ( opts . zoneId ) . c_str ( ) , printable ( opts . dcId ) . c_str ( ) ) ;
setThreadLocalDeterministicRandomSeed ( opts . randomSeed ) ;
enableBuggify ( opts . buggifyEnabled , BuggifyType : : General ) ;
2017-05-26 04:48:44 +08:00
delete FLOW_KNOBS ;
delete SERVER_KNOBS ;
delete CLIENT_KNOBS ;
2020-04-02 04:59:06 +08:00
FlowKnobs * flowKnobs = new FlowKnobs ;
ClientKnobs * clientKnobs = new ClientKnobs ;
ServerKnobs * serverKnobs = new ServerKnobs ;
2017-05-26 04:48:44 +08:00
FLOW_KNOBS = flowKnobs ;
SERVER_KNOBS = serverKnobs ;
CLIENT_KNOBS = clientKnobs ;
2019-08-06 08:08:42 +08:00
if ( ! serverKnobs - > setKnob ( " log_directory " , opts . logFolder ) ) ASSERT ( false ) ;
2018-06-02 06:21:40 +08:00
if ( role ! = Simulation ) {
2019-08-06 08:08:42 +08:00
if ( ! serverKnobs - > setKnob ( " commit_batches_mem_bytes_hard_limit " , std : : to_string ( opts . memLimit ) ) )
ASSERT ( false ) ;
2018-06-02 06:21:40 +08:00
}
2019-08-06 08:08:42 +08:00
for ( auto k = opts . knobs . begin ( ) ; k ! = opts . knobs . end ( ) ; + + k ) {
2017-05-26 04:48:44 +08:00
try {
if ( ! flowKnobs - > setKnob ( k - > first , k - > second ) & &
! clientKnobs - > setKnob ( k - > first , k - > second ) & &
! serverKnobs - > setKnob ( k - > first , k - > second ) )
{
2019-04-26 08:08:13 +08:00
fprintf ( stderr , " WARNING: Unrecognized knob option '%s' \n " , k - > first . c_str ( ) ) ;
TraceEvent ( SevWarnAlways , " UnrecognizedKnobOption " ) . detail ( " Knob " , printable ( k - > first ) ) ;
2017-05-26 04:48:44 +08:00
}
} catch ( Error & e ) {
if ( e . code ( ) = = error_code_invalid_option_value ) {
2020-03-05 07:50:04 +08:00
fprintf ( stderr , " WARNING: Invalid value '%s' for knob option '%s' \n " , k - > second . c_str ( ) , k - > first . c_str ( ) ) ;
2019-04-26 08:08:13 +08:00
TraceEvent ( SevWarnAlways , " InvalidKnobValue " ) . detail ( " Knob " , printable ( k - > first ) ) . detail ( " Value " , printable ( k - > second ) ) ;
} else {
2020-03-05 07:50:04 +08:00
fprintf ( stderr , " ERROR: Failed to set knob option '%s': %s \n " , k - > first . c_str ( ) , e . what ( ) ) ;
TraceEvent ( SevError , " FailedToSetKnob " ) . detail ( " Knob " , printable ( k - > first ) ) . detail ( " Value " , printable ( k - > second ) ) . error ( e ) ;
2019-04-26 08:08:13 +08:00
throw ;
2017-05-26 04:48:44 +08:00
}
}
}
2019-08-06 08:08:42 +08:00
if ( ! serverKnobs - > setKnob ( " server_mem_limit " , std : : to_string ( opts . memLimit ) ) ) ASSERT ( false ) ;
2017-05-26 04:48:44 +08:00
2020-04-02 04:59:06 +08:00
// Reinitialize knobs in order to update knobs that are dependent on explicitly set knobs
flowKnobs - > initialize ( true , role = = Simulation ) ;
clientKnobs - > initialize ( true ) ;
serverKnobs - > initialize ( true , clientKnobs , role = = Simulation ) ;
2019-05-13 14:50:04 +08:00
// evictionPolicyStringToEnum will throw an exception if the string is not recognized as a valid
EvictablePageCache : : evictionPolicyStringToEnum ( flowKnobs - > CACHE_EVICTION_POLICY ) ;
2019-05-07 14:32:57 +08:00
2019-10-03 04:28:24 +08:00
if ( opts . memLimit < = FLOW_KNOBS - > PAGE_CACHE_4K ) {
2019-09-14 04:02:06 +08:00
fprintf ( stderr , " ERROR: --memory has to be larger than --cache_memory \n " ) ;
2019-09-14 03:54:37 +08:00
flushAndExit ( FDB_EXIT_ERROR ) ;
}
2017-05-26 04:48:44 +08:00
if ( role = = SkipListTest ) {
skipListTest ( ) ;
flushAndExit ( FDB_EXIT_SUCCESS ) ;
}
if ( role = = DSLTest ) {
dsltest ( ) ;
flushAndExit ( FDB_EXIT_SUCCESS ) ;
}
if ( role = = VersionedMapTest ) {
versionedMapTest ( ) ;
flushAndExit ( FDB_EXIT_SUCCESS ) ;
}
// Initialize the thread pool
CoroThreadPool : : init ( ) ;
// Ordinarily, this is done when the network is run. However, network thread should be set before TraceEvents are logged. This thread will eventually run the network, so call it now.
2018-06-21 00:21:23 +08:00
TraceEvent : : setNetworkThread ( ) ;
2017-05-26 04:48:44 +08:00
2018-10-23 08:57:09 +08:00
std : : vector < Future < Void > > listenErrors ;
2017-05-26 04:48:44 +08:00
if ( role = = Simulation | | role = = CreateTemplateDatabase ) {
//startOldSimulator();
2019-08-07 00:25:40 +08:00
startNewSimulator ( ) ;
2019-08-06 08:08:42 +08:00
openTraceFile ( NetworkAddress ( ) , opts . rollsize , opts . maxLogsSize , opts . logFolder , " trace " , opts . logGroup ) ;
2017-05-26 04:48:44 +08:00
} else {
2020-03-07 10:22:46 +08:00
g_network = newNet2 ( opts . tlsConfig , opts . useThreadPool , true ) ;
2019-04-19 05:12:45 +08:00
FlowTransport : : createInstance ( false , 1 ) ;
2017-05-26 04:48:44 +08:00
2019-03-19 02:06:13 +08:00
const bool expectsPublicAddress = ( role = = FDBD | | role = = NetworkTestServer | | role = = Restore ) ;
2019-08-06 08:08:42 +08:00
if ( opts . publicAddressStrs . empty ( ) ) {
2019-03-19 02:06:13 +08:00
if ( expectsPublicAddress ) {
fprintf ( stderr , " ERROR: The -p or --public_address option is required \n " ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
}
2019-08-06 08:08:42 +08:00
openTraceFile ( opts . publicAddresses . address , opts . rollsize , opts . maxLogsSize , opts . logFolder , " trace " ,
opts . logGroup ) ;
2020-02-27 10:53:06 +08:00
g_network - > initTLS ( ) ;
2017-05-26 04:48:44 +08:00
2019-03-19 02:06:13 +08:00
if ( expectsPublicAddress ) {
2019-08-06 08:08:42 +08:00
for ( int ii = 0 ; ii < ( opts . publicAddresses . secondaryAddress . present ( ) ? 2 : 1 ) ; + + ii ) {
const NetworkAddress & publicAddress =
ii = = 0 ? opts . publicAddresses . address : opts . publicAddresses . secondaryAddress . get ( ) ;
const NetworkAddress & listenAddress =
ii = = 0 ? opts . listenAddresses . address : opts . listenAddresses . secondaryAddress . get ( ) ;
2018-10-31 04:44:37 +08:00
try {
const Future < Void > & errorF = FlowTransport : : transport ( ) . bind ( publicAddress , listenAddress ) ;
listenErrors . push_back ( errorF ) ;
if ( errorF . isReady ( ) ) errorF . get ( ) ;
} catch ( Error & e ) {
TraceEvent ( " BindError " ) . error ( e ) ;
fprintf ( stderr , " Error initializing networking with public address %s and listen address %s (%s) \n " ,
publicAddress . toString ( ) . c_str ( ) , listenAddress . toString ( ) . c_str ( ) , e . what ( ) ) ;
printHelpTeaser ( argv [ 0 ] ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
2017-05-26 04:48:44 +08:00
}
}
// Use a negative ioTimeout to indicate warn-only
2019-08-06 08:08:42 +08:00
Net2FileSystem : : newFileSystem ( opts . fileIoWarnOnly ? - opts . fileIoTimeout : opts . fileIoTimeout ,
opts . fileSystemPath ) ;
2017-05-26 04:48:44 +08:00
g_network - > initMetrics ( ) ;
FlowTransport : : transport ( ) . initMetrics ( ) ;
initTraceEventMetrics ( ) ;
}
double start = timer ( ) , startNow = now ( ) ;
std : : string cwd = " <unknown> " ;
try {
cwd = platform : : getWorkingDirectory ( ) ;
} catch ( Error & e ) {
// Allow for platform error by rethrowing all _other_ errors
if ( e . code ( ) ! = error_code_platform_error )
throw ;
}
TraceEvent ( " ProgramStart " )
2019-08-06 08:08:42 +08:00
. setMaxEventLength ( 12000 )
. detail ( " RandomSeed " , opts . randomSeed )
2019-11-16 04:26:51 +08:00
. detail ( " SourceVersion " , getSourceVersion ( ) )
2019-08-06 08:08:42 +08:00
. detail ( " Version " , FDB_VT_VERSION )
. detail ( " PackageName " , FDB_VT_PACKAGE_NAME )
. detail ( " FileSystem " , opts . fileSystemPath )
. detail ( " DataFolder " , opts . dataFolder )
. detail ( " WorkingDirectory " , cwd )
. detail ( " ClusterFile " , opts . connectionFile ? opts . connectionFile - > getFilename ( ) . c_str ( ) : " " )
. detail ( " ConnectionString " ,
opts . connectionFile ? opts . connectionFile - > getConnectionString ( ) . toString ( ) : " " )
. detailf ( " ActualTime " , " %lld " , DEBUG_DETERMINISM ? 0 : time ( NULL ) )
. setMaxFieldLength ( 10000 )
. detail ( " CommandLine " , opts . commandLine )
. setMaxFieldLength ( 0 )
. detail ( " BuggifyEnabled " , opts . buggifyEnabled )
. detail ( " MemoryLimit " , opts . memLimit )
. trackLatest ( " ProgramStart " ) ;
2017-05-26 04:48:44 +08:00
// Test for TraceEvent length limits
/*std::string foo(4096, 'x');
TraceEvent ( " TooLongDetail " ) . detail ( " Contents " , foo ) ;
TraceEvent ( " TooLongEvent " )
. detail ( " Contents1 " , foo )
. detail ( " Contents2 " , foo )
. detail ( " Contents3 " , foo )
. detail ( " Contents4 " , foo )
. detail ( " Contents5 " , foo )
. detail ( " Contents6 " , foo )
. detail ( " Contents7 " , foo )
. detail ( " Contents8 " , foo )
. detail ( " ExtraTest " , 1776 ) ; */
Error : : init ( ) ;
std : : set_new_handler ( & platform : : outOfMemory ) ;
2019-08-06 08:08:42 +08:00
setMemoryQuota ( opts . memLimit ) ;
2017-05-26 04:48:44 +08:00
Future < Optional < Void > > f ;
if ( role = = Simulation ) {
2019-08-06 08:08:42 +08:00
TraceEvent ( " Simulation " ) . detail ( " TestFile " , opts . testFile ) ;
2017-05-26 04:48:44 +08:00
clientKnobs - > trace ( ) ;
flowKnobs - > trace ( ) ;
serverKnobs - > trace ( ) ;
2019-08-06 08:08:42 +08:00
auto dataFolder = opts . dataFolder . size ( ) ? opts . dataFolder : " simfdb " ;
2017-05-26 04:48:44 +08:00
std : : vector < std : : string > directories = platform : : listDirectories ( dataFolder ) ;
for ( int i = 0 ; i < directories . size ( ) ; i + + )
2019-03-11 22:31:44 +08:00
if ( directories [ i ] . size ( ) ! = 32 & & directories [ i ] ! = " . " & & directories [ i ] ! = " .. " & &
2020-01-31 00:35:02 +08:00
directories [ i ] ! = " backups " & & directories [ i ] . find ( " snap " ) = = std : : string : : npos ) {
2019-09-10 01:21:16 +08:00
TraceEvent ( SevError , " IncompatibleDirectoryFound " )
. detail ( " DataFolder " , dataFolder )
. detail ( " SuspiciousFile " , directories [ i ] ) ;
2017-05-26 04:48:44 +08:00
fprintf ( stderr , " ERROR: Data folder `%s' had non fdb file `%s'; please use clean, fdb-only folder \n " , dataFolder . c_str ( ) , directories [ i ] . c_str ( ) ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
std : : vector < std : : string > files = platform : : listFiles ( dataFolder ) ;
2019-08-06 08:08:42 +08:00
if ( ( files . size ( ) > 1 | | ( files . size ( ) = = 1 & & files [ 0 ] ! = " restartInfo.ini " ) ) & & ! opts . restarting ) {
2017-05-26 04:48:44 +08:00
TraceEvent ( SevError , " IncompatibleFileFound " ) . detail ( " DataFolder " , dataFolder ) ;
fprintf ( stderr , " ERROR: Data folder `%s' is non-empty; please use clean, fdb-only folder \n " , dataFolder . c_str ( ) ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
2019-08-06 08:08:42 +08:00
} else if ( files . empty ( ) & & opts . restarting ) {
2017-05-26 04:48:44 +08:00
TraceEvent ( SevWarnAlways , " FileNotFound " ) . detail ( " DataFolder " , dataFolder ) ;
printf ( " ERROR: Data folder `%s' is empty, but restarting option selected. Run Phase 1 test first \n " , dataFolder . c_str ( ) ) ;
flushAndExit ( FDB_EXIT_ERROR ) ;
}
2019-03-26 09:31:08 +08:00
int isRestoring = 0 ;
2019-08-06 08:08:42 +08:00
if ( ! opts . restarting ) {
2017-05-26 04:48:44 +08:00
platform : : eraseDirectoryRecursive ( dataFolder ) ;
platform : : createDirectory ( dataFolder ) ;
2019-03-21 07:51:14 +08:00
} else {
2019-03-11 22:31:44 +08:00
CSimpleIni ini ;
ini . SetUnicode ( ) ;
2019-05-07 09:57:26 +08:00
std : : string absDataFolder = abspath ( dataFolder ) ;
ini . LoadFile ( joinPath ( absDataFolder , " restartInfo.ini " ) . c_str ( ) ) ;
2019-05-23 04:38:56 +08:00
int backupFailed = true ;
const char * isRestoringStr = ini . GetValue ( " RESTORE " , " isRestoring " , NULL ) ;
if ( isRestoringStr ) {
isRestoring = atoi ( isRestoringStr ) ;
const char * backupFailedStr = ini . GetValue ( " RESTORE " , " BackupFailed " , NULL ) ;
if ( isRestoring & & backupFailedStr ) {
backupFailed = atoi ( backupFailedStr ) ;
}
}
if ( isRestoring & & ! backupFailed ) {
2019-07-23 06:44:49 +08:00
std : : vector < std : : string > returnList ;
std : : string ext = " " ;
returnList = platform : : listDirectories ( absDataFolder ) ;
std : : string snapStr = ini . GetValue ( " RESTORE " , " RestoreSnapUID " ) ;
TraceEvent ( " RestoringDataFolder " ) . detail ( " DataFolder " , absDataFolder ) ;
TraceEvent ( " RestoreSnapUID " ) . detail ( " UID " , snapStr ) ;
// delete all files (except fdb.cluster) in non-snap directories
for ( const auto & dirEntry : returnList ) {
if ( dirEntry = = " . " | | dirEntry = = " .. " ) {
continue ;
2019-03-21 07:51:14 +08:00
}
2019-07-23 06:44:49 +08:00
if ( dirEntry . find ( snapStr ) ! = std : : string : : npos ) {
continue ;
2019-03-21 07:51:14 +08:00
}
2019-03-11 22:31:44 +08:00
2019-07-23 06:44:49 +08:00
std : : string childf = absDataFolder + " / " + dirEntry ;
std : : vector < std : : string > returnFiles = platform : : listFiles ( childf , ext ) ;
for ( const auto & fileEntry : returnFiles ) {
if ( fileEntry ! = " fdb.cluster " & & fileEntry ! = " fitness " ) {
TraceEvent ( " DeletingNonSnapfiles " )
. detail ( " FileBeingDeleted " , childf + " / " + fileEntry ) ;
deleteFile ( childf + " / " + fileEntry ) ;
2019-03-21 07:51:14 +08:00
}
2019-03-11 22:31:44 +08:00
}
2019-07-23 06:44:49 +08:00
}
// cleanup unwanted and partial directories
for ( const auto & dirEntry : returnList ) {
if ( dirEntry = = " . " | | dirEntry = = " .. " ) {
continue ;
}
std : : string dirSrc = absDataFolder + " / " + dirEntry ;
// delete snap directories which are not part of restoreSnapUID
if ( dirEntry . find ( snapStr ) = = std : : string : : npos ) {
if ( dirEntry . find ( " snap " ) ! = std : : string : : npos ) {
2019-05-07 09:57:26 +08:00
platform : : eraseDirectoryRecursive ( dirSrc ) ;
2019-03-21 07:51:14 +08:00
}
2019-07-23 06:44:49 +08:00
continue ;
2019-03-11 22:31:44 +08:00
}
2019-07-23 06:44:49 +08:00
// remove empty/partial snap directories
std : : vector < std : : string > childrenList = platform : : listFiles ( dirSrc ) ;
if ( childrenList . size ( ) = = 0 ) {
TraceEvent ( " RemovingEmptySnapDirectory " ) . detail ( " DirBeingDeleted " , dirSrc ) ;
platform : : eraseDirectoryRecursive ( dirSrc ) ;
continue ;
}
}
// move snapshotted files to appropriate locations
for ( const auto & dirEntry : returnList ) {
if ( dirEntry = = " . " | | dirEntry = = " .. " ) {
continue ;
}
std : : string dirSrc = absDataFolder + " / " + dirEntry ;
std : : string origDir = dirEntry . substr ( 0 , 32 ) ;
std : : string dirToMove = absDataFolder + " / " + origDir ;
if ( ( dirEntry . find ( " snap " ) ! = std : : string : : npos ) & &
( dirEntry . find ( " tlog " ) ! = std : : string : : npos ) ) {
// restore tlog files
restoreRoleFilesHelper ( dirSrc , dirToMove , " log " ) ;
} else if ( ( dirEntry . find ( " snap " ) ! = std : : string : : npos ) & &
( dirEntry . find ( " storage " ) ! = std : : string : : npos ) ) {
// restore storage files
restoreRoleFilesHelper ( dirSrc , dirToMove , " storage " ) ;
} else if ( ( dirEntry . find ( " snap " ) ! = std : : string : : npos ) & &
( dirEntry . find ( " coord " ) ! = std : : string : : npos ) ) {
// restore coordinator files
restoreRoleFilesHelper ( dirSrc , dirToMove , " coordination " ) ;
2019-05-07 09:57:26 +08:00
}
2019-03-11 22:31:44 +08:00
}
}
2017-05-26 04:48:44 +08:00
}
2020-02-22 11:09:16 +08:00
setupAndRun ( dataFolder , opts . testFile , opts . restarting , ( isRestoring > = 1 ) , opts . whitelistBinPaths ) ;
2017-05-26 04:48:44 +08:00
g_simulator . run ( ) ;
} else if ( role = = FDBD ) {
2020-01-29 09:53:41 +08:00
// Call fast restore for the class FastRestoreClass. This is a short-cut to run fast restore in circus
if ( opts . processClass = = ProcessClass : : FastRestoreClass ) {
printf ( " Run as fast restore worker \n " ) ;
2020-02-01 12:23:35 +08:00
ASSERT ( opts . connectionFile ) ;
auto dataFolder = opts . dataFolder ;
if ( ! dataFolder . size ( ) )
dataFolder = format ( " fdb/%d/ " , opts . publicAddresses . address . port ) ; // SOMEDAY: Better default
2020-01-29 09:53:41 +08:00
// Update the global blob credential files list
std : : vector < std : : string > * pFiles =
( std : : vector < std : : string > * ) g_network - > global ( INetwork : : enBlobCredentialFiles ) ;
if ( pFiles ! = nullptr ) {
for ( auto & f : opts . blobCredentials ) {
pFiles - > push_back ( f ) ;
}
}
2017-05-26 04:48:44 +08:00
2020-02-01 12:23:35 +08:00
vector < Future < Void > > actors ( listenErrors . begin ( ) , listenErrors . end ( ) ) ;
2020-02-04 03:11:31 +08:00
actors . push_back ( restoreWorker ( opts . connectionFile , opts . localities , dataFolder ) ) ;
2020-02-01 12:23:35 +08:00
f = stopAfter ( waitForAll ( actors ) ) ;
2020-01-31 10:49:01 +08:00
printf ( " Fast restore worker exits \n " ) ;
g_network - > run ( ) ;
printf ( " g_network->run() done \n " ) ;
2020-01-29 09:53:41 +08:00
} else { // Call fdbd roles in conventional way
ASSERT ( opts . connectionFile ) ;
2017-05-26 04:48:44 +08:00
2020-04-15 05:02:24 +08:00
setupRunLoopProfiler ( ) ;
2017-05-26 04:48:44 +08:00
2020-01-29 09:53:41 +08:00
auto dataFolder = opts . dataFolder ;
if ( ! dataFolder . size ( ) )
dataFolder = format ( " fdb/%d/ " , opts . publicAddresses . address . port ) ; // SOMEDAY: Better default
2017-05-26 04:48:44 +08:00
2020-01-29 09:53:41 +08:00
vector < Future < Void > > actors ( listenErrors . begin ( ) , listenErrors . end ( ) ) ;
actors . push_back ( fdbd ( opts . connectionFile , opts . localities , opts . processClass , dataFolder , dataFolder ,
opts . storageMemLimit , opts . metricsConnFile , opts . metricsPrefix , opts . rsssize ,
opts . whitelistBinPaths ) ) ;
// actors.push_back( recurring( []{}, .001 ) ); // for ASIO latency measurement
f = stopAfter ( waitForAll ( actors ) ) ;
2020-01-31 10:49:01 +08:00
g_network - > run ( ) ;
2020-01-29 09:53:41 +08:00
}
2017-05-26 04:48:44 +08:00
} else if ( role = = MultiTester ) {
2019-08-06 08:08:42 +08:00
f = stopAfter ( runTests ( opts . connectionFile , TEST_TYPE_FROM_FILE ,
opts . testOnServers ? TEST_ON_SERVERS : TEST_ON_TESTERS , opts . minTesterCount ,
opts . testFile , StringRef ( ) , opts . localities ) ) ;
2017-05-26 04:48:44 +08:00
g_network - > run ( ) ;
2018-02-15 01:50:12 +08:00
} else if ( role = = Test ) {
2019-08-06 08:08:42 +08:00
auto m = startSystemMonitor ( opts . dataFolder , opts . zoneId , opts . zoneId ) ;
f = stopAfter ( runTests ( opts . connectionFile , TEST_TYPE_FROM_FILE , TEST_HERE , 1 , opts . testFile , StringRef ( ) ,
opts . localities ) ) ;
2018-02-15 01:50:12 +08:00
g_network - > run ( ) ;
} else if ( role = = ConsistencyCheck ) {
2020-01-29 04:09:37 +08:00
setupRunLoopProfiler ( ) ;
2018-02-15 01:50:12 +08:00
2019-08-06 08:08:42 +08:00
auto m = startSystemMonitor ( opts . dataFolder , opts . zoneId , opts . zoneId ) ;
f = stopAfter ( runTests ( opts . connectionFile , TEST_TYPE_CONSISTENCY_CHECK , TEST_HERE , 1 , opts . testFile ,
StringRef ( ) , opts . localities ) ) ;
2017-05-26 04:48:44 +08:00
g_network - > run ( ) ;
} else if ( role = = CreateTemplateDatabase ) {
createTemplateDatabase ( ) ;
} else if ( role = = NetworkTestClient ) {
2019-08-06 08:08:42 +08:00
f = stopAfter ( networkTestClient ( opts . testServersStr ) ) ;
2017-05-26 04:48:44 +08:00
g_network - > run ( ) ;
} else if ( role = = NetworkTestServer ) {
f = stopAfter ( networkTestServer ( ) ) ;
g_network - > run ( ) ;
2018-10-10 09:47:28 +08:00
} else if ( role = = Restore ) {
2020-02-04 03:11:31 +08:00
f = stopAfter ( restoreWorker ( opts . connectionFile , opts . localities , opts . dataFolder ) ) ;
2018-10-10 09:47:28 +08:00
g_network - > run ( ) ;
2017-05-27 08:43:28 +08:00
} else if ( role = = KVFileIntegrityCheck ) {
2019-08-06 08:08:42 +08:00
f = stopAfter ( KVFileCheck ( opts . kvFile , true ) ) ;
2017-05-27 08:43:28 +08:00
g_network - > run ( ) ;
} else if ( role = = KVFileGenerateIOLogChecksums ) {
2018-09-11 01:51:41 +08:00
Optional < Void > result ;
try {
2019-08-06 08:08:42 +08:00
GenerateIOLogChecksumFile ( opts . kvFile ) ;
2018-09-11 01:51:41 +08:00
result = Void ( ) ;
}
catch ( Error & e ) {
fprintf ( stderr , " Fatal Error: %s \n " , e . what ( ) ) ;
}
f = result ;
2017-05-26 04:48:44 +08:00
}
int rc = FDB_EXIT_SUCCESS ;
if ( f . isValid ( ) & & f . isReady ( ) & & ! f . isError ( ) & & ! f . get ( ) . present ( ) ) {
rc = FDB_EXIT_ERROR ;
}
2019-05-11 05:01:52 +08:00
int unseed = noUnseed ? 0 : deterministicRandom ( ) - > randomInt ( 0 , 100001 ) ;
2017-05-26 04:48:44 +08:00
TraceEvent ( " ElapsedTime " ) . detail ( " SimTime " , now ( ) - startNow ) . detail ( " RealTime " , timer ( ) - start )
. detail ( " RandomUnseed " , unseed ) ;
if ( role = = Simulation ) {
printf ( " Unseed: %d \n " , unseed ) ;
printf ( " Elapsed: %f simsec, %f real seconds \n " , now ( ) - startNow , timer ( ) - start ) ;
//cout << format(" %d endpoints left\n", transport().getEndpointCount());
}
//IFailureMonitor::failureMonitor().address_info.clear();
// we should have shut down ALL actors associated with this machine; let's list all of the ones still live
/*{
auto living = Actor : : all ;
printf ( " %d surviving actors: \n " , living . size ( ) ) ;
for ( auto a = living . begin ( ) ; a ! = living . end ( ) ; + + a )
printf ( " #%lld %s %p \n " , ( * a ) - > creationIndex , ( * a ) - > getName ( ) , ( * a ) ) ;
}
{
auto living = DatabaseContext : : all ;
printf ( " %d surviving DatabaseContexts: \n " , living . size ( ) ) ;
for ( auto a = living . begin ( ) ; a ! = living . end ( ) ; + + a )
printf ( " #%lld %p \n " , ( * a ) - > creationIndex , ( * a ) ) ;
}
{
auto living = TransactionData : : all ;
printf ( " %d surviving TransactionData(s): \n " , living . size ( ) ) ;
for ( auto a = living . begin ( ) ; a ! = living . end ( ) ; + + a )
printf ( " #%lld %p \n " , ( * a ) - > creationIndex , ( * a ) ) ;
} */
/*cout << Actor::allActors.size() << " surviving actors:" << endl;
std : : map < std : : string , int > actorCount ;
for ( int i = 0 ; i < Actor : : allActors . size ( ) ; i + + )
+ + actorCount [ Actor : : allActors [ i ] - > getName ( ) ] ;
for ( auto i = actorCount . rbegin ( ) ; ! ( i = = actorCount . rend ( ) ) ; + + i )
cout < < " " < < i - > second < < " " < < i - > first < < endl ; */
// cout << " " << Actor::allActors[i]->getName() << endl;
int total = 0 ;
for ( auto i = Error : : errorCounts ( ) . begin ( ) ; i ! = Error : : errorCounts ( ) . end ( ) ; + + i )
total + = i - > second ;
if ( total )
printf ( " %d errors: \n " , total ) ;
for ( auto i = Error : : errorCounts ( ) . begin ( ) ; i ! = Error : : errorCounts ( ) . end ( ) ; + + i )
if ( i - > second > 0 )
printf ( " %d: %d %s \n " , i - > second , i - > first , Error : : fromCode ( i - > first ) . what ( ) ) ;
if ( & g_simulator = = g_network ) {
auto processes = g_simulator . getAllProcesses ( ) ;
for ( auto i = processes . begin ( ) ; i ! = processes . end ( ) ; + + i )
printf ( " %s %s: %0.3f Mclocks \n " , ( * i ) - > name , ( * i ) - > address . toString ( ) . c_str ( ) , ( * i ) - > cpuTicks / 1e6 ) ;
}
2017-12-16 10:20:33 +08:00
if ( role = = Simulation ) {
unsigned long sevErrorEventsLogged = TraceEvent : : CountEventsLoggedAt ( SevError ) ;
if ( sevErrorEventsLogged > 0 ) {
printf ( " %lu SevError events logged \n " , sevErrorEventsLogged ) ;
rc = FDB_EXIT_ERROR ;
}
}
2017-05-26 04:48:44 +08:00
//g_simulator.run();
# ifdef ALLOC_INSTRUMENTATION
{
std : : cout < < " Page Counts: "
< < FastAllocator < 16 > : : pageCount < < " "
< < FastAllocator < 32 > : : pageCount < < " "
< < FastAllocator < 64 > : : pageCount < < " "
< < FastAllocator < 128 > : : pageCount < < " "
< < FastAllocator < 256 > : : pageCount < < " "
< < FastAllocator < 512 > : : pageCount < < " "
< < FastAllocator < 1024 > : : pageCount < < " "
< < FastAllocator < 2048 > : : pageCount < < " "
2019-03-09 04:37:04 +08:00
< < FastAllocator < 4096 > : : pageCount < < " "
< < FastAllocator < 8192 > : : pageCount < < std : : endl ;
2017-05-26 04:48:44 +08:00
vector < std : : pair < std : : string , const char * > > typeNames ;
for ( auto i = allocInstr . begin ( ) ; i ! = allocInstr . end ( ) ; + + i ) {
std : : string s ;
# ifdef __linux__
char * demangled = abi : : __cxa_demangle ( i - > first , NULL , NULL , NULL ) ;
if ( demangled ) {
s = demangled ;
if ( StringRef ( s ) . startsWith ( LiteralStringRef ( " (anonymous namespace):: " ) ) )
s = s . substr ( LiteralStringRef ( " (anonymous namespace):: " ) . size ( ) ) ;
free ( demangled ) ;
} else
s = i - > first ;
# else
s = i - > first ;
if ( StringRef ( s ) . startsWith ( LiteralStringRef ( " class `anonymous namespace':: " ) ) )
s = s . substr ( LiteralStringRef ( " class `anonymous namespace':: " ) . size ( ) ) ;
else if ( StringRef ( s ) . startsWith ( LiteralStringRef ( " class " ) ) )
s = s . substr ( LiteralStringRef ( " class " ) . size ( ) ) ;
else if ( StringRef ( s ) . startsWith ( LiteralStringRef ( " struct " ) ) )
s = s . substr ( LiteralStringRef ( " struct " ) . size ( ) ) ;
# endif
typeNames . push_back ( std : : make_pair ( s , i - > first ) ) ;
}
std : : sort ( typeNames . begin ( ) , typeNames . end ( ) ) ;
for ( int i = 0 ; i < typeNames . size ( ) ; i + + ) {
const char * n = typeNames [ i ] . second ;
auto & f = allocInstr [ n ] ;
printf ( " %+d \t %+d \t %d \t %d \t %s \n " , f . allocCount , - f . deallocCount , f . allocCount - f . deallocCount , f . maxAllocated , typeNames [ i ] . first . c_str ( ) ) ;
}
// We're about to exit and clean up data structures, this will wreak havoc on allocation recording
memSample_entered = true ;
}
# endif
//printf("\n%d tests passed; %d tests failed\n", passCount, failCount);
flushAndExit ( rc ) ;
} catch ( Error & e ) {
fprintf ( stderr , " Error: %s \n " , e . what ( ) ) ;
TraceEvent ( SevError , " MainError " ) . error ( e ) ;
//printf("\n%d tests passed; %d tests failed\n", passCount, failCount);
flushAndExit ( FDB_EXIT_MAIN_ERROR ) ;
2020-02-21 08:53:01 +08:00
} catch ( boost : : system : : system_error & e ) {
2020-02-27 04:26:43 +08:00
ASSERT_WE_THINK ( false ) ; // boost errors shouldn't leak
2020-02-21 08:53:01 +08:00
fprintf ( stderr , " boost::system::system_error: %s (%d) " , e . what ( ) , e . code ( ) . value ( ) ) ;
TraceEvent ( SevError , " MainError " ) . error ( unknown_error ( ) ) . detail ( " RootException " , e . what ( ) ) ;
//printf("\n%d tests passed; %d tests failed\n", passCount, failCount);
flushAndExit ( FDB_EXIT_MAIN_EXCEPTION ) ;
2017-05-26 04:48:44 +08:00
} catch ( std : : exception & e ) {
fprintf ( stderr , " std::exception: %s \n " , e . what ( ) ) ;
2018-06-09 02:11:08 +08:00
TraceEvent ( SevError , " MainError " ) . error ( unknown_error ( ) ) . detail ( " RootException " , e . what ( ) ) ;
2017-05-26 04:48:44 +08:00
//printf("\n%d tests passed; %d tests failed\n", passCount, failCount);
flushAndExit ( FDB_EXIT_MAIN_EXCEPTION ) ;
}
static_assert ( LBLocalityData < StorageServerInterface > : : Present , " Storage server interface should be load balanced " ) ;
static_assert ( LBLocalityData < MasterProxyInterface > : : Present , " Master proxy interface should be load balanced " ) ;
static_assert ( LBLocalityData < TLogInterface > : : Present , " TLog interface should be load balanced " ) ;
static_assert ( ! LBLocalityData < MasterInterface > : : Present , " Master interface should not be load balanced " ) ;
}