percona-xtradb-cluster-galera-3.x-3.21/0000755000175000017500000000000013174615507017563 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/SConstruct0000644000175000017500000004327013136555240021616 0ustar jenkinsjenkins################################################################### # # Copyright (C) 2010-2016 Codership Oy # # SCons build script to build galera libraries # # How to control the build with environment variables: # Set CC to specify C compiler # Set CXX to specify C++ compiler # Set CPPFLAGS to add non-standard include paths and preprocessor macros # Set CCFLAGS to *override* optimization and architecture-specific options # Set CFLAGS to supply C compiler options # Set CXXFLAGS to supply C++ compiler options # Set LDFLAGS to *override* linking flags # Set LIBPATH to add non-standard linker paths # Set RPATH to add rpaths # # Script structure: # - Help message # - Default parameters # - Read commandline options # - Set up and configure default build environment # - Set up and configure check unit test build environment # - Run root SConscript with variant_dir # #################################################################### import os import platform import string import subprocess sysname = os.uname()[0].lower() machine = platform.machine() bits = ARGUMENTS.get('bits', platform.architecture()[0]) print 'Host: ' + sysname + ' ' + machine + ' ' + bits x86 = any(arch in machine for arch in [ 'x86', 'amd64', 'i686', 'i386', 'i86pc' ]) if bits == '32bit': bits = 32 elif bits == '64bit': bits = 64 # # Print Help # Help(''' Build targets: build tests check install all Default target: all Commandline Options: static_ssl=[0|1] Build with static SSL with_ssl=path Prefix for SSL debug=n debug build with optimization level n build_dir=dir build directory, default: '.' boost=[0|1] disable or enable boost libraries system_asio=[0|1] use system asio library, if available boost_pool=[0|1] use or not use boost pool allocator revno=XXXX source code revision number bpostatic=path a path to static libboost_program_options.a extra_sysroot=path a path to extra development environment (Fink, Homebrew, MacPorts, MinGW) bits=[32bit|64bit] ''') # bpostatic option added on Percona request # # Default params # build_target = 'all' # Optimization level opt_flags = ' -g -O3 -fno-omit-frame-pointer -DNDEBUG' # Architecture (defaults to build host type) compile_arch = '' link_arch = '' with_ssl = '' # Build directory build_dir = '' # # Read commandline options # build_dir = ARGUMENTS.get('build_dir', '') with_ssl = ARGUMENTS.get('with_ssl', '/usr/lib64') # Debug/dbug flags debug = ARGUMENTS.get('debug', -1) dbug = ARGUMENTS.get('dbug', False) debug_lvl = int(debug) if debug_lvl >= 0 and debug_lvl < 3: opt_flags = ' -g -O%d -fno-inline' % debug_lvl dbug = True elif debug_lvl == 3: opt_flags = ' -g -O3 -fno-omit-frame-pointer' if dbug: opt_flags = opt_flags + ' -DGU_DBUG_ON' if sysname == 'sunos': compile_arch = ' -mtune=native' elif x86: if bits == 32: if machine == 'x86_64': compile_arch = ' -mx32' else: compile_arch = ' -m32 -march=i686' if sysname == 'linux': link_arch = ' -Wl,-melf_i386' else: compile_arch = ' -m64' if sysname == 'linux': link_arch = ' -Wl,-melf_x86_64' link_arch = compile_arch + link_arch elif machine == 's390x': compile_arch = ' -mzarch' if bits == 32: compile_arch += ' -m32' boost = int(ARGUMENTS.get('boost', 1)) boost_pool = int(ARGUMENTS.get('boost_pool', 0)) static_ssl = int(ARGUMENTS.get('static_ssl', 0)) system_asio= int(ARGUMENTS.get('system_asio', 1)) ssl = int(ARGUMENTS.get('ssl', 1)) tests = int(ARGUMENTS.get('tests', 1)) deterministic_tests = int(ARGUMENTS.get('deterministic_tests', 0)) strict_build_flags = int(ARGUMENTS.get('strict_build_flags', 1)) GALERA_VER = ARGUMENTS.get('version', '3.21') GALERA_REV = ARGUMENTS.get('revno', 'XXXX') # export to any module that might have use of those Export('GALERA_VER', 'GALERA_REV') print 'Signature: version: ' + GALERA_VER + ', revision: ' + GALERA_REV LIBBOOST_PROGRAM_OPTIONS_A = ARGUMENTS.get('bpostatic', '') LIBBOOST_SYSTEM_A = string.replace(LIBBOOST_PROGRAM_OPTIONS_A, 'boost_program_options', 'boost_system') # # Set up and export default build environment # env = Environment(ENV = {'PATH' : os.environ['PATH'], 'HOME' : os.environ['HOME']}) # Set up environment for ccache and distcc #env['ENV']['HOME'] = os.environ['HOME'] #env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS'] #env['ENV']['CCACHE_PREFIX'] = os.environ['CCACHE_PREFIX'] if 'CCACHE_DIR' in os.environ: env['ENV']['CCACHE_DIR'] = os.environ['CCACHE_DIR'] if 'CCACHE_CPP2' in os.environ: env['ENV']['CCACHE_CPP2'] = os.environ['CCACHE_CPP2'] # Set CC and CXX compilers cc = os.getenv('CC', 'default') if cc != 'default': env.Replace(CC = cc) cxx = os.getenv('CXX', 'default') if cxx != 'default': env.Replace(CXX = cxx) link = os.getenv('LINK', 'default') if link != 'default': env.Replace(LINK = link) # Initialize CPPFLAGS and LIBPATH from environment to get user preferences env.Replace(CPPFLAGS = os.getenv('CPPFLAGS', '')) env.Replace(CCFLAGS = os.getenv('CCFLAGS', opt_flags + compile_arch)) env.Replace(CFLAGS = os.getenv('CFLAGS', '')) env.Replace(CXXFLAGS = os.getenv('CXXFLAGS', '')) env.Replace(LINKFLAGS = os.getenv('LDFLAGS', link_arch)) env.Replace(LIBPATH = [os.getenv('LIBPATH', '')]) env.Replace(RPATH = [os.getenv('RPATH', '')]) # Set -pthread flag explicitly to make sure that pthreads are # enabled on all platforms. env.Append(CCFLAGS = ' -pthread') # FreeBSD ports are usually installed under /usr/local if sysname == 'freebsd' or sysname == 'sunos': env.Append(LIBPATH = ['/usr/local/lib']) env.Append(CPPPATH = ['/usr/local/include']) if sysname == 'sunos': env.Replace(SHLINKFLAGS = '-shared ') # Add paths is extra_sysroot argument was specified extra_sysroot = ARGUMENTS.get('extra_sysroot', '') if sysname == 'darwin' and extra_sysroot == '': # common developer environments and paths if os.system('which -s port') == 0 and os.path.isfile('/opt/local/bin/port'): extra_sysroot = '/opt/local' elif os.system('which -s brew') == 0 and os.path.isfile('/usr/local/bin/brew'): extra_sysroot = '/usr/local' elif os.system('which -s fink') == 0 and os.path.isfile('/sw/bin/fink'): extra_sysroot = '/sw' if extra_sysroot != '': env.Append(LIBPATH = [extra_sysroot + '/lib']) env.Append(CCFLAGS = ' -I' + extra_sysroot + '/include') # print env.Dump() # Preprocessor flags if sysname != 'sunos' and sysname != 'darwin' and sysname != 'freebsd': env.Append(CPPFLAGS = ' -D_XOPEN_SOURCE=600') if sysname == 'sunos': env.Append(CPPFLAGS = ' -D__EXTENSIONS__') env.Append(CPPFLAGS = ' -DHAVE_COMMON_H') # Common C/CXX flags # These should be kept minimal as they are appended after C/CXX specific flags env.Append(CCFLAGS = ' -fPIC -Wall -Wextra -Wno-unused-parameter') # C-specific flags env.Prepend(CFLAGS = '-std=c99 -fno-strict-aliasing -pipe ') # CXX-specific flags # Note: not all 3rd-party libs like '-Wold-style-cast -Weffc++' # adding those after checks env.Prepend(CXXFLAGS = '-Wno-long-long -Wno-deprecated -ansi ') if sysname != 'sunos': env.Prepend(CXXFLAGS = '-pipe ') # Linker flags # TODO: enable ' -Wl,--warn-common -Wl,--fatal-warnings' after warnings from # static linking have beed addressed # #env.Prepend(LINKFLAGS = '-Wl,--warn-common -Wl,--fatal-warnings ') # # Check required headers and libraries (autoconf functionality) # # # Custom tests: # def CheckSystemASIOVersion(context): system_asio_test_source_file = """ #include #if ASIO_VERSION < 101001 #error "Included asio version is too old" #endif int main() { return 0; } """ context.Message('Checking ASIO version (> 1.10.1) ... ') result = context.TryLink(system_asio_test_source_file, '.cpp') context.Result(result) return result # # Construct confuration context # conf = Configure(env, custom_tests = {'CheckSystemASIOVersion': CheckSystemASIOVersion}) # System headers and libraries if not conf.CheckLib('pthread'): print 'Error: pthread library not found' Exit(1) # libatomic may be needed on some 32bit platforms (and 32bit userland PPC64) # for 8 byte atomics but not generally required if not x86: conf.CheckLib('atomic') if sysname != 'darwin': if not conf.CheckLib('rt'): print 'Error: rt library not found' Exit(1) if sysname == 'freebsd': if not conf.CheckLib('execinfo'): print 'Error: execinfo library not found' Exit(1) if sysname == 'sunos': if not conf.CheckLib('socket'): print 'Error: socket library not found' Exit(1) if not conf.CheckLib('crypto'): print 'Error: crypto library not found' Exit(1) if not conf.CheckLib('nsl'): print 'Error: nsl library not found' Exit(1) if conf.CheckHeader('sys/epoll.h'): conf.env.Append(CPPFLAGS = ' -DGALERA_USE_GU_NETWORK') if conf.CheckHeader('byteswap.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_BYTESWAP_H') if conf.CheckHeader('endian.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_ENDIAN_H') elif conf.CheckHeader('sys/endian.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_SYS_ENDIAN_H') elif conf.CheckHeader('sys/byteorder.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_SYS_BYTEORDER_H') elif sysname != 'darwin': print 'can\'t find byte order information' Exit(1) if conf.CheckHeader('execinfo.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_EXECINFO_H') # Additional C headers and libraries # boost headers if not conf.CheckCXXHeader('boost/shared_ptr.hpp'): print 'boost/shared_ptr.hpp not found or not usable' Exit(1) conf.env.Append(CPPFLAGS = ' -DHAVE_BOOST_SHARED_PTR_HPP') if conf.CheckCXXHeader('unordered_map'): conf.env.Append(CPPFLAGS = ' -DHAVE_UNORDERED_MAP') elif conf.CheckCXXHeader('tr1/unordered_map'): conf.env.Append(CPPFLAGS = ' -DHAVE_TR1_UNORDERED_MAP') else: if conf.CheckCXXHeader('boost/unordered_map.hpp'): conf.env.Append(CPPFLAGS = ' -DHAVE_BOOST_UNORDERED_MAP_HPP') else: print 'no unordered map header available' Exit(1) # pool allocator if boost == 1: # Default suffix for boost multi-threaded libraries if sysname == 'darwin': boost_library_suffix = '-mt' else: boost_library_suffix = '' if sysname == 'darwin' and extra_sysroot != '': boost_library_path = extra_sysroot + '/lib' else: boost_library_path = '' # Use nanosecond time precision conf.env.Append(CPPFLAGS = ' -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG=1') # Common procedure to find boost static library if bits == 64: boost_libpaths = [ boost_library_path, '/usr/lib64', '/usr/local/lib64' ] else: boost_libpaths = [ boost_library_path, '/usr/local/lib', '/usr/lib' ] def check_boost_library(libBaseName, header, configuredLibPath, autoadd = 1): libName = libBaseName + boost_library_suffix if configuredLibPath != '' and not os.path.isfile(configuredLibPath): print "Error: file '%s' does not exist" % configuredLibPath Exit(1) if configuredLibPath == '': for libpath in boost_libpaths: libname = libpath + '/lib%s.a' % libName if os.path.isfile(libname): configuredLibPath = libname break if configuredLibPath != '': if not conf.CheckCXXHeader(header): print "Error: header '%s' does not exist" % header Exit (1) if autoadd: conf.env.Append(LIBS=File(configuredLibPath)) else: return File(configuredLibPath) else: if not conf.CheckLibWithHeader(libs=[libName], header=header, language='CXX', autoadd=autoadd): print 'Error: library %s does not exist' % libName Exit (1) return [libName] # Required boost headers/libraries # if boost_pool == 1: if conf.CheckCXXHeader('boost/pool/pool_alloc.hpp'): print 'Using boost pool alloc' conf.env.Append(CPPFLAGS = ' -DGALERA_USE_BOOST_POOL_ALLOC=1') # due to a bug in boost >= 1.50 we need to link with boost_system # - should be a noop with no boost_pool. if sysname == 'darwin': if conf.CheckLib('boost_system' + boost_library_suffix): conf.env.Append(LIBS=['boost_system' + boost_library_suffix]) check_boost_library('boost_system', 'boost/system/error_code.hpp', LIBBOOST_SYSTEM_A) else: print 'Error: boost/pool/pool_alloc.hpp not found or not usable' Exit(1) libboost_program_options = check_boost_library('boost_program_options', 'boost/program_options.hpp', LIBBOOST_PROGRAM_OPTIONS_A, autoadd = 0) else: print 'Not using boost' # asio if system_asio == 1 and conf.CheckCXXHeader('asio.hpp') and conf.CheckSystemASIOVersion(): conf.env.Append(CPPFLAGS = ' -DHAVE_ASIO_HPP') else: system_asio = False print "Falling back to bundled asio" if not system_asio: # Make sure that -Iasio goes before other paths (e.g. -I/usr/local/include) # that may contain a system wide installed asio. We should use the bundled # asio if "scons system_asio=0" is specified. Thus use Prepend(). conf.env.Prepend(CPPPATH = [ '#/asio' ]) if conf.CheckCXXHeader('asio.hpp'): conf.env.Append(CPPFLAGS = ' -DHAVE_ASIO_HPP') else: print 'asio headers not found or not usable' Exit(1) # asio/ssl if ssl == 1: if conf.CheckCXXHeader('asio/ssl.hpp'): conf.env.Append(CPPFLAGS = ' -DHAVE_ASIO_SSL_HPP') else: print 'ssl support required but asio/ssl.hpp not found or not usable' print 'compile with ssl=0 or check that openssl devel headers are usable' Exit(1) if static_ssl == 0: if conf.CheckLib('ssl'): conf.CheckLib('crypto') else: print 'ssl support required but openssl library not found' print 'compile with ssl=0 or check that openssl library is usable' Exit(1) else: conf.env.Append(LIBPATH = [with_ssl]) if conf.CheckLib('libssl.a', autoadd=0) or \ conf.CheckLib('libcrypto.a', autoadd=0) or \ conf.CheckLib('libz.a', autoadd=0): pass else: print 'ssl support required but openssl library (static) not found' print 'compile with ssl=0 or check that' print 'openssl static librares - libssl.a, libcrypto.a, libz.a are available' Exit(1) # get compiler name/version, CXX may be set to "c++" which may be clang or gcc try: compiler_version = subprocess.check_output( conf.env['CXX'].split() + ['--version'], stderr=subprocess.STDOUT) except: # in case "$CXX --version" returns an error, e.g. "unknown option" compiler_version = 'unknown' # these will be used only with our software if strict_build_flags == 1: conf.env.Append(CCFLAGS = ' -Werror -pedantic') if 'clang' in compiler_version: conf.env.Append(CCFLAGS = ' -Wno-self-assign') conf.env.Append(CCFLAGS = ' -Wno-gnu-zero-variadic-macro-arguments') conf.env.Append(CXXFLAGS = ' -Wno-variadic-macros') # CXX may be something like "ccache clang++" if 'ccache' in conf.env['CXX'] or 'ccache' in conf.env['CC']: conf.env.Append(CCFLAGS = ' -Qunused-arguments') else: conf.env.Prepend(CXXFLAGS = '-Weffc++ -Wold-style-cast ') env = conf.Finish() Export('x86', 'bits', 'env', 'sysname', 'libboost_program_options', 'static_ssl', 'with_ssl') # # Actions to build .dSYM directories, containing debugging information for Darwin # if sysname == 'darwin' and int(debug) >= 0 and int(debug) < 3: env['LINKCOM'] = [env['LINKCOM'], 'dsymutil $TARGET'] env['SHLINKCOM'] = [env['SHLINKCOM'], 'dsymutil $TARGET'] # # Set up and export environment for check unit tests # # Clone base from default environment check_env = env.Clone() conf = Configure(check_env) # Check header and library if not conf.CheckHeader('check.h'): print 'Error: check header file not found or not usable' Exit(1) if not conf.CheckLib('check'): print 'Error: check library not found or not usable' Exit(1) if not conf.CheckLib('m'): print 'Error: math library not found or not usable' Exit(1) # potential check dependency, link if present conf.CheckLib('subunit') if sysname != 'darwin': if not conf.CheckLib('rt'): print 'Error: realtime library not found or not usable' Exit(1) conf.Finish() # # this follows recipes from http://www.scons.org/wiki/UnitTests # def builder_unit_test(target, source, env): app = str(source[0].abspath) if os.spawnl(os.P_WAIT, app, app)==0: open(str(target[0]),'w').write("PASSED\n") else: return 1 def builder_unit_test_dummy(target, source, env): return 0 # Create a builder for tests if tests == 1: bld = Builder(action = builder_unit_test) else: bld = Builder(action = builder_unit_test_dummy) check_env.Append(BUILDERS = {'Test' : bld}) Export('check_env') # # If deterministic_tests is given, export GALERA_TEST_DETERMINISTIC # so that the non-deterministic tests can be filtered out. # if deterministic_tests: os.environ['GALERA_TEST_DETERMINISTIC'] = '1' # # Run root SConscript with variant_dir # SConscript('SConscript', variant_dir=build_dir) percona-xtradb-cluster-galera-3.x-3.21/chromium/0000755000175000017500000000000013136555240021401 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/chromium/build_config.h0000644000175000017500000000244613136555240024204 0ustar jenkinsjenkins// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // This file adds defines about the platform we're currently building on. // Operating System: // OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) // Compiler: // COMPILER_MSVC / COMPILER_GCC // Processor: // ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64) // ARCH_CPU_32_BITS / ARCH_CPU_64_BITS #ifndef BUILD_BUILD_CONFIG_H_ #define BUILD_BUILD_CONFIG_H_ // A set of macros to use for platform detection. #if defined(__native_client__) #define OS_NACL 1 #elif defined(__ANDROID__) #define OS_ANDROID 1 #endif // Compiler detection. #if defined(__GNUC__) #define COMPILER_GCC 1 #elif defined(_MSC_VER) #define COMPILER_MSVC 1 #else #error Please add support for your compiler in build/build_config.h #endif // Processor architecture detection. For more info on what's defined, see: // http://msdn.microsoft.com/en-us/library/b0084kay.aspx // http://www.agner.org/optimize/calling_conventions.pdf // or with gcc, run: "echo | gcc -E -dM -" #if defined(_M_X64) || defined(__x86_64__) || defined(_M_IX86) || defined(__i386__) #define ARCH_CPU_X86_FAMILY 1 #endif #endif // BUILD_BUILD_CONFIG_H_ percona-xtradb-cluster-galera-3.x-3.21/chromium/compile_assert.h0000644000175000017500000000516413136555240024571 0ustar jenkinsjenkins// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Codership: this is a cut down version of base/basictypes.h to comtain // COMPILE_ASSERT only #ifndef COMPILE_ASSERT_H_ #define COMPILE_ASSERT_H_ // The COMPILE_ASSERT macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: // // COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES, // content_type_names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // // COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); // // The second argument to the macro is the name of the variable. If // the expression is false, most compilers will issue a warning/error // containing the name of the variable. namespace chromium { template struct CompileAssert { }; } // namespace chromium #undef CHROMIUM_COMPILE_ASSERT #define CHROMIUM_COMPILE_ASSERT(expr, msg) \ typedef chromium::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] // Implementation details of COMPILE_ASSERT: // // - COMPILE_ASSERT works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // // - The simpler definition // // #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] // // does not work, as gcc supports variable-length arrays whose sizes // are determined at run-time (this is gcc's extension and not part // of the C++ standard). As a result, gcc fails to reject the // following code with the simple definition: // // int foo; // COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is // // not a compile-time constant. // // - By using the type CompileAssert<(bool(expr))>, we ensures that // expr is a compile-time constant. (Template arguments must be // determined at compile-time.) // // - The outer parentheses in CompileAssert<(bool(expr))> are necessary // to work around a bug in gcc 3.4.4 and 4.0.1. If we had written // // CompileAssert // // instead, these compilers will refuse to compile // // COMPILE_ASSERT(5 > 0, some_message); // // (They seem to think the ">" in "5 > 0" marks the end of the // template argument list.) // // - The array size is (bool(expr) ? 1 : -1), instead of simply // // ((expr) ? 1 : -1). // // This is to avoid running into a bug in MS VC 7.1, which // causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. #endif // COMPILE_ASSERT_H_ percona-xtradb-cluster-galera-3.x-3.21/chromium/compiler_specific.h0000644000175000017500000001440213136555240025232 0ustar jenkinsjenkins// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_COMPILER_SPECIFIC_H_ #define BASE_COMPILER_SPECIFIC_H_ #include "build_config.h" #if defined(COMPILER_MSVC) // Macros for suppressing and disabling warnings on MSVC. // // Warning numbers are enumerated at: // http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx // // The warning pragma: // http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx // // Using __pragma instead of #pragma inside macros: // http://msdn.microsoft.com/en-us/library/d9x1s805.aspx // MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and // for the next line of the source file. #define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n)) // MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled. // The warning remains disabled until popped by MSVC_POP_WARNING. #define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ __pragma(warning(disable:n)) // MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level. The level // remains in effect until popped by MSVC_POP_WARNING(). Use 0 to disable all // warnings. #define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n)) // Pop effects of innermost MSVC_PUSH_* macro. #define MSVC_POP_WARNING() __pragma(warning(pop)) #define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off)) #define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on)) // DEPRECATED // // Prior to r83840 this was used to supress warning C4355 when using |this| as // an argument in constructor initializer lists: // http://msdn.microsoft.com/en-us/library/3c594ae3(VS.80).aspx // // C4355 is supressed globally during compilation and existing uses of this // macro should be removed. Refer to http://crbug.com/234765 for details. #define ALLOW_THIS_IN_INITIALIZER_LIST(code) code // Allows exporting a class that inherits from a non-exported base class. // This uses suppress instead of push/pop because the delimiter after the // declaration (either "," or "{") has to be placed before the pop macro. // // Example usage: // class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) { // // MSVC Compiler warning C4275: // non dll-interface class 'Bar' used as base for dll-interface class 'Foo'. // Note that this is intended to be used only when no access to the base class' // static data is done through derived classes or inline methods. For more info, // see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx #define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \ code #else // Not MSVC #define MSVC_SUPPRESS_WARNING(n) #define MSVC_PUSH_DISABLE_WARNING(n) #define MSVC_PUSH_WARNING_LEVEL(n) #define MSVC_POP_WARNING() #define MSVC_DISABLE_OPTIMIZE() #define MSVC_ENABLE_OPTIMIZE() #define ALLOW_THIS_IN_INITIALIZER_LIST(code) code #define NON_EXPORTED_BASE(code) code #endif // COMPILER_MSVC // Annotate a variable indicating it's ok if the variable is not used. // (Typically used to silence a compiler warning when the assignment // is important for some other reason.) // Use like: // int x ALLOW_UNUSED = ...; #if defined(COMPILER_GCC) #define ALLOW_UNUSED __attribute__((unused)) #else #define ALLOW_UNUSED #endif // Annotate a function indicating it should not be inlined. // Use like: // NOINLINE void DoStuff() { ... } #if defined(COMPILER_GCC) #define NOINLINE __attribute__((noinline)) #elif defined(COMPILER_MSVC) #define NOINLINE __declspec(noinline) #else #define NOINLINE #endif // Specify memory alignment for structs, classes, etc. // Use like: // class ALIGNAS(16) MyClass { ... } // ALIGNAS(16) int array[4]; #if defined(COMPILER_MSVC) #define ALIGNAS(byte_alignment) __declspec(align(byte_alignment)) #elif defined(COMPILER_GCC) #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) #endif // Return the byte alignment of the given type (available at compile time). Use // sizeof(type) prior to checking __alignof to workaround Visual C++ bug: // http://goo.gl/isH0C // Use like: // ALIGNOF(int32) // this would be 4 #if defined(COMPILER_MSVC) #define ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type)) #elif defined(COMPILER_GCC) #define ALIGNOF(type) __alignof__(type) #endif // Annotate a virtual method indicating it must be overriding a virtual // method in the parent class. // Use like: // virtual void foo() OVERRIDE; #if defined(COMPILER_MSVC) #define OVERRIDE override #elif defined(__clang__) #define OVERRIDE override #else #define OVERRIDE #endif // Annotate a function indicating the caller must examine the return value. // Use like: // int foo() WARN_UNUSED_RESULT; // To explicitly ignore a result, see |ignore_result()| in . #if defined(COMPILER_GCC) #define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else #define WARN_UNUSED_RESULT #endif // Tell the compiler a function is using a printf-style format string. // |format_param| is the one-based index of the format string parameter; // |dots_param| is the one-based index of the "..." parameter. // For v*printf functions (which take a va_list), pass 0 for dots_param. // (This is undocumented but matches what the system C headers do.) #if defined(COMPILER_GCC) #define PRINTF_FORMAT(format_param, dots_param) \ __attribute__((format(printf, format_param, dots_param))) #else #define PRINTF_FORMAT(format_param, dots_param) #endif // WPRINTF_FORMAT is the same, but for wide format strings. // This doesn't appear to yet be implemented in any compiler. // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 . #define WPRINTF_FORMAT(format_param, dots_param) // If available, it would look like: // __attribute__((format(wprintf, format_param, dots_param))) // MemorySanitizer annotations. #ifdef MEMORY_SANITIZER extern "C" { void __msan_unpoison(const void *p, unsigned long s); } // extern "C" // Mark a memory region fully initialized. // Use this to annotate code that deliberately reads uninitialized data, for // example a GC scavenging root set pointers from the stack. #define MSAN_UNPOISON(p, s) __msan_unpoison(p, s) #else // MEMORY_SANITIZER #define MSAN_UNPOISON(p, s) #endif // MEMORY_SANITIZER #endif // BASE_COMPILER_SPECIFIC_H_ percona-xtradb-cluster-galera-3.x-3.21/chromium/LICENSE0000644000175000017500000000303313136555240022405 0ustar jenkinsjenkins// Copyright (c) 2013 The Chromium Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. percona-xtradb-cluster-galera-3.x-3.21/chromium/aligned_memory.h0000644000175000017500000001150613136555240024550 0ustar jenkinsjenkins// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // AlignedMemory is a POD type that gives you a portable way to specify static // or local stack data of a given alignment and size. For example, if you need // static storage for a class, but you want manual control over when the object // is constructed and destructed (you don't want static initialization and // destruction), use AlignedMemory: // // static AlignedMemory my_class; // // // ... at runtime: // new(my_class.void_data()) MyClass(); // // // ... use it: // MyClass* mc = my_class.data_as(); // // // ... later, to destruct my_class: // my_class.data_as()->MyClass::~MyClass(); // // Alternatively, a runtime sized aligned allocation can be created: // // float* my_array = static_cast(AlignedAlloc(size, alignment)); // // // ... later, to release the memory: // AlignedFree(my_array); // // Or using scoped_ptr_malloc: // // scoped_ptr_malloc my_array( // static_cast(AlignedAlloc(size, alignment))); #ifndef BASE_MEMORY_ALIGNED_MEMORY_H_ #define BASE_MEMORY_ALIGNED_MEMORY_H_ #include "compile_assert.h" #include "compiler_specific.h" #if defined(COMPILER_MSVC) #include #else #include #endif namespace chromium { // AlignedMemory is specialized for all supported alignments. // Make sure we get a compiler error if someone uses an unsupported alignment. template struct AlignedMemory {}; #define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \ template \ class AlignedMemory { \ public: \ ALIGNAS(byte_alignment) unsigned char data_[Size]; \ void* void_data() { return static_cast(data_); } \ const void* void_data() const { \ return static_cast(data_); \ } \ template \ Type* data_as() { return static_cast(void_data()); } \ template \ const Type* data_as() const { \ return static_cast(void_data()); \ } \ private: \ void* operator new(size_t); \ void operator delete(void*); \ } // Specialization for all alignments is required because MSVC (as of VS 2008) // does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param). // Greater than 4096 alignment is not supported by some compilers, so 4096 is // the maximum specified here. BASE_DECL_ALIGNED_MEMORY(1); BASE_DECL_ALIGNED_MEMORY(2); BASE_DECL_ALIGNED_MEMORY(4); BASE_DECL_ALIGNED_MEMORY(8); BASE_DECL_ALIGNED_MEMORY(16); BASE_DECL_ALIGNED_MEMORY(32); BASE_DECL_ALIGNED_MEMORY(64); BASE_DECL_ALIGNED_MEMORY(128); BASE_DECL_ALIGNED_MEMORY(256); BASE_DECL_ALIGNED_MEMORY(512); BASE_DECL_ALIGNED_MEMORY(1024); BASE_DECL_ALIGNED_MEMORY(2048); BASE_DECL_ALIGNED_MEMORY(4096); #undef BASE_DECL_ALIGNED_MEMORY #if defined(OS_ANDROID) || defined(OS_NACL) #include #endif inline void* AlignedAlloc(size_t size, size_t alignment) { void* ptr = NULL; #if defined(COMPILER_MSVC) ptr = _aligned_malloc(size, alignment); #elif defined(OS_ANDROID) || defined(OS_NACL) // Both Android and NaCl technically support posix_memalign(), but do not expose // it in the current version of the library headers used by Chrome. Luckily, // memalign() on both platforms returns pointers which can safely be used with // free(), so we can use it instead. Issues filed with each project for docs: // http://code.google.com/p/android/issues/detail?id=35391 // http://code.google.com/p/chromium/issues/detail?id=138579 ptr = memalign(alignment, size); #else if (posix_memalign(&ptr, alignment, size)) ptr = NULL; #endif return ptr; } inline void AlignedFree(void* ptr) { #if defined(COMPILER_MSVC) _aligned_free(ptr); #else free(ptr); #endif } // Helper class for use with scoped_ptr_malloc. class ScopedPtrAlignedFree { public: inline void operator()(void* ptr) const { AlignedFree(ptr); } }; // Codership: added a convenience wsrapper over AlignedMemory template class AlignedBuffer { public: T* base_ptr() { return buf_.template data_as(); } const T* base_ptr() const { return buf_.template data_as(); } size_t size() const { return capacity; } private: // The buffer itself. It is not of type T because we don't want the // constructors and destructors to be automatically called. Define a POD // buffer of the right size instead. chromium::AlignedMemory buf_; #if defined(__GNUC__) && !defined(ARCH_CPU_X86_FAMILY) CHROMIUM_COMPILE_ASSERT(ALIGNOF(T) <= 16, crbug_115612); #endif }; } // namespace chromium #endif // BASE_MEMORY_ALIGNED_MEMORY_H_ percona-xtradb-cluster-galera-3.x-3.21/chromium/AUTHORS0000644000175000017500000002207513136555240022457 0ustar jenkinsjenkins# Names should be added to this file with this pattern: # # For individuals: # Name # # For organizations: # Organization # # See python fnmatch module documentation for more information. The Chromium Authors <*@chromium.org> Google Inc. <*@google.com> Mohamed I. Hammad Sergiy Byelozyorov Seo Sanghyeon Alex Scheele Andrew Brampton Paweł Hajdan jr Jesse Miller Szymon Piechowicz James Vega Marco Rodrigues Matthias Reitinger Peter Bright Arthur Lussos Masahiro Yado Yarin Kaul Gaetano Mendola Comodo CA Limited Torchmobile Inc. Craig Schlenter Ibrar Ahmed Naoki Takano Fabien Tassin Kunal Thakar Mohamed Mansour Joshua Roesslein Yong Shin Laszlo Radanyi Raman Tenneti Kyle Nahrgang Kim Christensen Paul Robinson Josué Ratelle Edward Crossman Nikita Ofitserov Sean Bryant Robert Sesek Janwar Dinata Will Hirsch Yoav Zilberberg Joel Stanley Jacob Mandelson Yuri Gorobets Paul Wicks Thiago Farina Viet-Trung Luu Pierre-Antoine LaFayette Song YeWen Philippe Beauchamp Vedran Šajatović Randy Posynick Bruno Calvignac Jaime Soriano Pastor Bryan Donlan Ramkumar Ramachandra Dominic Jodoin Kaspar Brand Clemens Fruhwirth Kevin Lee Helpingstine Bernard Cafarelli Vernon Tang Alexander Sulfrian Philippe Beaudoin Mark Hahnenberg Alex Gartrell Leith Bade James Choi Paul Kehrer Chamal De Silva Jay Soffian Brian G. Merrell Matthew Willis Brian Merrell, Novell Inc. Ryan Sleevi Satoshi Matsuzaki Benjamin Jemlich Ningxin Hu James Wei Haitao Feng Jared Wein Mingmin Xie Michael Gilbert Giuseppe Iuculano James Willcox Shreyas VA Steven Pennington Jorge Villatoro Paul Nettleship David Benjamin Sevan Janiyan Peter Beverloo Lauri Oherd Ben Karel Sam McDonald Magnus Danielsson Kushal Pisavadia Maarten Lankhorst Vipul Bhasin Ryan Norton Dillon Sellars Seshadri Mahalingam Clement Scheelfeldt Skau David Futcher Ramkumar Gokarnesan Matt Arpidone ruben NVIDIA Corporation <*@nvidia.com> Torsten Kurbad Max Perepelitsyn Luke Zarko Felix H. Dahlke Ali Vathi Mathias Bynens Mark Seaborn Amruth Raj Amruth Raj Gajendra Singh Ehsan Akhgari Christopher Dale Sanjoy Pal Mike Tilburg Peter Brophy Robert Goldberg Don Woodward Vinay Anantharaman Naveen Bobbili Vamshikrishna Yellenki Robert Nagy Nayan Kumar K ShankarGanesh K Goutham Jagannatha Rosen Dash Naveen Bobbili Ravi Phaneendra Kasibhatla Rosen Dash Parag Radke Ted Vessenes Yair Yogev Chandra Shekar Vallala Patrasciuc Sorin Cristian Halton Huo Shiliu Wang Gao Chun Clinton Staley Clinton Staley Devlin Cronin Junmin Zhu Cem Kocagil YoungKi Hong Lu Guanqun François Beaufort Eriq Augustine Francois Kritzinger Erik Hill Mao Yujie Pan Deng Aaron Leventhal Peter Collingbourne Aaron Randolph Yumikiyo Osanai Matthew Robertson Mao Yujie Xu Samuel Jin Yang Xinchao He Changbin Shao Stephen Searles Arun Mankuzhi Christophe Dumez Taylor Price Alexandru Chiculita Eric Rescorla Alexandre Abreu Erik Sjölund Simon Arlott Alexey Korepanov Mitchell Rosen Yongsheng Zhu Shouqun Liu Kangyuan Shu Jake Helfert Hongbo Min Anastasios Cassiotis Evangelos Foutras Pavel Ivanov Rene Bolldorf Petar Jovanovic Sergio Carlos Morales Angeles Mihai Maerean Kaustubh Atrawalkar Robert Bear Travis Robert Bear Travis Max Vujovic Jakob Weigert Catalin Badea Joshua Lock Dai Chunyang Joe Thomas Ruben Terrazas Josh Triplett Qiankun Miao Etienne Laurin Yang Gu Timo Reimann Sungguk Lim Martin Bednorz Kamil Jiwa Keene Pan Trevor Perrin Ion Rosca Sylvain Zimmer Sungmann Cho 方觉 (Fang Jue) Evan Peterson J. Ryan Stinnett Matheus Bratfisch Horia Olaru Horia Olaru Opera Software ASA <*@opera.com> Johannes Rudolph Aaron Jacobs Sam Larison Jun Jiang Bobby Powers Patrick Riordan Kenneth Rohde Christiansen Raphael Kubo da Costa Yandex LLC <*@yandex-team.ru> Yoshinori Sano Mrunal Kapade Yael Aharon Haojian Wu Sathish Kuppuswamy Joone Hur Sudarsana Babu Nagineni Jared Shumway Shez Baig percona-xtradb-cluster-galera-3.x-3.21/galerautils/0000755000175000017500000000000013136555240022072 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/galerautils/src/0000755000175000017500000000000013136555240022661 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_mem_pool.hpp0000644000175000017500000001271013136555240025675 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy */ /** * @file Self-adjusting pool of same size memory buffers. * * How it works: pool is never allowed to keep more than half of total * allocated buffers (plus min_count), so at least half of buffers must be * in use. As more than half goes out of use they will be deallocated rather * than placed back in the pool. * * $Id$ */ #ifndef _GU_MEM_POOL_HPP_ #define _GU_MEM_POOL_HPP_ #include "gu_lock.hpp" #include "gu_macros.hpp" #include #include #include namespace gu { typedef std::vector MemPoolVector; /* Since we specialize this template iwth thread_safe=true parameter below, * this makes it implicit thread_safe=false specialization. */ template class MemPool { public: explicit MemPool(int buf_size, int reserve = 0, const char* name = "") : pool_ (), hits_ (0), misses_ (0), allocd_ (0), name_ (name), buf_size_ (buf_size), reserve_ (reserve) { assert(buf_size_ > 0); pool_.reserve(reserve_); } ~MemPool() { /* all buffers must be returned to pool before destruction */ assert(pool_.size() == allocd_); for (size_t i(0); i < pool_.size(); ++i) { assert(pool_[i]); free(pool_[i]); } } void* acquire() { void* ret(from_pool()); if (!ret) ret = alloc(); return ret; } void recycle(void* buf) { if (!to_pool(buf)) free(buf); } void print(std::ostream& os) const { double hr(hits_); if (hr > 0) { assert(misses_ > 0); hr /= hits_ + misses_; } os << "MemPool(" << name_ << "): hit ratio: " << hr << ", misses: " << misses_ << ", in use: " << allocd_ - pool_.size() << ", in pool: " << pool_.size(); } size_t buf_size() const { return buf_size_; } protected: /* from_pool() and to_pool() will need to be called under mutex * in thread-safe version, so all object data are modified there. * alloc() and free() then can be called outside critical section. */ void* from_pool() { void* ret(NULL); if (pool_.size() > 0) { ret = pool_.back(); assert(ret); pool_.pop_back(); ++hits_; } else { ++allocd_; ++misses_; } return ret; } // returns false if buffer can't be returned to pool bool to_pool(void* buf) { assert(buf); bool const ret(reserve_ + allocd_/2 > pool_.size()); if (ret) { pool_.push_back(buf); } else { assert(allocd_ > 0); --allocd_; } return ret; } void* alloc() { return (operator new(buf_size_)); } void free(void* const buf) { assert(buf); operator delete(buf); } friend class MemPool; private: MemPoolVector pool_; size_t hits_; size_t misses_; size_t allocd_; const char* const name_; unsigned int const buf_size_; unsigned int const reserve_; MemPool (const MemPool&); MemPool operator= (const MemPool&); }; /* class MemPool: thread-unsafe */ /* Thread-safe MemPool specialization. * Even though MemPool technically IS-A MemPool, the need to * overload nearly all public methods and practical uselessness of * polymorphism in this case make inheritance undesirable. */ template <> class MemPool { public: explicit MemPool(int buf_size, int reserve = 0, const char* name = "") : base_(buf_size, reserve, name), mtx_ () {} ~MemPool() {} void* acquire() { void* ret; { Lock lock(mtx_); ret = base_.from_pool(); } if (!ret) ret = base_.alloc(); return ret; } void recycle(void* buf) { bool pooled; { Lock lock(mtx_); pooled = base_.to_pool(buf); } if (!pooled) base_.free(buf); } void print(std::ostream& os) const { Lock lock(mtx_); base_.print(os); } size_t buf_size() const { return base_.buf_size(); } private: MemPool base_; Mutex mtx_; }; /* class MemPool: thread-safe */ template std::ostream& operator << (std::ostream& os, const MemPool& mp) { mp.print(os); return os; } typedef MemPool MemPoolUnsafe; typedef MemPool MemPoolSafe; } /* namespace gu */ #endif /* _GU_MEM_POOL_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_debug_sync.hpp0000644000175000017500000000203113136555240026203 0ustar jenkinsjenkins// // Copyright (C) 2014 Codership Oy // // // Define -DGU_DBUG_ON to enable GU_DBUG macros // // Usage: // // GU_DBUG_SYNC_WAIT("sync_point_identifier") // // The macro above will block whenever "dbug=d,sync_point_identifier" // parameter has been passed to provider. // // Blocking waiters can be signalled by setting "signal=sync_point_identifier" // option. // // List of waiters can be monitored from wsrep debug_sync_waiters status // variable. // #ifndef GU_DEBUG_SYNC_HPP #define GU_DEBUG_SYNC_HPP #ifdef GU_DBUG_ON #include #include "gu_dbug.h" #define GU_DBUG_SYNC_WAIT(_c) \ GU_DBUG_EXECUTE(_c, gu_debug_sync_wait(_c);) // Wait for sync signal identified by sync string void gu_debug_sync_wait(const std::string& sync); // Signal waiter identified by sync string void gu_debug_sync_signal(const std::string& sync); // Get list of active sync waiters std::string gu_debug_sync_waiters(); #else #define GU_DBUG_SYNC_WAIT(_c) #endif // GU_DBUG_ON #endif // GU_DEBUG_SYNC_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_vlq.hpp0000644000175000017500000001124513136555240024672 0ustar jenkinsjenkins// // Copyright (C) 2011-2013 Codership Oy // //! // @file Variable-length quantity encoding for integers // // Unsigned integers: Implementation uses using unsigned LEB128, // see for example http://en.wikipedia.org/wiki/LEB128. // // Signed integers: TODO // #ifndef GU_VLQ_HPP #define GU_VLQ_HPP #include "gu_buffer.hpp" #include "gu_throw.hpp" #include "gu_macros.h" #define GU_VLQ_CHECKS #define GU_VLQ_ALEX namespace gu { //! // @brief Retun number of bytes required to represent given value in ULEB128 // representation. // // @param value Unsigned value // // @return Number of bytes required for value representation // template inline size_t uleb128_size(UI value) { size_t i(1); value >>= 7; for (; value != 0; value >>= 7, ++i) {} return i; } //! // @brief Encode unsigned type to ULEB128 representation // // @param value // @param buf // @param buflen // @param offset // // @return Offset // template inline size_t uleb128_encode(UI value, byte_t* buf, size_t buflen, size_t offset) { #ifdef GU_VLQ_ALEX assert (offset < buflen); buf[offset] = value & 0x7f; while (value >>= 7) { buf[offset] |= 0x80; ++offset; #ifdef GU_VLQ_CHECKS if (gu_unlikely(offset >= buflen)) gu_throw_fatal; #else assert(offset < buflen); #endif /* GU_VLQ_CHECKS */ buf[offset] = value & 0x7f; } return offset + 1; #else /* GU_VLQ_ALEX */ do { #ifdef GU_VLQ_CHECKS if (gu_unlikely(offset >= buflen)) gu_throw_fatal; #else assert(offset < buflen); #endif /* GU_VLQ_CHECKS */ buf[offset] = value & 0x7f; value >>= 7; if (gu_unlikely(value != 0)) { buf[offset] |= 0x80; } ++offset; } while (value != 0); return offset; #endif /* GU_VLQ_ALEX */ } template inline size_t uleb128_encode(UI value, byte_t* buf, size_t buflen) { return uleb128_encode(value, buf, buflen, 0); } /* checks helper for the uleb128_decode() below */ extern void uleb128_decode_checks (const byte_t* buf, size_t buflen, size_t offset, size_t avail_bits); //! // @brief Decode unsigned type from ULEB128 representation // // @param buf // @param buflen // @param offset // @param value // // @return Offset // template inline size_t uleb128_decode(const byte_t* buf, size_t buflen, size_t offset, UI& value) { // initial check for overflow, at least one byte must be readable #ifdef GU_VLQ_CHECKS if (gu_unlikely(offset >= buflen)) gu_throw_fatal; #endif #ifdef GU_VLQ_ALEX value = buf[offset] & 0x7f; size_t shift(0); while (buf[offset] & 0x80) { ++offset; shift +=7; #ifdef GU_VLQ_CHECKS ssize_t left_bits((sizeof(UI) << 3) - shift); if (gu_unlikely(offset >= buflen || left_bits < 7)) uleb128_decode_checks (buf, buflen, offset, left_bits); #endif value |= (UI(buf[offset] & 0x7f) << shift); } return offset + 1; #else /* GU_VLQ_ALEX */ value = 0; size_t shift(0); while (true) { value |= (UI(buf[offset] & 0x7f) << shift); if (gu_likely((buf[offset] & 0x80) == 0)) { // last byte ++offset; break; } ++offset; shift += 7; #ifdef GU_VLQ_CHECKS ssize_t left_bits((sizeof(UI) << 3) - shift); if (gu_unlikely(offset >= buflen || left_bits < 7)) uleb128_decode_checks (buf, buflen, offset, left_bits); #endif } return offset; #endif /* GU_VLQ_ALEX */ } template inline size_t uleb128_decode(const byte_t* buf, size_t buflen, UI& value) { return uleb128_decode(buf, buflen, 0, value); } } #endif // GU_VLQ_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_fnv.h0000644000175000017500000001311613136555240024320 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /*! * @file * * This header file defines FNV hash functions for 3 hash sizes: * 4, 8 and 16 bytes. * * Be wary of bitshift multiplication "optimization" (FNV_BITSHIFT_OPTIMIZATION): * FNV authors used to claim marginal speedup when using it, however on core2 * CPU it has shown no speedup for fnv32a and more than 2x slowdown for fnv64a * and fnv128a. Disabled by default. * * FNV vs. FNVa: FNVa has a better distribution: multiplication happens after * XOR and hence propagates XOR effect to all bytes of the hash. * Hence by default functions perform FNVa. GU_FNV_NORMAL macro * is needed for unit tests. * * gu_fnv*_internal() functions are endian-unsafe, their output should be * converted to little-endian format if it is to be exported to other machines. */ #ifndef _gu_fnv_h_ #define _gu_fnv_h_ #include "gu_int128.h" #include #include #include #include // ssize_t #include #define GU_FNV32_PRIME 16777619UL #define GU_FNV32_SEED 2166136261UL #if !defined(GU_FNVBITSHIFT_OPTIMIZATION) # define GU_FNV32_MUL(_x) _x *= GU_FNV32_PRIME #else /* GU_FNVBITSHIFT_OPTIMIZATION */ # define GU_FNV32_MUL(_x) \ _x += (_x << 1) + (_x << 4) + (_x << 7) + (_x << 8) + (_x << 24) #endif /* GU_FNVBITSHIFT_OPTIMIZATION */ #if !defined(GU_FNV_NORMAL) # define GU_FNV32_ITERATION(_s,_b) _s ^= _b; GU_FNV32_MUL(_s); #else # define GU_FNV32_ITERATION(_s,_b) GU_FNV32_MUL(_s); _s ^= _b; #endif static GU_FORCE_INLINE void gu_fnv32a_internal (const void* buf, ssize_t const len, uint32_t* seed) { const uint8_t* bp = (const uint8_t*)buf; const uint8_t* const be = bp + len; while (bp + 2 <= be) { GU_FNV32_ITERATION(*seed,*bp++); GU_FNV32_ITERATION(*seed,*bp++); } if (bp < be) { GU_FNV32_ITERATION(*seed,*bp++); } assert(be == bp); } #define GU_FNV64_PRIME 1099511628211ULL #define GU_FNV64_SEED 14695981039346656037ULL #if !defined(GU_FNVBITSHIFT_OPTIMIZATION) # define GU_FNV64_MUL(_x) _x *= GU_FNV64_PRIME #else /* GU_FNVBITSHIFT_OPTIMIZATION */ # define GU_FNV64_MUL(_x) \ _x +=(_x << 1) + (_x << 4) + (_x << 5) + (_x << 7) + (_x << 8) + (_x << 40); #endif /* GU_FNVBITSHIFT_OPTIMIZATION */ #if !defined(GU_FNV_NORMAL) # define GU_FNV64_ITERATION(_s,_b) _s ^= _b; GU_FNV64_MUL(_s); #else # define GU_FNV64_ITERATION(_s,_b) GU_FNV64_MUL(_s); _s ^= _b; #endif static GU_FORCE_INLINE void gu_fnv64a_internal (const void* buf, ssize_t const len, uint64_t* seed) { const uint8_t* bp = (const uint8_t*)buf; const uint8_t* const be = bp + len; while (bp + 2 <= be) { GU_FNV64_ITERATION(*seed,*bp++); GU_FNV64_ITERATION(*seed,*bp++); } if (bp < be) { GU_FNV64_ITERATION(*seed,*bp++); } assert(be == bp); } static gu_uint128_t const GU_SET128(GU_FNV128_PRIME, 0x0000000001000000ULL, 0x000000000000013BULL); static gu_uint128_t const GU_SET128(GU_FNV128_SEED, 0x6C62272E07BB0142ULL, 0x62B821756295C58DULL); #if defined(__SIZEOF_INT128__) #define GU_FNV128_XOR(_s,_b) _s ^= _b #if !defined(GU_FNVBITSHIFT_OPTIMIZATION) # define GU_FNV128_MUL(_x) _x *= GU_FNV128_PRIME #else /* GU_FNVBITSHIFT_OPTIMIZATION */ # define GU_FNV128_MUL(_x) \ _x +=(_x << 1) + (_x << 3) + (_x << 4) + (_x << 5) + (_x << 8) + (_x << 88); #endif /* GU_FNVBITSHIFT_OPTIMIZATION */ #else /* ! __SIZEOF_INT128__ */ #define GU_FNV128_XOR(_s,_b) (_s).u32[GU_32LO] ^= _b #if defined(GU_FNV128_FULL_MULTIPLICATION) # define GU_FNV128_MUL(_x) GU_MUL128_INPLACE(_x, GU_FNV128_PRIME) #else /* no FULL_MULTIPLICATION */ # define GU_FNV128_MUL(_x) { \ uint32_t carry = \ (((_x).u64[GU_64LO] & 0x00000000ffffffffULL) * 0x013b) >> 32; \ carry = (((_x).u64[GU_64LO] >> 32) * 0x013b + carry) >> 32; \ (_x).u64[GU_64HI] *= 0x013b; \ (_x).u64[GU_64HI] += ((_x).u64[GU_64LO] << 24) + carry; \ (_x).u64[GU_64LO] *= 0x013b; \ } #endif /* FULL_MULTIPLICATION */ #endif /* ! __SIZEOF_INT128__ */ #if !defined(GU_FNV_NORMAL) # define GU_FNV128_ITERATION(_s,_b) GU_FNV128_XOR(_s,_b); GU_FNV128_MUL(_s); #else # define GU_FNV128_ITERATION(_s,_b) GU_FNV128_MUL(_s); GU_FNV128_XOR(_s,_b); #endif inline static void gu_fnv128a_internal (const void* buf, ssize_t const len, gu_uint128_t* seed) { const uint8_t* bp = (const uint8_t*)buf; const uint8_t* const be = bp + len; /* this manual loop unrolling seems to be essential */ while (bp + 8 <= be) { GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); } if (bp + 4 <= be) { GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); } if (bp + 2 <= be) { GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); } if (bp < be) { GU_FNV128_ITERATION(*seed, *bp++); } assert(be == bp); } #endif /* _gu_fnv_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_assert.hpp0000644000175000017500000000127613136555240025374 0ustar jenkinsjenkins// Copyright (C) 2009 Codership Oy /** * @file Assert macro definition * * $Id$ */ #ifndef _gu_assert_hpp_ #define _gu_assert_hpp_ #ifndef DEBUG_ASSERT #include #else #include #undef assert #include "gu_logger.hpp" /** Assert that sleeps instead of aborting the program, saving it for gdb */ #define assert(expr) \ if (!(expr)) { \ log_fatal << "Assertion (" << __STRING(expr) << ") failed"; \ while(1) sleep(1); \ } #endif /* DEBUG_ASSERT */ #endif /* _gu_assert_hpp_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_datetime.cpp0000644000175000017500000000550713136555240025663 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy * * $Id$ */ #include "gu_datetime.hpp" #include "gu_logger.hpp" #include "gu_utils.hpp" extern "C" { #include "gu_time.h" } std::ostream& gu::datetime::operator<<(std::ostream& os, const Date& d) { os << d.get_utc(); return os; } std::ostream& gu::datetime::operator<<(std::ostream& os, const Period& p) { os << "P"; int64_t nsecs(p.get_nsecs()); if (nsecs/Year > 0) { os << (nsecs/Year) << "Y"; nsecs %= Year; } if (nsecs/Month > 0) { os << (nsecs/Month) << "M"; nsecs %= Month; } if (nsecs/Day > 0) { os << (nsecs/Day) << "D"; nsecs %= Day; } if (nsecs > 0) { os << "T"; } if (nsecs/Hour > 0) { os << (nsecs/Hour) << "H"; nsecs %= Hour; } if (nsecs/Min > 0) { os << (nsecs/Min) << "M"; nsecs %= Min; } if (double(nsecs)/Sec >= 1.e-9) { os << (double(nsecs)/Sec) << "S"; } return os; } void gu::datetime::Date::parse(const std::string& str) { if (str == "") { return; } gu_throw_fatal << "not implemented"; } const char* const gu::datetime::Period::period_regex = "^(P)(([0-9]+)Y)?(([0-9]+)M)?(([0-9]+)D)?" /* 1 23 45 67 */ "((T)?(([0-9]+)H)?(([0-9]+)M)?(([0-9]+)(\\.([0-9]+))?S)?)?"; /* 89 11 13 15 16 */ enum { GU_P = 1, GU_YEAR = 3, GU_MONTH = 5, GU_DAY = 7, GU_HOUR = 10, GU_MIN = 12, GU_SEC = 15, GU_SEC_D = 16, GU_NUM_PARTS = 17 }; gu::RegEx const gu::datetime::Period::regex(period_regex); void gu::datetime::Period::parse(const std::string& str) { std::vector parts = regex.match(str, GU_NUM_PARTS); if (parts[GU_P].is_set() == false) { if (str == "") { return; } else { gu_throw_error (EINVAL) << "Period " << str << " not valid"; } } if (parts[GU_YEAR].is_set()) { nsecs += from_string(parts[GU_YEAR].str())*Year; } if (parts[GU_MONTH].is_set()) { nsecs += from_string(parts[GU_MONTH].str())*Month; } if (parts[GU_DAY].is_set()) { nsecs += from_string(parts[GU_DAY].str())*Day; } if (parts[GU_HOUR].is_set()) { nsecs += from_string(parts[GU_HOUR].str())*Hour; } if (parts[GU_MIN].is_set()) { nsecs += from_string(parts[GU_MIN].str())*Min; } if (parts[GU_SEC].is_set()) { long long s(from_string(parts[GU_SEC].str())); nsecs += s*Sec; } if (parts[GU_SEC_D].is_set()) { double d(from_string(parts[GU_SEC_D].str())); nsecs += static_cast(d*Sec); } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_cond.hpp0000644000175000017500000000304313136555240025010 0ustar jenkinsjenkins/* * Copyright (C) 2009-2017 Codership Oy */ #ifndef __GU_COND__ #define __GU_COND__ #include "gu_threads.h" #include "gu_macros.h" #include "gu_exception.hpp" //#include #include // TODO: make exceptions more verbose namespace gu { class Cond { friend class Lock; // non-copyable Cond(const Cond&); void operator=(const Cond&); protected: gu_cond_t mutable cond; int mutable ref_count; public: Cond () : cond(), ref_count(0) { gu_cond_init (&cond, NULL); } ~Cond () { int ret; while (EBUSY == (ret = gu_cond_destroy(&cond))) { usleep (100); } if (gu_unlikely(ret != 0)) { log_fatal << "gu_cond_destroy() failed: " << ret << " (" << strerror(ret) << ". Aborting."; ::abort(); } } inline void signal () const { if (ref_count > 0) { int ret = gu_cond_signal (&cond); if (gu_unlikely(ret != 0)) throw Exception("gu_cond_signal() failed", ret); } } inline void broadcast () const { if (ref_count > 0) { int ret = gu_cond_broadcast (&cond); if (gu_unlikely(ret != 0)) throw Exception("gu_cond_broadcast() failed", ret); } } }; } #endif // __GU_COND__ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_buffer.hpp0000644000175000017500000000062413136555240025340 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy */ /*! * Byte buffer class. This is thin wrapper to std::vector */ #ifndef GU_BUFFER_HPP #define GU_BUFFER_HPP #include "gu_types.hpp" // for gu::byte_t #include #include namespace gu { typedef std::vector Buffer; typedef boost::shared_ptr SharedBuffer; } #endif // GU_BUFFER_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_exception.hpp0000644000175000017500000000231213136555240026061 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy * */ #ifndef __GU_EXCEPTION__ #define __GU_EXCEPTION__ #include #include #include "gu_errno.h" namespace gu { /*! Some utility exceptions to indicate special conditions. */ class NotSet {}; class NotFound {}; class Exception: public std::exception { public: Exception (const std::string& msg_, int err_) : msg (msg_), err (err_) {} virtual ~Exception () throw() {} const char* what () const throw() { return msg.c_str(); } int get_errno () const { return err; } void trace (const char* file, const char* func, int line); private: std::string msg; const int err; }; } /* to mark a place where exception was caught */ #define GU_TRACE(_exception_) _exception_.trace(__FILE__, __FUNCTION__, __LINE__) #ifndef NDEBUG /* enabled together with assert() */ #define gu_trace(_expr_) \ try { _expr_; } catch (gu::Exception& e) { GU_TRACE(e); throw; } #else #define gu_trace(_expr_) _expr_ #endif // NDEBUG #endif // __GU_EXCEPTION__ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_init.c0000644000175000017500000000077113136555240024470 0ustar jenkinsjenkins/* * Copyright (C) 2013-2016 Codership Oy * * $Id$ */ #include "gu_conf.h" #include "gu_limits.h" #include "gu_abort.h" #include "gu_crc32c.h" void gu_init (gu_log_cb_t log_cb) { gu_conf_set_log_callback (log_cb); /* this is needed in gu::MMap::sync() */ size_t const page_size = GU_PAGE_SIZE; if (page_size & (page_size - 1)) { gu_fatal("GU_PAGE_SIZE(%z) is not a power of 2", GU_PAGE_SIZE); gu_abort(); } gu_crc32c_configure(); } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_config.h0000644000175000017500000000335513136555240025000 0ustar jenkinsjenkins// Copyright (C) 2010-2014 Codership Oy /** * @file * C-interface for configuration management * * $Id$ */ #ifndef _gu_config_h_ #define _gu_config_h_ #include #include #include // for ssize_t #ifdef __cplusplus extern "C" { #endif typedef struct gu_config gu_config_t; gu_config_t* gu_config_create (void); void gu_config_destroy (gu_config_t* cnf); bool gu_config_has (gu_config_t* cnf, const char* key); bool gu_config_is_set (gu_config_t* cnf, const char* key); /* before setting a parameter, it must be added to a known parameter list*/ int gu_config_add (gu_config_t* cnf, const char* key, const char* val /*can be NULL*/); /* Getters/setters return 0 on success, 1 when key not set/not found, * negative error code in case of other errors (conversion failed and such) */ int gu_config_get_string (gu_config_t* cnf, const char* key, const char** val); int gu_config_get_int64 (gu_config_t* cnf, const char* key, int64_t* val); int gu_config_get_double (gu_config_t* cnf, const char* key, double* val); int gu_config_get_ptr (gu_config_t* cnf, const char* key, void** val); int gu_config_get_bool (gu_config_t* cnf, const char* key, bool* val); void gu_config_set_string (gu_config_t* cnf, const char* key, const char* val); void gu_config_set_int64 (gu_config_t* cnf, const char* key, int64_t val); void gu_config_set_double (gu_config_t* cnf, const char* key, double val); void gu_config_set_ptr (gu_config_t* cnf, const char* key, const void* val); void gu_config_set_bool (gu_config_t* cnf, const char* key, bool val); ssize_t gu_config_print (gu_config_t* cnf, char* buf, ssize_t buf_len); #ifdef __cplusplus } #endif #endif /* _gu_config_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_threads.h0000644000175000017500000001530413136555240025162 0ustar jenkinsjenkins// Copyright (C) 2017 Codership Oy /** * @file Abstracts naitive multithreading API behind POSIX threads-like API */ #ifndef _gu_mutex_h_ #define _gu_mutex_h_ #include "gu_types.h" // bool #if __unix__ #include typedef pthread_t gu_thread_t_SYS; #define gu_thread_create_SYS pthread_create #define gu_thread_join_SYS pthread_join #define gu_thread_cancel_SYS pthread_cancel #define gu_thread_exit_SYS pthread_exit #define gu_thread_detach_SYS pthread_detach #define gu_thread_self_SYS pthread_self #define gu_thread_equal_SYS pthread_equal #define GU_THREAD_INITIALIZER_SYS 0 typedef pthread_mutexattr_t gu_mutexattr_t_SYS; typedef pthread_mutex_t gu_mutex_t_SYS; #define gu_mutex_init_SYS pthread_mutex_init #define gu_mutex_lock_SYS pthread_mutex_lock #define gu_mutex_unlock_SYS pthread_mutex_unlock #define gu_mutex_destroy_SYS pthread_mutex_destroy #define GU_MUTEX_INITIALIZER_SYS PTHREAD_MUTEX_INITIALIZER typedef pthread_condattr_t gu_condattr_t_SYS; typedef pthread_cond_t gu_cond_t_SYS; #define gu_cond_init_SYS pthread_cond_init #define gu_cond_destroy_SYS pthread_cond_destroy #define gu_cond_wait_SYS pthread_cond_wait #define gu_cond_timedwait_SYS pthread_cond_timedwait #define gu_cond_signal_SYS pthread_cond_signal #define gu_cond_broadcast_SYS pthread_cond_broadcast #define GU_COND_INITIALIZER_SYS PTHREAD_COND_INITIALIZER #if defined(__APPLE__) /* emulate barriers missing on MacOS */ #ifdef __cplusplus extern "C" { #endif typedef int gu_barrierattr_t_SYS; typedef struct { gu_mutex_t_SYS mutex; gu_cond_t_SYS cond; int count; int tripCount; } gu_barrier_t_SYS; int gu_barrier_init_SYS (gu_barrier_t_SYS *barrier, const gu_barrierattr_t_SYS *attr,unsigned int count); int gu_barrier_destroy_SYS(gu_barrier_t_SYS *barrier); int gu_barrier_wait_SYS (gu_barrier_t_SYS *barrier); #define GU_BARRIER_SERIAL_THREAD_SYS -1 #ifdef __cplusplus } #endif #else /* native POSIX barriers */ typedef pthread_barrierattr_t gu_barrierattr_t_SYS; typedef pthread_barrier_t gu_barrier_t_SYS; #define gu_barrier_init_SYS pthread_barrier_init #define gu_barrier_destroy_SYS pthread_barrier_destroy #define gu_barrier_wait_SYS pthread_barrier_wait #define GU_BARRIER_SERIAL_THREAD_SYS PTHREAD_BARRIER_SERIAL_THREAD #endif /* native POSIX barriers */ #endif /* __unix__ */ /** * Depending on compile-time flags application will either use * normal or debug version of the API calls */ #ifndef GU_DEBUG_MUTEX /* GU_DEBUG_MUTEX not defined - use operating system definitions */ typedef gu_mutex_t_SYS gu_mutex_t; #define gu_mutex_init gu_mutex_init_SYS #define gu_mutex_lock gu_mutex_lock_SYS #define gu_mutex_unlock gu_mutex_unlock_SYS #define gu_mutex_destroy gu_mutex_destroy_SYS #define gu_cond_wait gu_cond_wait_SYS #define gu_cond_timedwait gu_cond_timedwait_SYS #define GU_MUTEX_INITIALIZER GU_MUTEX_INITIALIZER_SYS #else /* GU_DEBUG_MUTEX defined - use custom debug versions of some calls */ typedef struct { gu_mutex_t_SYS mutex; gu_cond_t_SYS cond; gu_thread_t_SYS thread; /* point in source code, where called from */ const char *file; int line; int waiter_count; //!< # of threads waiting for lock int cond_waiter_count; //!< # of threads waiting for some cond bool locked; //!< must be 0 or 1 } gu_mutex_t_DBG; #define GU_MUTEX_INITIALIZER { \ GU_MUTEX_INITIALIZER_SYS, \ GU_COND_INITIALIZER_SYS, \ GU_THREAD_INITIALIZER_SYS, \ __FILE__, \ __LINE__, \ 0, 0, false } #ifdef __cplusplus extern "C" { #endif /** @name Debug versions of basic mutex calls */ /*@{*/ extern int gu_mutex_init_DBG (gu_mutex_t_DBG *mutex, const gu_mutexattr_t_SYS *attr, const char *file, unsigned int line); extern int gu_mutex_lock_DBG (gu_mutex_t_DBG *mutex, const char *file, unsigned int line); extern int gu_mutex_unlock_DBG (gu_mutex_t_DBG *mutex, const char *file, unsigned int line); extern int gu_mutex_destroy_DBG (gu_mutex_t_DBG *mutex, const char *file, unsigned int line); extern int gu_cond_twait_DBG (gu_cond_t_SYS *cond, gu_mutex_t_DBG *mutex, const struct timespec *abstime, const char *file, unsigned int line); #ifdef __cplusplus } // extern "C" #endif static inline int gu_cond_wait_DBG (gu_cond_t_SYS *cond, gu_mutex_t_DBG *mutex, const char *file, unsigned int line) { return gu_cond_twait_DBG(cond, mutex, NULL, file, line); } static inline bool gu_mutex_locked (const gu_mutex_t_DBG* m) { return m->locked; } static inline bool gu_mutex_owned (const gu_mutex_t_DBG* m) { return m->locked && gu_thread_equal_SYS(gu_thread_self_SYS(), m->thread); } /*@}*/ typedef gu_mutex_t_DBG gu_mutex_t; #define gu_mutex_init(M,A) gu_mutex_init_DBG (M,A, __FILE__, __LINE__) #define gu_mutex_lock(M) gu_mutex_lock_DBG (M, __FILE__, __LINE__) #define gu_mutex_unlock(M) gu_mutex_unlock_DBG (M, __FILE__, __LINE__) #define gu_mutex_destroy(M) gu_mutex_destroy_DBG (M, __FILE__, __LINE__) #define gu_cond_wait(S,M) gu_cond_wait_DBG (S,M, __FILE__, __LINE__) #define gu_cond_timedwait(S,M,T) gu_cond_twait_DBG (S,M,T, __FILE__, __LINE__) #endif /* DEBUG_MUTEX */ /* declarations without debug variants */ typedef gu_mutexattr_t_SYS gu_mutexattr_t; typedef gu_thread_t_SYS gu_thread_t; #define gu_thread_create gu_thread_create_SYS #define gu_thread_join gu_thread_join_SYS #define gu_thread_cancel gu_thread_cancel_SYS #define gu_thread_exit gu_thread_exit_SYS #define gu_thread_detach gu_thread_detach_SYS #define gu_thread_self gu_thread_self_SYS #define gu_thread_equal gu_thread_equal_SYS typedef gu_condattr_t_SYS gu_condattr_t; typedef gu_cond_t_SYS gu_cond_t; #define gu_cond_init gu_cond_init_SYS #define gu_cond_destroy gu_cond_destroy_SYS #define gu_cond_signal gu_cond_signal_SYS #define gu_cond_broadcast gu_cond_broadcast_SYS #define GU_COND_INITIALIZER GU_COND_INITIALIZER_SYS typedef gu_barrierattr_t_SYS gu_barrierattr_t; typedef gu_barrier_t_SYS gu_barrier_t; #define gu_barrier_init gu_barrier_init_SYS #define gu_barrier_destroy gu_barrier_destroy_SYS #define gu_barrier_wait gu_barrier_wait_SYS #define GU_BARRIER_SERIAL_THREAD GU_BARRIER_SERIAL_THREAD_SYS #endif /* _gu_mutex_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_debug_sync.cpp0000644000175000017500000000237313136555240026207 0ustar jenkinsjenkins// // Copyright (C) 2014 Codership Oy // #ifdef GU_DBUG_ON #include "gu_debug_sync.hpp" #include "gu_lock.hpp" #include namespace { gu::Mutex sync_mutex; typedef std::multimap SyncMap; SyncMap sync_waiters; } void gu_debug_sync_wait(const std::string& sync) { gu::Lock lock(sync_mutex); gu::Cond cond; log_debug << "enter sync wait '" << sync << "'"; SyncMap::iterator i( sync_waiters.insert(std::make_pair(sync, &cond))); lock.wait(cond); sync_waiters.erase(i); log_debug << "leave sync wait '" << sync << "'"; } void gu_debug_sync_signal(const std::string& sync) { gu::Lock lock(sync_mutex); std::pair range(sync_waiters.equal_range(sync)); for (SyncMap::iterator i(range.first); i != range.second; ++i) { log_debug << "signalling waiter"; i->second->signal(); } } std::string gu_debug_sync_waiters() { std::string ret; gu::Lock lock(sync_mutex); for (SyncMap::iterator i(sync_waiters.begin()); i != sync_waiters.end();) { ret += i->first; ++i; if (i != sync_waiters.end()) ret += " "; } return ret; } #endif // GU_DBUG_ON percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_vlq.cpp0000644000175000017500000000326313136555240024666 0ustar jenkinsjenkins// // Copyright (C) 2013 Codership Oy // //! // @file Variable-length quantity encoding for integers // // Unsigned integers: Implementation uses using unsigned LEB128, // see for example http://en.wikipedia.org/wiki/LEB128. // // Signed integers: TODO // #include "gu_vlq.hpp" namespace gu { /* checks helper for the uleb128_decode() */ void uleb128_decode_checks (const byte_t* buf, size_t buflen, size_t offset, size_t avail_bits) { // Check if trying to read past last byte in buffer without // encountering byte without 0x80 bit set. if (offset >= buflen) { gu_throw_error(EINVAL) << "read value is not uleb128 representation, missing " << "terminating byte before end of input"; } assert(avail_bits > 0); if (avail_bits < 7) { // mask to check if the remaining value can be represented // with available bits gu::byte_t mask(~((1 << avail_bits) - 1)); if ((buf[offset] & mask) != 0) { gu_throw_error(EOVERFLOW) << "read value not representable with avail bits: " << avail_bits << " mask: 0x" << std::hex << static_cast(mask) << " buf: 0x" << std::hex << static_cast(buf[offset]) << " excess: 0x" << std::hex << static_cast(mask & buf[offset]); } } } } /* namespace gu */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_log.c0000644000175000017500000000775213136555240024314 0ustar jenkinsjenkins// Copyright (C) 2007-2014 Codership Oy /** * @file Logging functions definitions * * $Id$ */ #include #include #include #include #include #include #include #include "gu_log.h" #include "gu_macros.h" /* Global configurable variables */ static FILE* gu_log_file = NULL; bool gu_log_self_tstamp = false; gu_log_severity_t gu_log_max_level = GU_LOG_INFO; int gu_conf_set_log_file (FILE *file) { gu_debug ("Log file changed by application"); if (file) { gu_log_file = file; } else { gu_log_file = stderr; } return 0; } int gu_conf_self_tstamp_on () { gu_debug ("Turning self timestamping on"); gu_log_self_tstamp = true; return 0; } int gu_conf_self_tstamp_off () { gu_debug ("Turning self timestamping off"); gu_log_self_tstamp = false; return 0; } int gu_conf_debug_on () { gu_log_max_level = GU_LOG_DEBUG; gu_debug ("Turning debug logging on"); return 0; } int gu_conf_debug_off () { gu_debug ("Turning debug logging off"); gu_log_max_level = GU_LOG_INFO; return 0; } /** Returns current timestamp in the provided buffer */ static inline int log_tstamp (char* tstamp, size_t const len) { int ret = 0; struct tm date; struct timeval time; gettimeofday (&time, NULL); localtime_r (&time.tv_sec, &date); /* 23 symbols */ ret = snprintf (tstamp, len, "%04d-%02d-%02d %02d:%02d:%02d.%03d ", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec, (int)time.tv_usec / 1000); return ret; } const char* gu_log_level_str[GU_LOG_DEBUG + 2] = { "FATAL: ", "ERROR: ", " WARN: ", " INFO: ", "DEBUG: ", "XXXXX: " }; /** * @function * Default logging function: simply writes to stderr or gu_log_file if set. */ void gu_log_cb_default (int severity, const char* msg) { FILE* log_file = gu_log_file ? gu_log_file : stderr; fputs (msg, log_file); fputc ('\n', log_file); fflush (log_file); } /** * Log function handle. * Can be changed by application through gu_conf_set_log_callback() */ gu_log_cb_t gu_log_cb = gu_log_cb_default; int gu_conf_set_log_callback (gu_log_cb_t callback) { if (callback) { gu_debug ("Logging function changed by application"); gu_log_cb = callback; } else { gu_debug ("Logging function restored to default"); gu_log_cb = gu_log_cb_default; } return 0; } int gu_log (gu_log_severity_t severity, const char* file, const char* function, const int line, ...) { va_list ap; int max_string = 2048; char string[max_string]; /** @note: this can cause stack overflow * in kernel mode (both Linux and Windows). */ char* str = string; int len; if (gu_log_self_tstamp) { len = log_tstamp (str, max_string); str += len; max_string -= len; } if (gu_likely(max_string > 0)) { const char* log_level_str = gu_log_cb_default == gu_log_cb ? gu_log_level_str[severity] : ""; /* provide file:func():line info only if debug logging is on */ if (gu_likely(!gu_log_debug && severity > GU_LOG_ERROR)) { len = snprintf (str, max_string, "%s", log_level_str); } else { len = snprintf (str, max_string, "%s%s:%s():%d: ", log_level_str, file, function, line); } str += len; max_string -= len; va_start (ap, line); { const char* format = va_arg (ap, const char*); if (gu_likely(max_string > 0 && NULL != format)) { vsnprintf (str, max_string, format, ap); } } va_end (ap); } /* actual logging */ gu_log_cb (severity, string); return 0; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_threads.c0000644000175000017500000001765613136555240025171 0ustar jenkinsjenkins// Copyright (C) 2017 Codership Oy /** * Debug versions of thread functions */ #include "gu_threads.h" #include "gu_macros.h" #include "gu_log.h" #include #include #include // strerror() #ifdef GU_DEBUG_MUTEX int gu_mutex_init_DBG (gu_mutex_t_DBG *m, const gu_mutexattr_t_SYS* attr, const char *file, unsigned int line) { gu_mutex_init_SYS(&m->mutex, attr); gu_cond_init_SYS(&m->cond, NULL); m->thread = gu_thread_self_SYS(); m->file = file; m->line = line; m->waiter_count = 0; m->cond_waiter_count = 0; m->locked = false; return 0; // as per pthread spec } static inline void _wait_unlocked(gu_mutex_t_DBG* m) { m->waiter_count++; gu_cond_wait_SYS(&m->cond, &m->mutex); assert(m->waiter_count > 0); m->waiter_count--; } int gu_mutex_lock_DBG(gu_mutex_t_DBG *m, const char *file, unsigned int line) { gu_thread_t_SYS const self = gu_thread_self_SYS(); int const err = gu_mutex_lock_SYS(&m->mutex); if (gu_likely(0 == err)) { while (m->locked) { if (gu_thread_equal_SYS(self, m->thread)) { gu_fatal("Second mutex lock attempt by the same thread, %lx, " "at %s:%d, first locked at %s:%d", self, file, line, m->file, m->line); abort(); } _wait_unlocked(m); } m->locked = true; m->thread = self; m->file = file; m->line = line; gu_mutex_unlock_SYS(&m->mutex); } return err; } int gu_mutex_unlock_DBG (gu_mutex_t_DBG *m, const char *file, unsigned int line) { gu_thread_t_SYS const self = gu_thread_self_SYS(); int err = gu_mutex_lock_SYS(&m->mutex); if (gu_likely(0 == err)) { if (m->locked && !gu_thread_equal_SYS(self, m->thread)) { /** last time pthread_t was unsigned long int */ gu_fatal ("%lx attempts to unlock mutex at %s:%d " "locked by %lx at %s:%d", self, file, line, m->thread, m->file, m->line); assert(0); err = EPERM; /** return in case assert is undefined */ } /** must take into account that mutex unlocking can happen in * cleanup handlers when thread is terminated in cond_wait(). * Then holder_count would still be 0 (see gu_cond_wait()), * but cond_waiter - not */ else if (!m->locked && m->cond_waiter_count == 0) { gu_error ("%lx attempts to unlock unlocked mutex at %s:%d. " "Last use at %s:%d", self, file, line, m->file ? m->file : "" , m->line); assert(0 == m->waiter_count); assert(0); } else { m->file = file; m->line = line; m->locked = false; if (m->waiter_count > 0) gu_cond_signal_SYS(&m->cond); } gu_mutex_unlock_SYS(&m->mutex); } return err; } int gu_mutex_destroy_DBG (gu_mutex_t_DBG *m, const char *file, unsigned int line) { gu_thread_t_SYS const self = gu_thread_self_SYS(); int err = gu_mutex_lock_SYS(&m->mutex); if (gu_likely(0 == err)) { if (!m->file) { gu_fatal("%lx attempts to destroy uninitialized mutex at %s:%d", self, file, line); assert(0); } else if (m->locked) { if (gu_thread_equal_SYS(self, m->thread)) { gu_error ("%lx attempts to destroy mutex locked by " "itself at %s:%d", self, m->file, m->line); } else { gu_error ("%lx attempts to destroy a mutex at %s:%d " "locked by %lu at %s:%d (not error)", self, file, line, m->thread, m->file, m->line); } assert (0); /* logical error in program */ err = EBUSY; } else if (m->cond_waiter_count != 0) { gu_error ("%lx attempts to destroy a mutex at %s:%d " "that is waited by %d thread(s)", self, file, line, m->cond_waiter_count); assert (m->cond_waiter_count > 0); abort(); } else { assert(!m->locked); assert(0 == m->cond_waiter_count); gu_mutex_unlock_SYS(&m->mutex); if ((err = gu_mutex_destroy_SYS(&m->mutex))) { gu_debug("Error (%d: %s, %d) during mutex destroy at %s:%d", err, strerror(err), errno, file, line); } else { gu_cond_destroy_SYS(&m->cond); m->file = NULL; m->line = 0; m->thread = GU_THREAD_INITIALIZER_SYS; } return err; } gu_mutex_unlock_SYS(&m->mutex); } return err; } int gu_cond_twait_DBG (gu_cond_t_SYS *cond, gu_mutex_t_DBG *m, const struct timespec *abstime, const char *file, unsigned int line) { gu_thread_t_SYS const self = gu_thread_self_SYS(); int err = gu_mutex_lock_SYS(&m->mutex); if (gu_likely(!err)) { if (gu_unlikely(!m->locked && 0 == m->cond_waiter_count)) { gu_fatal ("%lx tries to wait for condition on unlocked mutex " "at %s %d", self, file, line); assert (0); } else if (!gu_thread_equal_SYS(self, m->thread)) { gu_fatal ("%lx tries to wait for condition on the mutex locked " "by %lx at %s %d", self, m->thread, file, line); assert (0); } /** gu_cond_wait_SYS frees the mutex */ m->locked = false; m->thread = self; m->file = file; m->line = line; if (m->waiter_count > 0) gu_cond_signal_SYS(&m->cond); m->cond_waiter_count++; if (NULL == abstime) err = gu_cond_wait_SYS (cond, &m->mutex); else err = gu_cond_timedwait_SYS (cond, &m->mutex, abstime); assert(m->cond_waiter_count > 0); m->cond_waiter_count--; /* now wait till the the mutex is "unlocked" */ while (m->locked && 0 == err) { _wait_unlocked(m); } m->locked = true; assert(!gu_thread_equal_SYS(self, m->thread) || 0 != err); m->thread = self; m->file = file; m->line = line; gu_mutex_unlock_SYS(&m->mutex); } return err; } #endif /* GU_DEBUG_MUTEX */ #if defined(__APPLE__) int gu_barrier_init_SYS (gu_barrier_t_SYS *barrier, const gu_barrierattr_t_SYS *attr, unsigned int count) { if(count == 0) { errno = EINVAL; return -1; } if(gu_mutex_init_SYS (&barrier->mutex, 0) < 0) { return -1; } if(gu_cond_init_SYS (&barrier->cond, 0) < 0) { gu_mutex_destroy_SYS (&barrier->mutex); return -1; } barrier->tripCount = count; barrier->count = 0; return 0; } int gu_barrier_destroy_SYS (gu_barrier_t_SYS *barrier) { gu_cond_destroy_SYS (&barrier->cond); gu_mutex_destroy_SYS (&barrier->mutex); return 0; } int gu_barrier_wait_SYS (gu_barrier_t_SYS *barrier) { gu_mutex_lock_SYS (&barrier->mutex); ++(barrier->count); if(barrier->count >= barrier->tripCount) { barrier->count = 0; gu_cond_broadcast_SYS (&barrier->cond); gu_mutex_unlock_SYS (&barrier->mutex); return GU_BARRIER_THREAD_SYS; } else { gu_cond_wait_SYS (&barrier->cond, &(barrier->mutex)); gu_mutex_unlock_SYS (&barrier->mutex); return !GU_BARRIER_THREAD_SYS; } } #endif /* __APPLE__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_reserved_container.hpp0000644000175000017500000001616013136555240027752 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /*! * ReservedContainer template. It is a wrapper for a container and a reserved * buffer to allocate elements from. * * For more rationale see * http://src.chromium.org/chrome/trunk/src/base/containers/stack_container.h * * It is not called "StackContainer" because it is not only for objects * allocated on the stack. * * $Id$ */ #ifndef _GU_RESERVED_CONTAINER_ #define _GU_RESERVED_CONTAINER_ #include "chromium/aligned_memory.h" #include "gu_logger.hpp" #include // size_t, ptrdiff_t and NULL #include // malloc() and free() #include #include // placement new and std::bad_alloc namespace gu { /*! * ReservedAllocator is an allocator for STL containers that can use a * prealocated buffer (supplied at construction time) for initial container * storage allocation. If the number of elements exceeds buffer capacity, it * overflows to heap. * * Unlike the Chromium code, this does not derive from std::allocator, but * implements the whole thing. * * NOTE1: container must support reserve() method. * * NOTE2: it won't work with containers that require allocator to have default * constructor, like std::basic_string */ template class ReservedAllocator { public: typedef chromium::AlignedBuffer Buffer; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; typedef size_t size_type; // making size_type unsigned int does not seem to reduce footprint typedef ptrdiff_t difference_type; template struct rebind { typedef ReservedAllocator other; }; T* address(T& t) const { return &t; } const T* address(const T& t) const { return &t; } size_type max_size() const { return size_type(-1)/2/sizeof(T); } void construct (T* const p, const T& t) const { new (p) T(t); } void destroy (T* const p) const { p->~T(); } // Storage allocated from this can't be deallocated from other bool operator==(const ReservedAllocator& other) const { return (buffer_ == other.buffer_); } bool operator!=(const ReservedAllocator& other) const { return !(*this == other); } ReservedAllocator(Buffer& buf, size_type n = 0) : buffer_(&buf), used_(n) {} ReservedAllocator(const ReservedAllocator& other) : buffer_(other.buffer_), used_(other.used_) { // log_debug << "Copy ctor\n"; } template ReservedAllocator(const ReservedAllocator&) : buffer_(NULL), used_(reserved) { // log_debug << "Rebinding ctor\n"; } ~ReservedAllocator() {} T* allocate(size_type const n, void* hint = NULL) { if (n == 0) return NULL; if (reserved - used_ >= n /* && buffer_ != NULL */) { assert (buffer_ != NULL); if (diagnostic) { log_info << "Allocating " << n << '/' << (reserved - used_) << " from reserve"; } T* const ret(buffer_->base_ptr() + used_); used_ += n; return ret; } if (n <= max_size()) { if (diagnostic) { log_warn << "Allocating " << n << " from heap"; } void* ret = malloc(n * sizeof(T)); if (NULL != ret) return static_cast(ret); } throw std::bad_alloc(); } void deallocate(T* const p, size_type const n) { if (size_type(p - buffer_->base_ptr()) < reserved) { assert (used_ > 0); if (buffer_->base_ptr() + used_ == p + n) { /* last allocated buffer, can shrink */ used_ -= n; } else { /* cannot recycle reserved space in this case */ assert(p + n <= buffer_->base_ptr() + used_); } } else { free(p); } } size_type used() const { return used_; } private: /* even though we initially allocate buffer in ReservedContainer directly * before this, STL containers insist on copying allocators, so we need * a pointer to buffer to be an explicit member (and waste another 8 bytes*/ Buffer* buffer_; size_type used_; ReservedAllocator& operator=(const ReservedAllocator&); }; /* class ReservedAllocator */ /*! * ReservedContainer is a wrapper for * - fixed size nicely aligned buffer * - ReservedAllocator that uses the buffer * - container type that uses allocator * * the point is to have a container allocated on the stack to use stack buffer * for element storage. */ template class ReservedContainer { public: ReservedContainer() : buffer_ (), /* Actual Allocator instance used by container_ should be * copy-constructed from the temporary passed to container ctor. * Copy-construction preserves pointer to buffer, which is not * temporary. This works at least with std::vector */ container_(Allocator(buffer_)) { /* Make the container use most of the buffer by reserving our buffer * size before doing anything else. */ container_.reserve(reserved); } /* * Getters for the actual container. * * Danger: any copies of this made using the copy constructor must have * shorter lifetimes than the source. The copy will share the same allocator * and therefore the same stack buffer as the original. Use std::copy to * copy into a "real" container for longer-lived objects. */ ContainerType& container() { return container_; } const ContainerType& container() const { return container_; } ContainerType& operator()() { return container_; } const ContainerType& operator()() const { return container_; } /* * Support operator-> to get to the container. * This allows nicer syntax like: * ReservedContainer<...> foo; * std::sort(foo->begin(), foo->end()); */ ContainerType* operator->() { return &container_; } const ContainerType* operator->() const { return &container_; } /* For testing only */ typedef typename ContainerType::value_type ContainedType; const ContainedType* reserved_buffer() const { return buffer_.base_ptr(); } private: typedef ReservedAllocator Allocator; typedef typename Allocator::Buffer Buffer; Buffer buffer_; ContainerType container_; /* Note that container will use another instance of Allocator, copy * constructed from allocator_, so any changes won't be re*/ ReservedContainer(const ReservedContainer&); ReservedContainer& operator=(const ReservedContainer&); }; /* class ReservedContainer */ } /* namespace gu */ #endif /* _GU_RESERVED_CONTAINER_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_status.hpp0000644000175000017500000000165013136555240025412 0ustar jenkinsjenkins// Copyright (C) 2014 Codership Oy //! // @file // Common class for gathering Galera wide status. The class is simple // string based key-value store. // #ifndef GU_STATUS_HPP #define GU_STATUS_HPP #include "gu_exception.hpp" #include #include namespace gu { class Status { public: typedef std::map VarMap; typedef VarMap::iterator iterator; typedef VarMap::const_iterator const_iterator; Status() : vars_() { } void insert(const std::string& key, const std::string& val) { vars_.insert(std::make_pair(key, val)); } const_iterator begin() { return vars_.begin(); } const_iterator end() { return vars_.end(); } size_t size() const { return vars_.size(); } private: VarMap vars_; }; } #endif // !GU_STATUS_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_assert.h0000644000175000017500000000104213136555240025023 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy /** * @file Assert macro definition * * $Id$ */ #ifndef _gu_assert_h_ #define _gu_assert_h_ #include "gu_log.h" #ifndef DEBUG_ASSERT #include #else #include #undef assert /** Assert that sleeps instead of aborting the program, saving it for gdb */ #define assert(expr) if (!(expr)) { \ gu_fatal ("Assertion (%s) failed", __STRING(expr)); \ while(1) sleep(1); } #endif /* DEBUG_ASSERT */ #endif /* _gu_assert_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_utils.h0000644000175000017500000000157313136555240024673 0ustar jenkinsjenkins// Copyright (C) 2010 Codership Oy /** * @file Miscellaneous utility functions * * $Id$ */ #ifndef _gu_utils_h_ #define _gu_utils_h_ #include #ifdef __cplusplus extern "C" { #endif /* * The string conversion functions below are slighly customized * versions of standard libc functions designed to understand 'on'/'off' and * K/M/G size modifiers and the like. * * They return pointer to the next character after conversion: * - if (ret == str) no conversion was made * - if (ret[0] == '\0') whole string was converted */ extern const char* gu_str2ll (const char* str, long long* ll); extern const char* gu_str2dbl (const char* str, double* dbl); extern const char* gu_str2bool (const char* str, bool* b); extern const char* gu_str2ptr (const char* str, void** ptr); #ifdef __cplusplus } #endif #endif /* _gu_utils_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_mmap.hpp0000644000175000017500000000115613136555240025022 0ustar jenkinsjenkins/* * Copyright (C) 2009-2016 Codership Oy * * $Id$ */ #ifndef __GCACHE_MMAP__ #define __GCACHE_MMAP__ #include "gu_fdesc.hpp" namespace gu { class MMap { public: size_t const size; void* const ptr; MMap (const FileDescriptor& fd, bool sequential = false); ~MMap (); void dont_need() const; void sync(void *addr, size_t length) const; void sync() const; void unmap(); private: bool mapped; // This class is definitely non-copyable MMap (const MMap&); MMap& operator = (const MMap); }; } /* namespace gu */ #endif /* __GCACHE_MMAP__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_profile.hpp0000644000175000017500000002060613136555240025531 0ustar jenkinsjenkins// // Copyright (C) 2010 Codership Oy // /*! * @file gu_profile.hpp * * @brief Lightweight profiling utility. * * Profiling utility suitable for getting runtime code profile information * with minimal overhead. Macros profile_enter() and profile_leave() * can be inserted around the code and will be expanded to profiling * code if GU_PROFILE is defined. * * Example usage: * @code * * Profile prof("prof"); * * void func() * { * if (is_true()) * { * profile_enter(prof); // This is line 227 * // Do something * // ... * profile_leave(prof); * } * else * { * profile_enter(prof); // This is line 250 * // Do something else * // ... * profile_leave(prof); * } * } * * // Somewhere else in your code * log_info << prof; * @endcode * */ #ifndef GU_PROFILE_HPP #define GU_PROFILE_HPP #include "gu_time.h" #include "gu_datetime.hpp" #include "gu_lock.hpp" #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) #include #elif defined(HAVE_UNORDERED_MAP) #include #elif defined(HAVE_TR1_UNORDERED_MAP) #include #else #include #endif // HAVE_BOOST_UNORDERED_MAP_HPP #include namespace gu { namespace prof { class Key; class KeyHash; class Point; class Profile; std::ostream& operator<<(std::ostream&, const Key&); std::ostream& operator<<(std::ostream&, const Profile&); } } /*! * Profile key storing human readable point description :: * and entry time. */ class gu::prof::Key { public: Key(const char* const file, const char* const func, const int line) : file_(file), func_(func), line_(line) { } bool operator==(const Key& cmp) const { return (line_ == cmp.line_ && func_ == cmp.func_ && file_ == cmp.file_); } bool operator<(const Key& cmp) const { return (line_ < cmp.line_ || (line_ == cmp.line_ && (func_ < cmp.func_ || (func_ == cmp.func_ && file_ < cmp.file_)))); } std::string to_string() const { std::ostringstream os; os << *this; return os.str(); } private: friend class KeyHash; friend class Point; friend class Profile; friend std::ostream& operator<<(std::ostream& os, const Key&); const char* const file_; const char* const func_; const int line_; }; #ifdef HAVE_BOOST_UNORDERED_MAP_HPP class gu::prof::KeyHash { public: size_t operator()(const Key& key) const { return boost::hash_value(key.file_) ^ boost::hash_value(key.func_) ^ boost::hash_value(key.line_); } }; #endif // HAVE_BOOST_UNORDERED_MAP_HPP inline std::ostream& gu::prof::operator<<(std::ostream& os, const gu::prof::Key& key) { return os << key.file_ << ":" << key.func_ << ":" << key.line_; } class gu::prof::Point { public: Point(const Profile& prof, const char* file, const char* func, const int line); ~Point(); private: friend class Profile; const Profile& prof_; const Key key_; mutable long long int enter_time_calendar_; mutable long long int enter_time_thread_cputime_; }; /*! * Profile class for collecting statistics about profile points. */ class gu::prof::Profile { struct PointStats { PointStats(long long int count = 0, long long int time_calendar = 0, long long int time_thread_cputime = 0) : count_ (count ), time_calendar_ (time_calendar ), time_thread_cputime_(time_thread_cputime) { } PointStats operator+(const PointStats& add) const { return PointStats(count_ + add.count_, time_calendar_ + add.time_calendar_, time_thread_cputime_+ add.time_thread_cputime_); } long long int count_; long long int time_calendar_; long long int time_thread_cputime_; }; #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::unordered_map Map; #elif defined(HAVE_UNORDERED_MAP) typedef std::unordered_map Map; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::unordered_map Map; #else typedef std::map Map; #endif public: /*! * Default constructor. * * @param name_ Name identifying the profile in ostream output. */ Profile(const std::string& name = "profile") : name_(name), start_time_calendar_(gu_time_calendar()), start_time_thread_cputime_(gu_time_thread_cputime()), mutex_(), points_() { } void enter(const Point& point) const { point.enter_time_calendar_ = gu_time_calendar(); point.enter_time_thread_cputime_ = gu_time_thread_cputime(); gu::Lock lock(mutex_); points_[point.key_].count_++; } void leave(const Point& point) const { long long int t_cal(gu_time_calendar()); long long int t_thdcpu(gu_time_thread_cputime()); gu::Lock lock(mutex_); PointStats& pointst(points_[point.key_]); pointst.time_calendar_ += (t_cal - point.enter_time_calendar_); pointst.time_thread_cputime_ += (t_thdcpu - point.enter_time_thread_cputime_); } void clear() const { gu::Lock lock(mutex_); points_.clear(); } friend std::ostream& operator<<(std::ostream&, const Profile&); std::string const name_; long long int const start_time_calendar_; long long int const start_time_thread_cputime_; gu::Mutex mutex_; mutable Map points_; }; inline gu::prof::Point::Point(const Profile& prof, const char* file, const char* func, const int line) : prof_(prof), key_(file, func, line), enter_time_calendar_(), enter_time_thread_cputime_() { prof_.enter(*this); } inline gu::prof::Point::~Point() { prof_.leave(*this); } // // Ostream operator for Profile class. // inline std::ostream& gu::prof::operator<<(std::ostream& os, const Profile& prof) { Profile::PointStats cumul; char prev_fill(os.fill()); os.fill(' '); os << "\nprofile name: " << prof.name_; os << std::left << std::fixed << std::setprecision(3); os << "\n\n"; os << std::setw(40) << "point"; os << std::setw(10) << "count"; os << std::setw(10) << "calendar"; os << std::setw(10) << "cpu"; os << "\n" << std::setfill('-') << std::setw(70) << "" << std::setfill(' ') << "\n"; for (Profile::Map::const_iterator i = prof.points_.begin(); i != prof.points_.end(); ++i) { os << std::setw(40) << std::left << i->first.to_string(); os << std::right; os << std::setw(10) << i->second.count_; os << std::setw(10) << double(i->second.time_calendar_)*1.e-9; os << std::setw(10) << double(i->second.time_thread_cputime_)*1.e-9; os << std::left; os << "\n"; cumul = cumul + i->second; } os << "\ntot count : " << cumul.count_; os << "\ntot calendar time : " << double(cumul.time_calendar_)*1.e-9; os << "\ntot thread cputime: " << double(cumul.time_thread_cputime_)*1.e-9; os << "\ntot ct since ctor : " << double(gu::datetime::Date::now().get_utc() - prof.start_time_calendar_)*1.e-9; os.fill(prev_fill); return os; } // // Convenience macros for defining profile entry and leave points. // If GU_PROFILE is undefined, these macros expand to no-op. // #ifdef GU_PROFILE #define profile_enter(__p) \ do { \ const gu::prof::Point __point((__p), __FILE__, \ __FUNCTION__, __LINE__); \ #define profile_leave(__p) \ } while (0) #else #define profile_enter(__p) #define profile_leave(__p) #endif // GU_PROFILE #endif // GU_PROFILE_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_limits.h0000644000175000017500000000252613136555240025033 0ustar jenkinsjenkins// Copyright (C) 2008-2016 Codership Oy /** * @file system limit macros * * $Id$ */ #ifndef _gu_limits_h_ #define _gu_limits_h_ #include #ifdef __cplusplus extern "C" { #endif extern size_t gu_page_size(void); extern size_t gu_phys_pages(void); extern size_t gu_avphys_pages(void); #ifdef __cplusplus } // extern "C" #endif #define GU_PAGE_SIZE gu_page_size() /* returns multiple of page size that is no less than page size */ static inline size_t gu_page_size_multiple(size_t const requested_size) { size_t const sys_page_size = GU_PAGE_SIZE; size_t const multiple = requested_size / sys_page_size; return sys_page_size * (0 == multiple ? 1 : multiple); } static inline size_t gu_avphys_bytes() { // to detect overflow on systems with >4G of RAM, see #776 unsigned long long avphys = gu_avphys_pages(); avphys *= gu_page_size(); size_t max = -1; return (avphys < max ? avphys : max); } #include #define GU_ULONG_MAX ULONG_MAX #define GU_LONG_MAX LONG_MAX #define GU_LONG_MIN LONG_MIN #ifdef ULLONG_MAX #define GU_ULLONG_MAX ULLONG_MAX #define GU_LLONG_MAX LLONG_MAX #define GU_LLONG_MIN LLONG_MIN #else #define GU_ULLONG_MAX 0xffffffffffffffffULL #define GU_LLONG_MAX 0x7fffffffffffffffLL #define GU_LLONG_MIN (-GU_LONG_LONG_MAX - 1) #endif #endif /* _gu_limits_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_monitor.hpp0000644000175000017500000000332213136555240025554 0ustar jenkinsjenkins/* * Copyright (C) 2008-2017 Codership Oy * * $Id$ */ /*! * @file gu_monitor.hpp * * */ #ifndef __GU_MONITOR_HPP__ #define __GU_MONITOR_HPP__ #include #include namespace gu { class Monitor; class Critical; } class gu::Monitor { int mutable refcnt; Mutex mutex; Cond cond; #ifndef NDEBUG gu_thread_t mutable holder; #endif // copy contstructor and operator= disabled by mutex and cond members. // but on Darwin, we got an error 'class gu::Monitor' has pointer data members // so make non-copyable explicitly Monitor(const Monitor&); void operator=(const Monitor&); public: #ifndef NDEBUG Monitor() : refcnt(0), mutex(), cond(), holder(0) {} #else Monitor() : refcnt(0), mutex(), cond() {} #endif ~Monitor() {} void enter() const { Lock lock(mutex); // Teemu, pthread_equal() check seems redundant, refcnt too (counted in cond) // while (refcnt > 0 && pthread_equal(holder, pthread_self()) == 0) while (refcnt) { lock.wait(cond); } refcnt++; #ifndef NDEBUG holder = gu_thread_self(); #endif } void leave() const { Lock lock(mutex); assert(refcnt > 0); assert(gu_thread_equal(holder, gu_thread_self()) != 0); refcnt--; if (refcnt == 0) { cond.signal(); } } }; class gu::Critical { const Monitor& mon; Critical (const Critical&); Critical& operator= (const Critical&); public: Critical(const Monitor& m) : mon(m) { mon.enter(); } ~Critical() { mon.leave(); } }; #endif /* __GU_MONITOR_HPP__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_limits.c0000644000175000017500000000740713136555240025031 0ustar jenkinsjenkins// Copyright (C) 2013-2016 Codership Oy /** * @file system limit macros * * $Id:$ */ #include "gu_limits.h" #include "gu_log.h" #include #include #include #if defined(__APPLE__) #include // doesn't seem to be used directly, but jst in case #include static long darwin_phys_pages (void) { /* Note: singleton pattern would be useful here */ vm_statistics64_data_t vm_stat; unsigned int count = HOST_VM_INFO64_COUNT; kern_return_t ret = host_statistics64 (mach_host_self (), HOST_VM_INFO64, (host_info64_t) &vm_stat, &count); if (ret != KERN_SUCCESS) { gu_error ("host_statistics64 failed with code %d", ret); return 0; } /* This gives a value a little less than physical memory of computer */ return vm_stat.free_count + vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count; /* Exact value may be obtain via sysctl ({CTL_HW, HW_MEMSIZE}) */ /* Note: sysctl is 60% slower compared to host_statistics64 */ } static long darwin_avphys_pages (void) { vm_statistics64_data_t vm_stat; unsigned int count = HOST_VM_INFO64_COUNT; kern_return_t ret = host_statistics64 (mach_host_self (), HOST_VM_INFO64, (host_info64_t) &vm_stat, &count); if (ret != KERN_SUCCESS) { gu_error ("host_statistics64 failed with code %d", ret); return 0; } /* Note: * vm_stat.free_count == vm_page_free_count + vm_page_speculative_count */ return vm_stat.free_count - vm_stat.speculative_count; } static inline size_t page_size() { return getpagesize(); } static inline size_t phys_pages() { return darwin_phys_pages(); } static inline size_t avphys_pages() { return darwin_avphys_pages(); } #elif defined(__FreeBSD__) #include // VM_TOTAL #include // struct vmtotal #include static long freebsd_avphys_pages (void) { /* TODO: 1) sysctlnametomib may be called once */ /* 2) vm.stats.vm.v_cache_count is potentially free memory too */ int mib_vm_stats_vm_v_free_count[4]; size_t mib_sz = 4; int rc = sysctlnametomib ("vm.stats.vm.v_free_count", mib_vm_stats_vm_v_free_count, &mib_sz); if (rc != 0) { gu_error ("sysctlnametomib(vm.stats.vm.v_free_count) failed, code %d", rc); return 0; } unsigned int vm_stats_vm_v_free_count; size_t sz = sizeof (vm_stats_vm_v_free_count); rc = sysctl (mib_vm_stats_vm_v_free_count, mib_sz, &vm_stats_vm_v_free_count, &sz, NULL, 0); if (rc != 0) { gu_error ("sysctl(vm.stats.vm.v_free_count) failed with code %d", rc); return 0; } return vm_stats_vm_v_free_count; } static inline size_t page_size() { return sysconf(_SC_PAGESIZE); } static inline size_t phys_pages() { return sysconf(_SC_PHYS_PAGES); } static inline size_t avphys_pages() { return freebsd_avphys_pages(); } #else /* !__APPLE__ && !__FreeBSD__ */ static inline size_t page_size() { return sysconf(_SC_PAGESIZE); } static inline size_t phys_pages() { return sysconf(_SC_PHYS_PAGES); } static inline size_t avphys_pages() { return sysconf(_SC_AVPHYS_PAGES); } #endif /* !__APPLE__ && !__FreeBSD__ */ #define GU_DEFINE_FUNCTION(func) \ size_t gu_##func() \ { \ static size_t ret = 0; \ if (0 == ret) ret = func(); \ return ret; \ } GU_DEFINE_FUNCTION(page_size) GU_DEFINE_FUNCTION(phys_pages) GU_DEFINE_FUNCTION(avphys_pages) percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_utils.c0000644000175000017500000000406013136555240024660 0ustar jenkinsjenkins// Copyright (C) 2010 Codership Oy /** * @file Miscellaneous utility functions * * $Id$ */ #include "gu_utils.h" #include #include #include #include #include #include const char* gu_str2ll (const char* str, long long* ll) { char* ret; int shift = 0; long long llret = strtoll (str, &ret, 0); switch (ret[0]) { case 't': case 'T': shift += 10; case 'g': case 'G': shift += 10; case 'm': case 'M': shift += 10; case 'k': case 'K': shift += 10; ret++; if (llret == ((llret << (shift + 1)) >> (shift + 1))) { llret <<= shift; } else { /* ERANGE */ if (llret > 0) llret = LLONG_MAX; else llret = LLONG_MIN; errno = ERANGE; } default: *ll = llret; } return ret; } const char* gu_str2dbl (const char* str, double* dbl) { char* ret; *dbl = strtod (str, &ret); return ret; } const char* gu_str2bool (const char* str, bool* b) { size_t len = strlen(str); int res = -1; /* no conversion */ switch (len) { case 1: switch (str[0]) { case '0': case 'N': case 'n': res = 0; break; case '1': case 'Y': case 'y': res = 1; break; } break; case 2: if (!strcasecmp(str, "on")) res = 1; if (!strcasecmp(str, "no")) res = 0; break; case 3: if (!strcasecmp(str, "off")) res = 0; if (!strcasecmp(str, "yes")) res = 1; break; case 4: if (!strcasecmp(str, "true")) res = 1; if (!strcasecmp(str, "sure")) res = 1; if (!strcasecmp(str, "nope")) res = 0; break; case 5: if (!strcasecmp(str, "false")) res = 0; break; } *b = (res > 0); return (res >= 0) ? (str + len) : str; } const char* gu_str2ptr (const char* str, void** ptr) { char* ret; *ptr = (void*) (intptr_t)strtoll (str, &ret, 16); return ret; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_atomic.h0000644000175000017500000000660113136555240025004 0ustar jenkinsjenkins// Copyright (C) 2013-2014 Codership Oy /** * @file Atomic memory access functions. At the moment these follow * __atomic_XXX convention from GCC. */ #ifndef GU_ATOMIC_H #define GU_ATOMIC_H #ifdef __cplusplus extern "C" { #endif // So far in tests full memory sync shows the most consistent performance - // and it's the safest. @todo: reassess this later. #define GU_ATOMIC_SYNC_DEFAULT GU_ATOMIC_SYNC_FULL #ifdef __GNUC__ #if defined(__ATOMIC_RELAXED) // use __atomic_XXX builtins #define GU_ATOMIC_SYNC_NONE __ATOMIC_RELAXED #define GU_ATOMIC_SYNC_DEPEND __ATOMIC_ACQ_REL #define GU_ATOMIC_SYNC_FULL __ATOMIC_SEQ_CST #define gu_atomic_fetch_and_add(ptr, val) \ __atomic_fetch_add(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_sub(ptr, val) \ __atomic_fetch_sub(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_or(ptr, val) \ __atomic_fetch_or(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_and(ptr, val) \ __atomic_fetch_and(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_xor(ptr, val) \ __atomic_fetch_xor(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_nand(ptr, val) \ __atomic_fetch_nand(ptr, val,GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_add_and_fetch(ptr, val) \ __atomic_add_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_sub_and_fetch(ptr, val) \ __atomic_sub_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_or_and_fetch(ptr, val) \ __atomic_or_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_and_and_fetch(ptr, val) \ __atomic_and_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_xor_and_fetch(ptr, val) \ __atomic_xor_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_nand_and_fetch(ptr, val) \ __atomic_nand_fetch(ptr, val,GU_ATOMIC_SYNC_DEFAULT) // stores contents of vptr into ptr #define gu_atomic_set(ptr, vptr) \ __atomic_store(ptr, vptr, GU_ATOMIC_SYNC_DEFAULT) // loads contents of ptr to vptr #define gu_atomic_get(ptr, vptr) \ __atomic_load(ptr, vptr, GU_ATOMIC_SYNC_DEFAULT) #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) // use __sync_XXX builtins #define GU_ATOMIC_SYNC_NONE 0 #define GU_ATOMIC_SYNC_DEPEND 0 #define GU_ATOMIC_SYNC_FULL 0 #define gu_atomic_fetch_and_add __sync_fetch_and_add #define gu_atomic_fetch_and_sub __sync_fetch_and_sub #define gu_atomic_fetch_and_or __sync_fetch_and_or #define gu_atomic_fetch_and_and __sync_fetch_and_and #define gu_atomic_fetch_and_xor __sync_fetch_and_xor #define gu_atomic_fetch_and_nand __sync_fetch_and_nand #define gu_atomic_add_and_fetch __sync_add_and_fetch #define gu_atomic_sub_and_fetch __sync_sub_and_fetch #define gu_atomic_or_and_fetch __sync_or_and_fetch #define gu_atomic_and_and_fetch __sync_and_and_fetch #define gu_atomic_xor_and_fetch __sync_xor_and_fetch #define gu_atomic_nand_and_fetch __sync_nand_and_fetch #define gu_atomic_set(ptr, vptr) \ while (!__sync_bool_compare_and_swap(ptr, *ptr, *vptr)); #define gu_atomic_get(ptr, vptr) *vptr = __sync_fetch_and_or(ptr, 0) #else #error "This GCC version does not support 8-byte atomics on this platform. Use GCC >= 4.7.x." #endif /* __ATOMIC_RELAXED */ #else /* __GNUC__ */ #error "Compiler not supported" #endif #ifdef __cplusplus } #endif #endif /* !GU_ATOMIC_H */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_histogram.cpp0000644000175000017500000000420413136555240026055 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #include "gu_histogram.hpp" #include "gu_logger.hpp" #include "gu_throw.hpp" #include "gu_string_utils.hpp" // strsplit() #include #include #include #include gu::Histogram::Histogram(const std::string& vals) : cnt_() { std::vector varr = gu::strsplit(vals, ','); for (std::vector::const_iterator i = varr.begin(); i != varr.end(); ++i) { double val; std::istringstream is(*i); is >> val; if (is.fail()) { gu_throw_fatal << "Parse error"; } if (cnt_.insert(std::make_pair(val, 0)).second == false) { gu_throw_fatal << "Failed to insert value: " << val; } } } void gu::Histogram::insert(const double val) { if (val < 0.0) { log_warn << "Negative value (" << val << "), discarding"; return; } // Returns element that has key greater to val, // the correct bin is one below that std::map::iterator i(cnt_.upper_bound(val)); if (i == cnt_.end()) { ++cnt_.rbegin()->second; } else if (i == cnt_.begin()) { log_warn << "value " << val << " below histogram range, discarding"; } else { --i; ++i->second; } } void gu::Histogram::clear() { for (std::map::iterator i = cnt_.begin(); i != cnt_.end(); ++i) { i->second = 0; } } std::ostream& gu::operator<<(std::ostream& os, const Histogram& hs) { std::map::const_iterator i, i_next; long long norm = 0; for (i = hs.cnt_.begin(); i != hs.cnt_.end(); ++i) { norm += i->second; } for (i = hs.cnt_.begin(); i != hs.cnt_.end(); i = i_next) { i_next = i; ++i_next; os << i->first << ":" << std::fabs(double(i->second)/double(norm)); if (i_next != hs.cnt_.end()) os << ","; } return os; } std::string gu::Histogram::to_string() const { std::ostringstream os; os << *this; return os.str(); } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_throw.hpp0000644000175000017500000000511313136555240025230 0ustar jenkinsjenkins/* * Copyright (C) 2009-2013 Codership Oy * * $Id$ */ /*! * @file Classes to allow throwing more verbose exceptions. Should be only * used from one-line macros below. Concrete classes intended to be final. */ #ifndef __GU_THROW__ #define __GU_THROW__ #include #include #include #include #include "gu_macros.h" #include "gu_exception.hpp" namespace gu { /*! "base" class */ class ThrowBase { protected: const char* const file; const char* const func; int const line; std::ostringstream os; ThrowBase (const char* file_, const char* func_, int line_) : file (file_), func (func_), line (line_), os () {} private: ThrowBase (const ThrowBase&); ThrowBase& operator= (const ThrowBase&); friend class ThrowError; friend class ThrowFatal; }; /* final*/ class ThrowError //: public ThrowBase { public: ThrowError (const char* file_, const char* func_, int line_, int err_) : base (file_, func_, line_), err (err_) {} ~ThrowError() GU_NORETURN { base.os << ": " << err << " (" << ::strerror(err) << ')'; Exception e(base.os.str(), err); e.trace (base.file, base.func, base.line); // cppcheck-suppress exceptThrowInDestructor throw e; } std::ostringstream& msg () { return base.os; } private: ThrowBase base; int const err; }; /* final*/ class ThrowFatal { public: ThrowFatal (const char* file, const char* func, int line) : base (file, func, line) {} ~ThrowFatal () GU_NORETURN { base.os << " (FATAL)"; Exception e(base.os.str(), ENOTRECOVERABLE); e.trace (base.file, base.func, base.line); // cppcheck-suppress exceptThrowInDestructor throw e; } std::ostringstream& msg () { return base.os; } private: ThrowBase base; }; } // Usage: gu_throw_xxxxx << msg1 << msg2 << msg3; #define gu_throw_error(err_) \ gu::ThrowError(__FILE__, __FUNCTION__, __LINE__, err_).msg() #define gu_throw_fatal \ gu::ThrowFatal(__FILE__, __FUNCTION__, __LINE__).msg() #endif // __GU_THROW__ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_macros.hpp0000644000175000017500000000130713136555240025352 0ustar jenkinsjenkins// Copyright (C) 2009 Codership Oy /** * @file Miscellaneous C++-related macros * * $Id$ */ #ifndef _gu_macros_hpp_ #define _gu_macros_hpp_ /* To protect against "old-style" casts in libc macros * must be included after respective libc headers */ #if defined(SIG_IGN) extern "C" { static void (* const GU_SIG_IGN)(int) = SIG_IGN; } #endif #if defined(MAP_FAILED) extern "C" { static const void* const GU_MAP_FAILED = MAP_FAILED; } #endif namespace gu { template struct CompileAssert {}; } /* namespace gu */ #define GU_COMPILE_ASSERT(expr,msg) \ typedef gu::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] __attribute__((unused)) #endif /* _gu_macros_hpp_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_mem.c0000644000175000017500000001011313136555240024272 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy /** * Debugging versions of memmory functions * * $Id$ */ #include #include #include #include "gu_mem.h" #include "gu_log.h" /* Some global counters - can be inspected by gdb */ static volatile ssize_t gu_mem_total = 0; static volatile ssize_t gu_mem_allocs = 0; static volatile ssize_t gu_mem_reallocs = 0; static volatile ssize_t gu_mem_frees = 0; typedef struct mem_head { const char* file; unsigned int line; size_t used; size_t allocated; uint32_t signature; } mem_head_t; #define MEM_SIGNATURE 0x13578642 /**< Our special marker */ // Returns pointer to the first byte after the head structure #define TAIL(head) ((void*)((mem_head_t*)(head) + 1)) // Returns pointer to the head preceding tail #define HEAD(tail) ((mem_head_t*)(tail) - 1) void* gu_malloc_dbg (size_t size, const char* file, unsigned int line) { if (size) { size_t const total_size = size + sizeof(mem_head_t); mem_head_t* const ret = (mem_head_t*) malloc (total_size); if (ret) { gu_mem_total += total_size; gu_mem_allocs++; ret->signature = MEM_SIGNATURE; ret->allocated = total_size; ret->used = size; ret->file = file; ret->line = line; // cppcheck-suppress memleak return TAIL(ret); } } return NULL; } void* gu_calloc_dbg (size_t nmemb, size_t size, const char* file, unsigned int line) { if (size != 0 && nmemb != 0) { size_t const total_size = size*nmemb + sizeof(mem_head_t); mem_head_t* const ret = (mem_head_t*) calloc (total_size, 1); if (ret) { size_t const total_size = size*nmemb + sizeof(mem_head_t); gu_mem_total += total_size; gu_mem_allocs++; ret->signature = MEM_SIGNATURE; ret->allocated = total_size; ret->used = size; ret->file = file; ret->line = line; return TAIL(ret); } } return NULL; } void* gu_realloc_dbg (void* ptr, size_t size, const char* file, unsigned int line) { if (ptr) { if (size > 0) { mem_head_t* const old = HEAD(ptr); if (MEM_SIGNATURE != old->signature) { gu_error ("Attempt to realloc uninitialized pointer at " "file: %s, line: %d", file, line); assert (0); } size_t const total_size = size + sizeof(mem_head_t); mem_head_t* const ret = (mem_head_t*) realloc (old, total_size); if (ret) { gu_mem_reallocs++; gu_mem_total -= ret->allocated; // old size ret->allocated = total_size; gu_mem_total += ret->allocated; // new size ret->used = size; ret->file = file; ret->line = line; return TAIL(ret); } else { // realloc failed return NULL; } } else { gu_free_dbg (ptr, file, line); return NULL; } } else { return gu_malloc_dbg (size, file, line); } return NULL; } void gu_free_dbg (void* ptr, const char* file, unsigned int line) { mem_head_t* head; if (NULL == ptr) { gu_debug ("Attempt to free NULL pointer at file: %s, line: %d", file, line); return; /* As per specification - no operation is performed */ } head = HEAD(ptr); if (MEM_SIGNATURE != head->signature) { gu_error ("Attempt to free uninitialized pointer " "at file: %s, line: %d", file, line); assert (0); } if (0 == head->used) { gu_error ("Attempt to free pointer the second time at " "file: %s, line: %d. " "Was allocated at file: %s, line: %d.", file, line, head->file, head->line); assert (0); } gu_mem_total -= head->allocated; gu_mem_frees++; head->allocated = 0; head->used = 0; free (head); } void gu_mem_stats (ssize_t* total, ssize_t* allocs, ssize_t* reallocs, ssize_t* deallocs) { *total = gu_mem_total; *allocs = gu_mem_allocs; *reallocs = gu_mem_reallocs; *deallocs = gu_mem_frees; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_serialize.hpp0000644000175000017500000002557013136555240026065 0ustar jenkinsjenkins/* * Copyright (C) 2009-2012 Codership Oy */ /*! * @file Helper templates for serialization/unserialization. * As we are usually working on little endian platforms, integer * storage order is little-endian - in other words we use "Galera" * order, which is by default little-endian. * * What is going on down there? Templates are good. However we do * not serialize the value of size_t variable into sizeof(size_t) * bytes. We serialize it into a globally consistent, fixed number * of bytes, regardless of the local size of size_t variable. * * Hence templating by the source variable size should not be used. * Instead there are functions/templates that serialize to an explicit * number of bytes. * * @todo Templates are safe to use with integer types only. Adjust them * to work also with classes that have special serialization * routines. * @todo Make buffer serialization functions Buffer class methods. * @todo Alignment issues. */ #ifndef GU_SERIALIZE_HPP #define GU_SERIALIZE_HPP #include "gu_throw.hpp" #include "gu_byteswap.hpp" #include "gu_buffer.hpp" #include "gu_macros.hpp" #include namespace gu { template inline size_t serial_size(const T& t) { return t.serial_size(); } template <> inline size_t serial_size(const uint8_t& b) { return sizeof(b); } template <> inline size_t serial_size(const uint16_t& b) { return sizeof(b); } template <> inline size_t serial_size(const uint32_t& b) { return sizeof(b); } template <> inline size_t serial_size(const uint64_t& b) { return sizeof(b); } /* Should not be used directly! */ template inline size_t __private_serialize(const FROM& f, void* const buf, size_t const buflen, size_t const offset) { GU_COMPILE_ASSERT(std::numeric_limits::is_integer, not_integer1); GU_COMPILE_ASSERT(std::numeric_limits::is_integer, not_integer2); GU_COMPILE_ASSERT(sizeof(FROM) == sizeof(TO), size_differs); size_t const ret = offset + sizeof(TO); if (gu_unlikely(ret > buflen)) { gu_throw_error(EMSGSIZE) << ret << " > " << buflen; } void* const pos(reinterpret_cast(buf) + offset); *reinterpret_cast(pos) = htog(f); return ret; } /* Should not be used directly! */ template inline size_t __private_unserialize(const void* const buf, size_t const buflen, size_t const offset, TO& t) { GU_COMPILE_ASSERT(std::numeric_limits::is_integer, not_integer1); GU_COMPILE_ASSERT(std::numeric_limits::is_integer, not_integer2); GU_COMPILE_ASSERT(sizeof(FROM) == sizeof(TO), size_differs); size_t const ret = offset + sizeof(t); if (gu_unlikely(ret > buflen)) { gu_throw_error(EMSGSIZE) << ret << " > " << buflen; } const void* const pos(reinterpret_cast(buf) + offset); t = gtoh(*reinterpret_cast(pos)); return ret; } template GU_FORCE_INLINE size_t serialize1(const T& t, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(t, buf, buflen, offset); } template GU_FORCE_INLINE size_t unserialize1(const void* const buf, size_t const buflen, size_t const offset, T& t) { return __private_unserialize(buf, buflen, offset, t); } template GU_FORCE_INLINE size_t serialize2(const T& t, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(t, buf, buflen, offset); } template GU_FORCE_INLINE size_t unserialize2(const void* const buf, size_t const buflen, size_t const offset, T& t) { return __private_unserialize(buf, buflen, offset, t); } template GU_FORCE_INLINE size_t serialize4(const T& t, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(t, buf, buflen, offset); } template GU_FORCE_INLINE size_t unserialize4(const void* const buf, size_t const buflen, size_t const offset, T& t) { return __private_unserialize(buf, buflen, offset, t); } template GU_FORCE_INLINE size_t serialize8(const T& t, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(t, buf, buflen, offset); } template GU_FORCE_INLINE size_t unserialize8(const void* const buf, size_t const buflen, size_t const offset, T& t) { return __private_unserialize(buf, buflen, offset, t); } template inline size_t __private_serial_size(const Buffer& sb) { GU_COMPILE_ASSERT(std::numeric_limits::is_integer, must_be_integer); if (sb.size() > std::numeric_limits::max()) gu_throw_error(ERANGE) << sb.size() << " unrepresentable in " << sizeof(ST) << " bytes."; return sizeof(ST) + sb.size(); } GU_FORCE_INLINE size_t serial_size1(const Buffer& sb) { return __private_serial_size(sb); } GU_FORCE_INLINE size_t serial_size2(const Buffer& sb) { return __private_serial_size(sb); } GU_FORCE_INLINE size_t serial_size4(const Buffer& sb) { return __private_serial_size(sb); } GU_FORCE_INLINE size_t serial_size8(const Buffer& sb) { return __private_serial_size(sb); } template inline size_t __private_serialize(const Buffer& b, void* const buf, size_t const buflen, size_t offset) { size_t const ret = offset + __private_serial_size(b); if (ret > buflen) { gu_throw_error(EMSGSIZE) << ret << " > " << buflen; } offset = __private_serialize(static_cast(b.size()), buf, buflen, offset); copy(b.begin(), b.end(), reinterpret_cast(buf) + offset); return ret; } template inline size_t __private_unserialize(const void* const buf, size_t const buflen, size_t offset, Buffer& b) { GU_COMPILE_ASSERT(std::numeric_limits::is_integer, must_be_integer); ST len(0); size_t ret = offset + sizeof(len); if (ret > buflen) gu_throw_error(EMSGSIZE) << ret << " > " << buflen; offset = __private_unserialize(buf, buflen, offset, len); ret += len; if (ret > buflen) gu_throw_error(EMSGSIZE) << ret << " > " << buflen; b.resize(len); const byte_t* const ptr(reinterpret_cast(buf)); copy(ptr + offset, ptr + ret, b.begin()); return ret; } GU_FORCE_INLINE size_t serialize1(const Buffer& b, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(b, buf, buflen, offset); } GU_FORCE_INLINE size_t unserialize1(const void* const buf, size_t const buflen, size_t const offset, Buffer& b) { return __private_unserialize(buf, buflen, offset, b); } GU_FORCE_INLINE size_t serialize2(const Buffer& b, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(b, buf, buflen, offset); } GU_FORCE_INLINE size_t unserialize2(const void* const buf, size_t const buflen, size_t const offset, Buffer& b) { return __private_unserialize(buf, buflen, offset, b); } GU_FORCE_INLINE size_t serialize4(const Buffer& b, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(b, buf, buflen, offset); } GU_FORCE_INLINE size_t unserialize4(const void* const buf, size_t const buflen, size_t const offset, Buffer& b) { return __private_unserialize(buf, buflen, offset, b); } GU_FORCE_INLINE size_t serialize8(const Buffer& b, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(b, buf, buflen, offset); } GU_FORCE_INLINE size_t unserialize8(const void* const buf, size_t const buflen, size_t const offset, Buffer& b) { return __private_unserialize(buf, buflen, offset, b); } } // namespace gu #endif // GU_SERIALIZE_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_resolver.hpp0000644000175000017500000001644713136555240025742 0ustar jenkinsjenkins/* * Copyright (C) 2008-2012 Codership Oy * * $Id$ */ /*! * @file gu_resolver.hpp Simple resolver utility */ #ifndef __GU_RESOLVER_HPP__ #define __GU_RESOLVER_HPP__ #include "gu_throw.hpp" #include #include #include #include // Forward declarations namespace gu { class URI; } // namespace gu // Declarations namespace gu { namespace net { /*! * @class Sockaddr * * @brief Class encapsulating struct sockaddr. * * Class encapsulating struct sockaddr and providing * simple interface to access sockaddr fields. */ class Sockaddr; /*! * @class IMReq * * @brief Class encapsulating imreq structs. */ class MReq; /*! * @class Addrinfo * * @brief Class encapsulating struct addrinfo. * * Class encapsulating struct addrinfo and providing interface * to access addrinfo fields. */ class Addrinfo; /*! * Resolve address given in @uri * * @return Addrinfo object representing address * * @throw gu::Exception in case of failure */ Addrinfo resolve(const gu::URI& uri); } // namespace net } // namespace gu class gu::net::Sockaddr { public: /*! * Default constuctor. * * @param sa Pointer to sockaddr struct * @param sa_len Length of sockaddr struct */ Sockaddr(const sockaddr* sa, socklen_t sa_len); /*! * Copy constructor. * * @param sa Reference to Sockaddr */ Sockaddr(const Sockaddr& sa); /*! * Destructor */ ~Sockaddr(); /*! * Get address family. * * @return Address family */ sa_family_t get_family() const { return sa_->sa_family; } /*! * Get port in network byte order. This is applicable only * for AF_INET, AF_INET6. * * @return Port in nework byte order */ unsigned short get_port() const { switch(sa_->sa_family) { case AF_INET: return reinterpret_cast(sa_)->sin_port; case AF_INET6: return reinterpret_cast(sa_)->sin6_port; default: gu_throw_fatal; } } /*! * Get pointer to address. Return value is pointer to void, * user must do casting by himself. * * @todo: Figure out how this could be done in type safe way. * * @return Void pointer to address element. */ const void* get_addr() const { switch(sa_->sa_family) { case AF_INET: return &reinterpret_cast(sa_)->sin_addr; case AF_INET6: return &reinterpret_cast(sa_)->sin6_addr; default: gu_throw_fatal << "invalid address family: " << sa_->sa_family; } } socklen_t get_addr_len() const { switch(sa_->sa_family) { case AF_INET: return sizeof(reinterpret_cast(sa_)->sin_addr); case AF_INET6: return sizeof(reinterpret_cast(sa_)->sin6_addr); default: gu_throw_fatal; } } /*! * Get non-const reference to sockaddr struct. * * @return Non-const reference to sockaddr struct. */ sockaddr& get_sockaddr() { return *sa_; } /*! * Get const reference to sockaddr struct. * * @return Const reference to sockaddr struct. */ const sockaddr& get_sockaddr() const { return *sa_; } /*! * Get length of sockaddr struct. * * @return Length of sockaddr struct */ socklen_t get_sockaddr_len() const { return sa_len_; } bool is_multicast() const; bool is_broadcast() const; bool is_anyaddr() const; static Sockaddr get_anyaddr(const Sockaddr& sa) { Sockaddr ret(sa); switch(ret.sa_->sa_family) { case AF_INET: reinterpret_cast(ret.sa_)->sin_addr.s_addr = 0; break; case AF_INET6: memset(&reinterpret_cast(ret.sa_)->sin6_addr, 0, sizeof(struct in6_addr)); break; default: gu_throw_fatal << "invalid address family: " << ret.sa_->sa_family; } return ret; } Sockaddr& operator=(const Sockaddr& sa) { memcpy(sa_, sa.sa_, sa_len_); return *this; } private: sockaddr* sa_; socklen_t sa_len_; }; class gu::net::MReq { public: MReq(const Sockaddr& mcast_addr, const Sockaddr& if_addr); ~MReq(); const void* get_mreq() const { return mreq_; } socklen_t get_mreq_len() const { return mreq_len_; } int get_ipproto() const { return ipproto_; } int get_add_membership_opt() const { return add_membership_opt_; } int get_drop_membership_opt() const { return drop_membership_opt_; } int get_multicast_if_opt() const { return multicast_if_opt_; } int get_multicast_loop_opt() const { return multicast_loop_opt_; } int get_multicast_ttl_opt() const { return multicast_ttl_opt_; } const void* get_multicast_if_value() const; int get_multicast_if_value_size() const; private: MReq(const MReq&); void operator=(const MReq&); void* mreq_; socklen_t mreq_len_; int ipproto_; int add_membership_opt_; int drop_membership_opt_; int multicast_if_opt_; int multicast_loop_opt_; int multicast_ttl_opt_; }; class gu::net::Addrinfo { public: /*! * Default constructor. * * @param ai Const reference to addrinfo struct */ Addrinfo(const addrinfo& ai); /*! * Copy costructor. * * @param ai Const reference to Addrinfo object to copy */ Addrinfo(const Addrinfo& ai); /*! * Copy constructor that replaces @ai sockaddr struct. * * @param ai Const reference to Addrinfo object to copy * @param sa Const reference to Sockaddr struct that replaces * @ai sockaddr data */ Addrinfo(const Addrinfo& ai, const Sockaddr& sa); /*! * Destructor. */ ~Addrinfo(); /*! * Get address family, AF_INET, AF_INET6 etc. * * @return Address family */ int get_family() const { return ai_.ai_family; } /*! * Get socket type, SOCK_STREAM, SOCK_DGRAM etc * * @return Socket type */ int get_socktype() const { return ai_.ai_socktype; } /*! * Get protocol. * * @return Protocol */ int get_protocol() const { return ai_.ai_protocol; } /*! * Get length of associated sockaddr struct * * @return Length of associated sockaddr struct */ socklen_t get_addrlen() const { return ai_.ai_addrlen; } /*! * Get associated Sockaddr object. * * @return Associated Sockaddr object */ Sockaddr get_addr() const { return Sockaddr(ai_.ai_addr, ai_.ai_addrlen); } /*! * Get string representation of the addrinfo. * * @return String representation of the addrinfo */ std::string to_string() const; private: addrinfo ai_; }; #endif /* __GU_RESOLVER_HPP__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_macros.h0000644000175000017500000000353213136555240025014 0ustar jenkinsjenkins// Copyright (C) 2007-2013 Codership Oy /** * @file Miscellaneous macros * * $Id$ */ #ifndef _gu_macros_h_ #define _gu_macros_h_ /* * Platform-dependent macros */ #if defined(_MSC_VER) # define GU_NORETURN __declspec(noreturn) # define GU_INLINE __forceinline # define GU_FORCE_INLINE __forceinline # define GU_UNUSED # define GU_LONG(x) (x) # define GU_ULONG(x) (x) # define GU_LONG_LONG(x) (x) # define GU_ULONG_LONG(x) (x) # define GU_DEBUG_NORETURN #else /* !defined(_MSC_VER) */ # define GU_NORETURN __attribute__((noreturn)) # define GU_INLINE inline # define GU_FORCE_INLINE inline __attribute__((always_inline)) # define GU_UNUSED __attribute__((unused)) # define GU_LONG(x) (x##L) # define GU_ULONG(x) (x##LU) # define GU_LONG_LONG(x) (x##LL) # define GU_ULONG_LONG(x) (x##LLU) # ifndef __OPTIMIZE__ # define GU_DEBUG_NORETURN abort(); # else # define GU_DEBUG_NORETURN # endif #endif /* !defined(_MSC_VER) */ /* * End of paltform-dependent macros */ /* "Shamelessly stolen" (tm) goods from Linux kernel */ /* * min()/max() macros that also do * strict type-checking.. See the * "unnecessary" pointer comparison. */ #if 0 // typeof() is not in C99 #define GU_MAX(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x > _y ? _x : _y; }) #define GU_MIN(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x < _y ? _x : _y; }) #endif #define gu_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #if __GNUC__ >= 3 # define gu_likely(x) __builtin_expect((x), 1) # define gu_unlikely(x) __builtin_expect((x), 0) #else # define gu_likely(x) (x) # define gu_unlikely(x) (x) #endif #endif /* _gu_macros_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_unordered.hpp0000644000175000017500000001503413136555240026057 0ustar jenkinsjenkins// // Copyright (C) 2010 Codership Oy // //! // @file gu_unordered.hpp unordered_[multi]map definition // // We still have environments where neither boost or std unordered // stuff is available. Wrapper classes are provided for alternate // implementations with standard semantics. // // For usage see either boost or tr1 specifications for unordered_[multi]map // #ifndef GU_UNORDERED_HPP #define GU_UNORDERED_HPP #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) #include #include #elif defined(HAVE_UNORDERED_MAP) #include #include #elif defined(HAVE_TR1_UNORDERED_MAP) #include #include #else #error "no unordered map available" #endif #include "gu_throw.hpp" namespace gu { template class UnorderedHash { public: #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::hash Type; #elif defined(HAVE_UNORDERED_MAP) typedef std::hash Type; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::hash Type; #endif size_t operator()(const K& k) const { return Type()(k); } }; template size_t HashValue(const K& key) { return UnorderedHash()(key); } template , class P = std::equal_to, class A = std::allocator > class UnorderedSet { #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::unordered_set type; #elif defined(HAVE_UNORDERED_MAP) typedef std::unordered_set type; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::unordered_set type; #endif type impl_; public: typedef typename type::value_type value_type; typedef typename type::iterator iterator; typedef typename type::const_iterator const_iterator; UnorderedSet() : impl_() { } explicit UnorderedSet(A a) : impl_(a) { } iterator begin() { return impl_.begin(); } const_iterator begin() const { return impl_.begin(); } iterator end() { return impl_.end(); } const_iterator end() const { return impl_.end(); } std::pair insert(const value_type& k) { return impl_.insert(k); } iterator insert_unique(const value_type& k) { std::pair ret(insert(k)); if (ret.second == false) gu_throw_fatal << "insert unique failed"; return ret.first; } iterator find(const K& key) { return impl_.find(key); } const_iterator find(const K& key) const { return impl_.find(key); } iterator erase(iterator i) { return impl_.erase(i); } size_t size() const { return impl_.size(); } bool empty() const { return impl_.empty(); } void clear() { impl_.clear(); } void rehash(size_t n) { impl_.rehash(n); } size_t bucket_count() { return impl_.bucket_count(); } }; template , class P = std::equal_to, class A = std::allocator > > class UnorderedMap { #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::unordered_map type; #elif defined(HAVE_UNORDERED_MAP) typedef std::unordered_map type; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::unordered_map type; #endif type impl_; public: typedef typename type::value_type value_type; typedef typename type::iterator iterator; typedef typename type::const_iterator const_iterator; UnorderedMap() : impl_() { } iterator begin() { return impl_.begin(); } const_iterator begin() const { return impl_.begin(); } iterator end() { return impl_.end(); } const_iterator end() const { return impl_.end(); } std::pair insert(const std::pair& kv) { return impl_.insert(kv); } iterator insert_unique(const std::pair& kv) { std::pair ret(insert(kv)); if (ret.second == false) gu_throw_fatal << "insert unique failed"; return ret.first; } iterator find(const K& key) { return impl_.find(key); } const_iterator find(const K& key) const { return impl_.find(key); } iterator erase(iterator i) { return impl_.erase(i); } size_t size() const { return impl_.size(); } bool empty() const { return impl_.empty(); } void clear() { impl_.clear(); } void rehash(size_t n) { impl_.rehash(n); } #if defined(HAVE_UNORDERED_MAP) void reserve(size_t n) { impl_.reserve(n); } #endif size_t bucket_count() { return impl_.bucket_count(); } }; template > class UnorderedMultimap { #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::unordered_multimap type; #elif defined(HAVE_UNORDERED_MAP) typedef std::unordered_multimap type; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::unordered_multimap type; #endif type impl_; public: typedef typename type::value_type value_type; typedef typename type::iterator iterator; typedef typename type::const_iterator const_iterator; UnorderedMultimap() : impl_() { } void clear() { impl_.clear(); } iterator begin() { return impl_.begin(); } const_iterator begin() const { return impl_.begin(); } iterator end() { return impl_.end(); } const_iterator end() const { return impl_.end(); } iterator insert(const std::pair& kv) { return impl_.insert(kv); } iterator find(const K& key) { return impl_.find(key); } const_iterator find(const K& key) const { return impl_.find(key); } std::pair equal_range(const K& key) { return impl_.equal_range(key); } std::pair equal_range(const K& key) const { return impl_.equal_range(key); } void erase(iterator i) { impl_.erase(i); } size_t size() const { return impl_.size(); } bool empty() const { return impl_.empty(); } #if defined(HAVE_UNORDERED_MAP) void reserve(size_t n) { impl_.reserve(n); } #endif size_t bucket_count() { return impl_.bucket_count(); } }; } #endif // GU_UNORDERED_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_lock.hpp0000644000175000017500000000327413136555240025023 0ustar jenkinsjenkins/* * Copyright (C) 2009-2017 Codership Oy * */ #ifndef __GU_LOCK__ #define __GU_LOCK__ #include "gu_exception.hpp" #include "gu_logger.hpp" #include "gu_mutex.hpp" #include "gu_cond.hpp" #include "gu_datetime.hpp" #include #include namespace gu { class Lock { const Mutex& mtx_; Lock (const Lock&); Lock& operator=(const Lock&); public: Lock (const Mutex& mtx) : mtx_(mtx) { int const err(mtx_.lock()); if (gu_unlikely(err)) { std::string msg = "Mutex lock failed: "; msg = msg + strerror(err); throw Exception(msg.c_str(), err); } } virtual ~Lock () { #ifdef GU_DEBUG_MUTEX assert(mtx_.owned()); #endif int const err(mtx_.unlock()); if (gu_unlikely(err)) { log_fatal << "Mutex unlock failed: " << err << " (" << strerror(err) << "), Aborting."; ::abort(); } // log_debug << "Unlocked mutex " << value; } inline void wait (const Cond& cond) { cond.ref_count++; gu_cond_wait (&(cond.cond), &mtx_.impl()); cond.ref_count--; } inline void wait (const Cond& cond, const datetime::Date& date) { timespec ts; date._timespec(ts); cond.ref_count++; int ret = gu_cond_timedwait (&(cond.cond), &mtx_.impl(), &ts); cond.ref_count--; if (gu_unlikely(ret)) gu_throw_error(ret); } }; } #endif /* __GU_LOCK__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_conf.h0000644000175000017500000000112513136555240024451 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy /** * @file * Configuration interface for libgalerautils * * $Id$ */ #ifndef _gu_conf_h_ #define _gu_conf_h_ #ifdef __cplusplus extern "C" { #endif /* Logging options */ #include #include "gu_log.h" extern int gu_conf_set_log_file (FILE* file); extern int gu_conf_set_log_callback (gu_log_cb_t callback); extern int gu_conf_self_tstamp_on (); extern int gu_conf_self_tstamp_off (); extern int gu_conf_debug_on (); extern int gu_conf_debug_off (); #ifdef __cplusplus } #endif #endif // _gu_conf_h_ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_atomic.hpp0000644000175000017500000000331113136555240025337 0ustar jenkinsjenkins// // Copyright (C) 2010-2014 Codership Oy // // // @todo Check that the at least the following gcc versions are supported // gcc version 4.1.2 20080704 (Red Hat 4.1.2-48) // #ifndef GU_ATOMIC_HPP #define GU_ATOMIC_HPP #include "gu_atomic.h" #include namespace gu { template class Atomic { public: Atomic(I i = 0) : i_(i) { } I operator()() const { I i; gu_atomic_get(&i_, &i); return i; } Atomic& operator=(I i) { gu_atomic_set(&i_, &i); return *this; } I fetch_and_zero() { return gu_atomic_fetch_and_and(&i_, 0); } I fetch_and_add(I i) { return gu_atomic_fetch_and_add(&i_, i); } I add_and_fetch(I i) { return gu_atomic_add_and_fetch(&i_, i); } I sub_and_fetch(I i) { return gu_atomic_sub_and_fetch(&i_, i); } Atomic& operator++() { gu_atomic_fetch_and_add(&i_, 1); return *this; } Atomic& operator--() { gu_atomic_fetch_and_sub(&i_, 1); return *this; } Atomic& operator+=(I i) { gu_atomic_fetch_and_add(&i_, i); return *this; } bool operator!=(I i) { return (operator()() != i); } private: #if !defined(__ATOMIC_RELAXED) // implementation of gu_atomic_get() via __sync_fetch_and_or() // is not read-only for GCC mutable #endif I i_; }; } #endif // ::GU_ATOMIC_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_serializable.hpp0000644000175000017500000000603113136555240026533 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @file Declaration of serializeble interface that all serializable classes * should inherit. * * $Id$ */ #ifndef GU_SERIALIZABLE_HPP #define GU_SERIALIZABLE_HPP #include "gu_types.hpp" #include "gu_throw.hpp" #include "gu_assert.hpp" #include #include // for std::length_error namespace gu { class Serializable { public: /*! returns the size of a buffer required to serialize the object */ ssize_t serial_size () const { return my_serial_size(); } /*! * serializes this object into buf and returns serialized size * * @param buf pointer to buffer * @param size size of buffer * @return serialized size * * may throw exceptions */ ssize_t serialize_to (void* const buf, ssize_t const size) const { return my_serialize_to (buf, size); } /*! * serializes this object into byte vector v, reallocating it if needed * returns the size of serialized object */ ssize_t serialize_to (std::vector& v) const { size_t const old_size (v.size()); size_t const new_size (serial_size() + old_size); try { v.resize (new_size, 0); } catch (std::length_error& l) { gu_throw_error(EMSGSIZE) << "length_error: " << l.what(); } catch (...) { gu_throw_error(ENOMEM) << "could not resize to " << new_size << " bytes"; } try { return serialize_to (&v[old_size], new_size - old_size); } catch (...) { v.resize (old_size); throw; } } protected: ~Serializable() {} private: virtual ssize_t my_serial_size () const = 0; virtual ssize_t my_serialize_to (void* buf, ssize_t size) const = 0; }; static inline std::vector& operator << (std::vector& out, const Serializable& s) { s.serialize_to (out); return out; } #if 0 // seems to be a pointless idea class DeSerializable { public: /* serial size of an object stored at ptr, may be not implemented */ template static ssize_t serial_size (const byte_t* const buf, ssize_t const size) { assert (size > 0); return DS::my_serial_size (buf, size); } /* serial size of an object stored at ptr, may be not implemented */ ssize_t deserialize_from (const byte_t* const buf, ssize_t const size) { assert (size > 0); return my_deserialize_from (buf, size); } ssize_t deserialize_from (const std::vector& in,size_t const offset) { return deserialize_from (&in[offset], in.size() - offset); } protected: ~DeSerializable() {} private: /* serial size of an object stored at ptr, may be not implemented */ virtual ssize_t my_deserialize_from (const byte_t* buf, ssize_t size) = 0; }; #endif // 0 } /* namespace gu */ #endif /* GU_SERIALIZABLE_HPP */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_thread.cpp0000644000175000017500000000473113136555240025334 0ustar jenkinsjenkins// // Copyright (C) 2016 Codership Oy // #include "gu_thread.hpp" #include "gu_utils.hpp" #include "gu_string_utils.hpp" #include "gu_throw.hpp" #include #include static std::string const SCHED_OTHER_STR ("other"); static std::string const SCHED_FIFO_STR ("fifo"); static std::string const SCHED_RR_STR ("rr"); static std::string const SCHED_UNKNOWN_STR("unknown"); static inline void parse_thread_schedparam(const std::string& param, int& policy, int& prio) { std::vector sv(gu::strsplit(param, ':')); if (sv.size() != 2) { gu_throw_error(EINVAL) << "Invalid schedparam: " << param; } if (sv[0] == SCHED_OTHER_STR) policy = SCHED_OTHER; else if (sv[0] == SCHED_FIFO_STR) policy = SCHED_FIFO; else if (sv[0] == SCHED_RR_STR) policy = SCHED_RR; else gu_throw_error(EINVAL) << "Invalid scheduling policy: " << sv[0]; prio = gu::from_string(sv[1]); } gu::ThreadSchedparam gu::ThreadSchedparam::system_default(SCHED_OTHER, 0); gu::ThreadSchedparam::ThreadSchedparam(const std::string& param) : policy_(), prio_ () { if (param == "") { *this = system_default; } else { parse_thread_schedparam(param, policy_, prio_); } } void gu::ThreadSchedparam::print(std::ostream& os) const { std::string policy_str; switch (policy()) { case SCHED_OTHER: policy_str = SCHED_OTHER_STR ; break; case SCHED_FIFO: policy_str = SCHED_FIFO_STR ; break; case SCHED_RR: policy_str = SCHED_RR_STR ; break; default: policy_str = SCHED_UNKNOWN_STR; break; } os << policy_str << ":" << prio(); } gu::ThreadSchedparam gu::thread_get_schedparam(pthread_t thd) { int policy; struct sched_param sp; int err; if ((err = pthread_getschedparam(thd, &policy, &sp)) != 0) { gu_throw_error(err) << "Failed to read thread schedparams"; } return ThreadSchedparam(policy, sp.sched_priority); } void gu::thread_set_schedparam(pthread_t thd, const gu::ThreadSchedparam& sp) { #if defined(__sun__) struct sched_param spstr = { sp.prio(), { 0, } /* sched_pad array */}; #else struct sched_param spstr = { sp.prio() }; #endif int err; if ((err = pthread_setschedparam(thd, sp.policy(), &spstr)) != 0) { gu_throw_error(err) << "Failed to set thread schedparams " << sp; } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_mem.h0000644000175000017500000000400413136555240024301 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy /** * @file * Declarations of memory allocation functions and macros * * $Id$ */ #ifndef _gu_mem_h_ #define _gu_mem_h_ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** @name Functions to help with dynamic allocation debugging. * Take additional __FILE__ and __LINE__ arguments. Should be * used as part of macros defined below */ /*@{*/ void* gu_malloc_dbg (size_t size, const char* file, unsigned int line); void* gu_calloc_dbg (size_t nmemb, size_t size, const char* file, unsigned int line); void* gu_realloc_dbg (void* ptr, size_t size, const char* file, unsigned int line); void gu_free_dbg (void* ptr, const char* file, unsigned int line); /*@}*/ /** Reports statistics on the current amount of allocated memory * total number of allocations and deallocations */ void gu_mem_stats (ssize_t* total, ssize_t* allocs, ssize_t* reallocs, ssize_t* deallocs); /** @name Applications should use the following macros */ /*@{*/ #ifdef DEBUG_MALLOC #define gu_malloc(S) gu_malloc_dbg ((S), __FILE__, __LINE__) #define gu_calloc(N,S) gu_calloc_dbg ((N), (S), __FILE__, __LINE__) #define gu_realloc(P,S) gu_realloc_dbg ((P), (S), __FILE__, __LINE__) #define gu_free(P) gu_free_dbg ((P), __FILE__, __LINE__) #else /* !DEBUG_MALLOC - use standard allocation routines */ #define gu_malloc(S) malloc ((S)) #define gu_calloc(N,S) calloc ((N), (S)) #define gu_realloc(P,S) realloc ((P), (S)) #define gu_free(P) free ((P)) #endif /* DEBUG_MALLOC */ /** Convenience macros - to avoid code clutter */ #define GU_MALLOC(type) (type*) gu_malloc (sizeof(type)) #define GU_MALLOCN(N,type) (type*) gu_malloc ((N) * sizeof(type)) #define GU_CALLOC(N,type) (type*) gu_calloc ((N), sizeof(type)) #define GU_REALLOC(P,N,type) (type*) gu_realloc((P), (N) * sizeof(type)) /*@}*/ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _gu_mem_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_byteswap.hpp0000644000175000017500000000246013136555240025725 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /** * @file Endian conversion templates for serialization * * $Id$ */ #ifndef _gu_byteswap_hpp_ #define _gu_byteswap_hpp_ #include "gu_byteswap.h" #include namespace gu { /* General template: undefined */ template T gtoh (const T& val) { // to generate error on compilation rather then linking return val.this_template_does_not_support_this_type(); } /* Specialized templates */ template <> GU_FORCE_INLINE uint8_t gtoh (const uint8_t& val) { return val; } template <> GU_FORCE_INLINE uint16_t gtoh (const uint16_t& val) { return gtoh16(val); } template <> GU_FORCE_INLINE unsigned int gtoh (const unsigned int& val) { return gtoh32(val); } #if __LONG_MAX__ == __INT_MAX__ template <> GU_FORCE_INLINE unsigned long gtoh (const unsigned long& val) { return gtoh32(val); } #elif __LONG_MAX__ == __LONG_LONG_MAX__ template <> GU_FORCE_INLINE unsigned long gtoh (const unsigned long& val) { return gtoh64(val); } #else # error can not determine size of long #endif template <> GU_FORCE_INLINE unsigned long long gtoh (const unsigned long long& val) { return gtoh64(val); } template T htog (const T& val) { return gtoh(val); } } /* namespace gu */ #endif /* _gu_byteswap_hpp_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_byteswap.h0000644000175000017500000000655613136555240025377 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /** * @file Byte swapping functions/macros * * $Id$ */ #ifndef _gu_byteswap_h_ #define _gu_byteswap_h_ #include "gu_arch.h" #include "gu_types.h" #include "gu_macros.h" /* * Platform-dependent macros */ #if defined(_MSC_VER) #include #define GU_ROTL32(x,y) _rotl(x,y) #define GU_ROTL64(x,y) _rotl64(x,y) #else /* !defined(_MSC_VER) */ static GU_FORCE_INLINE uint32_t GU_ROTL32 (uint32_t x, int8_t r) { return (x << r) | (x >> (32 - r)); } static GU_FORCE_INLINE uint64_t GU_ROTL64 (uint64_t x, int8_t r) { return (x << r) | (x >> (64 - r)); } #endif /* !defined(_MSC_VER) */ /* * End of paltform-dependent macros */ #if defined(HAVE_BYTESWAP_H) # include // for bswap_16(x), bswap_32(x), bswap_64(x) #elif defined(__APPLE__) # include // for OSSwapInt16(x), etc. #endif /* HAVE_BYTESWAP_H */ #if defined(__APPLE__) /* do not use OSSwapIntXX, because gcc44 gives old-style cast warnings */ # define gu_bswap16 _OSSwapInt16 # define gu_bswap32 _OSSwapInt32 # define gu_bswap64 _OSSwapInt64 #elif defined(__FreeBSD__) /* do not use bswapXX, because gcc44 gives old-style cast warnings */ # define gu_bswap16 __bswap16_var # define gu_bswap32 __bswap32_var # define gu_bswap64 __bswap64_var #elif defined(__sun__) # define gu_bswap16 BSWAP_16 # define gu_bswap32 BSWAP_32 # define gu_bswap64 BSWAP_64 #elif defined(bswap16) # define gu_bswap16 bswap16 # define gu_bswap32 bswap32 # define gu_bswap64 bswap64 #elif defined(bswap_16) # define gu_bswap16 bswap_16 # define gu_bswap32 bswap_32 # define gu_bswap64 bswap_64 #else # error "No byteswap macros are defined" #endif /* @note: there are inline functions behind these macros below, * so typesafety is taken care of... However C++ still has issues: */ #ifdef __cplusplus // To pacify C++. Not loosing much optimization on 2 bytes anyways. #include #undef gu_bswap16 static GU_FORCE_INLINE uint16_t gu_bswap16(uint16_t const x) // Even though x is declared as 'uint16_t', g++-4.4.1 still treats results // of operations with it as 'int' and freaks out on return with -Wconversion. { return static_cast((x >> 8) | (x << 8)); } #endif // __cplusplus #if defined(GU_LITTLE_ENDIAN) /* convert to/from Little Endian representation */ #define gu_le16(x) (x) #define gu_le32(x) (x) #define gu_le64(x) (x) /* convert to/from Big Endian representation */ #define gu_be16(x) gu_bswap16(x) #define gu_be32(x) gu_bswap32(x) #define gu_be64(x) gu_bswap64(x) #else /* Big-Endian */ /* convert to/from Little Endian representation */ #define gu_le16(x) gu_bswap16(x) #define gu_le32(x) gu_bswap32(x) #define gu_le64(x) gu_bswap64(x) /* convert to/from Big Endian representation */ #define gu_be16(x) (x) #define gu_be32(x) (x) #define gu_be64(x) (x) #endif /* Big-Endian */ /* Analogues to htonl and friends. Since we'll be dealing mostly with * little-endian architectures, there is more sense to use little-endian * as default */ #define htogs(x) gu_le16(x) #define gtohs(x) htogs(x) #define htogl(x) gu_le32(x) #define gtohl(x) htogl(x) /* Analogues to htogs() and friends, suffixed with type width */ #define htog16(x) gu_le16(x) #define gtoh16(x) htog16(x) #define htog32(x) gu_le32(x) #define gtoh32(x) htog32(x) #define htog64(x) gu_le64(x) #define gtoh64(x) htog64(x) #endif /* _gu_byteswap_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_alloc.cpp0000644000175000017500000001074713136555240025163 0ustar jenkinsjenkins/* Copyright (C) 2013-2016 Codership Oy */ /*! * @file allocator main functions * * $Id$ */ #include "gu_alloc.hpp" #include "gu_throw.hpp" #include "gu_assert.hpp" #include "gu_limits.h" #include #include // for std::setfill() and std::setw() gu::Allocator::HeapPage::HeapPage (page_size_type const size) : Page (static_cast(::malloc(size)), size) { if (0 == base_ptr_) gu_throw_error (ENOMEM); } gu::Allocator::Page* gu::Allocator::HeapStore::my_new_page (page_size_type const size) { if (gu_likely(size <= left_)) { /* to avoid too frequent allocation, make it (at least) 64K */ static page_size_type const PAGE_SIZE(gu_page_size_multiple(1 << 16)); page_size_type const page_size (std::min(std::max(size, PAGE_SIZE), left_)); Page* ret = new HeapPage (page_size); assert (ret != 0); left_ -= page_size; return ret; } gu_throw_error (ENOMEM) << "out of memory in RAM pool"; } gu::Allocator::FilePage::FilePage (const std::string& name, page_size_type const size) : Page (0, 0), fd_ (name, size, false, false), mmap_(fd_, true) { base_ptr_ = reinterpret_cast(mmap_.ptr); ptr_ = base_ptr_; left_ = mmap_.size; } gu::Allocator::Page* gu::Allocator::FileStore::my_new_page (page_size_type const size) { Page* ret = 0; try { std::ostringstream fname; fname << base_name_ << '.' << std::dec << std::setfill('0') << std::setw(6) << n_; ret = new FilePage(fname.str(), std::max(size, page_size_)); assert (ret != 0); ++n_; } catch (std::exception& e) { gu_throw_error(ENOMEM) << e.what(); } return ret; } #ifdef GU_ALLOCATOR_DEBUG void gu::Allocator::add_current_to_bufs() { page_size_type const current_size (current_page_->size()); if (current_size) { if (bufs_->empty() || bufs_->back().ptr != current_page_->base()) { Buf b = { current_page_->base(), current_size }; bufs_->push_back (b); } else { bufs_->back().size = current_size; } } } size_t gu::Allocator::gather (std::vector& out) const { if (bufs_().size()) out.insert (out.end(), bufs_().begin(), bufs_().end()); Buf b = { current_page_->base(), current_page_->size() }; out.push_back (b); return size_; } #endif /* GU_ALLOCATOR_DEBUG */ gu::byte_t* gu::Allocator::alloc (page_size_type const size, bool& new_page) { new_page = false; if (gu_unlikely(0 == size)) return 0; byte_t* ret = current_page_->alloc (size); if (gu_unlikely(0 == ret)) { Page* np = 0; try { np = current_store_->new_page(size); } catch (Exception& e) { if (current_store_ != &heap_store_) throw; /* no fallbacks left */ /* fallback to disk store */ current_store_ = &file_store_; np = current_store_->new_page(size); } assert (np != 0); // it should have thrown above pages_().push_back (np); #ifdef GU_ALLOCATOR_DEBUG add_current_to_bufs(); #endif /* GU_ALLOCATOR_DEBUG */ current_page_ = np; new_page = true; ret = np->alloc (size); assert (ret != 0); // the page should be sufficiently big } size_ += size; return ret; } gu::Allocator::BaseNameDefault const gu::Allocator::BASE_NAME_DEFAULT; gu::Allocator::Allocator (const BaseName& base_name, byte_t* reserved, page_size_type reserved_size, heap_size_type max_ram, page_size_type disk_page_size) : first_page_ (reserved, reserved_size), current_page_ (&first_page_), heap_store_ (max_ram), file_store_ (base_name, disk_page_size), current_store_(&heap_store_), pages_ (), #ifdef GU_ALLOCATOR_DEBUG bufs_ (), #endif /* GU_ALLOCATOR_DEBUG */ size_ (0) { assert (NULL != reserved || 0 == reserved_size); assert (current_page_ != 0); pages_->push_back (current_page_); } gu::Allocator::~Allocator () { for (int i(pages_->size() - 1); i > 0 /* don't delete first_page_ - we didn't allocate it */; --i) { delete (pages_[i]); } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_abort.c0000644000175000017500000000234013136555240024626 0ustar jenkinsjenkins// Copyright (C) 2011-2013 Codership Oy /** * @file Clean abort function * * $Id$ */ #include "gu_abort.h" #include "gu_system.h" #include "gu_log.h" #include /* for setrlimit() */ #include /* for signal() */ #include /* for abort() */ #ifdef __linux__ #include /* for prctl() */ #endif /* __linux__ */ static void (* app_callback) (void) = NULL; void gu_abort (void) { /* avoid coredump */ struct rlimit core_limits = { 0, 0 }; setrlimit (RLIMIT_CORE, &core_limits); #ifdef __linux__ /* Linux with its coredump piping option requires additional care. * See e.g. https://patchwork.kernel.org/patch/1091782/ */ prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); #endif /* __linux__ */ /* restore default SIGABRT handler */ signal (SIGABRT, SIG_DFL); #if defined(GU_SYS_PROGRAM_NAME) gu_info ("%s: Terminated.", GU_SYS_PROGRAM_NAME); #else gu_info ("Program terminated."); #endif if (app_callback) { app_callback(); } abort(); } /* Register the application callback that be called before exiting: */ void gu_abort_register_cb (void (* callback) (void)) { app_callback = callback; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_thread.hpp0000644000175000017500000000505313136555240025337 0ustar jenkinsjenkins// // Copyright (C) 2016-2017 Codership Oy // // // Threading utilities // #ifndef GU_THREAD_HPP #define GU_THREAD_HPP #include "gu_threads.h" #include namespace gu { // // Wrapper class for thread scheduling parameters. For details, // about values see sched_setscheduler() and pthread_setschedparams() // documentation. // class ThreadSchedparam { public: // // Default constructor. Initializes to default system // scheduling parameters. // ThreadSchedparam() : policy_(SCHED_OTHER), prio_ (0) { } // // Construct ThreadSchedparam from given policy and priority // integer values. // ThreadSchedparam(int policy, int prio) : policy_(policy), prio_ (prio) { } // // Construct ThreadSchedparam from given string representation // which must have form of // // : // // wehre policy is one of "other", "fifo", "rr" and priority // is an integer. // ThreadSchedparam(const std::string& param); // Return scheduling policy int policy() const { return policy_; } // Return scheduling priority int prio() const { return prio_ ; } // Equal to operator overload bool operator==(const ThreadSchedparam& other) const { return (policy_ == other.policy_ && prio_ == other.prio_); } // Not equal to operator overload bool operator!=(const ThreadSchedparam& other) const { return !(*this == other); } // Default system ThreadSchedparam static ThreadSchedparam system_default; void print(std::ostream& os) const; private: int policy_; // Scheduling policy int prio_; // Scheduling priority }; // // Return current scheduling parameters for given thread // ThreadSchedparam thread_get_schedparam(gu_thread_t thread); // // Set scheduling parameters for given thread. // // Throws gu::Exception if setting parameters fails. // void thread_set_schedparam(gu_thread_t thread, const ThreadSchedparam&); // // Insertion operator for ThreadSchedparam // inline std::ostream& operator<<(std::ostream& os, const gu::ThreadSchedparam& sp) { sp.print(os); return os; } } #endif // GU_THREAD_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_asio.cpp0000644000175000017500000001104113136555240025010 0ustar jenkinsjenkins// // Copyright (C) 2014-2015 Codership Oy // #include "gu_config.hpp" #include "gu_asio.hpp" #include void gu::ssl_register_params(gu::Config& conf) { // register SSL config parameters conf.add(gu::conf::use_ssl); conf.add(gu::conf::ssl_cipher); conf.add(gu::conf::ssl_compression); conf.add(gu::conf::ssl_key); conf.add(gu::conf::ssl_cert); conf.add(gu::conf::ssl_ca); conf.add(gu::conf::ssl_password_file); } /* checks if all mandatory SSL options are set */ static bool ssl_check_conf(const gu::Config& conf) { using namespace gu; bool explicit_ssl(false); if (conf.is_set(conf::use_ssl)) { if (conf.get(conf::use_ssl) == false) { return false; // SSL is explicitly disabled } else { explicit_ssl = true; } } int count(0); count += conf.is_set(conf::ssl_key); count += conf.is_set(conf::ssl_cert); bool const use_ssl(explicit_ssl || count > 0); if (use_ssl && count < 2) { gu_throw_error(EINVAL) << "To enable SSL at least both of '" << conf::ssl_key << "' and '" << conf::ssl_cert << "' must be set"; } return use_ssl; } void gu::ssl_init_options(gu::Config& conf) { bool use_ssl(ssl_check_conf(conf)); if (use_ssl == true) { // set defaults // cipher list const std::string cipher_list(conf.get(conf::ssl_cipher, "AES128-SHA")); conf.set(conf::ssl_cipher, cipher_list); // compression bool compression(conf.get(conf::ssl_compression, true)); if (compression == false) { log_info << "disabling SSL compression"; sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); } conf.set(conf::ssl_compression, compression); // verify that asio::ssl::context can be initialized with provided // values try { asio::io_service io_service; asio::ssl::context ctx(io_service, asio::ssl::context::sslv23); ssl_prepare_context(conf, ctx); } catch (asio::system_error& ec) { gu_throw_error(EINVAL) << "Initializing SSL context failed: " << extra_error_info(ec.code()); } } } namespace { // Callback for reading SSL key protection password from file class SSLPasswordCallback { public: SSLPasswordCallback(const gu::Config& conf) : conf_(conf) { } std::string get_password() const { std::string file(conf_.get(gu::conf::ssl_password_file)); std::ifstream ifs(file.c_str(), std::ios_base::in); if (ifs.good() == false) { gu_throw_error(errno) << "could not open password file '" << file << "'"; } std::string ret; std::getline(ifs, ret); return ret; } private: const gu::Config& conf_; }; } void gu::ssl_prepare_context(const gu::Config& conf, asio::ssl::context& ctx, bool verify_peer_cert) { ctx.set_verify_mode(asio::ssl::context::verify_peer | (verify_peer_cert == true ? asio::ssl::context::verify_fail_if_no_peer_cert : 0)); SSLPasswordCallback cb(conf); ctx.set_password_callback( boost::bind(&SSLPasswordCallback::get_password, &cb)); std::string param; try { param = conf::ssl_key; ctx.use_private_key_file(conf.get(param), asio::ssl::context::pem); param = conf::ssl_cert; ctx.use_certificate_file(conf.get(param), asio::ssl::context::pem); param = conf::ssl_ca; ctx.load_verify_file(conf.get(param, conf.get(conf::ssl_cert))); param = conf::ssl_cipher; SSL_CTX_set_cipher_list(ctx.impl(), conf.get(param).c_str()); ctx.set_options(asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3 | asio::ssl::context::no_tlsv1); } catch (asio::system_error& ec) { gu_throw_error(EINVAL) << "Bad value '" << conf.get(param, "") << "' for SSL parameter '" << param << "': " << extra_error_info(ec.code()); } catch (gu::NotSet& ec) { gu_throw_error(EINVAL) << "Missing required value for SSL parameter '" << param << "'"; } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_uuid.h0000644000175000017500000000552713136555240024504 0ustar jenkinsjenkins/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /* * Universally Unique IDentifier. RFC 4122. * Time-based implementation. * */ #ifndef _gu_uuid_h_ #define _gu_uuid_h_ #include "gu_types.h" #ifdef __cplusplus extern "C" { #endif /*! UUID internally is represented as a BE integer which allows using * memcmp() as comparison function and straightforward printing */ #define GU_UUID_LEN 16 typedef struct { uint8_t data[GU_UUID_LEN]; } gu_uuid_t; extern const gu_uuid_t GU_UUID_NIL; /*! length of string representation */ #define GU_UUID_STR_LEN 36 /*! Macros for pretty printing */ #define GU_UUID_FORMAT \ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" #define GU_UUID_ARGS(uuid) \ (uuid)->data[ 0], (uuid)->data[ 1], (uuid)->data[ 2], (uuid)->data[ 3],\ (uuid)->data[ 4], (uuid)->data[ 5], (uuid)->data[ 6], (uuid)->data[ 7],\ (uuid)->data[ 8], (uuid)->data[ 9], (uuid)->data[10], (uuid)->data[11],\ (uuid)->data[12], (uuid)->data[13], (uuid)->data[14], (uuid)->data[15] /* this is used for scanf, variables are by reference */ #define GU_UUID_FORMAT_SCANF \ "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" #define GU_UUID_ARGS_SCANF(uuid) \ &(uuid)->data[ 0], &(uuid)->data[ 1], &(uuid)->data[ 2], &(uuid)->data[ 3],\ &(uuid)->data[ 4], &(uuid)->data[ 5], &(uuid)->data[ 6], &(uuid)->data[ 7],\ &(uuid)->data[ 8], &(uuid)->data[ 9], &(uuid)->data[10], &(uuid)->data[11],\ &(uuid)->data[12], &(uuid)->data[13], &(uuid)->data[14], &(uuid)->data[15] /*! * Generates new UUID. * If node is NULL, will generate random (if /dev/urand is present) or * pseudorandom data instead. * @param uuid * pointer to uuid_t * @param node * some unique data that goes in place of "node" field in the UUID * @param node_len * length of the node buffer */ extern void gu_uuid_generate (gu_uuid_t* uuid, const void* node, size_t node_len); /*! * Compare two UUIDs according to RFC * @return -1, 0, 1 if left is respectively less, equal or greater than right */ extern long gu_uuid_compare (const gu_uuid_t* left, const gu_uuid_t* right); /*! * Compare ages of two UUIDs * @return -1, 0, 1 if left is respectively younger, equal or older than right */ extern long gu_uuid_older (const gu_uuid_t* left, const gu_uuid_t* right); /*! * Print UUID into buffer * @return Number of bytes printed (not including trailing '\0') or -1 on error. */ extern ssize_t gu_uuid_print(const gu_uuid_t* uuid, char* buf, size_t buflen); /*! * Scan UUID from buffer * @return Number of bytes read (should match to sizeof(uuid)) or -1 on error */ extern ssize_t gu_uuid_scan(const char* buf, size_t buflen, gu_uuid_t* uuid); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _gu_uuid_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_uuid.hpp0000644000175000017500000000755113136555240025043 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy * */ #ifndef _gu_uuid_hpp_ #define _gu_uuid_hpp_ #include "gu_uuid.h" #include "gu_assert.hpp" #include "gu_buffer.hpp" #include "gu_throw.hpp" #include inline bool operator==(const gu_uuid_t& a, const gu_uuid_t& b) { return gu_uuid_compare(&a, &b) == 0; } inline bool operator!=(const gu_uuid_t& a, const gu_uuid_t& b) { return !(a == b); } inline std::ostream& operator<<(std::ostream& os, const gu_uuid_t& uuid) { char uuid_buf[GU_UUID_STR_LEN + 1]; ssize_t ret(gu_uuid_print(&uuid, uuid_buf, sizeof(uuid_buf))); (void)ret; assert(ret == GU_UUID_STR_LEN); uuid_buf[GU_UUID_STR_LEN] = '\0'; return (os << uuid_buf); } inline ssize_t gu_uuid_from_string(const std::string& s, gu_uuid_t& uuid) { ssize_t ret(gu_uuid_scan(s.c_str(), s.size(), &uuid)); if (ret == -1) { gu_throw_error(EINVAL) << "could not parse UUID from '" << s << '\'' ; } return ret; } inline std::istream& operator>>(std::istream& is, gu_uuid_t& uuid) { char str[GU_UUID_STR_LEN + 1]; is.width(GU_UUID_STR_LEN + 1); is >> str; gu_uuid_from_string(str, uuid); return is; } inline size_t gu_uuid_serial_size(const gu_uuid_t& uuid) { return sizeof(uuid.data); } inline size_t gu_uuid_serialize(const gu_uuid_t& uuid, gu::byte_t* buf, size_t buflen, size_t offset) { if (offset + gu_uuid_serial_size(uuid) > buflen) gu_throw_error (EMSGSIZE) << gu_uuid_serial_size(uuid) << " > " << (buflen - offset); memcpy(buf + offset, uuid.data, gu_uuid_serial_size(uuid)); offset += gu_uuid_serial_size(uuid); return offset; } inline size_t gu_uuid_unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, gu_uuid_t& uuid) { if (offset + gu_uuid_serial_size(uuid) > buflen) gu_throw_error (EMSGSIZE) << gu_uuid_serial_size(uuid) << " > " << (buflen - offset); memcpy(uuid.data, buf + offset, gu_uuid_serial_size(uuid)); offset += gu_uuid_serial_size(uuid); return offset; } namespace gu { class UUID; } class gu::UUID { public: UUID() : uuid_(GU_UUID_NIL) {} UUID(const void* node, const size_t node_len) : uuid_() { gu_uuid_generate(&uuid_, node, node_len); } UUID(gu_uuid_t uuid) : uuid_(uuid) {} virtual ~UUID() {} size_t unserialize(const gu::byte_t* buf, const size_t buflen, const size_t offset) { return gu_uuid_unserialize(buf, buflen, offset, uuid_); } size_t serialize(gu::byte_t* buf, const size_t buflen, const size_t offset) const { return gu_uuid_serialize(uuid_, buf, buflen, offset); } static size_t serial_size() { return sizeof(gu_uuid_t); } const gu_uuid_t* uuid_ptr() const { return &uuid_; } bool operator<(const UUID& cmp) const { return (gu_uuid_compare(&uuid_, &cmp.uuid_) < 0); } bool operator==(const UUID& cmp) const { return (gu_uuid_compare(&uuid_, &cmp.uuid_) == 0); } bool operator!=(const UUID& cmp) const { return !(*this == cmp); } bool older(const UUID& cmp) const { return (gu_uuid_older(&uuid_, &cmp.uuid_) > 0); } void write_stream(std::ostream& os) const { os << uuid_; } void read_stream(std::istream& is) { is >> uuid_; } protected: gu_uuid_t uuid_; }; // class UUID namespace gu { inline std::ostream& operator<<(std::ostream& os, const gu::UUID& uuid) { uuid.write_stream(os); return os; } inline std::istream& operator>>(std::istream& is, gu::UUID& uuid) { uuid.read_stream(is); return is; } } // namespace gu #endif // _gu_uuid_hpp_ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_fnv_bench.c0000644000175000017500000001403113136555240025447 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /*! * @file Benchmark for different hash implementations: * fnv32, fnv64, fnv128, mmh3, md5 from libssl and md5 from crypto++ * * To compile on Ubuntu: g++ -DHAVE_ENDIAN_H -DHAVE_BYTESWAP_H -DGALERA_LOG_H_ENABLE_CXX \ -O3 -march=native -msse4 -Wall -Werror -I../.. gu_fnv_bench.c gu_crc32c.c \ gu_mmh3.c gu_spooky.c gu_log.c ../../www.evanjones.ca/crc32c.c \ -lssl -lcrypto -lcrypto++ -o gu_fnv_bench * * on CentOS some play with -lcrypto++ may be needed (also see includes below) * * To run: * gu_fnv_bench */ #include "gu_crc32c.h" #include "gu_fnv.h" #include "gu_mmh3.h" #include "gu_spooky.h" #include "gu_hash.h" #include #include #include #include #include #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 #include //#include enum algs { CRC32sw, CRC32hw, FNV32, FNV64, FNV128, MMH32, MMH128, SPOOKYS, SPOOKY, MD5SSL, MD5CPP, FAST128, TABLE }; static int timer (const void* const buf, ssize_t const len, long long const loops, enum algs const type) { double begin, end; struct timeval tv; const char* alg = "undefined"; size_t volatile h; // this variable serves to prevent compiler from // optimizing out the calls gettimeofday (&tv, NULL); begin = (double)tv.tv_sec + 1.e-6 * tv.tv_usec; long long i; #ifdef EXTERNAL_LOOP #define EXTERNAL_LOOP_BEGIN for (i = 0; i < loops; i++) { #define EXTERNAL_LOOP_END } #define INTERNAL_LOOP_BEGIN #define INTERNAL_LOOP_END #else #define EXTERNAL_LOOP_BEGIN #define EXTERNAL_LOOP_END #define INTERNAL_LOOP_BEGIN for (i = 0; i < loops; i++) { #define INTERNAL_LOOP_END } #endif EXTERNAL_LOOP_BEGIN switch (type) { case CRC32sw: case CRC32hw: { if (CRC32sw == type) alg = "crc32sw"; else alg = "crc32hw"; INTERNAL_LOOP_BEGIN // gu_crc32c_t crc = GU_CRC32C_INIT; h = gu_crc32c (buf, len); // h = hash; INTERNAL_LOOP_END break; } case FNV32: { alg = "fnv32a"; INTERNAL_LOOP_BEGIN uint32_t hash = GU_FNV32_SEED; gu_fnv32a_internal (buf, len, &hash); h = hash; INTERNAL_LOOP_END break; } case FNV64: { alg = "fnv64a"; INTERNAL_LOOP_BEGIN uint64_t hash = GU_FNV64_SEED;; gu_fnv64a_internal (buf, len, &hash); h = hash; INTERNAL_LOOP_END break; } case FNV128: { alg = "fnv128"; INTERNAL_LOOP_BEGIN gu_uint128_t hash = GU_FNV128_SEED; gu_fnv128a_internal (buf, len, &hash); #if defined(__SIZEOF_INT128__) h = hash; #else h = hash.u32[GU_32LO]; #endif INTERNAL_LOOP_END break; } case MMH32: { alg = "mmh32"; INTERNAL_LOOP_BEGIN h = gu_mmh32 (buf, len); INTERNAL_LOOP_END break; } case MMH128: { alg = "mmh128"; INTERNAL_LOOP_BEGIN gu_uint128_t hash; gu_mmh128 (buf, len, &hash); #if defined(__SIZEOF_INT128__) h = hash; #else h = hash.u32[GU_32LO]; #endif INTERNAL_LOOP_END break; } case SPOOKYS: { alg = "SpookyS"; INTERNAL_LOOP_BEGIN uint64_t hash[2]; gu_spooky_short (buf, len, hash); h = hash[0]; INTERNAL_LOOP_END break; } case SPOOKY: { alg = "Spooky"; INTERNAL_LOOP_BEGIN uint64_t hash[2]; gu_spooky_inline (buf, len, hash); h = hash[0]; INTERNAL_LOOP_END break; } case MD5SSL: { alg = "md5ssl"; INTERNAL_LOOP_BEGIN unsigned char md[MD5_DIGEST_LENGTH]; MD5 ((const unsigned char*)buf, len, md); INTERNAL_LOOP_END break; } case MD5CPP: { alg = "md5cpp"; INTERNAL_LOOP_BEGIN unsigned char md[16]; CryptoPP::Weak::MD5().CalculateDigest(md, (const byte*)buf, len); INTERNAL_LOOP_END break; } case FAST128: { alg = "fast128"; INTERNAL_LOOP_BEGIN uint64_t hash[2]; gu_fast_hash128 (buf, len, hash); h = hash[0]; INTERNAL_LOOP_END break; } case TABLE: { alg = "table"; INTERNAL_LOOP_BEGIN h = gu_table_hash (buf, len); INTERNAL_LOOP_END break; } } EXTERNAL_LOOP_END gettimeofday (&tv, NULL); end = (double)tv.tv_sec + 1.e-6 * tv.tv_usec; end -= begin; return printf ("%s: %lld loops, %6.3f seconds, %8.3f Mb/sec%s\n", alg, loops, end, (double)(loops * len)/end/1024/1024, h ? "" : " "); } int main (int argc, char* argv[]) { ssize_t buf_size = (1<<20); // 1Mb long long loops = 10000; if (argc > 1) buf_size = strtoll (argv[1], NULL, 10); if (argc > 2) loops = strtoll (argv[2], NULL, 10); /* initialization of data buffer */ ssize_t buf_size_int = buf_size / sizeof(int) + 1; int* buf = (int*) malloc (buf_size_int * sizeof(int)); if (!buf) return ENOMEM; while (buf_size_int) buf[--buf_size_int] = rand(); timer (buf, buf_size, loops, CRC32sw); CRC32CFunctionPtr const old = gu_crc32c_func; gu_crc32c_configure(); if (old != gu_crc32c_func) timer(buf, buf_size, loops, CRC32hw); timer (buf, buf_size, loops, FNV32); timer (buf, buf_size, loops, FNV64); timer (buf, buf_size, loops, FNV128); timer (buf, buf_size, loops, MMH32); timer (buf, buf_size, loops, MMH128); // timer (buf, buf_size, loops, SPOOKYS); timer (buf, buf_size, loops, SPOOKY); // timer (buf, buf_size, loops, MD5SSL); // timer (buf, buf_size, loops, MD5CPP); timer (buf, buf_size, loops, FAST128); timer (buf, buf_size, loops, TABLE); return 0; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_buf.h0000644000175000017500000000051513136555240024302 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy */ /** * @file generic buffer declaration * * $Id$ */ #ifndef _gu_buf_h_ #define _gu_buf_h_ #include "gu_types.h" #ifdef __cplusplus extern "C" { #endif struct gu_buf { const void* ptr; ssize_t size; }; #ifdef __cplusplus } #endif #endif /* _gu_buf_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_errno.h0000644000175000017500000000131313136555240024650 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #ifndef GU_ERRNO_H #define GU_ERRNO_H #include #if defined(__APPLE__) || defined(__FreeBSD__) # define GU_ELAST ELAST #else /* must be high enough to not collide with system errnos but lower than 256 */ # define GU_ELAST 200 #endif #ifndef EBADFD # define EBADFD (GU_ELAST+1) #endif #ifndef EREMCHG # define EREMCHG (GU_ELAST+2) #endif #ifndef ENOTUNIQ # define ENOTUNIQ (GU_ELAST+3) #endif #ifndef ERESTART # define ERESTART (GU_ELAST+4) #endif #ifndef ENOTRECOVERABLE # define ENOTRECOVERABLE (GU_ELAST+5) #endif #ifndef ENODATA # define ENODATA (GU_ELAST+6) #endif #endif /* GU_STR_H */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_convert.hpp0000644000175000017500000000675313136555240025560 0ustar jenkinsjenkins// Copyright (C) 2009 Codership Oy /** * @file Routines for safe integer conversion * * $Id$ */ #ifndef _gu_convert_hpp_ #define _gu_convert_hpp_ #include "gu_macros.h" #include "gu_throw.hpp" #include namespace gu { /*! * Converts from type FROM to type TO with range checking. * Generic template is for the case sizeof(FROM) > sizeof(TO). * * @param from value to convert * @param to destination (provides type TO for template instantiation) * @return value cast to TO */ template inline TO convert (const FROM& from, const TO& to) { if (gu_unlikely(from > std::numeric_limits::max() || from < std::numeric_limits::min())) { // @todo: figure out how to print type name without RTTI gu_throw_error (ERANGE) << from << " is unrepresentable with " << (std::numeric_limits::is_signed ? "signed" : "unsigned") << " " << sizeof(TO) << " bytes."; } return static_cast(from); } /* Specialized templates are for signed conversion */ template <> inline long long convert (const unsigned long long& from, const long long& to) { if (gu_unlikely(from > static_cast (std::numeric_limits::max()))) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'long long'"; } return static_cast(from); } template <> inline unsigned long long convert (const long long& from, const unsigned long long& to) { if (gu_unlikely(from < 0)) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'unsigned long long'"; } return static_cast(from); } template <> inline long convert (const unsigned long& from, const long& to) { if (gu_unlikely(from > static_cast (std::numeric_limits::max()))) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'long'"; } return static_cast(from); } template <> inline unsigned long convert (const long& from, const unsigned long& to) { if (gu_unlikely(from < 0)) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'unsigned long'"; } return static_cast(from); } template <> inline int convert (const unsigned int& from, const int& to) { if (gu_unlikely(from > static_cast (std::numeric_limits::max()))) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'long'"; } return static_cast(from); } template <> inline unsigned int convert (const int& from, const unsigned int& to) { if (gu_unlikely(from < 0)) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'unsigned long'"; } return static_cast(from); } } #endif /* _gu_convert_hpp_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_vector.hpp0000644000175000017500000001051513136555240025371 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /*! * @file implementation of STL vector functionality "on the stack", that is * with initial buffer for allocations reserved inside the object: * * gu::Vector v; * v().resize(5); // uses internal buffer (in this case on the stack) * v().resize(20); // overflows into heap * * In many cases, when the number of elements in a vector is predictably low or * even known exactly, this will save us from going to heap just to allocate * few elements. * * Rather than manually rewriting all std::vector methods, we return * a reference to std::vector object via operator(). operator[] is also * rewritten to provide the familiar v[i] interface. * * $Id$ */ #ifndef _GU_VECTOR_HPP_ #define _GU_VECTOR_HPP_ #include "gu_reserved_container.hpp" #include namespace gu { /* gu::VectorBase is an interface to generalize gu::Vector template over * capacity so that it is possible to pass gu::Vector objects * by reference to gu::VectorBase */ template class VectorBase { public: typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef typename ReservedAllocator::size_type size_type; virtual reference operator[] (size_type i) = 0; virtual const_reference operator[] (size_type i) const = 0; virtual size_type size () const = 0; virtual void reserve (size_type n) = 0; virtual void resize (size_type n, value_type val = value_type()) = 0; // Now iterators, which I have no time for ATM. Leaving unfinished. protected: VectorBase() {} virtual ~VectorBase() {} }; /* a base class to be used as a member of other classes */ template ::size_type capacity> class Vector { public: Vector() : rv_() {} Vector(const Vector& other) : rv_() { rv_().assign(other().begin(), other().end()); } Vector& operator= (Vector other) { using namespace std; swap(other); return *this; } typedef ReservedAllocator Allocator; typedef std::vector ContainerType; ContainerType& operator() () { return rv_.container(); } const ContainerType& operator() () const { return rv_.container(); } ContainerType* operator-> () { return rv_.operator->(); } const ContainerType* operator-> () const { return rv_.operator->(); } typedef typename VectorBase::size_type size_type; T& operator[] (size_type i) { return operator()()[i]; } const T& operator[] (size_type i) const { return operator()()[i]; } size_type size () const { return operator()().size(); } void reserve (size_type n) { operator()().reserve(n); } typedef typename VectorBase::value_type value_type; void resize (size_type n, value_type val = value_type()) { operator()().resize(n, val); } bool in_heap() const // for testing { return (rv_.reserved_buffer() != &rv_.container()[0]); } private: ReservedContainer rv_; }; /* class Vector*/ /* Vector class derived from VectorBase - to be passed as a parameter */ template ::size_type capacity> class VectorDerived : public VectorBase { public: typedef typename VectorBase::size_type size_type; typedef typename VectorBase::value_type value_type; typedef typename VectorBase::reference reference; typedef typename VectorBase::const_reference const_reference; VectorDerived() : VectorBase(), v_() {} template ::size_type C> VectorDerived(const Vector& other) : VectorBase(), v_() { v_().assign(other().begin(), other().end()); } reference operator[] (size_type i) { return v_[i]; } const_reference operator[] (size_type i) const { return v_[i]; } size_type size () const { return v_.size(); } void reserve (size_type n) { v_.reserve(); } void resize (size_type n, value_type val = value_type()) { v_.resize(); } private: Vector v_; }; /* class VectorDerived */ } /* namespace gu */ #endif /* _GU_VECTOR_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_regex.cpp0000644000175000017500000000225213136555240025173 0ustar jenkinsjenkins// Copyright (C) 2009 Codership Oy /** * @file Regular expressions parser based on POSIX regex functions in * * $Id$ */ #include "gu_utils.hpp" #include "gu_regex.hpp" namespace gu { using std::string; using std::vector; string RegEx::strerror (int rc) const { char buf[128]; regerror(rc, ®ex, buf, sizeof(buf)); return string (buf); } static inline RegEx::Match regmatch2Match (const string& str, const regmatch_t& rm) { if (rm.rm_so == -1) return RegEx::Match(); return RegEx::Match (str.substr(rm.rm_so, rm.rm_eo - rm.rm_so)); } vector RegEx::match (const string& str, size_t num) const { vector ret; int rc; VLA matches(num); if ((rc = regexec(®ex, str.c_str(), num, &matches, 0))) { gu_throw_error (EINVAL) << "regexec(" << str << "): " << strerror(rc); } for (size_t i = 0; i < num; ++i) { ret.push_back (regmatch2Match (str, matches[i])); } return ret; } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_rand.c0000644000175000017500000000212413136555240024443 0ustar jenkinsjenkins// Copyright (C) 2013-2015 Codership Oy /** * @file routines to generate "random" seeds for RNGs by collecting some easy * entropy. * * gu_rand_seed_long() goes for srand48() * * gu_rand_seed_int() goes for srand() and rand_r() * * $Id$ */ #include "gu_rand.h" #include "gu_hash.h" /*! Structure to hold entropy data. * Should be at least 20 bytes on 32-bit systems and 28 bytes on 64-bit */ /* Packed to avoid uninitialized data warnings when passed to hash */ struct gu_rse { long long time; const void* heap_ptr; const void* stack_ptr; long pid; }__attribute__((packed)); typedef struct gu_rse gu_rse_t; long int gu_rand_seed_long (long long time, const void* heap_ptr, pid_t pid) { gu_rse_t rse = { time, heap_ptr, &time, pid }; return gu_fast_hash64_medium (&rse, sizeof(rse)); } #if GU_WORDSIZE == 32 unsigned int gu_rand_seed_int (long long time, const void* heap_ptr, pid_t pid) { gu_rse_t rse = { time, heap_ptr, &time, pid }; return gu_fast_hash32_short (&rse, sizeof(rse)); } #endif /* GU_WORDSIZE == 32 */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_vec16.h0000644000175000017500000000352713136555240024460 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @file 16-byte "vector" type and operations - mostly for checksums/hashes * * $Id$ */ #ifndef _gu_vec16_h_ #define _gu_vec16_h_ #include "gu_macros.h" #include "gu_byteswap.h" #include #include #include /* bool */ #ifdef __cplusplus extern "C" { #endif /* this type will generate SIMD instructions where possible: good for XORing */ typedef unsigned long gu_vec16__ __attribute__ ((vector_size (16))); typedef union gu_vec16 { gu_vec16__ vec_; uint64_t int_[2]; /* for equality we better use scalar type * since we need scalar return */ } gu_vec16_t; static GU_FORCE_INLINE gu_vec16_t gu_vec16_from_byte (unsigned char b) { gu_vec16_t ret; memset (&ret, b, sizeof(ret)); return ret; } static GU_FORCE_INLINE gu_vec16_t gu_vec16_from_ptr (const void* ptr) { gu_vec16_t ret; memcpy (&ret, ptr, sizeof(ret)); return ret; } static GU_FORCE_INLINE gu_vec16_t gu_vec16_xor (gu_vec16_t l, gu_vec16_t r) { gu_vec16_t ret; ret.vec_ = (l.vec_ ^ r.vec_); return ret; } static GU_FORCE_INLINE bool gu_vec16_neq (gu_vec16_t l, gu_vec16_t r) { return (l.int_[0] != r.int_[0] || l.int_[1] != r.int_[1]); } static GU_FORCE_INLINE bool gu_vec16_eq (gu_vec16_t l, gu_vec16_t r) { return !(gu_vec16_neq (l, r)); } static GU_FORCE_INLINE gu_vec16_t gu_vec16_bswap (gu_vec16_t x) { gu_vec16_t ret; ret.int_[0] = gu_bswap64 (x.int_[1]); ret.int_[1] = gu_bswap64 (x.int_[0]); return ret; } #ifdef __cplusplus } static GU_FORCE_INLINE gu_vec16_t operator^ (const gu_vec16_t& l, const gu_vec16_t& r) { return (gu_vec16_xor (l, r)); } static GU_FORCE_INLINE bool operator== (const gu_vec16_t& l, const gu_vec16_t& r) { return (gu_vec16_eq (l, r)); } #endif #endif /* _gu_vec16_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_prodcons.hpp0000644000175000017500000001021413136555240025712 0ustar jenkinsjenkins/* * Copyright (C) 2008 Codership Oy * * $Id:$ */ /*! * @file gu_prodcons.hpp Synchronous producer/consumer interface */ #include "gu_lock.hpp" // For byte_t #include "gu_buffer.hpp" /* Forward declarations */ namespace gu { namespace prodcons { class MessageData; class Message; class MessageQueue; class Producer; class Consumer; } } class gu::prodcons::MessageData { public: virtual ~MessageData() { } }; /*! * @brief Message class for Producer/Consumer communication */ class gu::prodcons::Message { Producer* producer; /*! Producer associated to this message */ int val; /*! Integer value (command/errno) */ const MessageData* data; public: /*! * @brief Constructor * * @param prod_ Producer associated to the message * @param data_ Message data * @param val_ Integer value associated to the message */ Message(Producer* prod_ = 0, const MessageData* data_ = 0, int val_ = -1) : producer(prod_), val(val_), data(data_) { } Message(const Message& msg) : producer(msg.producer), val(msg.val), data(msg.data) { } Message& operator=(const Message& msg) { producer = msg.producer; val = msg.val; data = msg.data; return *this; } /*! * @brief Get producer associated to the message * * @return Producer associated to the message */ Producer& get_producer() const { return *producer; } /*! * @brief Get data associated to the message * * @return Data associated to the message */ const MessageData* get_data() const { return data; } /*! * @brief Get int value associated to the message * * @return Int value associated to the message */ int get_val() const { return val; } }; /*! * @brief Producer interface */ class gu::prodcons::Producer { gu::Cond cond; /*! Condition variable */ Consumer& cons; /*! Consumer associated to this producer */ /*! * @brief Return reference to condition variable * * @return Reference to condition variable */ Cond& get_cond() { return cond; } friend class Consumer; public: /*! * @brief Consturctor * * @param cons_ Consumer associated to this producer */ Producer(Consumer& cons_) : cond(), cons(cons_) { } /*! * @brief Send message to the consumer and wait for response * * @param[in] msg Message to be sent to consumer * @param[out] ack Ack message returned by the Consumer, containing error code */ void send(const Message& msg, Message* ack); }; /*! * @brief Consumer interface */ class gu::prodcons::Consumer { Mutex mutex; /*! Mutex for internal locking */ MessageQueue* mque; /*! Message queue for producer messages */ MessageQueue* rque; /*! Message queue for ack messages */ Consumer(const Consumer&); void operator=(const Consumer&); protected: /*! * @brief Get the first message from the message queue * * Get the first message from the message queue. Note that * this method does not remove the first message from message queue. * * @return Next message from the message queue */ const Message* get_next_msg(); /*! * @brief Return ack message for the producer * * Return ack message for the producer. Note that this method * pops the first message from the message queue. * * @param msg Ack message corresponding the current head of mque */ void return_ack(const Message& msg); /*! * @brief Virtual method to notify consumer about queued message */ virtual void notify() = 0; public: /*! * @brief Default constructor */ Consumer(); /*! * @brief Default destructor */ virtual ~Consumer(); /*! * @brief Queue message and wait for ack * * @param[in] msg Message to be queued * @param[out] ack Ack returned by consumer */ void queue_and_wait(const Message& msg, Message* ack); }; percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_arch.h0000644000175000017500000000263713136555240024452 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /** * @file CPU architecture related functions/macros * * $Id$ */ #ifndef _gu_arch_h_ #define _gu_arch_h_ #if defined(HAVE_ENDIAN_H) # include #elif defined(HAVE_SYS_ENDIAN_H) /* FreeBSD */ # include #elif defined(HAVE_SYS_BYTEORDER_H) # include #elif defined(__APPLE__) # include #else # error "No byte order header file detected" #endif #if defined(__BYTE_ORDER) # if __BYTE_ORDER == __LITTLE_ENDIAN # define GU_LITTLE_ENDIAN # endif #elif defined(_BYTE_ORDER) /* FreeBSD */ # if _BYTE_ORDER == _LITTLE_ENDIAN # define GU_LITTLE_ENDIAN # endif #elif defined(__APPLE__) && defined(__DARWIN_BYTE_ORDER) # if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN # define GU_LITTLE_ENDIAN # endif #elif defined(__sun__) # if !defined(_BIG_ENDIAN) # define GU_LITTLE_ENDIAN # endif #else # error "Byte order not defined" #endif #if defined(__sun__) # if defined (_LP64) # define GU_WORDSIZE 64 # else # define GU_WORDSIZE 32 # endif #elif defined(__APPLE__) || defined(__FreeBSD__) # include # define GU_WORDSIZE __WORDSIZE #else # include # define GU_WORDSIZE __WORDSIZE #endif #if (GU_WORDSIZE != 32) && (GU_WORDSIZE != 64) # error "Unsupported wordsize" #endif /* I'm not aware of the platforms that don't, but still */ #define GU_ALLOW_UNALIGNED_READS 1 #endif /* _gu_arch_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_histogram.hpp0000644000175000017500000000107613136555240026066 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #ifndef _gu_histogram_hpp_ #define _gu_histogram_hpp_ #include #include namespace gu { class Histogram { public: Histogram(const std::string&); void insert(const double); void clear(); friend std::ostream& operator<<(std::ostream&, const Histogram&); std::string to_string() const; private: std::map cnt_; }; std::ostream& operator<<(std::ostream&, const Histogram&); } #endif // _gu_histogram_hpp_ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_crc.hpp0000644000175000017500000000131613136555240024635 0ustar jenkinsjenkins/* * Copyright (C) 2013 Codership Oy * * @file header for various CRC stuff * * $Id$ */ #ifndef GU_CRC_HPP #define GU_CRC_HPP #include "gu_crc32c.h" namespace gu { class CRC32C { public: CRC32C() : state_(GU_CRC32C_INIT) {} void append(const void* const data, size_t const size) { gu_crc32c_append (&state_, data, size); } uint32_t get() const { return gu_crc32c_get(state_); } uint32_t operator() () const { return get(); } static uint32_t digest(const void* const data, size_t const size) { return gu_crc32c(data, size); } private: gu_crc32c_t state_; }; /* class CRC32C */ } /* namespace gu */ #endif /* GU_CRC_HPP */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_init.h0000644000175000017500000000063213136555240024471 0ustar jenkinsjenkins/* * Copyright (C) 2013 Codership Oy * * $Id$ */ /*! @file Common initializer for various galerautils parts. Currently it is * logger and CRC32C implementation. */ #ifndef _GU_INIT_H_ #define _GU_INIT_H_ #if defined(__cplusplus) extern "C" { #endif #include "gu_log.h" extern void gu_init (gu_log_cb_t log_cb); #if defined(__cplusplus) } #endif #endif /* _GU_INIT_H_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_mmh3.c0000644000175000017500000000707613136555240024376 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /** * @file MurmurHash3 implementation * (slightly rewritten from the refrence C++ impl.) * * $Id$ */ #include "gu_mmh3.h" void gu_mmh3_32 (const void* const key, int const len, uint32_t const seed, void* const out) { uint32_t const res = _mmh32_seed (key, len, seed); *((uint32_t*)out) = gu_le32(res); } //----------------------------------------------------------------------------- #if 0 /* x86 variant is faulty and unsuitable for short keys, ignore */ void gu_mmh3_x86_128 (const void* key, const int len, const uint32_t seed, void* out) { const uint8_t* data = (const uint8_t*)key; const int nblocks = len >> 4; uint32_t h1 = seed; uint32_t h2 = seed; uint32_t h3 = seed; uint32_t h4 = seed; const uint32_t c1 = 0x239b961b; const uint32_t c2 = 0xab0e9789; const uint32_t c3 = 0x38b34ae5; const uint32_t c4 = 0xa1e38b93; //---------- // body const uint32_t* blocks = (const uint32_t*)(data + (nblocks << 4)); int i; for(i = -nblocks; i; i++) { uint32_t k1 = gu_le32(blocks[(i << 2) + 0]); uint32_t k2 = gu_le32(blocks[(i << 2) + 1]); uint32_t k3 = gu_le32(blocks[(i << 2) + 2]); uint32_t k4 = gu_le32(blocks[(i << 2) + 3]); k1 *= c1; k1 = GU_ROTL32(k1,15); k1 *= c2; h1 ^= k1; h1 = GU_ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b; k2 *= c2; k2 = GU_ROTL32(k2,16); k2 *= c3; h2 ^= k2; h2 = GU_ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747; k3 *= c3; k3 = GU_ROTL32(k3,17); k3 *= c4; h3 ^= k3; h3 = GU_ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35; k4 *= c4; k4 = GU_ROTL32(k4,18); k4 *= c1; h4 ^= k4; h4 = GU_ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17; } //---------- // tail const uint8_t * tail = (const uint8_t*)(blocks); uint32_t k1 = 0; uint32_t k2 = 0; uint32_t k3 = 0; uint32_t k4 = 0; switch(len & 15) { case 15: k4 ^= tail[14] << 16; case 14: k4 ^= tail[13] << 8; case 13: k4 ^= tail[12] << 0; k4 *= c4; k4 = GU_ROTL32(k4,18); k4 *= c1; h4 ^= k4; case 12: k3 ^= tail[11] << 24; case 11: k3 ^= tail[10] << 16; case 10: k3 ^= tail[ 9] << 8; case 9: k3 ^= tail[ 8] << 0; k3 *= c3; k3 = GU_ROTL32(k3,17); k3 *= c4; h3 ^= k3; case 8: k2 ^= tail[ 7] << 24; case 7: k2 ^= tail[ 6] << 16; case 6: k2 ^= tail[ 5] << 8; case 5: k2 ^= tail[ 4] << 0; k2 *= c2; k2 = GU_ROTL32(k2,16); k2 *= c3; h2 ^= k2; case 4: k1 ^= tail[ 3] << 24; case 3: k1 ^= tail[ 2] << 16; case 2: k1 ^= tail[ 1] << 8; case 1: k1 ^= tail[ 0] << 0; k1 *= c1; k1 = GU_ROTL32(k1,15); k1 *= c2; h1 ^= k1; }; //---------- // finalization h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len; h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; h1 = _mmh3_fmix32(h1); h2 = _mmh3_fmix32(h2); h3 = _mmh3_fmix32(h3); h4 = _mmh3_fmix32(h4); h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; ((uint32_t*)out)[0] = gu_le32(h1); ((uint32_t*)out)[1] = gu_le32(h2); ((uint32_t*)out)[2] = gu_le32(h3); ((uint32_t*)out)[3] = gu_le32(h4); } #endif /* 0 */ //----------------------------------------------------------------------------- void gu_mmh3_x64_128 (const void* key, int len, uint32_t const seed, void* const out) { uint64_t* const res = (uint64_t*)out; _mmh3_128_seed (key, len, seed, seed, res); res[0] = gu_le64(res[0]); res[1] = gu_le64(res[1]); } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_backtrace.h0000644000175000017500000000141113136555240025441 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy #ifndef GU_BACKTRACE_H #define GU_BACKTRACE_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /*! * Get current backtrace. Return buffer will contain backtrace symbols if * available. NULL pointer is returned if getting backtrace is not supported * on current platform. Maximum number of frames in backtrace is passed * in size parameter, number of frames in returned backtrace is assigned * in size parameter on return. * * @param size Pointer to integer containing maximum number of frames * in backtrace * * @return Allocated array of strings containing backtrace symbols */ char** gu_backtrace(int* size); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* GU_BACKTRACE_H */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_lock_step.c0000644000175000017500000000671113136555240025510 0ustar jenkinsjenkins/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /* * Universally Unique IDentifier. RFC 4122. * Time-based implementation. * */ #include // abort() #include // error codes #include #include #include // strerror() #include "gu_log.h" #include "gu_assert.h" #include "gu_time.h" #include "gu_lock_step.h" void gu_lock_step_init (gu_lock_step_t* ls) { gu_mutex_init (&ls->mtx, NULL); gu_cond_init (&ls->cond, NULL); ls->wait = 0; ls->cont = 0; ls->enabled = false; } void gu_lock_step_destroy (gu_lock_step_t* ls) { // this is not really fool-proof, but that's not for fools to use while (gu_lock_step_cont(ls, 10)) {}; gu_cond_destroy (&ls->cond); gu_mutex_destroy (&ls->mtx); assert (0 == ls->wait); } void gu_lock_step_enable (gu_lock_step_t* ls, bool enable) { if (!gu_mutex_lock (&ls->mtx)) { ls->enabled = enable; gu_mutex_unlock (&ls->mtx); } else { gu_fatal ("Mutex lock failed"); assert (0); abort(); } } void gu_lock_step_wait (gu_lock_step_t* ls) { if (!gu_mutex_lock (&ls->mtx)) { if (ls->enabled) { if (!ls->cont) { // wait for signal ls->wait++; gu_cond_wait (&ls->cond, &ls->mtx); } else { // signal to signaller gu_cond_signal (&ls->cond); ls->cont--; } } gu_mutex_unlock (&ls->mtx); } else { gu_fatal ("Mutex lock failed"); assert (0); abort(); } } /* returns how many waiters are there */ long gu_lock_step_cont (gu_lock_step_t* ls, long timeout_ms) { long ret = -1; if (!gu_mutex_lock (&ls->mtx)) { if (ls->enabled) { if (ls->wait > 0) { // somebody's waiting ret = ls->wait; gu_cond_signal (&ls->cond); ls->wait--; } else if (timeout_ms > 0) { // wait for waiter // what a royal mess with times! Why timeval exists? struct timeval now; struct timespec timeout; long err; gettimeofday (&now, NULL); gu_timeval_add (&now, timeout_ms * 0.001); timeout.tv_sec = now.tv_sec; timeout.tv_nsec = now.tv_usec * 1000; ls->cont++; do { err = gu_cond_timedwait (&ls->cond, &ls->mtx, &timeout); } while (EINTR == err); assert ((0 == err) || (ETIMEDOUT == err && ls->cont > 0)); ret = (0 == err); // successful rendezvous with waiter ls->cont -= (0 != err); // self-decrement in case of error } else if (timeout_ms < 0) { // wait forever long err; ls->cont++; err = gu_cond_wait (&ls->cond, &ls->mtx); ret = (0 == err); // successful rendezvous with waiter ls->cont -= (0 != err); // self-decrement in case of error } else { // don't wait ret = 0; } } gu_mutex_unlock (&ls->mtx); } else { gu_fatal ("Mutex lock failed"); assert (0); abort(); } return ret; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_mutex.hpp0000644000175000017500000000364613136555240025240 0ustar jenkinsjenkins/* * Copyright (C) 2009-2017 Codership Oy * */ #ifndef __GU_MUTEX__ #define __GU_MUTEX__ #include "gu_macros.h" #include "gu_threads.h" #include "gu_throw.hpp" #include #include namespace gu { class Mutex { public: Mutex () : value() { gu_mutex_init (&value, NULL); // always succeeds } ~Mutex () { int err = gu_mutex_destroy (&value); if (gu_unlikely(err != 0)) { gu_throw_error (err) << "gu_mutex_destroy()"; } } int lock() const { return gu_mutex_lock(&value); } int unlock() const { return gu_mutex_unlock(&value); } gu_mutex_t& impl() const { return value; } #ifdef GU_DEBUG_MUTEX bool locked() const { return gu_mutex_locked(&value); } bool owned() const { return gu_mutex_owned(&value); } #endif /* GU_DEBUG_MUTEX */ protected: gu_mutex_t mutable value; private: Mutex (const Mutex&); Mutex& operator= (const Mutex&); friend class Lock; }; class RecursiveMutex { public: RecursiveMutex() : mutex_() { pthread_mutexattr_t mattr; pthread_mutexattr_init(&mattr); pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mutex_, &mattr); pthread_mutexattr_destroy(&mattr); } ~RecursiveMutex() { pthread_mutex_destroy(&mutex_); } void lock() { if (pthread_mutex_lock(&mutex_)) gu_throw_fatal; } void unlock() { if (pthread_mutex_unlock(&mutex_)) gu_throw_fatal; } private: RecursiveMutex(const RecursiveMutex&); void operator=(const RecursiveMutex&); pthread_mutex_t mutex_; }; } #endif /* __GU_MUTEX__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_hash.h0000644000175000017500000001007313136555240024451 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /** * @file Defines 3 families of standard Galera hash methods * * 1) gu_hash - a general use universal hash: 128, 64 and 32-bit variants. * * 2) gu_fast_hash - optimized for 64-bit Intel CPUs, limited to whole message * only, also comes in 128, 64 and 32-bit flavors. * 3) gu_table_hash - possibly even faster, platform-optimized, globally * inconsistent hash functions to be used only in local hash * tables. Only size_t variants defined. * * 128-bit result is returned through void* parameter as a byte array in * canonical order. * 64/32-bit results are returned as uint64_t/uint32_t integers and thus in host * byte order (require conversion to network/Galera byte order for serialization). * * $Id$ */ #ifndef _gu_hash_h_ #define _gu_hash_h_ #ifdef __cplusplus extern "C" { #endif #include "gu_fnv.h" #include "gu_mmh3.h" #include "gu_spooky.h" /* * General purpose globally consistent _fast_ hash, if in doubt use that. */ /* This is to hash multipart message */ #define gu_hash_t gu_mmh128_ctx_t #define gu_hash_init(_hash) gu_mmh128_init(_hash) #define gu_hash_append(_hash, _msg, _len) gu_mmh128_append(_hash, _msg, _len) #define gu_hash_get128(_hash, _res) gu_mmh128_get(_hash, _res) #define gu_hash_get64(_hash) gu_mmh128_get64(_hash) #define gu_hash_get32(_hash) gu_mmh128_get32(_hash) /* This is to hash a whole message in one go */ #define gu_hash128(_msg, _len, _res) gu_mmh128(_msg, _len, _res) #define gu_hash64(_msg, _len) gu_mmh128_64(_msg, _len) #define gu_hash32(_msg, _len) gu_mmh128_32(_msg, _len) /* * Hash optimized for speed, can't do multipart messages, but should still * be usable as global identifier */ #define GU_SHORT64_LIMIT 16 #define GU_MEDIUM64_LIMIT 512 static GU_INLINE void gu_fast_hash128 (const void* const msg, size_t const len, void* const res) { if (len < GU_MEDIUM64_LIMIT) { gu_mmh128 (msg, len, res); } else { gu_spooky128 (msg, len, res); } } static GU_FORCE_INLINE uint64_t gu_fast_hash64_short (const void* const msg, size_t const len) { uint64_t res = GU_FNV64_SEED; gu_fnv64a_internal (msg, len, &res); /* mix to improve avalanche effect */ res *= GU_ROTL64(res, 56); return res ^ GU_ROTL64(res, 43); } #define gu_fast_hash64_medium gu_mmh128_64 #define gu_fast_hash64_long gu_spooky64 static GU_INLINE uint64_t gu_fast_hash64 (const void* const msg, size_t const len) { if (len < GU_SHORT64_LIMIT) { return gu_fast_hash64_short (msg, len); } else if (len < GU_MEDIUM64_LIMIT) { return gu_fast_hash64_medium (msg, len); } else { return gu_fast_hash64_long (msg, len); } } #define gu_fast_hash32_short gu_mmh32 #define gu_fast_hash32_medium gu_mmh128_32 #define gu_fast_hash32_long gu_spooky32 #define GU_SHORT32_LIMIT 32 #define GU_MEDIUM32_LIMIT 512 static GU_INLINE uint32_t gu_fast_hash32 (const void* const msg, size_t const len) { if (len < GU_SHORT32_LIMIT) { return gu_fast_hash32_short (msg, len); } else if (len < GU_MEDIUM32_LIMIT) { return gu_fast_hash32_medium (msg, len); } else { return gu_fast_hash32_long (msg, len); } } /* * Platform-optimized hashes only for local hash tables, don't produce globally * consistent results. No 128-bit version for obvious reasons. * * Resulting gu_table_hash() will be the fastest hash function returning size_t */ #if GU_WORDSIZE == 64 #define gu_table_hash gu_fast_hash64 /* size_t is normally 64-bit here */ #elif GU_WORDSIZE == 32 /* on 32-bit platform MurmurHash32 is only insignificantly slower than FNV32a * on messages < 10 bytes but produces far better hash. */ #define gu_table_hash gu_mmh32 /* size_t is normally 32-bit here */ #else /* GU_WORDSIZE neither 64 nor 32 bits */ # error Unsupported wordsize! #endif #ifdef __cplusplus } #endif #endif /* _gu_hash_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_barrier.hpp0000644000175000017500000000217213136555240025515 0ustar jenkinsjenkins// // Copyright (C) 2016-2017 Codership Oy // #ifndef GU_BARRIER #define GU_BARRIER #include #include "gu_throw.hpp" namespace gu { class Barrier { public: Barrier(unsigned count) : barrier_() { int err; if ((err = gu_barrier_init(&barrier_, 0, count)) != 0) { gu_throw_error(err) << "Barrier init failed"; } } ~Barrier() { int err; if ((err = gu_barrier_destroy(&barrier_)) != 0) { assert(0); log_warn << "Barrier destroy failed: " << ::strerror(err); } } void wait() { int err(gu_barrier_wait(&barrier_)); if (err != 0 && err != GU_BARRIER_SERIAL_THREAD) { gu_throw_error(err) << "Barrier wait failed"; } } private: // Non-copyable Barrier(const Barrier&); Barrier& operator=(const Barrier&); gu_barrier_t barrier_; }; } #endif // GU_BARRIER percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_types.h0000644000175000017500000000102113136555240024663 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @file Location of some "standard" types definitions * * $Id$ */ #ifndef _gu_types_h_ #define _gu_types_h_ #define _FILE_OFFSET_BITS 64 #include /* intXX_t and friends */ #include /* bool */ #include /* ssize_t */ #include /* ptrdiff_t */ #include /* off_t */ #ifdef __cplusplus extern "C" { #endif typedef unsigned char gu_byte_t; #ifdef __cplusplus } #endif #endif /* _gu_types_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_logger.hpp0000644000175000017500000000661313136555240025352 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy * * This code is based on an excellent article at Dr.Dobb's: * http://www.ddj.com/cpp/201804215?pgno=1 * * It looks ugly because it has to integrate with C logger - * in order to produce identical output */ #ifndef __GU_LOGGER__ #define __GU_LOGGER__ #include extern "C" { #include "gu_log.h" #include "gu_conf.h" } namespace gu { // some portability stuff #ifdef _gu_log_h_ enum LogLevel { LOG_FATAL = GU_LOG_FATAL, LOG_ERROR = GU_LOG_ERROR, LOG_WARN = GU_LOG_WARN, LOG_INFO = GU_LOG_INFO, LOG_DEBUG = GU_LOG_DEBUG, LOG_MAX }; typedef gu_log_cb_t LogCallback; #else enum LogLevel { LOG_FATAL, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG, LOG_MAX }; typedef void (*LogCallback) (int, const char*); #endif class Logger { private: Logger(const Logger&); Logger& operator =(const Logger&); void prepare_default (); const LogLevel level; #ifndef _gu_log_h_ static LogLevel max_level; static bool do_timestamp; static LogCallback logger; static void default_logger (int, const char*); #else #define max_level gu_log_max_level #define logger gu_log_cb #define default_logger gu_log_cb_default #endif protected: std::ostringstream os; public: Logger(LogLevel _level = LOG_INFO) : level (_level), os () {} virtual ~Logger() { logger (level, os.str().c_str()); } std::ostringstream& get(const char* file, const char* func, int line) { if (default_logger == logger) { prepare_default(); // prefix with timestamp and log level } /* provide file:func():line info only when debug logging is on */ if (static_cast(LOG_DEBUG) == static_cast(max_level)) { os << file << ':' << func << "():" << line << ": "; } return os; } static bool no_log (LogLevel lvl) { return (static_cast(lvl) > static_cast(max_level)); } static void set_debug_filter(const std::string&); static bool no_debug(const std::string&, const std::string&, const int); #ifndef _gu_log_h_ static void enable_tstamp (bool); static void enable_debug (bool); static void set_logger (LogCallback); #endif }; #define GU_LOG_CPP(level) \ if (gu::Logger::no_log(level)) {} \ else gu::Logger(level).get(__FILE__, __FUNCTION__, __LINE__) // USAGE: LOG(level) << item_1 << item_2 << ... << item_n; #define log_fatal GU_LOG_CPP(gu::LOG_FATAL) #define log_error GU_LOG_CPP(gu::LOG_ERROR) #define log_warn GU_LOG_CPP(gu::LOG_WARN) #define log_info GU_LOG_CPP(gu::LOG_INFO) #define log_debug \ if (gu::Logger::no_debug(__FILE__, __FUNCTION__, __LINE__)) {} else \ GU_LOG_CPP(gu::LOG_DEBUG) } #endif // __GU_LOGGER__ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_mmap.cpp0000644000175000017500000000676113136555240025024 0ustar jenkinsjenkins/* * Copyright (C) 2009-2016 Codership Oy * * $Id$ */ #include "gu_mmap.hpp" #include "gu_logger.hpp" #include "gu_throw.hpp" #include "gu_macros.hpp" #include "gu_limits.h" // GU_PAGE_SIZE #include #include #include #include #include #include #include "gu_limits.h" #if defined(__FreeBSD__) && defined(MAP_NORESERVE) /* FreeBSD has never implemented this flags and will deprecate it. */ #undef MAP_NORESERVE #endif #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 #endif // to avoid -Wold-style-cast extern "C" { static const void* const GU_MAP_FAILED = MAP_FAILED; } namespace gu { MMap::MMap (const FileDescriptor& fd, bool const sequential) : size (fd.size()), ptr (mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, fd.get(), 0)), mapped (ptr != GU_MAP_FAILED) { if (!mapped) { gu_throw_error(errno) << "mmap() on '" << fd.name() << "' failed"; } #if defined(MADV_DONTFORK) if (posix_madvise (ptr, size, MADV_DONTFORK)) { # define MMAP_INHERIT_OPTION "MADV_DONTFORK" #elif defined(__FreeBSD__) if (minherit (ptr, size, INHERIT_NONE)) { # define MMAP_INHERIT_OPTION "INHERIT_NONE" #endif #if defined(MMAP_INHERIT_OPTION) int const err(errno); log_warn << "Failed to set " MMAP_INHERIT_OPTION " on " << fd.name() << ": " << err << " (" << strerror(err) << ")"; } #endif /* benefits are questionable */ if (sequential && posix_madvise (ptr, size, MADV_SEQUENTIAL)) { int const err(errno); log_warn << "Failed to set MADV_SEQUENTIAL on " << fd.name() << ": " << err << " (" << strerror(err) << ")"; } log_debug << "Memory mapped: " << ptr << " (" << size << " bytes)"; } void MMap::dont_need() const { if (posix_madvise(reinterpret_cast(ptr), size, MADV_DONTNEED)) { log_warn << "Failed to set MADV_DONTNEED on " << ptr << ": " << errno << " (" << strerror(errno) << ')'; } } void MMap::sync(void* const addr, size_t const length) const { /* libc msync() only accepts addresses multiple of page size, * rounding down */ static uint64_t const PAGE_SIZE_MASK(~(GU_PAGE_SIZE - 1)); uint8_t* const sync_addr(reinterpret_cast (uint64_t(addr) & PAGE_SIZE_MASK)); size_t const sync_length (length + (static_cast(addr) - sync_addr)); if (::msync(sync_addr, sync_length, MS_SYNC) < 0) { gu_throw_error(errno) << "msync(" << sync_addr << ", " << sync_length << ") failed"; } } void MMap::sync () const { log_info << "Flushing memory map to disk..."; sync(ptr, size); } void MMap::unmap () { if (munmap (ptr, size) < 0) { gu_throw_error(errno) << "munmap(" << ptr << ", " << size << ") failed"; } mapped = false; log_debug << "Memory unmapped: " << ptr << " (" << size <<" bytes)"; } MMap::~MMap () { if (mapped) { try { unmap(); } catch (Exception& e) { log_error << e.what(); } } } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_fifo.c0000644000175000017500000003543213136555240024452 0ustar jenkinsjenkins/* * Copyright (C) 2008-2017 Codership Oy * * Queue (FIFO) class implementation * * The driving idea behind this class is avoiding mallocs * at all costs on one hand, on the other - make it almost * as infinite as an ordinary linked list. FIFO properties * help achieving that. * * When needed this FIFO can be made very big, holding * millions or even billions of items while taking up * minimum space when there are few items in the queue. */ #define _DEFAULT_SOURCE #include #include #include #include "gu_assert.h" #include "gu_limits.h" #include "gu_mem.h" #include "gu_threads.h" #include "gu_log.h" #include "gu_fifo.h" #include "galerautils.h" struct gu_fifo { ulong col_shift; ulong col_mask; ulong rows_num; ulong head; ulong tail; ulong row_size; ulong length; ulong length_mask; ulong alloc; long get_wait; long put_wait; long long q_len; long long q_len_samples; uint item_size; uint used; uint used_max; uint used_min; int get_err; bool closed; #ifndef NDEBUG bool locked; #endif gu_mutex_t lock; gu_cond_t get_cond; gu_cond_t put_cond; void* rows[]; }; /* Don't make rows less than 1K */ #define GCS_FIFO_MIN_ROW_POWER 10 typedef unsigned long long ull; /* constructor */ gu_fifo_t *gu_fifo_create (size_t length, size_t item_size) { int row_pwr = GCS_FIFO_MIN_ROW_POWER; ull row_len = 1 << row_pwr; ull row_size = row_len * item_size; int array_pwr = 1; // need at least 2 rows for alteration ull array_len = 1 << array_pwr; ull array_size = array_len * sizeof(void*); gu_fifo_t *ret = NULL; if (length > 0 && item_size > 0) { /* find the best ratio of width and height: * the size of a row array must be equal to that of the row */ while (array_len * row_len < length) { if (array_size < row_size) { array_pwr++; array_len = 1 << array_pwr; array_size = array_len * sizeof(void*); } else { row_pwr++; row_len = 1 << row_pwr; row_size = row_len * item_size; } } ull alloc_size = array_size + sizeof (gu_fifo_t); if (alloc_size > (size_t)-1) { gu_error ("Initial FIFO size %llu exceeds size_t range %zu", alloc_size, (size_t)-1); return NULL; } ull max_size = array_len * row_size + alloc_size; if (max_size > (size_t)-1) { gu_error ("Maximum FIFO size %llu exceeds size_t range %zu", max_size, (size_t)-1); return NULL; } if (max_size > gu_avphys_bytes()) { gu_error ("Maximum FIFO size %llu exceeds available memory " "limit %llu", max_size, gu_avphys_bytes()); return NULL; } if ((array_len * row_len) > (ull)GU_LONG_MAX) { gu_error ("Resulting queue length %llu exceeds max allowed %ld", array_len * row_len, GU_LONG_MAX); return NULL; } gu_debug ("Creating FIFO buffer of %llu elements of size %llu, " "memory min used: %zu, max used: %zu", array_len * row_len, item_size, alloc_size, alloc_size + array_len*row_size); ret = gu_malloc (alloc_size); if (ret) { memset (ret, 0, alloc_size); ret->col_shift = row_pwr; ret->col_mask = row_len - 1; ret->rows_num = array_len; ret->length = row_len * array_len; ret->length_mask = ret->length - 1; ret->item_size = item_size; ret->row_size = row_size; ret->alloc = alloc_size; gu_mutex_init (&ret->lock, NULL); gu_cond_init (&ret->get_cond, NULL); gu_cond_init (&ret->put_cond, NULL); } else { gu_error ("Failed to allocate %zu bytes for FIFO", alloc_size); } } return ret; } // defined as macro for proper line reporting #ifdef NDEBUG #define fifo_lock(q) \ if (gu_likely (0 == gu_mutex_lock (&q->lock))) {} \ else { \ gu_fatal ("Failed to lock queue"); \ abort(); \ } #else /* NDEBUG */ #define fifo_lock(q) \ if (gu_likely (0 == gu_mutex_lock (&q->lock))) { \ q->locked = true; \ } \ else { \ gu_fatal ("Failed to lock queue"); \ abort(); \ } #endif /* NDEBUG */ static inline int fifo_unlock (gu_fifo_t* q) { #ifndef NDEBUG q->locked = false; #endif return -gu_mutex_unlock (&q->lock); } #ifndef NDEBUG bool gu_fifo_locked (gu_fifo_t* q) { return q->locked; } #endif /* lock the queue */ void gu_fifo_lock (gu_fifo_t *q) { fifo_lock(q); } /* unlock the queue */ void gu_fifo_release (gu_fifo_t *q) { fifo_unlock(q); } static int fifo_flush (gu_fifo_t* q) { int ret = 0; /* if there are items in the queue, wait until they are all fetched */ while (q->used > 0 && 0 == ret) { /* will make getters to signal every time item is removed */ gu_warn ("Waiting for %lu items to be fetched.", q->used); q->put_wait++; ret = gu_cond_wait (&q->put_cond, &q->lock); } return ret; } static void fifo_close (gu_fifo_t* q) { if (!q->closed) { q->closed = true; /* force putters to quit */ /* don't overwrite existing get_err status, see gu_fifo_resume_gets() */ if (!q->get_err) q->get_err = -ENODATA; // signal all the idle waiting threads gu_cond_broadcast (&q->put_cond); q->put_wait = 0; gu_cond_broadcast (&q->get_cond); q->get_wait = 0; #if 0 (void) fifo_flush (q); #endif } } void gu_fifo_close (gu_fifo_t* q) { fifo_lock (q); fifo_close (q); fifo_unlock (q); } void gu_fifo_open (gu_fifo_t* q) { fifo_lock (q); q->closed = false; q->get_err = 0; fifo_unlock (q); } /* lock the queue and wait if it is empty */ static inline int fifo_lock_get (gu_fifo_t *q) { int ret = 0; fifo_lock(q); while (0 == ret && !(ret = q->get_err) && 0 == q->used) { q->get_wait++; #ifndef NDEBUG q->locked = false; #endif ret = -gu_cond_wait (&q->get_cond, &q->lock); #ifndef NDEBUG q->locked = true; #endif } return ret; } /* unlock the queue after getting item */ static inline int fifo_unlock_get (gu_fifo_t *q) { assert (q->used < q->length || 0 == q->length); if (q->put_wait > 0) { q->put_wait--; gu_cond_signal (&q->put_cond); } return fifo_unlock(q); } /* lock the queue and wait if it is full */ static inline int fifo_lock_put (gu_fifo_t *q) { int ret = 0; fifo_lock(q); while (0 == ret && q->used == q->length && !q->closed) { #ifndef NDEBUG q->locked = false; #endif q->put_wait++; ret = -gu_cond_wait (&q->put_cond, &q->lock); #ifndef NDEBUG q->locked = true; #endif } return ret; } /* unlock the queue after putting an item */ static inline int fifo_unlock_put (gu_fifo_t *q) { assert (q->used > 0); if (q->get_wait > 0) { q->get_wait--; gu_cond_signal (&q->get_cond); } return fifo_unlock(q); } #define FIFO_ROW(q,x) ((x) >> q->col_shift) /* div by row width */ #define FIFO_COL(q,x) ((x) & q->col_mask) /* remnant */ #define FIFO_PTR(q,x) \ ((uint8_t*)q->rows[FIFO_ROW(q, x)] + FIFO_COL(q, x) * q->item_size) /* Increment and roll over */ #define FIFO_INC(q,x) (((x) + 1) & q->length_mask) /*! If FIFO is not empty, returns pointer to the head item and locks FIFO, * otherwise blocks. Or returns NULL if FIFO is closed. */ void* gu_fifo_get_head (gu_fifo_t* q, int* err) { *err = fifo_lock_get (q); if (gu_likely(-ECANCELED != *err && q->used)) { return (FIFO_PTR(q, q->head)); } else { assert (q->get_err); fifo_unlock (q); return NULL; } } /*! Advances FIFO head and unlocks FIFO. */ void gu_fifo_pop_head (gu_fifo_t* q) { if ((FIFO_COL(q, q->head) == q->col_mask) && (FIFO_ROW(q, q->head) != FIFO_ROW(q, q->tail))) { /* free the row if we are removing the last unit from the row and * if the tail is not in the same row as the head */ ulong row = FIFO_ROW (q, q->head); assert (q->rows[row] != NULL); gu_free (q->rows[row]); q->rows[row] = NULL; q->alloc -= q->row_size; } q->head = FIFO_INC(q, q->head); q->used--; if (gu_unlikely(q->used < q->used_min)) { q->used_min = q->used; } if (fifo_unlock_get(q)) { gu_fatal ("Failed to unlock queue to get item."); abort(); } } /*! If FIFO is not full, returns pointer to the tail item and locks FIFO, * otherwise blocks. Or returns NULL if FIFO is closed. */ void* gu_fifo_get_tail (gu_fifo_t* q) { fifo_lock_put (q); if (gu_likely(!q->closed)) { // stop adding items when closed ulong row = FIFO_ROW(q, q->tail); assert (q->used < q->length); // check if row is allocated and allocate if not. if (NULL == q->rows[row] && NULL == (q->alloc += q->row_size, q->rows[row] = gu_malloc(q->row_size))) { q->alloc -= q->row_size; } else { return ((uint8_t*)q->rows[row] + FIFO_COL(q, q->tail) * q->item_size); } #if 0 // for debugging if (NULL == q->rows[row]) { gu_debug ("Allocating row %lu of queue %p, rows %p", row, q, q->rows); if (NULL == (q->rows[row] = gu_malloc(q->row_size))) { gu_debug ("Allocating row %lu failed", row); fifo_unlock (q); return NULL; } q->alloc += q->row_size; } return (q->rows[row] + FIFO_COL(q, q->tail) * q->item_size); #endif } fifo_unlock (q); return NULL; } /*! Advances FIFO tail and unlocks FIFO. */ void gu_fifo_push_tail (gu_fifo_t* q) { q->tail = FIFO_INC(q, q->tail); q->q_len += q->used; q->used++; if (gu_unlikely(q->used > q->used_max)) { q->used_max = q->used; } q->q_len_samples++; if (fifo_unlock_put(q)) { gu_fatal ("Failed to unlock queue to put item."); abort(); } } /*! returns how many items are in the queue */ long gu_fifo_length (gu_fifo_t* q) { return q->used; } /*! Returns the maximum number of items allowed in the queue */ long gu_fifo_max_length (gu_fifo_t* q) { /* tail always points to the next free item, so there must * always be one free slot, thus the max length is q->length-1 */ return q->length-1; } /*! returns how many items were in the queue per push_tail() */ void gu_fifo_stats_get (gu_fifo_t* q, int* q_len, int* q_len_max, int* q_len_min, double* q_len_avg) { fifo_lock (q); *q_len = q->used; *q_len_max = q->used_max; *q_len_min = q->used_min; long long len = q->q_len; long long samples = q->q_len_samples; fifo_unlock (q); if (len >= 0 && samples >= 0) { if (samples > 0) { *q_len_avg = ((double)len) / samples; } else { assert (0 == len); *q_len_avg = 0.0; } } else { *q_len_avg = -1.0; } } void gu_fifo_stats_flush(gu_fifo_t* q) { fifo_lock (q); q->used_max = q->used; q->used_min = q->used; q->q_len = 0; q->q_len_samples = 0; fifo_unlock (q); } /* destructor - would block until all members are dequeued */ void gu_fifo_destroy (gu_fifo_t *queue) { fifo_lock (queue); { if (!queue->closed) fifo_close(queue); fifo_flush (queue); } fifo_unlock (queue); assert (queue->tail == queue->head); while (gu_cond_destroy (&queue->put_cond)) { fifo_lock (queue); gu_cond_signal (&queue->put_cond); fifo_unlock (queue); /* when thread sees that ret->used == 0, it must terminate */ } while (gu_cond_destroy (&queue->get_cond)) { fifo_lock (queue); gu_cond_signal (&queue->get_cond); fifo_unlock (queue); /* when thread sees that ret->used == 0, it must terminate */ } while (gu_mutex_destroy (&queue->lock)) continue; /* only one row might be left */ { ulong row = FIFO_ROW(queue, queue->tail); if (queue->rows[row]) { gu_free (queue->rows[row]); queue->alloc -= queue->row_size; } else { assert (FIFO_COL(queue, queue->tail) == 0); } gu_free (queue); } } char *gu_fifo_print (gu_fifo_t *queue) { size_t tmp_len = 4096; char tmp[tmp_len]; char *ret; snprintf (tmp, tmp_len, "Queue (%p):\n" "\tlength = %lu\n" "\trows = %lu\n" "\tcolumns = %lu\n" "\tused = %u (%zu bytes)\n" "\talloctd = %lu bytes\n" "\thead = %lu, tail = %lu\n" "\tavg.len = %f" //", next = %lu" , (void*)queue, queue->length, queue->rows_num, queue->col_mask + 1, queue->used, (size_t)queue->used * queue->item_size, queue->alloc, queue->head, queue->tail, queue->q_len_samples > 0 ? ((double)queue->q_len)/queue->q_len_samples : 0.0 //, queue->next ); ret = strdup (tmp); return ret; } int gu_fifo_cancel_gets (gu_fifo_t* q) { assert(q->locked); if (q->get_err && -ENODATA != q->get_err) { gu_error ("Attempt to cancel FIFO gets in state: %d (%s)", q->get_err, strerror(-q->get_err)); return -EBADFD; } assert (!q->get_err || q->closed); q->get_err = -ECANCELED; /* force getters to quit with specific error */ if (q->get_wait) { gu_cond_broadcast (&q->get_cond); q->get_wait = 0; } return 0; } int gu_fifo_resume_gets (gu_fifo_t* q) { int ret = -1; fifo_lock(q); if (-ECANCELED == q->get_err) { q->get_err = q->closed ? -ENODATA : 0; ret = 0; } else { gu_error ("Attempt to resume FIFO gets in state: %d (%s)", q->get_err, strerror(-q->get_err)); ret = -EBADFD; } fifo_unlock(q); return ret; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_fdesc.cpp0000644000175000017500000001562413136555240025154 0ustar jenkinsjenkins/* * Copyright (C) 2009-2016 Codership Oy * * $Id$ */ #include "gu_fdesc.hpp" #include "gu_logger.hpp" #include "gu_throw.hpp" extern "C" { #include "gu_limits.h" } #if !defined(_XOPEN_SOURCE) && !defined(__APPLE__) #define _XOPEN_SOURCE 600 #endif #include #include #include #include #include #include #ifndef O_CLOEXEC // CentOS < 6.0 does not have it #define O_CLOEXEC 0 #endif #ifndef O_NOATIME #define O_NOATIME 0 #endif namespace gu { static int const OPEN_FLAGS = O_RDWR | O_NOATIME | O_CLOEXEC; static int const CREATE_FLAGS = OPEN_FLAGS | O_CREAT /*| O_TRUNC*/; /* respect user umask by allowing all bits by default */ static mode_t const CREATE_MODE = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ; FileDescriptor::FileDescriptor (const std::string& fname, bool const sync) : name_(fname), fd_ (open (name_.c_str(), OPEN_FLAGS)), size_(fd_ < 0 ? 0 : lseek (fd_, 0, SEEK_END)), sync_(sync) { constructor_common(); } static unsigned long long available_storage(const std::string& name, size_t size) { static size_t const reserve(1 << 20); // reserve 1M free space struct statvfs stat; int const err(statvfs(name.c_str(), &stat)); if (0 == err) { unsigned long long const free_size= static_cast(stat.f_bavail) * stat.f_bsize; if (reserve < free_size) { return free_size - reserve; } else { return 0; } } else { int const errn(errno); log_warn << "statvfs() failed on '" << name << "' partition: " << errn << " (" << strerror(errn) <<"). Proceeding anyway."; return std::numeric_limits::max(); } } FileDescriptor::FileDescriptor (const std::string& fname, size_t const size, bool const allocate, bool const sync) : name_(fname), fd_ (open (fname.c_str(), CREATE_FLAGS, CREATE_MODE)), size_(size), sync_(sync) { constructor_common(); off_t const current_size(lseek (fd_, 0, SEEK_END)); if (current_size < size_) { unsigned long long const available(available_storage(name_, size_)); if (size_t(size_) > available) { ::close(fd_); ::unlink(name_.c_str()); gu_throw_error(ENOSPC) << "Requested size " << size_ << " for '" << name_ << "' exceeds available storage space " << available; } if (allocate) { // reserve space that hasn't been reserved prealloc (current_size); } else { // reserve size or bus error follows mmap() write_byte (size_ - 1); } } else if (current_size > size_) { log_debug << "Truncating '" << name_<< "' to " << size_<< " bytes."; if (ftruncate(fd_, size_)) { gu_throw_error(errno) << "Failed to truncate '" << name_ << "' to " << size_ << " bytes."; } } else { log_debug << "Reusing existing '" << name_ << "'."; } } void FileDescriptor::constructor_common() { if (fd_ < 0) { gu_throw_error(errno) << "Failed to open file '" + name_ + '\''; } #if !defined(__APPLE__) /* Darwin does not have posix_fadvise */ /* benefits are questionable int err(posix_fadvise (value, 0, size, POSIX_FADV_SEQUENTIAL)); if (err != 0) { log_warn << "Failed to set POSIX_FADV_SEQUENTIAL on " << name << ": " << err << " (" << strerror(err) << ")"; } */ #endif log_debug << "Opened file '" << name_ << "', size: " << size_; log_debug << "File descriptor: " << fd_; } FileDescriptor::~FileDescriptor () { if (sync_) { try { sync(); } catch (Exception& e) { log_error << e.what(); } } if (close(fd_) != 0) { int const err(errno); log_error << "Failed to close file '" << name_ << "': " << err << " (" << strerror(err) << '\''; } else { log_debug << "Closed file '" << name_ << "'"; } } void FileDescriptor::sync () const { log_debug << "Flushing file '" << name_ << "'"; if (fsync (fd_) < 0) { gu_throw_error(errno) << "fsync() failed on '" + name_ + '\''; } log_debug << "Flushed file '" << name_ << "'"; } bool FileDescriptor::write_byte (off_t offset) { byte_t const byte (0); if (lseek (fd_, offset, SEEK_SET) != offset) gu_throw_error(errno) << "lseek() failed on '" << name_ << '\''; if (write (fd_, &byte, sizeof(byte)) != sizeof(byte)) gu_throw_error(errno) << "write() failed on '" << name_ << '\''; return true; } /*! prealloc() fallback */ void FileDescriptor::write_file (off_t const start) { // last byte of the start page off_t offset= (start / GU_PAGE_SIZE) * GU_PAGE_SIZE + (GU_PAGE_SIZE - 1); log_info << "Preallocating " << (size_ - start) << '/' << size_ << " bytes in '" << name_ << "'..."; while (offset < size_ && write_byte (offset)) { offset += GU_PAGE_SIZE; } if (offset >= size_ && write_byte (size_ - 1)) { sync(); return; } gu_throw_error (errno) << "File preallocation failed"; } void FileDescriptor::prealloc(off_t const start) { off_t const diff (size_ - start); log_debug << "Preallocating " << diff << '/' << size_ << " bytes in '" << name_ << "'..."; #if defined(__APPLE__) if (0 != fcntl (fd_, F_SETSIZE, size_) && 0 != ftruncate (fd_, size_)) #else if (0 != posix_fallocate (fd_, start, diff)) #endif { if ((EINVAL == errno || ENOSYS == errno) && start >= 0 && diff > 0) { // FS does not support the operation, try physical write write_file (start); } else { gu_throw_error (errno) << "File preallocation failed"; } } } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_time.c0000644000175000017500000001442213136555240024461 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @file time manipulation functions/macros * * $Id: $ */ #if defined(__APPLE__) #include #include // struct timespec #include // gettimeofday #include // clock_get_time #include // host_get_clock_service #include // mach_absolute_time, mach_timebase_info #include #include "gu_time.h" #define NSEC_PER_SEC 1000000000 #define NSEC_PER_USEC 1000 # if defined(__LP64__) // OS X comm page time offsets // see http://www.opensource.apple.com/source/xnu/xnu-2050.22.13/osfmk/i386/cpu_capabilities.h #define nt_tsc_base "0x50" #define nt_scale "0x58" #define nt_shift "0x5c" #define nt_ns_base "0x60" #define nt_generation "0x68" #define gtod_generation "0x6c" #define gtod_ns_base "0x70" #define gtod_sec_base "0x78" static inline int64_t nanotime (void) { int64_t ntime; __asm volatile ( "mov $0x7fffffe00000, %%rbx;" /* comm page base */ "0:" /* Loop trying to take a consistent snapshot of the time parameters. */ "movl "gtod_generation"(%%rbx), %%r8d;" "testl %%r8d, %%r8d;" "jz 1f;" "movl "nt_generation"(%%rbx), %%r9d;" "testl %%r9d, %%r9d;" "jz 0b;" "rdtsc;" "movq "nt_tsc_base"(%%rbx), %%r10;" "movl "nt_scale"(%%rbx), %%r11d;" "movq "nt_ns_base"(%%rbx), %%r12;" "cmpl "nt_generation"(%%rbx), %%r9d;" "jne 0b;" "movq "gtod_ns_base"(%%rbx), %%r13;" "movq "gtod_sec_base"(%%rbx), %%r14;" "cmpl "gtod_generation"(%%rbx), %%r8d;" "jne 0b;" /* Gathered all the data we need. Compute time. */ /* ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base - gtod_ns_base + gtod_sec_base*1e9 */ /* The multiply and shift extracts the top 64 bits of the 96-bit product. */ "shlq $32, %%rdx;" "addq %%rdx, %%rax;" "subq %%r10, %%rax;" "mulq %%r11;" "shrdq $32, %%rdx, %%rax;" "addq %%r12, %%rax;" "subq %%r13, %%rax;" "imulq $1000000000, %%r14;" "addq %%r14, %%rax;" "jmp 2f;" "1:" /* Fall back to system call (usually first call in this thread). */ "movq %%rsp, %%rdi;" /* rdi must be non-nil, unused */ "movq $0, %%rsi;" "movl $(0x2000000+116), %%eax;" /* SYS_gettimeofday */ "syscall; /* may destroy rcx and r11 */" /* sec is in rax, usec in rdx */ /* return nsec in rax */ "imulq $1000000000, %%rax;" "imulq $1000, %%rdx;" "addq %%rdx, %%rax;" "2:" : "=a"(ntime) : /* no input parameters */ : "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14" ); return ntime; } static inline int64_t nanouptime (void) { int64_t ntime; __asm volatile ( "movabs $0x7fffffe00000, %%rbx;" /* comm page base */ "0:" /* Loop trying to take a consistent snapshot of the time parameters. */ "movl "nt_generation"(%%rbx), %%r9d;" "testl %%r9d, %%r9d;" "jz 0b;" "rdtsc;" "movq "nt_tsc_base"(%%rbx), %%r10;" "movl "nt_scale"(%%rbx), %%r11d;" "movq "nt_ns_base"(%%rbx), %%r12;" "cmpl "nt_generation"(%%rbx), %%r9d;" "jne 0b;" /* Gathered all the data we need. Compute time. */ /* ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base */ /* The multiply and shift extracts the top 64 bits of the 96-bit product. */ "shlq $32, %%rdx;" "addq %%rdx, %%rax;" "subq %%r10, %%rax;" "mulq %%r11;" "shrdq $32, %%rdx, %%rax;" "addq %%r12, %%rax;" : "=a"(ntime) : /* no input parameters */ : "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", "%r9", "%r10", "%r11", "%r12" ); return ntime; } int clock_gettime (clockid_t clk_id, struct timespec * tp) { int64_t abstime = 0; if (tp == NULL) { return EFAULT; } switch (clk_id) { case CLOCK_REALTIME: abstime = nanotime (); break; case CLOCK_MONOTONIC: abstime = nanouptime (); break; default: errno = EINVAL; return -1; } tp->tv_sec = abstime / (uint64_t)NSEC_PER_SEC; tp->tv_nsec = (uint32_t)(abstime % (uint64_t)NSEC_PER_SEC); return 0; } #else /* !__LP64__ */ static struct mach_timebase_info g_mti; int clock_gettime (clockid_t clk_id, struct timespec * tp) { int64_t abstime = 0; mach_timebase_info_data_t mti; /* {uint32_t numer, uint32_t denom} */ if (tp == NULL) { return EFAULT; } switch (clk_id) { case CLOCK_REALTIME: struct timeval tv; if (gettimeofday (&tv, NULL) != 0) { return -1; } tp->tv_sec = tv.tv_sec; tp->tv_nsec = tv.tv_usec * NSEC_PER_USEC; return 0; case CLOCK_MONOTONIC: abstime = mach_absolute_time (); break; default: errno = EINVAL; return -1; } if (g_mti.denom == 0) { struct mach_timebase_info mti; mach_timebase_info (&mti); g_mti.numer = mti.numer; OSMemoryBarrier (); g_mti.denom = mti.denom; } nanos = (uint64_t)(abstime * (((double)g_mti.numer) / ((double)g_mti.denom))); tp->tv_sec = nanos / (uint64_t)NSEC_PER_SEC; tp->tv_nsec = (uint32_t)(nanos % (uint64_t)NSEC_PER_SEC); return 0; } #endif /* !__LP64__ */ #else /* !__APPLE__ */ #ifdef __GNUC__ // error: ISO C forbids an empty translation unit int dummy_var_gu_time; #endif #endif /* __APPLE__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_backtrace.hpp0000644000175000017500000000256513136555240026014 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy #ifndef GU_BACKTRACE_HPP #define GU_BACKTRACE_HPP #include "gu_backtrace.h" #include #include namespace gu { /*! * Utility class to print backtraces. */ class Backtrace { public: /*! * Construct backtrace object. * * @param Maximum number of backtrace symbols resolved (default 50). */ Backtrace(int size = 50) : symbols_size_(size), symbols_(gu_backtrace(&symbols_size_)) { } ~Backtrace() { free(symbols_); } /*! * Print backtrace into ostream. * * @param os Ostream to print backtrace into. * @param delim Delimiter separating backtrace symbols. */ void print(std::ostream& os, char delim = '\n') { if (symbols_ != 0) { for (int i(0); i < symbols_size_; ++i) { os << symbols_[i] << delim; } } else { os << "no backtrace available"; } } private: Backtrace(const Backtrace&); void operator=(const Backtrace&); int symbols_size_; char** symbols_; }; } #endif // GU_BACKTRACE_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_datetime.hpp0000644000175000017500000001465113136555240025670 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy * * $Id$ */ /*! * @file Date/time manipulation classes providing nanosecond resolution. */ #ifndef __GU_DATETIME__ #define __GU_DATETIME__ #include "gu_exception.hpp" #include "gu_regex.hpp" #include "gu_time.h" #include #include #include namespace gu { namespace datetime { /* Multiplier constants */ const long long NSec = 1; const long long USec = 1000*NSec; const long long MSec = 1000*USec; const long long Sec = 1000*MSec; const long long Min = 60*Sec; const long long Hour = 60*Min; const long long Day = 24*Hour; const long long Month = 30*Day; const long long Year = 12*Month; /*! * @brief Class representing time periods instead of * system clock time. */ class Period { public: /*! * @brief Constructor * * Duration format is PnYnMnDTnHnMnS where Y is year, M is month, * D is day, T is the time designator separating date and time * parts, H denotes hours, M (after T) is minutes and S seconds. * * All other n:s are expected to be integers except the one * before S which can be decimal to represent fractions of second. * * @param str Time period represented in ISO8601 duration format. */ Period(const std::string& str = "") : nsecs() { if (str != "") parse(str); } Period(const long long nsecs_) : nsecs(nsecs_) { } static Period min() { return 0; } static Period max() { return std::numeric_limits::max();} bool operator==(const Period& cmp) const { return (nsecs == cmp.nsecs); } bool operator<(const Period& cmp) const { return (nsecs < cmp.nsecs); } bool operator>=(const Period& cmp) const { return !(*this < cmp); } Period operator+(const long long add) const { return (nsecs + add); } Period operator-(const long long dec) const { return (nsecs - dec); } Period operator*(const long long mul) const { return (nsecs*mul); } Period operator/(const long long div) const { return (nsecs/div); } long long get_nsecs() const { return nsecs; } Period operator+(const Period& add) const { return (nsecs + add.nsecs); } Period operator-(const Period& dec) const { return (nsecs - dec.nsecs); } private: friend class Date; friend std::istream& operator>>(std::istream&, Period&); static const char* const period_regex; /*! regexp string */ static RegEx const regex; /*! period string parser */ /*! * @brief Parse period string. */ void parse(const std::string&); long long nsecs; }; /*! * @brief Date/time representation. * * @todo Parsing date from string is not implemented yet, * only possible to get current system time or * maximum time. */ class Date { public: /*! * @brief Get system time. * @note This call should be deprecated in favor of calendar() * and monotonic(). */ static inline Date now() { return gu_time_monotonic(); } /*! * @brief Get time from system-wide realtime clock. */ static inline Date calendar() { return gu_time_calendar(); } /*! * @brief Get time from monotonic clock. */ static inline Date monotonic() { return gu_time_monotonic(); } /*! * @brief Get maximum representable timestamp. */ static inline Date max() { return std::numeric_limits::max(); } /*! * @brief Get zero time */ static inline Date zero() { return 0; } /*! * Return 64-bit timestamp representing system time in nanosecond * resolution. */ long long get_utc() const { return utc; } /* Standard comparision operators */ bool operator==(const Date cmp) const { return (utc == cmp.utc); } bool operator<(const Date cmp) const { return (utc < cmp.utc); } /*! * @brief Add period to Date */ Date operator+(const Period& add) const { return (utc + add.get_nsecs()); } /*! * @brief Decrement period from Date */ Date operator-(const Period& dec) const { return (utc - dec.get_nsecs()); } Period operator-(const Date& dec) const { return (utc - dec.utc); } Date(const long long utc_ = 0) : utc(utc_) { } /*! convert to timespec - for internal use */ void _timespec(timespec& ts) const { ts.tv_sec = utc / 1000000000L; ts.tv_nsec = utc % 1000000000L; } private: long long utc; /*!< System time in nanosecond precision */ /*! * @brief Parse date from string. * @todo Not implemented yet */ void parse(const std::string& str_); }; /*! * @brief Output operator for Date class. * @todo Not implemented yet */ std::ostream& operator<<(std::ostream&, const Date&); /*! * @brief Output operator for Period type. */ std::ostream& operator<<(std::ostream&, const Period&); inline std::string to_string(const Period& p) { std::ostringstream os; os << p; return os.str(); } inline std::istream& operator>>(std::istream& is, Period& p) { std::string str; is >> str; p.parse(str); return is; } } // namespace datetime } // namespace gu #endif // __GU_DATETIME__ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_lock_step.h0000644000175000017500000000165113136555240025513 0ustar jenkinsjenkins/* * Copyright (C) 2009-2017 Codership Oy * * $Id$ */ // This is a small class to facilitate lock-stepping in multithreaded unit tests #ifndef _gu_lock_step_h_ #define _gu_lock_step_h_ #include #include "gu_threads.h" typedef struct gu_lock_step { gu_mutex_t mtx; gu_cond_t cond; long wait; long cont; bool enabled; } gu_lock_step_t; extern void gu_lock_step_init (gu_lock_step_t* ls); /* enable or disable lock-stepping */ extern void gu_lock_step_enable (gu_lock_step_t* ls, bool enable); extern void gu_lock_step_wait (gu_lock_step_t* ls); /* returns how many waiters there were, * waits for timeout_ms milliseconds if no waiters, if timeout_ms < 0 waits forever, * if 0 - no wait at all */ extern long gu_lock_step_cont (gu_lock_step_t* ls, long timeout_ms); extern void gu_lock_step_destroy (gu_lock_step_t* ls); #endif /* _gu_lock_step_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_hexdump.hpp0000644000175000017500000000201713136555240025537 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @file operator << for hexdumps. * * Usage: std::cout << gu::Hexdump(ptr, size) * * $Id$ */ #ifndef _GU_HEXDUMP_HPP_ #define _GU_HEXDUMP_HPP_ #include "gu_types.hpp" #include namespace gu { class Hexdump { public: Hexdump (const void* const buf, size_t const size, bool const alpha = false) : buf_ (reinterpret_cast(buf)), size_ (size), alpha_(alpha) {} std::ostream& to_stream (std::ostream& os) const; // according to clang C++98 wants copy ctor to be public for temporaries Hexdump (const Hexdump& h) : buf_(h.buf_), size_(h.size_), alpha_(h.alpha_) {} private: const byte_t* const buf_; size_t const size_; bool const alpha_; Hexdump& operator = (const Hexdump&); }; inline std::ostream& operator << (std::ostream& os, const Hexdump& h) { return h.to_stream(os); } } #endif /* _GU_HEXDUMP_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_prodcons.cpp0000644000175000017500000000341613136555240025713 0ustar jenkinsjenkins// Copyright (C) 2009 Codership Oy #include "gu_prodcons.hpp" #include #include using namespace std; class gu::prodcons::MessageQueue { public: MessageQueue() : que() { } bool empty() const { return que.empty(); } size_t size() const { return que.size(); } const Message& front() const { return que.front(); } void pop_front() { que.pop_front(); } void push_back(const Message& msg) { que.push_back(msg); } private: std::deque que; }; void gu::prodcons::Producer::send(const Message& msg, Message* ack) { cons.queue_and_wait(msg, ack); } const gu::prodcons::Message* gu::prodcons::Consumer::get_next_msg() { const Message* ret = 0; Lock lock(mutex); if (mque->empty() == false) { ret = &mque->front(); } return ret; } void gu::prodcons::Consumer::queue_and_wait(const Message& msg, Message* ack) { Lock lock(mutex); mque->push_back(msg); if (mque->size() == 1) { notify(); } lock.wait(msg.get_producer().get_cond()); assert(&rque->front().get_producer() == &msg.get_producer()); if (ack) { *ack = rque->front(); } rque->pop_front(); if (rque->empty() == false) { rque->front().get_producer().get_cond().signal(); } } void gu::prodcons::Consumer::return_ack(const Message& ack) { Lock lock(mutex); assert(&ack.get_producer() == &mque->front().get_producer()); rque->push_back(ack); mque->pop_front(); if (rque->size() == 1) { ack.get_producer().get_cond().signal(); } } gu::prodcons::Consumer::Consumer() : mutex(), mque(new MessageQueue), rque(new MessageQueue) { } gu::prodcons::Consumer::~Consumer() { delete mque; delete rque; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_abort.h0000644000175000017500000000105513136555240024635 0ustar jenkinsjenkins// Copyright (C) 2012-2013 Codership Oy /** * @file "Clean" abort function to avoid stack and core dumps * * $Id$ */ #ifndef _gu_abort_h_ #define _gu_abort_h_ #ifdef __cplusplus extern "C" { #endif #include "gu_macros.h" /* This function is for clean aborts, when we can't gracefully exit otherwise */ extern void gu_abort() GU_NORETURN; /* Register the application callback that be called before exiting: */ extern void gu_abort_register_cb (void (* callback) (void)); #ifdef __cplusplus } #endif #endif /* _gu_abort_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_buffer.cpp0000644000175000017500000000013113136555240025324 0ustar jenkinsjenkins// // Copyright (C) 2010 Codership Oy // #include "gu_buffer.hpp" percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_system.h0000644000175000017500000000151213136555240025050 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @system/os/platform dependent functions/macros * * $Id$ */ #ifndef _gu_system_h_ #define _gu_system_h_ #define _GNU_SOURCE // program_invocation_name, program_invocation_short_name #include #include // getexecname, getprogname #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* See: http://lists.gnu.org/archive/html/bug-gnulib/2010-12/txtrjMzutB7Em.txt * for implementation of GU_SYS_PROGRAM_NAME on other platforms */ #if defined(__sun__) # define GU_SYS_PROGRAM_NAME getexecname () #elif defined(__APPLE__) || defined(__FreeBSD__) # define GU_SYS_PROGRAM_NAME getprogname () #elif defined(__linux__) # define GU_SYS_PROGRAM_NAME program_invocation_name #endif #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _gu_system_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_log.h0000644000175000017500000000526513136555240024316 0ustar jenkinsjenkins// Copyright (C) 2007-2014 Codership Oy /** * @file Logging API * * $Id$ */ #ifndef _gu_log_h_ #define _gu_log_h_ #include "gu_macros.h" #include /* For NULL */ #if defined(__cplusplus) extern "C" { #endif /** * @typedef * Defines severity classes for log messages: * FATAL - is a fatal malfunction of the library which cannot be recovered * from. Application must close. * error - error condition in the library which prevents further normal * operation but can be recovered from by the application. E.g. EAGAIN. * warn - some abnormal condition which library can recover from by itself. * * info - just an informative log message. * * debug - debugging message. */ typedef enum gu_log_severity { GU_LOG_FATAL, GU_LOG_ERROR, GU_LOG_WARN, GU_LOG_INFO, GU_LOG_DEBUG } gu_log_severity_t; /** * @typedef * Defines a type of callback function that application can provide * to do the logging */ typedef void (*gu_log_cb_t) (int severity, const char* msg); /** Helper for macros defined below. Should not be called directly. */ extern int gu_log (gu_log_severity_t severity, const char* file, const char* function, const int line, ...); /** This variable is made global only for the purpose of using it in * gu_debug() macro and avoid calling gu_log() when debug is off. * Don't use it directly! */ extern gu_log_severity_t gu_log_max_level; #define gu_log_debug (GU_LOG_DEBUG == gu_log_max_level) #if defined(__cplusplus) } #endif #if !defined(__cplusplus) || defined(GALERA_LOG_H_ENABLE_CXX) // NOTE: don't add "\n" here even if you really want to do it #define GU_LOG_C(level, ...)\ gu_log(level, __FILE__, __func__, __LINE__,\ __VA_ARGS__, NULL) /** * @name Logging macros. * Must be implemented as macros to report the location of the code where * they are called. */ /*@{*/ #define gu_fatal(...) GU_LOG_C(GU_LOG_FATAL, __VA_ARGS__, NULL) #define gu_error(...) GU_LOG_C(GU_LOG_ERROR, __VA_ARGS__, NULL) #define gu_warn(...) GU_LOG_C(GU_LOG_WARN, __VA_ARGS__, NULL) #define gu_info(...) GU_LOG_C(GU_LOG_INFO, __VA_ARGS__, NULL) #define gu_debug(...) if (gu_unlikely(gu_log_debug)) \ { GU_LOG_C(GU_LOG_DEBUG, __VA_ARGS__, NULL); } /*@}*/ #endif /* __cplusplus */ #endif /* _gu_log_h_ */ #ifdef __GU_LOGGER__ // C++ logger should use the same stuff, so export it #ifndef _gu_log_extra_ #define _gu_log_extra_ extern "C" { extern bool gu_log_self_tstamp; extern gu_log_cb_t gu_log_cb; extern void gu_log_cb_default (int, const char*); extern const char* gu_log_level_str[]; } #endif /* _gu_log_extra_ */ #endif /* __GU_LOGGER__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_buf.hpp0000644000175000017500000000037613136555240024647 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy */ /** * @file generic buffer declaration * * $Id$ */ #ifndef _GU_BUF_HPP_ #define _GU_BUF_HPP_ #include "gu_buf.h" namespace gu { typedef struct gu_buf Buf; } #endif /* _GU_BUF_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_str.h0000644000175000017500000001057413136555240024344 0ustar jenkinsjenkins/* * Copyright (C) 2010 Codership Oy */ #ifndef GU_STR_H #define GU_STR_H #include #include #include #include /*! * Append after position */ static inline char* gu_str_append(char* str, size_t* off, const char* app, size_t app_len) { char* tmp; assert(str == NULL || *(str + *off - 1) == '\0'); tmp = realloc(str, *off + app_len + 1); if (tmp != NULL) { memcpy(tmp + *off, app, app_len + 1); *off += app_len + 1; } return tmp; } /*! * Get next string after position */ static inline const char* gu_str_next(const char* str) { return strchr(str, '\0') + 1; } /*! * Advance position starting from over n */ static inline const char* gu_str_advance(const char* str, size_t n) { const char* ptr = str; while (n-- > 0) { ptr = gu_str_next(ptr); } return ptr; } /* * Utilities to construct and scan tables from null terminated strings. * The table format is the following: * * name\0\columns\0\rows\0 * colname0\0colname1\0... * elem00\0elem01\0elem02\0... * elem10\0elem11\0elem\12\... * . * . * . */ static inline char* gu_str_table_set_name(char* str, size_t* off, const char* name) { return gu_str_append(str, off, name, strlen(name)); } static inline const char* gu_str_table_get_name(const char* str) { return str; } static inline char* gu_str_table_append_size(char* str, size_t* off, size_t n) { char buf[10]; size_t len = snprintf(buf, sizeof(buf), "%zu", n); return gu_str_append(str, off, buf, len); } static inline char* gu_str_table_set_n_cols(char* str, size_t* off, size_t n) { return gu_str_table_append_size(str, off, n); } static inline size_t gu_str_table_get_n_cols(const char* str) { str = gu_str_advance(str, 1); return strtoul(str, NULL, 0); } static inline char* gu_str_table_set_n_rows(char* str, size_t* off, size_t n) { return gu_str_table_append_size(str, off, n); } static inline size_t gu_str_table_get_n_rows(const char* str) { str = gu_str_advance(str, 2); return strtoul(str, NULL, 0); } static inline char* gu_str_table_set_cols(char* str, size_t *off, size_t n, const char* cols[]) { size_t i; for (i = 0; i < n; ++i) { str = gu_str_append(str, off, cols[i], strlen(cols[i])); } return str; } static inline char* gu_str_table_append_row(char* str, size_t *off, size_t n, const char* row[]) { size_t i; for (i = 0; i < n; ++i) { str = gu_str_append(str, off, row[i], strlen(row[i])); } return str; } static inline const char* gu_str_table_get_cols(const char* str, size_t n, char const* row[]) { size_t i; str = gu_str_advance(str, 3); for (i = 0; i < n; i++) { row[i] = str; str = gu_str_next(str); } return str; } static inline const char* gu_str_table_rows_begin(const char* str, size_t n) { return gu_str_advance(str, 3 + n); } static inline const char* gu_str_table_row_get(const char* str, size_t n, char const* row[]) { size_t i; for (i = 0; i < n; ++i) { row[i] = str; str = gu_str_next(str); } return str; } static inline void gu_str_table_print_row(FILE* file, size_t n, const char* const row[]) { size_t i; for (i = 0; i < n; ++i) { fprintf(file, "%s ", row[i]); } fprintf(file, "\n"); } static inline void gu_str_table_print(FILE* file, const char* str) { size_t i; size_t n_cols, n_rows; const char* ptr; char const**vec; fprintf(file, "%s\n", gu_str_table_get_name(str)); n_cols = gu_str_table_get_n_cols(str); n_rows = gu_str_table_get_n_rows(str); vec = malloc(n_cols*sizeof(char*)); ptr = gu_str_table_get_cols(str, n_cols, vec); gu_str_table_print_row(file, n_cols, vec); for (i = 0; i < n_rows; ++i) { ptr = gu_str_table_row_get(ptr, n_cols, vec); gu_str_table_print_row(file, n_cols, vec); } free(vec); } #endif /* GU_STR_H */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_regex.hpp0000644000175000017500000000344413136555240025204 0ustar jenkinsjenkins// Copyright (C) 2009 Codership Oy /** * @file Regular expressions parser based on POSIX regex functions in * * $Id$ */ #ifndef _gu_regex_hpp_ #define _gu_regex_hpp_ #include #include #include #include "gu_throw.hpp" namespace gu { class RegEx { regex_t regex; std::string strerror (int rc) const; public: /*! * @param expr regular expression string */ RegEx (const std::string& expr) : regex() { int rc; if ((rc = regcomp(®ex, expr.c_str(), REG_EXTENDED)) != 0) { gu_throw_fatal << "regcomp(" << expr << "): " << strerror(rc); } } ~RegEx () { regfree (®ex); } /*! * This class is to differentiate between an empty and unset strings. * @todo: find a proper name for it and move to gu_utils.hpp */ class Match { std::string value; bool set; public: Match() : value(), set(false) {} Match(const std::string& s) : value(s), set(true) {} // throws NotSet const std::string& str() const { if (set) return value; throw NotSet(); } bool is_set() const { return set; } }; /*! * @brief Matches given string * * @param str string to match with expression * @param num number of matches to return * * @return vector of matched substrings */ std::vector match (const std::string& str, size_t num) const; }; } #endif /* _gu_regex_hpp_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_spooky.c0000644000175000017500000000044013136555240025042 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /** * @file external Spooky hash implementation to avoid code bloat * * $Id$ */ #include "gu_spooky.h" void gu_spooky128_host (const void* const msg, size_t const len, uint64_t* res) { gu_spooky_inline (msg, len, res); } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_dbug.h0000644000175000017500000001453213136555240024453 0ustar jenkinsjenkins/****************************************************************************** * * * N O T I C E * * * * Copyright Abandoned, 1987, Fred Fish * * * * * * This previously copyrighted work has been placed into the public * * domain by the author and may be freely used for any purpose, * * private or commercial. * * * * Because of the number of inquiries I was receiving about the use * * of this product in commercially developed works I have decided to * * simply make it public domain to further its unrestricted use. I * * specifically would be most happy to see this material become a * * part of the standard Unix distributions by AT&T and the Berkeley * * Computer Science Research Group, and a standard part of the GNU * * system from the Free Software Foundation. * * * * I would appreciate it, as a courtesy, if this notice is left in * * all copies and derivative works. Thank you. * * * * The author makes no warranty of any kind with respect to this * * product and explicitly disclaims any implied warranties of mer- * * chantability or fitness for any particular purpose. * * * ****************************************************************************** */ /* * FILE * * dbug.c runtime support routines for dbug package * * SCCS * * @(#)dbug.c 1.25 7/25/89 * * DESCRIPTION * * These are the runtime support routines for the dbug package. * The dbug package has two main components; the user include * file containing various macro definitions, and the runtime * support routines which are called from the macro expansions. * * Externally visible functions in the runtime support module * use the naming convention pattern "_db_xx...xx_", thus * they are unlikely to collide with user defined function names. * * AUTHOR(S) * * Fred Fish (base code) * Enhanced Software Technologies, Tempe, AZ * asuvax!mcdphx!estinc!fnf * * Binayak Banerjee (profiling enhancements) * seismo!bpa!sjuvax!bbanerje * * Michael Widenius: * DBUG_DUMP - To dump a pice of memory. * PUSH_FLAG "O" - To be used instead of "o" if we don't * want flushing (for slow systems) * PUSH_FLAG "A" - as 'O', but we will append to the out file instead * of creating a new one. * Check of malloc on entry/exit (option "S") * * Alexey Yurchenko: * Renamed global symbols for use with galera project to avoid * collisions with other software (notably MySQL) * * $Id$ */ #ifndef _dbug_h #define _dbug_h #include #include typedef unsigned int uint; typedef unsigned long ulong; #define THREAD 1 #ifdef __cplusplus extern "C" { #endif extern char _gu_dig_vec[]; extern FILE* _gu_db_fp_; #define GU_DBUG_FILE _gu_db_fp_ #if defined(GU_DBUG_ON) && !defined(_lint) extern int _gu_db_on_; extern int _gu_no_db_; extern char* _gu_db_process_; extern int _gu_db_keyword_(const char* keyword); extern void _gu_db_setjmp_ (void); extern void _gu_db_longjmp_(void); extern void _gu_db_push_ (const char* control); extern void _gu_db_pop_ (void); extern void _gu_db_enter_ (const char* _func_, const char* _file_, uint _line_, const char** _sfunc_, const char** _sfile_, uint* _slevel_, char***); extern void _gu_db_return_ (uint _line_, const char** _sfunc_, const char** _sfile_, uint* _slevel_); extern void _gu_db_pargs_ (uint _line_, const char* keyword); extern void _gu_db_doprnt_ (const char* format, ...); extern void _gu_db_dump_ (uint _line_, const char *keyword, const char *memory, uint length); extern void _gu_db_lock_file (void); extern void _gu_db_unlock_file(void); #define GU_DBUG_ENTER(a) \ const char *_gu_db_func_, *_gu_db_file_; \ uint _gu_db_level_; \ char **_gu_db_framep_; \ _gu_db_enter_ (a, __FILE__, __LINE__, &_gu_db_func_, &_gu_db_file_, \ &_gu_db_level_, &_gu_db_framep_) #define GU_DBUG_LEAVE \ (_gu_db_return_ (__LINE__, &_gu_db_func_, &_gu_db_file_, \ &_gu_db_level_)) #define GU_DBUG_RETURN(a1) {GU_DBUG_LEAVE; return(a1);} #define GU_DBUG_VOID_RETURN {GU_DBUG_LEAVE; return; } #define GU_DBUG_EXECUTE(keyword,a1) \ {if (_gu_db_on_) {if (_gu_db_keyword_ (keyword)) { a1 }}} #define GU_DBUG_PRINT(keyword,arglist) \ {if (_gu_db_on_) {_gu_db_pargs_(__LINE__,keyword); \ _gu_db_doprnt_ arglist;}} #define GU_DBUG_PUSH(a1) _gu_db_push_ (a1) #define GU_DBUG_POP() _gu_db_pop_ () #define GU_DBUG_PROCESS(a1) (_gu_db_process_ = a1) #define GU_DBUG_SETJMP(a1) (_gu_db_setjmp_ (), setjmp (a1)) #define GU_DBUG_LONGJMP(a1,a2) (_gu_db_longjmp_ (), longjmp (a1, a2)) #define GU_DBUG_DUMP(keyword,a1,a2)\ {if (_gu_db_on_) {_gu_db_dump_(__LINE__,keyword,a1,a2);}} #define GU_DBUG_IN_USE (_gu_db_fp_ && _gu_db_fp_ != stderr) #define GU_DEBUGGER_OFF _no_gu_db_=1;_gu_db_on_=0; #define GU_DEBUGGER_ON _no_gu_db_=0 #define GU_DBUG_my_pthread_mutex_lock_FILE { _gu_db_lock_file(); } #define GU_DBUG_my_pthread_mutex_unlock_FILE { _gu_db_unlock_file(); } #define GU_DBUG_ASSERT(A) assert(A) #else /* No debugger */ #define GU_DBUG_ENTER(a1) #define GU_DBUG_RETURN(a1) return(a1) #define GU_DBUG_VOID_RETURN return #define GU_DBUG_EXECUTE(keyword,a1) {} #define GU_DBUG_PRINT(keyword,arglist) {} #define GU_DBUG_PUSH(a1) {} #define GU_DBUG_POP() {} #define GU_DBUG_PROCESS(a1) {} #define GU_DBUG_SETJMP setjmp #define GU_DBUG_LONGJMP longjmp #define GU_DBUG_DUMP(keyword,a1,a2) {} #define GU_DBUG_IN_USE 0 #define GU_DEBUGGER_OFF #define GU_DEBUGGER_ON #define GU_DBUG_my_pthread_mutex_lock_FILE #define GU_DBUG_my_pthread_mutex_unlock_FILE #define GU_DBUG_ASSERT(A) {} #endif #ifdef __cplusplus } #endif #endif percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_backtrace.c0000644000175000017500000000115113136555240025435 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy #include "gu_backtrace.h" #include "gu_log.h" #if defined(HAVE_EXECINFO_H) && defined(__GNUC__) #include #include char** gu_backtrace(int* size) { char** strings; void** array = malloc(*size * sizeof(void*)); if (!array) { gu_error("could not allocate memory for %d pointers\n", *size); return NULL; } *size = backtrace(array, *size); strings = backtrace_symbols(array, *size); free(array); return strings; } #else char **gu_backtrace(int* size) { return NULL; } #endif /* */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_logger.cpp0000644000175000017500000000657513136555240025354 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy * * This code is based on an excellent article at Dr.Dobb's: * http://www.ddj.com/cpp/201804215?pgno=1 */ #include #include #include #include #include #include "gu_logger.hpp" #include "gu_string_utils.hpp" // strsplit #include #include #include using std::string; using std::vector; using std::set; namespace gu { class DebugFilter { set filter; public: DebugFilter() : filter() { if (::getenv("LOGGER_DEBUG_FILTER")) { set_filter(::getenv("LOGGER_DEBUG_FILTER")); } } ~DebugFilter() {} void set_filter(const string& str) { vector dvec = gu::strsplit(str, ','); for (vector::const_iterator i = dvec.begin(); i != dvec.end(); ++i) { filter.insert(*i); } } size_t size() const { return filter.size(); } bool is_set(const string& str) const { return filter.find(str) != filter.end() || filter.find(str.substr(0, str.find_first_of(":"))) != filter.end(); } }; static DebugFilter debug_filter; void Logger::set_debug_filter(const string& str) { debug_filter.set_filter(str); } bool Logger::no_debug(const string& file, const string& func, const int line) { return debug_filter.size() > 0 && debug_filter.is_set(func) == false; } #ifndef _gu_log_h_ void Logger::enable_tstamp (bool yes) { do_timestamp = yes; } void Logger::enable_debug (bool yes) { if (yes) { max_level = LOG_DEBUG; } else { max_level = LOG_INFO; } } void Logger::default_logger (int lvl, const char* msg) { fputs (msg, stderr); fputc ('\n', stderr); fflush (stderr); } void Logger::set_logger (LogCallback cb) { if (0 == cb) { logger = default_logger; } else { logger = cb; } } static const char* level_str[LOG_MAX] = { "FATAL: ", "ERROR: ", " WARN: ", " INFO: ", "DEBUG: " }; bool Logger::do_timestamp = false; LogLevel Logger::max_level = LOG_INFO; LogCallback Logger::logger = default_logger; #else #define do_timestamp gu_log_self_tstamp == true #define level_str gu_log_level_str #endif // _gu_log_h_ void Logger::prepare_default() { if (do_timestamp) { using namespace std; struct tm date; struct timeval time; gettimeofday (&time, NULL); localtime_r (&time.tv_sec, &date); os << date.tm_year + 1900 << '-' << setw(2) << setfill('0') << (date.tm_mon + 1) << '-' << setw(2) << setfill('0') << date.tm_mday << ' ' << setw(2) << setfill('0') << date.tm_hour << ':' << setw(2) << setfill('0') << date.tm_min << ':' << setw(2) << setfill('0') << date.tm_sec << '.' << setw(3) << setfill('0') << (time.tv_usec / 1000) << ' '; } os << level_str[level]; } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_hexdump.cpp0000644000175000017500000000152113136555240025531 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @file operator << for hexdump - definiton * * $Id$ */ #include "gu_hexdump.hpp" #include "gu_hexdump.h" #include "gu_logger.hpp" namespace gu { static size_t const hexdump_bytes_per_go(GU_HEXDUMP_BYTES_PER_LINE * 2); static size_t const hexdump_reserve_string( hexdump_bytes_per_go*2 /* chars */ + hexdump_bytes_per_go/4 /* whitespace */ + 1 /* \0 */ ); std::ostream& Hexdump::to_stream (std::ostream& os) const { char str[hexdump_reserve_string]; size_t off(0); while (off < size_) { size_t const to_print(std::min(size_ - off, hexdump_bytes_per_go)); gu_hexdump (buf_ + off, to_print, str, sizeof(str), alpha_); off += to_print; os << str; if (off < size_) os << '\n'; } return os; } } // namespace gu percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_uri.hpp0000644000175000017500000001525513136555240024674 0ustar jenkinsjenkins/* * Copyright (C) 2009-2012 Codership Oy * * $Id$ */ /*! * @file gu_url.hpp * * @brief Utility to parse URIs * * Follows http://tools.ietf.org/html/rfc3986 * * @author Teemu Ollakka */ #ifndef __GU_URI_HPP__ #define __GU_URI_HPP__ #include #include #include #include "gu_utils.hpp" #include "gu_regex.hpp" namespace gu { /*! * @brief URIQueryList * * std::multimap is used to implement query list in URI. * @todo This should be changed to real class having get_key(), * get_value() methods for iterators and to get rid of std::multimap * dependency in header. */ typedef std::multimap URIQueryList; /*! * @brief Utility class to parse URIs */ class URI { public: /*! * @class Helper class for authority list representation. */ class Authority { public: /*! * @brief Get "user" part of authority * * @return user substring * @throws NotSet */ const std::string& user() const { return user_.str(); } /*! * @brief Get "host" part of authority * * @return host substring * @throws NotSet */ const std::string& host() const { return host_.str(); } /*! * @brief Get "port" part of authority * * @return port * @throws NotSet */ const std::string& port() const { return port_.str(); } private: friend class gu::URI; Authority() : user_(), host_(), port_() { } RegEx::Match user_; RegEx::Match host_; RegEx::Match port_; }; typedef std::vector AuthorityList; /*! * @brief Construct URI from string * * @param strict if true, throw exception when scheme is not found, * else use a default one * @throws std::invalid_argument if URI is not valid * @throws std::logic_error in case of internal error * @throws NotSet */ URI (const std::string&, bool strict = true); /*! * @brief Get URI string * @return URI string */ const std::string& to_string() const { if (modified_) recompose(); return str_; } /*! * @brief Get URI scheme * * @return URI scheme (always set) * @throws NotSet */ const std::string& get_scheme() const { return scheme_.str(); } /*! * @brief Get URI authority component * * @return URI authority substring * @throws NotSet */ std::string get_authority() const; /*! * @brief Get "user" part of the first entry in authority list * * @return User substring * @throws NotSet */ const std::string& get_user() const { if (authority_.empty()) throw NotSet(); return authority_.front().user(); } /*! * @brief Get "host" part of the first entry in authority list * * @return Host substring * @throws NotSet */ const std::string& get_host() const { if (authority_.empty()) throw NotSet(); return authority_.front().host(); } /*! * @brief Get "port" part of the first entry in authority list * * @return Port substring * @throws NotSet */ const std::string& get_port() const { if (authority_.empty()) throw NotSet(); return authority_.front().port(); } /*! * @brief Get authority list * * @return Authority list */ const AuthorityList& get_authority_list() const { return authority_; } /*! * @brief Get URI path * * @return URI path (always set) */ const std::string& get_path() const { return path_.str(); } /*! * @brief Get URI path * * @return URI path * @throws NotSet */ const std::string& get_fragment() const { return fragment_.str(); } /*! * @brief Add query param to URI */ void set_query_param(const std::string&, const std::string&, bool override); void set_option(const std::string& key, const std::string& val) { set_query_param(key, val, true); } void append_option(const std::string& key, const std::string& val) { set_query_param(key, val, false); } /*! * @brief Get URI query list */ const URIQueryList& get_query_list() const { return query_list_; } /*! * @brief return opton by name, * @throws NotFound */ const std::string& get_option(const std::string&) const; const std::string& get_option(const std::string& opt, const std::string& def) const { try { return get_option(opt); } catch (NotFound& ) { return def ; } } private: bool modified_; mutable std::string str_; /*! URI string */ RegEx::Match scheme_; /*! URI scheme part */ AuthorityList authority_; RegEx::Match path_; /*! URI path part */ RegEx::Match fragment_; /*! URI fragment part */ URIQueryList query_list_; /*! URI query list */ /*! * @brief Parse URI from str */ void parse (const std::string& s, bool strict); /*! * @brief Recompose URI in str */ void recompose() const; /*! @throws NotSet */ std::string get_authority(const Authority&) const; static const char* const uri_regex_; /*! regexp string to parse URI */ static RegEx const regex_; /*! URI regexp parser */ }; inline std::ostream& operator<<(std::ostream& os, const URI& uri) { os << uri.to_string(); return os; } } #endif /* __GU_URI_HPP__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_resolver.cpp0000644000175000017500000003346513136555240025734 0ustar jenkinsjenkins// Copyright (C) 2009-2013 Codership Oy #include "gu_resolver.hpp" #include "gu_logger.hpp" #include "gu_utils.hpp" #include "gu_throw.hpp" #include "gu_uri.hpp" #include #include #include // for close() #include #include #include #define BSD_COMP /* For SIOCGIFCONF et al on Solaris */ #include #include #include #if defined(__APPLE__) || defined(__FreeBSD__) # include # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP # define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #else /* !__APPLE__ && !__FreeBSD__ */ extern "C" /* old style cast */ { static int const GU_SIOCGIFCONF = SIOCGIFCONF; static int const GU_SIOCGIFINDEX = SIOCGIFINDEX; } #endif /* !__APPLE__ && !__FreeBSD__ */ //using namespace std; using std::make_pair; // Map from scheme string to addrinfo class SchemeMap { public: typedef std::map Map; typedef Map::const_iterator const_iterator; SchemeMap() : ai_map() { ai_map.insert(make_pair("tcp", get_addrinfo(0, AF_UNSPEC, SOCK_STREAM, 0))); ai_map.insert(make_pair("ssl", get_addrinfo(0, AF_UNSPEC, SOCK_STREAM, 0))); ai_map.insert(make_pair("udp", get_addrinfo(0, AF_UNSPEC, SOCK_DGRAM, 0))); // TODO: } const_iterator find(const std::string& key) const { return ai_map.find(key); } const_iterator end() const { return ai_map.end(); } static const addrinfo* get_addrinfo(const_iterator i) { return &i->second; } private: Map ai_map; struct addrinfo get_addrinfo(int flags, int family, int socktype, int protocol) { struct addrinfo ret = { flags, family, socktype, protocol, #if defined(__FreeBSD__) 0, // FreeBSD gives ENOMEM error with non-zero value #else sizeof(struct sockaddr), #endif 0, 0, 0 }; return ret; } }; static SchemeMap scheme_map; // Helper to copy addrinfo structs. static void copy(const addrinfo& from, addrinfo& to) { to.ai_flags = from.ai_flags; to.ai_family = from.ai_family; to.ai_socktype = from.ai_socktype; to.ai_protocol = from.ai_protocol; to.ai_addrlen = from.ai_addrlen; if (from.ai_addr != 0) { if ((to.ai_addr = reinterpret_cast(malloc(to.ai_addrlen))) == 0) { gu_throw_fatal << "out of memory while trying to allocate " << to.ai_addrlen << " bytes"; } memcpy(to.ai_addr, from.ai_addr, to.ai_addrlen); } to.ai_canonname = 0; to.ai_next = 0; } ///////////////////////////////////////////////////////////////////////// // Sockaddr implementation ///////////////////////////////////////////////////////////////////////// bool gu::net::Sockaddr::is_multicast() const { switch (sa_->sa_family) { case AF_INET: return IN_MULTICAST(ntohl(reinterpret_cast(sa_)->sin_addr.s_addr)); case AF_INET6: return IN6_IS_ADDR_MULTICAST(&reinterpret_cast(sa_)->sin6_addr); default: gu_throw_fatal; } } bool gu::net::Sockaddr::is_anyaddr() const { switch (sa_->sa_family) { case AF_INET: return (ntohl(reinterpret_cast(sa_)->sin_addr.s_addr) == INADDR_ANY); case AF_INET6: return IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast(sa_)->sin6_addr); default: gu_throw_fatal; } } gu::net::Sockaddr::Sockaddr(const sockaddr* sa, socklen_t sa_len) : sa_ (0 ), sa_len_(sa_len) { if ((sa_ = reinterpret_cast(malloc(sa_len_))) == 0) { gu_throw_fatal; } memcpy(sa_, sa, sa_len_); } gu::net::Sockaddr::Sockaddr(const Sockaddr& s) : sa_ (0 ), sa_len_(s.sa_len_) { if ((sa_ = reinterpret_cast(malloc(sa_len_))) == 0) { gu_throw_fatal; } memcpy(sa_, s.sa_, sa_len_); } gu::net::Sockaddr::~Sockaddr() { free(sa_); } ///////////////////////////////////////////////////////////////////////// // MReq implementation ///////////////////////////////////////////////////////////////////////// static unsigned int get_ifindex_by_addr(const gu::net::Sockaddr& addr) { if (addr.is_anyaddr() == true) { return 0; } unsigned int idx(-1); int err(0); #if defined(__APPLE__) || defined(__FreeBSD__) struct ifaddrs *if_addrs = NULL; struct ifaddrs *if_addr = NULL; if (getifaddrs (&if_addrs) != 0) { err = errno; goto out; } for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next) { try { gu::net::Sockaddr sa (if_addr->ifa_addr, sizeof (struct sockaddr)); if (sa.get_family () == addr.get_family () && memcmp (sa.get_addr (), addr.get_addr (), addr.get_addr_len ()) == 0) { idx = if_nametoindex (if_addr->ifa_name); goto out; } } catch (gu::Exception& e) { } } out: # else /* !__APPLE__ && !__FreeBSD__ */ struct ifconf ifc; memset(&ifc, 0, sizeof(struct ifconf)); ifc.ifc_len = 16*sizeof(struct ifreq); std::vector ifr(16); ifc.ifc_req = &ifr[0]; int fd(socket(AF_INET, SOCK_DGRAM, 0)); if (fd == -1) { err = errno; gu_throw_error(err) << "could not create socket"; } if ((err = ioctl(fd, GU_SIOCGIFCONF, &ifc)) == -1) { err = errno; goto out; } log_debug << "read: " << ifc.ifc_len; for (size_t i(0); i < ifc.ifc_len/sizeof(struct ifreq); ++i) { struct ifreq* ifrp(&ifr[i]); try { log_debug << "read: " << ifrp->ifr_name; gu::net::Sockaddr sa(&ifrp->ifr_addr, sizeof(struct sockaddr)); if (sa.get_family() == addr.get_family() && memcmp(sa.get_addr(), addr.get_addr(), addr.get_addr_len()) == 0) { if ((err = ioctl(fd, GU_SIOCGIFINDEX, ifrp, sizeof(struct ifreq))) == -1) { err = errno; } #if defined(__linux__) idx = ifrp->ifr_ifindex; #elif defined(__sun__) idx = ifrp->ifr_index; #else # error "Unsupported ifreq structure" #endif goto out; } } catch (gu::Exception& e) { } } out: close(fd); #endif /* !__APPLE__ && !__FreeBSD__ */ if (err != 0) { gu_throw_error(err) << "failed to get interface index"; } else { log_debug << "returning ifindex: " << idx; } return idx; } gu::net::MReq::MReq(const Sockaddr& mcast_addr, const Sockaddr& if_addr) : mreq_ ( 0), mreq_len_ ( 0), ipproto_ ( 0), add_membership_opt_ (-1), drop_membership_opt_(-1), multicast_if_opt_ (-1), multicast_loop_opt_ (-1), multicast_ttl_opt_ (-1) { log_debug << mcast_addr.get_family() << " " << if_addr.get_family(); if (mcast_addr.get_family() != if_addr.get_family()) { gu_throw_fatal << "address families do not match: " << mcast_addr.get_family() << ", " << if_addr.get_family(); } if (mcast_addr.get_family() != AF_INET && mcast_addr.get_family() != AF_INET6) { gu_throw_fatal << "Mreq: address family " << mcast_addr.get_family() << " not supported"; } get_ifindex_by_addr(if_addr); mreq_len_ = (mcast_addr.get_family() == AF_INET ? sizeof(struct ip_mreq) : sizeof(struct ipv6_mreq)); if ((mreq_ = malloc(mreq_len_)) == 0) { gu_throw_fatal << "could not allocate memory"; } memset(mreq_, 0, mreq_len_); switch (mcast_addr.get_family()) { case AF_INET: { struct ip_mreq* mr(reinterpret_cast(mreq_)); mr->imr_multiaddr.s_addr = *reinterpret_cast(mcast_addr.get_addr()); mr->imr_interface.s_addr = *reinterpret_cast(if_addr.get_addr()); ipproto_ = IPPROTO_IP; add_membership_opt_ = IP_ADD_MEMBERSHIP; drop_membership_opt_ = IP_DROP_MEMBERSHIP; multicast_if_opt_ = IP_MULTICAST_IF; multicast_loop_opt_ = IP_MULTICAST_LOOP; multicast_ttl_opt_ = IP_MULTICAST_TTL; break; } case AF_INET6: { struct ipv6_mreq* mr(reinterpret_cast(mreq_)); mr->ipv6mr_multiaddr = *reinterpret_cast(mcast_addr.get_addr()); mr->ipv6mr_interface = get_ifindex_by_addr(if_addr); ipproto_ = IPPROTO_IPV6; add_membership_opt_ = IPV6_ADD_MEMBERSHIP; drop_membership_opt_ = IPV6_DROP_MEMBERSHIP; multicast_loop_opt_ = IPV6_MULTICAST_LOOP; multicast_ttl_opt_ = IPV6_MULTICAST_HOPS; break; } } } gu::net::MReq::~MReq() { free(mreq_); } const void* gu::net::MReq::get_multicast_if_value() const { switch (ipproto_) { case IPPROTO_IP: return &reinterpret_cast(mreq_)->imr_interface; case IPPROTO_IPV6: return &reinterpret_cast(mreq_)->ipv6mr_interface; default: gu_throw_fatal << "get_multicast_if_value() not implemented for: " << ipproto_; } } int gu::net::MReq::get_multicast_if_value_size() const { switch (ipproto_) { case IPPROTO_IP: return sizeof(reinterpret_cast(mreq_)->imr_interface); case IPPROTO_IPV6: return sizeof(reinterpret_cast(mreq_)->ipv6mr_interface); default: gu_throw_fatal << "get_multicast_if_value_size() not implemented for: " << ipproto_; } } ///////////////////////////////////////////////////////////////////////// // Addrinfo implementation ///////////////////////////////////////////////////////////////////////// gu::net::Addrinfo::Addrinfo(const addrinfo& ai) : ai_() { copy(ai, ai_); } gu::net::Addrinfo::Addrinfo(const Addrinfo& ai) : ai_() { copy(ai.ai_, ai_); } gu::net::Addrinfo::Addrinfo(const Addrinfo& ai, const Sockaddr& sa) : ai_() { if (ai.get_addrlen() != sa.get_sockaddr_len()) { gu_throw_fatal; } copy(ai.ai_, ai_); memcpy(ai_.ai_addr, &sa.get_sockaddr(), ai_.ai_addrlen); } gu::net::Addrinfo::~Addrinfo() { free(ai_.ai_addr); } std::string gu::net::Addrinfo::to_string() const { static const size_t max_addr_str_len = (6 /* tcp|udp:// */ + INET6_ADDRSTRLEN + 2 /* [] */ + 6 /* :portt */); std::string ret; ret.reserve(max_addr_str_len); Sockaddr addr(ai_.ai_addr, ai_.ai_addrlen); switch (get_socktype()) { case SOCK_STREAM: ret += "tcp://"; break; case SOCK_DGRAM: ret += "udp://"; break; default: gu_throw_error(EINVAL) << "invalid socktype: " << get_socktype(); } char dst[INET6_ADDRSTRLEN + 1]; if (inet_ntop(get_family(), addr.get_addr(), dst, sizeof(dst)) == 0) { gu_throw_error(errno) << "inet ntop failed"; } switch (get_family()) { case AF_INET: ret += dst; break; case AF_INET6: ret += "["; ret += dst; ret += "]"; break; default: gu_throw_error(EINVAL) << "invalid address family: " << get_family(); } ret += ":" + gu::to_string(ntohs(addr.get_port())); ret.reserve(0); // free unused space if possible return ret; } ///////////////////////////////////////////////////////////////////////// // Public methods ///////////////////////////////////////////////////////////////////////// gu::net::Addrinfo gu::net::resolve(const URI& uri) { SchemeMap::const_iterator i(scheme_map.find(uri.get_scheme())); if (i == scheme_map.end()) { gu_throw_error(EINVAL) << "invalid scheme: " << uri.get_scheme(); } try { std::string host(uri.get_host()); // remove [] if this is IPV6 address size_t pos(host.find_first_of('[')); if (pos != std::string::npos) { host.erase(pos, pos + 1); pos = host.find_first_of(']'); if (pos == std::string::npos) { gu_throw_error(EINVAL) << "invalid host: " << uri.get_host(); } host.erase(pos, pos + 1); } int err; addrinfo* ai(0); try { err = getaddrinfo(host.c_str(), uri.get_port().c_str(), SchemeMap::get_addrinfo(i), &ai); } catch (NotSet&) { err = getaddrinfo(host.c_str(), NULL, SchemeMap::get_addrinfo(i), &ai); } if (err != 0) { // Use EHOSTUNREACH as generic error number in case errno // is zero. Real error should be apparent from exception message gu_throw_error(errno == 0 ? EHOSTUNREACH : errno) << "getaddrinfo failed with error '" << gai_strerror(err) << "' (" << err << ") for " << uri.to_string(); } // Assume that the first entry is ok Addrinfo ret(*ai); freeaddrinfo(ai); return ret; } catch (NotFound& nf) { gu_throw_error(EINVAL) << "invalid URI: " << uri.to_string(); } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_config.hpp0000644000175000017500000001622513136555240025340 0ustar jenkinsjenkins// Copyright (C) 2010-2014 Codership Oy /** * @file * Configuration management class * * $Id$ */ #ifndef _gu_config_hpp_ #define _gu_config_hpp_ #include "gu_string_utils.hpp" #include "gu_exception.hpp" #include "gu_utils.hpp" #include "gu_throw.hpp" #include "gu_logger.hpp" #include #include namespace gu { class Config; } extern "C" const char* gu_str2ll (const char* str, long long* ll); class gu::Config { public: static const char PARAM_SEP; // parameter separator static const char KEY_VALUE_SEP; // key-value separator static const char ESCAPE; // escape symbol Config (); bool has (const std::string& key) const { return (params_.find(key) != params_.end()); } bool is_set (const std::string& key) const { param_map_t::const_iterator const i(params_.find(key)); if (i != params_.end()) { return i->second.is_set(); } else { throw NotFound(); } } /* adds parameter to the known parameter list */ void add (const std::string& key) { if (!has(key)) { params_[key] = Parameter(); } } /* adds parameter to the known parameter list and sets its value */ void add (const std::string& key, const std::string& value) { if (!has(key)) { params_[key] = Parameter(value); } } /* sets a known parameter to some value, otherwise throws NotFound */ void set (const std::string& key, const std::string& value) { param_map_t::iterator const i(params_.find(key)); if (i != params_.end()) { i->second.set(value); } else { #ifndef NDEBUG log_debug << "Key '" << key << "' not recognized."; #endif throw NotFound(); } } void set (const std::string& key, const char* value) { set(key, std::string(value)); } /* Parse a string of semicolumn separated key=value pairs into a vector. * Throws Exception in case of parsing error. */ static void parse (std::vector >& params_vector, const std::string& params_string); /* Parse a string of semicolumn separated key=value pairs and * set the values. * Throws NotFound if key was not explicitly added before. */ void parse (const std::string& params_string); /* General template for integer types */ template void set (const std::string& key, T val) { set_longlong (key, val); } /*! @throws NotSet, NotFound */ const std::string& get (const std::string& key) const { param_map_t::const_iterator const i(params_.find(key)); if (i == params_.end()) throw NotFound(); if (i->second.is_set()) return i->second.value(); log_debug << key << " not set."; throw NotSet(); } const std::string& get (const std::string& key, const std::string& def) const { try { return get(key); } catch (NotSet&) { return def ; } } /*! @throws NotFound */ template inline T get (const std::string& key) const { return from_config (get(key)); } template inline T get(const std::string& key, const T& def) const { try { return get(key); } catch (NotSet&) { return def; } } void print (std::ostream& os, bool include_not_set = false) const; /*! Convert string configuration values to other types. * General template for integers, specialized templates follow below. * @throw gu::Exception in case conversion failed */ template static inline T from_config (const std::string& value) { const char* str = value.c_str(); long long ret; errno = 0; // this is needed to detect overflow const char* endptr = gu_str2ll (str, &ret); check_conversion (str, endptr, "integer", ERANGE == errno); switch (sizeof(T)) { case 1: return overflow_char (ret); case 2: return overflow_short (ret); case 4: return overflow_int (ret); default: return ret; } } /* iterator stuff */ class Parameter { public: explicit Parameter(const std::string& value) : value_(value), set_(true) {} Parameter() : value_(), set_(false) {} const std::string& value() const { return value_; } bool is_set() const { return set_ ; } void set(const std::string& value) { value_ = value; set_ = true; } private: std::string value_; bool set_; }; typedef std::map param_map_t; typedef param_map_t::const_iterator const_iterator; const_iterator begin() const { return params_.begin(); } const_iterator end() const { return params_.end(); } private: static void check_conversion (const char* ptr, const char* endptr, const char* type, bool range_error = false); static char overflow_char(long long ret); static short overflow_short(long long ret); static int overflow_int(long long ret); void set_longlong (const std::string& key, long long value); param_map_t params_; }; extern "C" const char* gu_str2dbl (const char* str, double* dbl); extern "C" const char* gu_str2bool (const char* str, bool* bl); extern "C" const char* gu_str2ptr (const char* str, void** ptr); namespace gu { std::ostream& operator<<(std::ostream&, const gu::Config&); /*! Specialized templates for "funny" types */ template <> inline double Config::from_config (const std::string& value) { const char* str = value.c_str(); double ret; errno = 0; // this is needed to detect over/underflow const char* endptr = gu_str2dbl (str, &ret); check_conversion (str, endptr, "double", ERANGE == errno); return ret; } template <> inline bool Config::from_config (const std::string& value) { const char* str = value.c_str(); bool ret; const char* endptr = gu_str2bool (str, &ret); check_conversion (str, endptr, "boolean"); return ret; } template <> inline void* Config::from_config (const std::string& value) { const char* str = value.c_str(); void* ret; const char* endptr = gu_str2ptr (str, &ret); check_conversion (str, endptr, "pointer"); return ret; } template <> inline void Config::set (const std::string& key, const void* value) { set (key, to_string(value)); } template <> inline void Config::set (const std::string& key, double val) { set (key, to_string(val)); } template <> inline void Config::set (const std::string& key, bool val) { const char* val_str(val ? "YES" : "NO"); // YES/NO is most generic set (key, val_str); } } #endif /* _gu_config_hpp_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_uuid.c0000644000175000017500000001152513136555240024472 0ustar jenkinsjenkins/* * Copyright (C) 2008-2017 Codership Oy * * $Id$ */ /* * Universally Unique IDentifier. RFC 4122. * Time-based implementation. * */ #include "gu_uuid.h" #include "gu_byteswap.h" #include "gu_log.h" #include "gu_assert.h" #include "gu_threads.h" #include "gu_time.h" #include "gu_rand.h" #include // for rand_r() #include // for memcmp() #include // for fopen() et al #include // for gettimeofday() #include // for getpid() #include // for errno #include const gu_uuid_t GU_UUID_NIL = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; #define UUID_NODE_LEN 6 /** Returns 64-bit system time in 100 nanoseconds */ static uint64_t uuid_get_time () { static long long check = 0; static gu_mutex_t mtx = GU_MUTEX_INITIALIZER; long long t; gu_mutex_lock (&mtx); do { t = gu_time_calendar() / 100; } while (check == t); check = t; gu_mutex_unlock (&mtx); return (t + 0x01B21DD213814000LL); // offset since the start of 15 October 1582 } #ifndef UUID_URAND // This function can't be called too often, // apparently due to lack of entropy in the pool. /** Fills node part of the uuid with true random data from /dev/urand */ static int uuid_urand_node (uint8_t* node, size_t node_len) { static const char urand_name[] = "/dev/urandom"; FILE* urand; size_t i = 0; int c; urand = fopen (urand_name, "r"); if (NULL == urand) { gu_debug ("Failed to open %s for reading (%d).", urand_name, -errno); return -errno; } while (i < node_len && (c = fgetc (urand)) != EOF) { node[i] = (uint8_t) c; i++; } fclose (urand); return 0; } #else #define uuid_urand_node(a,b) true #endif /** Fills node part with pseudorandom data from rand_r() */ static void uuid_rand_node (uint8_t* node, size_t node_len) { unsigned int seed = gu_rand_seed_int (gu_time_calendar(), node, getpid()); size_t i; for (i = 0; i < node_len; i++) { uint32_t r = (uint32_t) rand_r (&seed); /* combine all bytes into the lowest byte */ node[i] = (uint8_t)((r) ^ (r >> 8) ^ (r >> 16) ^ (r >> 24)); } } static inline void uuid_fill_node (uint8_t* node, size_t node_len) { if (uuid_urand_node (node, node_len)) { uuid_rand_node (node, node_len); } } void gu_uuid_generate (gu_uuid_t* uuid, const void* node, size_t node_len) { assert (NULL != uuid); assert (NULL == node || 0 != node_len); uint32_t* uuid32 = (uint32_t*) uuid->data; uint16_t* uuid16 = (uint16_t*) uuid->data; uint64_t uuid_time = uuid_get_time (); uint16_t clock_seq = gu_rand_seed_int (uuid_time, &GU_UUID_NIL, getpid()); /* time_low */ uuid32[0] = gu_be32 (uuid_time & 0xFFFFFFFF); /* time_mid */ uuid16[2] = gu_be16 ((uuid_time >> 32) & 0xFFFF); /* time_high_and_version */ uuid16[3] = gu_be16 (((uuid_time >> 48) & 0x0FFF) | (1 << 12)); /* clock_seq_and_reserved */ uuid16[4] = gu_be16 ((clock_seq & 0x3FFF) | 0x8000); /* node */ if (NULL != node && 0 != node_len) { memcpy (&uuid->data[10], node, node_len > UUID_NODE_LEN ? UUID_NODE_LEN : node_len); } else { uuid_fill_node (&uuid->data[10], UUID_NODE_LEN); uuid->data[10] |= 0x02; /* mark as "locally administered" */ } return; } /** * Compare two UUIDs * @return -1, 0, 1 if left is respectively less, equal or greater than right */ long gu_uuid_compare (const gu_uuid_t* left, const gu_uuid_t* right) { return memcmp (left, right, sizeof(gu_uuid_t)); } static uint64_t uuid_time (const gu_uuid_t* uuid) { uint64_t uuid_time; /* time_high_and_version */ uuid_time = gu_be16 (((uint16_t*)uuid->data)[3]) & 0x0FFF; /* time_mid */ uuid_time = (uuid_time << 16) + gu_be16 (((uint16_t*)uuid->data)[2]); /* time_low */ uuid_time = (uuid_time << 32) + gu_be32 (((uint32_t*)uuid->data)[0]); return uuid_time; } /** * Compare ages of two UUIDs * @return -1, 0, 1 if left is respectively younger, equal or older than right */ long gu_uuid_older (const gu_uuid_t* left, const gu_uuid_t* right) { uint64_t time_left = uuid_time (left); uint64_t time_right = uuid_time (right); if (time_left < time_right) return 1; if (time_left > time_right) return -1; return 0; } ssize_t gu_uuid_print(const gu_uuid_t* uuid, char* buf, size_t buflen) { if (buflen < GU_UUID_STR_LEN) return -1; return sprintf(buf, GU_UUID_FORMAT, GU_UUID_ARGS(uuid)); } ssize_t gu_uuid_scan(const char* buf, size_t buflen, gu_uuid_t* uuid) { ssize_t ret; if (buflen < GU_UUID_STR_LEN) return -1; ret = sscanf(buf, GU_UUID_FORMAT_SCANF, GU_UUID_ARGS_SCANF(uuid)); if (ret != sizeof(uuid->data)) return -1; return ret; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_string_utils.cpp0000644000175000017500000000447613136555240026621 0ustar jenkinsjenkins// Copyright (C) 2009-2010 Codership Oy #include "gu_string_utils.hpp" #include "gu_assert.hpp" #include using std::string; using std::vector; vector gu::strsplit(const string& s, char sep) { vector ret; size_t pos, prev_pos = 0; while ((pos = s.find_first_of(sep, prev_pos)) != string::npos) { ret.push_back(s.substr(prev_pos, pos - prev_pos)); prev_pos = pos + 1; } if (s.length() > prev_pos) { ret.push_back(s.substr(prev_pos, s.length() - prev_pos)); } return ret; } vector gu::tokenize(const string& s, const char sep, const char esc, const bool empty) { vector ret; size_t pos, prev_pos, search_pos; prev_pos = search_pos = 0; while ((pos = s.find_first_of(sep, search_pos)) != string::npos) { assert (pos >= prev_pos); if (esc != '\0' && pos > search_pos && esc == s[pos - 1]) { search_pos = pos + 1; continue; } if (pos > prev_pos || empty) { string t = s.substr(prev_pos, pos - prev_pos); // get rid of escapes size_t p, search_p = 0; while ((p = t.find_first_of(esc, search_p)) != string::npos && esc != '\0') { if (p > search_p) { t.erase(p, 1); search_p = p + 1; } } ret.push_back(t); } prev_pos = search_pos = pos + 1; } if (s.length() > prev_pos) { ret.push_back(s.substr(prev_pos, s.length() - prev_pos)); } else if (s.length() == prev_pos && empty) { assert(0 == prev_pos || s[prev_pos - 1] == sep); ret.push_back(""); } return ret; } void gu::trim (string& s) { const ssize_t s_length = s.length(); for (ssize_t begin = 0; begin < s_length; ++begin) { if (!isspace(s[begin])) { for (ssize_t end = s_length - 1; end >= begin; --end) { if (!isspace(s[end])) { s = s.substr(begin, end - begin + 1); return; } } assert(0); } } s.clear(); } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_spooky.h0000644000175000017500000003255413136555240025062 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /*! * @file Spooky hash by Bob Jenkins: * http://www.burtleburtle.net/bob/c/spooky.h * * Original author comments preserved in C++ style. * Original code is public domain * * $Id$ */ #ifndef _gu_spooky_h_ #define _gu_spooky_h_ #include "gu_types.h" #include "gu_byteswap.h" #ifdef __cplusplus extern "C" { #endif #include // for memcpy() /*! GCC complains about 'initializer element is not constant', hence macros */ #define _spooky_numVars 12 #define _spooky_blockSize 96 /* (_spooky_numVars * 8) */ #define _spooky_bufSize 192 /* (_spooky_blockSize * 2) */ static uint64_t const _spooky_const = GU_ULONG_LONG(0xDEADBEEFDEADBEEF); // // This is used if the input is 96 bytes long or longer. // // The internal state is fully overwritten every 96 bytes. // Every input bit appears to cause at least 128 bits of entropy // before 96 other bytes are combined, when run forward or backward // For every input bit, // Two inputs differing in just that input bit // Where "differ" means xor or subtraction // And the base value is random // When run forward or backwards one Mix // I tried 3 pairs of each; they all differed by at least 212 bits. // static GU_FORCE_INLINE void _spooky_mix( const uint64_t *data, uint64_t* s0, uint64_t* s1, uint64_t* s2, uint64_t* s3, uint64_t* s4, uint64_t* s5, uint64_t* s6, uint64_t* s7, uint64_t* s8, uint64_t* s9, uint64_t* sA, uint64_t* sB) { *s0 += gu_le64(data[0]); *s2 ^= *sA; *sB ^= *s0; *s0 =GU_ROTL64(*s0,11); *sB += *s1; *s1 += gu_le64(data[1]); *s3 ^= *sB; *s0 ^= *s1; *s1 =GU_ROTL64(*s1,32); *s0 += *s2; *s2 += gu_le64(data[2]); *s4 ^= *s0; *s1 ^= *s2; *s2 =GU_ROTL64(*s2,43); *s1 += *s3; *s3 += gu_le64(data[3]); *s5 ^= *s1; *s2 ^= *s3; *s3 =GU_ROTL64(*s3,31); *s2 += *s4; *s4 += gu_le64(data[4]); *s6 ^= *s2; *s3 ^= *s4; *s4 =GU_ROTL64(*s4,17); *s3 += *s5; *s5 += gu_le64(data[5]); *s7 ^= *s3; *s4 ^= *s5; *s5 =GU_ROTL64(*s5,28); *s4 += *s6; *s6 += gu_le64(data[6]); *s8 ^= *s4; *s5 ^= *s6; *s6 =GU_ROTL64(*s6,39); *s5 += *s7; *s7 += gu_le64(data[7]); *s9 ^= *s5; *s6 ^= *s7; *s7 =GU_ROTL64(*s7,57); *s6 += *s8; *s8 += gu_le64(data[8]); *sA ^= *s6; *s7 ^= *s8; *s8 =GU_ROTL64(*s8,55); *s7 += *s9; *s9 += gu_le64(data[9]); *sB ^= *s7; *s8 ^= *s9; *s9 =GU_ROTL64(*s9,54); *s8 += *sA; *sA += gu_le64(data[10]); *s0 ^= *s8; *s9 ^= *sA; *sA =GU_ROTL64(*sA,22); *s9 += *sB; *sB += gu_le64(data[11]); *s1 ^= *s9; *sA ^= *sB; *sB =GU_ROTL64(*sB,46); *sA += *s0; } // // Mix all 12 inputs together so that h0, h1 are a hash of them all. // // For two inputs differing in just the input bits // Where "differ" means xor or subtraction // And the base value is random, or a counting value starting at that bit // The final result will have each bit of h0, h1 flip // For every input bit, // with probability 50 +- .3% // For every pair of input bits, // with probability 50 +- 3% // // This does not rely on the last Mix() call having already mixed some. // Two iterations was almost good enough for a 64-bit result, but a // 128-bit result is reported, so End() does three iterations. // static GU_FORCE_INLINE void _spooky_end_part( uint64_t* h0, uint64_t* h1, uint64_t* h2, uint64_t* h3, uint64_t* h4, uint64_t* h5, uint64_t* h6, uint64_t* h7, uint64_t* h8, uint64_t* h9, uint64_t* h10,uint64_t* h11) { *h11+= *h1; *h2 ^= *h11; *h1 = GU_ROTL64(*h1,44); *h0 += *h2; *h3 ^= *h0; *h2 = GU_ROTL64(*h2,15); *h1 += *h3; *h4 ^= *h1; *h3 = GU_ROTL64(*h3,34); *h2 += *h4; *h5 ^= *h2; *h4 = GU_ROTL64(*h4,21); *h3 += *h5; *h6 ^= *h3; *h5 = GU_ROTL64(*h5,38); *h4 += *h6; *h7 ^= *h4; *h6 = GU_ROTL64(*h6,33); *h5 += *h7; *h8 ^= *h5; *h7 = GU_ROTL64(*h7,10); *h6 += *h8; *h9 ^= *h6; *h8 = GU_ROTL64(*h8,13); *h7 += *h9; *h10^= *h7; *h9 = GU_ROTL64(*h9,38); *h8 += *h10; *h11^= *h8; *h10= GU_ROTL64(*h10,53); *h9 += *h11; *h0 ^= *h9; *h11= GU_ROTL64(*h11,42); *h10+= *h0; *h1 ^= *h10; *h0 = GU_ROTL64(*h0,54); } static GU_FORCE_INLINE void _spooky_end( uint64_t* h0, uint64_t* h1, uint64_t* h2, uint64_t* h3, uint64_t* h4, uint64_t* h5, uint64_t* h6, uint64_t* h7, uint64_t* h8, uint64_t* h9, uint64_t* h10,uint64_t* h11) { #if 0 _spooky_end_part(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); _spooky_end_part(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); _spooky_end_part(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); #endif int i; for (i = 0; i < 3; i++) { _spooky_end_part(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); } } // // The goal is for each bit of the input to expand into 128 bits of // apparent entropy before it is fully overwritten. // n trials both set and cleared at least m bits of h0 h1 h2 h3 // n: 2 m: 29 // n: 3 m: 46 // n: 4 m: 57 // n: 5 m: 107 // n: 6 m: 146 // n: 7 m: 152 // when run forwards or backwards // for all 1-bit and 2-bit diffs // with diffs defined by either xor or subtraction // with a base of all zeros plus a counter, or plus another bit, or random // static GU_FORCE_INLINE void _spooky_short_mix(uint64_t* h0, uint64_t* h1, uint64_t* h2, uint64_t* h3) { *h2 = GU_ROTL64(*h2,50); *h2 += *h3; *h0 ^= *h2; *h3 = GU_ROTL64(*h3,52); *h3 += *h0; *h1 ^= *h3; *h0 = GU_ROTL64(*h0,30); *h0 += *h1; *h2 ^= *h0; *h1 = GU_ROTL64(*h1,41); *h1 += *h2; *h3 ^= *h1; *h2 = GU_ROTL64(*h2,54); *h2 += *h3; *h0 ^= *h2; *h3 = GU_ROTL64(*h3,48); *h3 += *h0; *h1 ^= *h3; *h0 = GU_ROTL64(*h0,38); *h0 += *h1; *h2 ^= *h0; *h1 = GU_ROTL64(*h1,37); *h1 += *h2; *h3 ^= *h1; *h2 = GU_ROTL64(*h2,62); *h2 += *h3; *h0 ^= *h2; *h3 = GU_ROTL64(*h3,34); *h3 += *h0; *h1 ^= *h3; *h0 = GU_ROTL64(*h0,5); *h0 += *h1; *h2 ^= *h0; *h1 = GU_ROTL64(*h1,36); *h1 += *h2; *h3 ^= *h1; } // // Mix all 4 inputs together so that h0, h1 are a hash of them all. // // For two inputs differing in just the input bits // Where "differ" means xor or subtraction // And the base value is random, or a counting value starting at that bit // The final result will have each bit of h0, h1 flip // For every input bit, // with probability 50 +- .3% (it is probably better than that) // For every pair of input bits, // with probability 50 +- .75% (the worst case is approximately that) // static GU_FORCE_INLINE void _spooky_short_end(uint64_t* h0, uint64_t* h1, uint64_t* h2, uint64_t* h3) { *h3 ^= *h2; *h2 = GU_ROTL64(*h2,15); *h3 += *h2; *h0 ^= *h3; *h3 = GU_ROTL64(*h3,52); *h0 += *h3; *h1 ^= *h0; *h0 = GU_ROTL64(*h0,26); *h1 += *h0; *h2 ^= *h1; *h1 = GU_ROTL64(*h1,51); *h2 += *h1; *h3 ^= *h2; *h2 = GU_ROTL64(*h2,28); *h3 += *h2; *h0 ^= *h3; *h3 = GU_ROTL64(*h3,9); *h0 += *h3; *h1 ^= *h0; *h0 = GU_ROTL64(*h0,47); *h1 += *h0; *h2 ^= *h1; *h1 = GU_ROTL64(*h1,54); *h2 += *h1; *h3 ^= *h2; *h2 = GU_ROTL64(*h2,32); *h3 += *h2; *h0 ^= *h3; *h3 = GU_ROTL64(*h3,25); *h0 += *h3; *h1 ^= *h0; *h0 = GU_ROTL64(*h0,63); *h1 += *h0; } // // short hash ... it could be used on any message, // but it's used by Spooky just for short messages. // static GU_INLINE void gu_spooky_short_host( const void* const message, size_t const length, uint64_t* const hash) { union { const uint8_t* p8; uint32_t* p32; uint64_t* p64; #if !GU_ALLOW_UNALIGNED_READS size_t i; #endif /* !GU_ALLOW_UNALIGNED_READS */ } u; u.p8 = (const uint8_t *)message; #if !GU_ALLOW_UNALIGNED_READS if (u.i & 0x7) { uint64_t buf[_spooky_numVars << 1]; memcpy(buf, message, length); u.p64 = buf; } #endif /* !GU_ALLOW_UNALIGNED_READS */ size_t remainder = length & 0x1F; /* length%32 */ /* author version : */ // uint64_t a = gu_le64(*hash[0]); // uint64_t b = gu_le64(*hash[1]); /* consistent seed version: */ uint64_t a = 0; uint64_t b = 0; uint64_t c = _spooky_const; uint64_t d = _spooky_const; if (length > 15) { const uint64_t *end = u.p64 + ((length >> 5) << 2); /* (length/32)*4 */ // handle all complete sets of 32 bytes for (; u.p64 < end; u.p64 += 4) { c += gu_le64(u.p64[0]); d += gu_le64(u.p64[1]); _spooky_short_mix(&a, &b, &c, &d); a += gu_le64(u.p64[2]); b += gu_le64(u.p64[3]); } //Handle the case of 16+ remaining bytes. if (remainder >= 16) { c += gu_le64(u.p64[0]); d += gu_le64(u.p64[1]); _spooky_short_mix(&a, &b, &c, &d); u.p64 += 2; remainder -= 16; } } // Handle the last 0..15 bytes, and its length d = ((uint64_t)length) << 56; switch (remainder) { case 15: d += ((uint64_t)u.p8[14]) << 48; case 14: d += ((uint64_t)u.p8[13]) << 40; case 13: d += ((uint64_t)u.p8[12]) << 32; case 12: d += gu_le32(u.p32[2]); c += gu_le64(u.p64[0]); break; case 11: d += ((uint64_t)u.p8[10]) << 16; case 10: d += ((uint64_t)u.p8[9]) << 8; case 9: d += (uint64_t)u.p8[8]; case 8: c += gu_le64(u.p64[0]); break; case 7: c += ((uint64_t)u.p8[6]) << 48; case 6: c += ((uint64_t)u.p8[5]) << 40; case 5: c += ((uint64_t)u.p8[4]) << 32; case 4: c += gu_le32(u.p32[0]); break; case 3: c += ((uint64_t)u.p8[2]) << 16; case 2: c += ((uint64_t)u.p8[1]) << 8; case 1: c += (uint64_t)u.p8[0]; break; case 0: c += _spooky_const; d += _spooky_const; } _spooky_short_end(&a, &b, &c, &d); // @note - in native-endian order! hash[0] = a; hash[1] = b; } static GU_FORCE_INLINE void gu_spooky_short( const void* message, size_t length, void* const hash) { uint64_t* const u64 = (uint64_t*)hash; gu_spooky_short_host(message, length, u64); u64[0] = gu_le64(u64[0]); u64[1] = gu_le64(u64[1]); } // do the whole hash in one call static GU_INLINE void gu_spooky_inline ( const void* const message, size_t const length, uint64_t* const hash) { #ifdef GU_USE_SPOOKY_SHORT if (length < _spooky_bufSize) { gu_spooky_short_base (message, length, hash); return; } #endif /* GU_USE_SPOOKY_SHORT */ uint64_t h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11; uint64_t buf[_spooky_numVars]; uint64_t* end; union { const uint8_t* p8; uint64_t* p64; #if !GU_ALLOW_UNALIGNED_READS size_t i; #endif /* !GU_ALLOW_UNALIGNED_READS */ } u; size_t remainder; /* this is how the author wants it: a possibility for different seeds h0=h3=h6=h9 = gu_le64(hash[0]); h1=h4=h7=h10 = gu_le64(hash[1]); * this is how we want it - constant seed */ h0=h3=h6=h9 = 0; h1=h4=h7=h10 = 0; h2=h5=h8=h11 = _spooky_const; u.p8 = (const uint8_t*) message; end = u.p64 + (length/_spooky_blockSize)*_spooky_numVars; // handle all whole _spooky_blockSize blocks of bytes #if !GU_ALLOW_UNALIGNED_READS if ((u.i & 0x7) == 0) { #endif /* !GU_ALLOW_UNALIGNED_READS */ while (u.p64 < end) { _spooky_mix(u.p64, &h0,&h1,&h2,&h3,&h4,&h5,&h6,&h7,&h8,&h9,&h10,&h11); u.p64 += _spooky_numVars; } #if !GU_ALLOW_UNALIGNED_READS } else { while (u.p64 < end) { memcpy(buf, u.p64, _spooky_blockSize); _spooky_mix(buf, &h0,&h1,&h2,&h3,&h4,&h5,&h6,&h7,&h8,&h9,&h10,&h11); u.p64 += _spooky_numVars; } } #endif /* !GU_ALLOW_UNALIGNED_READS */ // handle the last partial block of _spooky_blockSize bytes remainder = (length - ((const uint8_t*)end - (const uint8_t*)message)); memcpy(buf, end, remainder); memset(((uint8_t*)buf) + remainder, 0, _spooky_blockSize - remainder); ((uint8_t*)buf)[_spooky_blockSize - 1] = remainder; _spooky_mix(buf, &h0,&h1,&h2,&h3,&h4,&h5,&h6,&h7,&h8,&h9,&h10,&h11); // do some final mixing _spooky_end(&h0,&h1,&h2,&h3,&h4,&h5,&h6,&h7,&h8,&h9,&h10,&h11); /*! @note: in native order */ hash[0] = h0; hash[1] = h1; } /* As is apparent from the gu_spooky_inline(), Spooky hash is enormous. * Since it has advantage only on long messages, it makes sense to make it * a regular function to avoid code bloat. * WARNING: does not do final endian conversion! */ extern void gu_spooky128_host (const void* const msg, size_t const len, uint64_t* res); /* returns hash in the canonical byte order, as a byte array */ static GU_FORCE_INLINE void gu_spooky128 (const void* const msg, size_t const len, void* const res) { uint64_t* const r = (uint64_t*)res; gu_spooky128_host (msg, len, r); r[0] = gu_le64(r[0]); r[1] = gu_le64(r[1]); } /* returns hash as an integer, in host byte-order */ static GU_FORCE_INLINE uint64_t gu_spooky64 (const void* const msg, size_t const len) { uint64_t res[2]; gu_spooky128_host (msg, len, res); return res[0]; } /* returns hash as an integer, in host byte-order */ static GU_FORCE_INLINE uint32_t gu_spooky32 (const void* const msg, size_t const len) { uint64_t res[2]; gu_spooky128_host (msg, len, res); return (uint32_t)res[0]; } #ifdef __cplusplus } #endif #endif /* _gu_spooky_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_dbug.c0000644000175000017500000015150713136555240024452 0ustar jenkinsjenkins/****************************************************************************** * * * N O T I C E * * * * Copyright Abandoned, 1987, Fred Fish * * * * * * This previously copyrighted work has been placed into the public * * domain by the author and may be freely used for any purpose, * * private or commercial. * * * * Because of the number of inquiries I was receiving about the use * * of this product in commercially developed works I have decided to * * simply make it public domain to further its unrestricted use. I * * specifically would be most happy to see this material become a * * part of the standard Unix distributions by AT&T and the Berkeley * * Computer Science Research Group, and a standard part of the GNU * * system from the Free Software Foundation. * * * * I would appreciate it, as a courtesy, if this notice is left in * * all copies and derivative works. Thank you. * * * * The author makes no warranty of any kind with respect to this * * product and explicitly disclaims any implied warranties of mer- * * chantability or fitness for any particular purpose. * * * ****************************************************************************** */ /* * FILE * * dbug.c runtime support routines for dbug package * * SCCS * * @(#)dbug.c 1.25 7/25/89 * * DESCRIPTION * * These are the runtime support routines for the dbug package. * The dbug package has two main components; the user include * file containing various macro definitions, and the runtime * support routines which are called from the macro expansions. * * Externally visible functions in the runtime support module * use the naming convention pattern "_db_xx...xx_", thus * they are unlikely to collide with user defined function names. * * AUTHOR(S) * * Fred Fish (base code) * Enhanced Software Technologies, Tempe, AZ * asuvax!mcdphx!estinc!fnf * * Binayak Banerjee (profiling enhancements) * seismo!bpa!sjuvax!bbanerje * * Michael Widenius: * DBUG_DUMP - To dump a pice of memory. * PUSH_FLAG "O" - To be used insted of "o" if we don't * want flushing (for slow systems) * PUSH_FLAG "A" - as 'O', but we will append to the out file instead * of creating a new one. * Check of malloc on entry/exit (option "S") * * Alexey Yurchenko: * - Renamed global symbols for use with galera project to avoid * collisions with other software (notably MySQL) * * Teemu Ollakka: * - Slight cleanups, removed some MySQL dependencies. * - All global variables should now have _gu_db prefix. * - Thread -> state mapping for multithreaded programs. * - Changed initialization so that it is done on the first * call to _gu_db_push(). * * $Id$ */ #include #include #include #include #include #include #ifndef GU_DBUG_ON #define GU_DBUG_ON #endif #include "gu_dbug.h" /* Make a new type: bool_t */ typedef enum { FALSE = (0 != 0), TRUE = (!FALSE) } bool_t; #define _VARARGS(X) X #define FN_LIBCHAR 1024 #define FN_REFLEN 1024 #define NullS "" #include #if defined(MSDOS) || defined(__WIN__) #include #endif #ifdef _GU_DBUG_CONDITION_ #define _GU_DBUG_START_CONDITION_ "d:t" #else #define _GU_DBUG_START_CONDITION_ "" #endif /* * Manifest constants that should not require any changes. */ #define EOS '\000' /* End Of String marker */ /* * Manifest constants which may be "tuned" if desired. */ #define PRINTBUF 1024 /* Print buffer size */ #define INDENT 2 /* Indentation per trace level */ #define MAXDEPTH 200 /* Maximum trace depth default */ /* * The following flags are used to determine which * capabilities the user has enabled with the state * push macro. */ #define TRACE_ON 000001 /* Trace enabled */ #define DEBUG_ON 000002 /* Debug enabled */ #define FILE_ON 000004 /* File name print enabled */ #define LINE_ON 000010 /* Line number print enabled */ #define DEPTH_ON 000020 /* Function nest level print enabled */ #define PROCESS_ON 000040 /* Process name print enabled */ #define NUMBER_ON 000100 /* Number each line of output */ #define PROFILE_ON 000200 /* Print out profiling code */ #define PID_ON 000400 /* Identify each line with process id */ #define SANITY_CHECK_ON 001000 /* Check my_malloc on GU_DBUG_ENTER */ #define FLUSH_ON_WRITE 002000 /* Flush on every write */ #define TRACING (_gu_db_stack -> flags & TRACE_ON) #define DEBUGGING (_gu_db_stack -> flags & DEBUG_ON) #define PROFILING (_gu_db_stack -> flags & PROFILE_ON) #define STREQ(a,b) (strcmp(a,b) == 0) #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) /* * Typedefs to make things more obvious.??? */ #ifndef __WIN__ typedef int BOOLEAN; #else #define BOOLEAN BOOL #endif /* * Make it easy to change storage classes if necessary. */ #define IMPORT extern /* Names defined externally */ #define EXPORT /* Allocated here, available globally */ #define AUTO auto /* Names to be allocated on stack */ #define REGISTER register /* Names to be placed in registers */ /* * The default file for profiling. Could also add another flag * (G?) which allowed the user to specify this. * * If the automatic variables get allocated on the stack in * reverse order from their declarations, then define AUTOS_REVERSE. * This is used by the code that keeps track of stack usage. For * forward allocation, the difference in the dbug frame pointers * represents stack used by the callee function. For reverse allocation, * the difference represents stack used by the caller function. * */ #define PROF_FILE "dbugmon.out" #define PROF_EFMT "E\t%ld\t%s\n" #define PROF_SFMT "S\t%lx\t%lx\t%s\n" #define PROF_XFMT "X\t%ld\t%s\n" #ifdef M_I386 /* predefined by xenix 386 compiler */ #define AUTOS_REVERSE 1 #endif /* * Variables which are available externally but should only * be accessed via the macro package facilities. */ FILE *_gu_db_fp_ = (FILE*) 0; /* Output stream, default stderr */ char *_gu_db_process_ = (char*) "dbug"; /* Pointer to process name; argv[0] */ FILE *_gu_db_pfp_ = (FILE*) 0; /* Profile stream, 'dbugmon.out' */ BOOLEAN _gu_db_on_ = FALSE; /* TRUE if debugging currently on */ BOOLEAN _gu_db_pon_ = FALSE; /* TRUE if profile currently on */ BOOLEAN _gu_no_db_ = TRUE; /* TRUE if no debugging at all */ /* * Externally supplied functions. */ IMPORT int _sanity(const char *file, uint line); /* * The user may specify a list of functions to trace or * debug. These lists are kept in a linear linked list, * a very simple implementation. */ struct link { char *str; /* Pointer to link's contents */ struct link *next_link; /* Pointer to the next link */ }; /* * Debugging states can be pushed or popped off of a * stack which is implemented as a linked list. Note * that the head of the list is the current state and the * stack is pushed by adding a new state to the head of the * list or popped by removing the first link. */ struct state { int flags; /* Current state flags */ int maxdepth; /* Current maximum trace depth */ uint delay; /* Delay after each output line */ int sub_level; /* Sub this from code_state->level */ FILE* out_file; /* Current output stream */ FILE* prof_file; /* Current profiling stream */ char name[FN_REFLEN]; /* Name of output file */ struct link* functions; /* List of functions */ struct link* p_functions; /* List of profiled functions */ struct link* keywords; /* List of debug keywords */ struct link* processes; /* List of process names */ struct state* next_state; /* Next state in the list */ }; /* * Local variables not seen by user. */ static struct state* _gu_db_stack = 0; typedef struct st_code_state { int lineno; /* Current debugger output line number */ int level; /* Current function nesting level */ const char* func; /* Name of current user function */ const char* file; /* Name of current user file */ char** framep; /* Pointer to current frame */ int jmplevel; /* Remember nesting level at setjmp () */ const char* jmpfunc; /* Remember current function for setjmp */ const char* jmpfile; /* Remember current file for setjmp */ /* * The following variables are used to hold the state information * between the call to _gu_db_pargs_() and _gu_db_doprnt_(), during * expansion of the GU_DBUG_PRINT macro. This is the only macro * that currently uses these variables. * * These variables are currently used only by _gu_db_pargs_() and * _gu_db_doprnt_(). */ uint u_line; /* User source code line number */ const char* u_keyword; /* Keyword for current macro */ int locked; /* If locked with _gu_db_lock_file */ } CODE_STATE; /* Parse a debug command string */ static struct link *ListParse(char *ctlp); /* Make a fresh copy of a string */ static char *StrDup(const char *str); /* Open debug output stream */ static void GU_DBUGOpenFile(const char *name, int append); #ifndef THREAD /* Open profile output stream */ static FILE *OpenProfile(const char *name); /* Profile if asked for it */ static BOOLEAN DoProfile(void); /* Return current user time (ms) */ static unsigned long Clock(void); #endif /* Close debug output stream */ static void CloseFile(FILE * fp); /* Push current debug state */ static void PushState(void); /* Test for tracing enabled */ static BOOLEAN DoTrace(CODE_STATE * state); /* Test to see if file is writable */ #if !(!defined(HAVE_ACCESS) || defined(MSDOS)) static BOOLEAN Writable(char *pathname); /* Change file owner and group */ static void ChangeOwner(char *pathname); /* Allocate memory for runtime support */ #endif static char *DbugMalloc(int size); /* Remove leading pathname components */ static char *BaseName(const char *pathname); static void DoPrefix(uint line); static void FreeList(struct link *linkp); static void Indent(int indent); static BOOLEAN InList(struct link *linkp, const char *cp); static void dbug_flush(CODE_STATE *); static void DbugExit(const char *why); static int DelayArg(int value); /* Supplied in Sys V runtime environ */ /* Break string into tokens */ static char *static_strtok(char *s1, char chr); /* * Miscellaneous printf format strings. */ #define ERR_MISSING_RETURN "%s: missing GU_DBUG_RETURN or GU_DBUG_VOID_RETURN macro in function \"%s\"\n" #define ERR_OPEN "%s: can't open debug output stream \"%s\": " #define ERR_CLOSE "%s: can't close debug file: " #define ERR_ABORT "%s: debugger aborting because %s\n" #define ERR_CHOWN "%s: can't change owner/group of \"%s\": " /* * Macros and defines for testing file accessibility under UNIX and MSDOS. */ #undef EXISTS #if !defined(HAVE_ACCESS) || defined(MSDOS) #define EXISTS(pathname) (FALSE) /* Assume no existance */ #define Writable(name) (TRUE) #else #define EXISTS(pathname) (access (pathname, F_OK) == 0) #define WRITABLE(pathname) (access (pathname, W_OK) == 0) #endif #ifndef MSDOS #define ChangeOwner(name) #endif /* * Translate some calls among different systems. */ #if defined(unix) || defined(xenix) || defined(VMS) || defined(__NetBSD__) # define Delay(A) sleep((uint) A) #elif defined(AMIGA) IMPORT int Delay(); /* Pause for given number of ticks */ #else static int Delay(int ticks); #endif /* ** Macros to allow dbugging with threads */ #ifdef THREAD #include pthread_once_t _gu_db_once = PTHREAD_ONCE_INIT; pthread_mutex_t _gu_db_mutex = PTHREAD_MUTEX_INITIALIZER; struct state_map { pthread_t th; CODE_STATE *state; struct state_map *prev; struct state_map *next; }; #define _GU_DB_STATE_MAP_BUCKETS (1 << 7) static struct state_map *_gu_db_state_map[_GU_DB_STATE_MAP_BUCKETS]; /* * This hash is probably good enough. Golden ratio 2654435761U from * http://www.concentric.net/~Ttwang/tech/inthash.htm * * UPDATE: it is good enough for input with significant variation in * 32 lower bits. */ static inline unsigned long pt_hash(const pthread_t th) { unsigned long k = (unsigned long)th; uint64_t ret = 2654435761U * k; // since we're returning a masked hash key, all considerations // for "reversibility" can be dropped. Instead we can help // higher input bits influence lower output bits. XOR rules. return (ret ^ (ret >> 32)) & (_GU_DB_STATE_MAP_BUCKETS - 1); } static CODE_STATE *state_map_find(const pthread_t th) { unsigned int key = pt_hash(th); struct state_map *sm = _gu_db_state_map[key]; while (sm && sm->th != th) sm = sm->next; return sm ? sm->state : NULL; } void state_map_insert(const pthread_t th, CODE_STATE *state) { unsigned int key; struct state_map *sm; assert(state_map_find(th) == NULL); key = pt_hash(th); sm = malloc(sizeof(struct state_map)); sm->state = state; sm->th = th; pthread_mutex_lock(&_gu_db_mutex); sm->prev = NULL; sm->next = _gu_db_state_map[key]; if (sm->next) sm->next->prev = sm; _gu_db_state_map[key] = sm; pthread_mutex_unlock(&_gu_db_mutex); } void state_map_erase(const pthread_t th) { unsigned int key; struct state_map *sm; key = pt_hash(th); sm = _gu_db_state_map[key]; while (sm && sm->th != th) sm = sm->next; assert(sm); pthread_mutex_lock(&_gu_db_mutex); if (sm->prev) { sm->prev->next = sm->next; } else { assert(_gu_db_state_map[key] == sm); _gu_db_state_map[key] = sm->next; } if (sm->next) sm->next->prev = sm->prev; pthread_mutex_unlock(&_gu_db_mutex); free(sm); } static CODE_STATE * code_state(void) { CODE_STATE *state = 0; if ((state = state_map_find(pthread_self())) == NULL) { state = malloc(sizeof(CODE_STATE)); memset(state, 0, sizeof(CODE_STATE)); state->func = "?func"; state->file = "?file"; state->u_keyword = "?"; state_map_insert(pthread_self(), state); } return state; } static void code_state_cleanup(CODE_STATE *state) { if (state->level == 0) { state_map_erase(pthread_self()); free(state); } } static void _gu_db_init() { if (!_gu_db_fp_) _gu_db_fp_ = stderr; /* Output stream, default stderr */ memset(_gu_db_state_map, 0, sizeof(_gu_db_state_map)); } #else /* !THREAD */ #define _gu_db_init() #define code_state() (&static_code_state) #define code_state_cleanup(A) do {} while (0) #define pthread_mutex_lock(A) {} #define pthread_mutex_unlock(A) {} static CODE_STATE static_code_state = { 0, 0, "?func", "?file", NULL, 0, NULL, NULL, 0, "?", 0 }; #endif /* * FUNCTION * * _gu_db_push_ push current debugger state and set up new one * * SYNOPSIS * * VOID _gu_db_push_ (control) * char *control; * * DESCRIPTION * * Given pointer to a debug control string in "control", pushes * the current debug state, parses the control string, and sets * up a new debug state. * * The only attribute of the new state inherited from the previous * state is the current function nesting level. This can be * overridden by using the "r" flag in the control string. * * The debug control string is a sequence of colon separated fields * as follows: * * ::...: * * Each field consists of a mandatory flag character followed by * an optional "," and comma separated list of modifiers: * * flag[,modifier,modifier,...,modifier] * * The currently recognized flag characters are: * * d Enable output from GU_DBUG_ macros for * for the current state. May be followed * by a list of keywords which selects output * only for the GU_DBUG macros with that keyword. * A null list of keywords implies output for * all macros. * * D Delay after each debugger output line. * The argument is the number of tenths of seconds * to delay, subject to machine capabilities. * I.E. -#D,20 is delay two seconds. * * f Limit debugging and/or tracing, and profiling to the * list of named functions. Note that a null list will * disable all functions. The appropriate "d" or "t" * flags must still be given, this flag only limits their * actions if they are enabled. * * F Identify the source file name for each * line of debug or trace output. * * i Identify the process with the pid for each line of * debug or trace output. * * g Enable profiling. Create a file called 'dbugmon.out' * containing information that can be used to profile * the program. May be followed by a list of keywords * that select profiling only for the functions in that * list. A null list implies that all functions are * considered. * * L Identify the source file line number for * each line of debug or trace output. * * n Print the current function nesting depth for * each line of debug or trace output. * * N Number each line of dbug output. * * o Redirect the debugger output stream to the * specified file. The default output is stderr. * * O As O but the file is really flushed between each * write. When neaded the file is closed and reopened * between each write. * * p Limit debugger actions to specified processes. * A process must be identified with the * GU_DBUG_PROCESS macro and match one in the list * for debugger actions to occur. * * P Print the current process name for each * line of debug or trace output. * * r When pushing a new state, do not inherit * the previous state's function nesting level. * Useful when the output is to start at the * left margin. * * S Do function _sanity(_file_,_line_) at each * debugged function until _sanity() returns * something that differs from 0. * (Moustly used with my_malloc) * * t Enable function call/exit trace lines. * May be followed by a list (containing only * one modifier) giving a numeric maximum * trace level, beyond which no output will * occur for either debugging or tracing * macros. The default is a compile time * option. * * Some examples of debug control strings which might appear * on a shell command line (the "-#" is typically used to * introduce a control string to an application program) are: * * -#d:t * -#d:f,main,subr1:F:L:t,20 * -#d,input,output,files:n * * For convenience, any leading "-#" is stripped off. * */ void _gu_db_push_(const char *control) { register char *scan; register struct link *temp; CODE_STATE *state; char *new_str; pthread_once(&_gu_db_once, &_gu_db_init); if (control && *control == '-') { if (*++control == '#') control++; } if (*control) _gu_no_db_ = FALSE; /* We are using dbug after all */ else return; new_str = StrDup(control); PushState(); state = code_state(); scan = static_strtok(new_str, ':'); for (; scan != NULL; scan = static_strtok((char *) NULL, ':')) { switch (*scan++) { case 'd': _gu_db_on_ = TRUE; _gu_db_stack->flags |= DEBUG_ON; if (*scan++ == ',') { _gu_db_stack->keywords = ListParse(scan); } break; case 'D': _gu_db_stack->delay = 0; if (*scan++ == ',') { temp = ListParse(scan); _gu_db_stack->delay = DelayArg(atoi(temp->str)); FreeList(temp); } break; case 'f': if (*scan++ == ',') { _gu_db_stack->functions = ListParse(scan); } break; case 'F': _gu_db_stack->flags |= FILE_ON; break; case 'i': _gu_db_stack->flags |= PID_ON; break; #ifndef THREAD case 'g': _gu_db_pon_ = TRUE; if (OpenProfile(PROF_FILE)) { _gu_db_stack->flags |= PROFILE_ON; if (*scan++ == ',') _gu_db_stack->p_functions = ListParse(scan); } break; #endif case 'L': _gu_db_stack->flags |= LINE_ON; break; case 'n': _gu_db_stack->flags |= DEPTH_ON; break; case 'N': _gu_db_stack->flags |= NUMBER_ON; break; case 'A': case 'O': _gu_db_stack->flags |= FLUSH_ON_WRITE; case 'a': case 'o': if (*scan++ == ',') { temp = ListParse(scan); GU_DBUGOpenFile(temp->str, (int) (scan[-2] == 'A' || scan[-2] == 'a')); FreeList(temp); } else { GU_DBUGOpenFile("-", 0); } break; case 'p': if (*scan++ == ',') { _gu_db_stack->processes = ListParse(scan); } break; case 'P': _gu_db_stack->flags |= PROCESS_ON; break; case 'r': _gu_db_stack->sub_level = state->level; break; case 't': _gu_db_stack->flags |= TRACE_ON; if (*scan++ == ',') { temp = ListParse(scan); _gu_db_stack->maxdepth = atoi(temp->str); FreeList(temp); } break; case 'S': _gu_db_stack->flags |= SANITY_CHECK_ON; break; } } free(new_str); } /* * FUNCTION * * _gu_db_pop_ pop the debug stack * * DESCRIPTION * * Pops the debug stack, returning the debug state to its * condition prior to the most recent _gu_db_push_ invocation. * Note that the pop will fail if it would remove the last * valid state from the stack. This prevents user errors * in the push/pop sequence from screwing up the debugger. * Maybe there should be some kind of warning printed if the * user tries to pop too many states. * */ void _gu_db_pop_() { register struct state *discard; discard = _gu_db_stack; if (discard != NULL && discard->next_state != NULL) { _gu_db_stack = discard->next_state; _gu_db_fp_ = _gu_db_stack->out_file; _gu_db_pfp_ = _gu_db_stack->prof_file; if (discard->keywords != NULL) { FreeList(discard->keywords); } if (discard->functions != NULL) { FreeList(discard->functions); } if (discard->processes != NULL) { FreeList(discard->processes); } if (discard->p_functions != NULL) { FreeList(discard->p_functions); } CloseFile(discard->out_file); if (discard->prof_file) CloseFile(discard->prof_file); free((char *) discard); if (!(_gu_db_stack->flags & DEBUG_ON)) _gu_db_on_ = 0; } else { if (_gu_db_stack) _gu_db_stack->flags &= ~DEBUG_ON; _gu_db_on_ = 0; } } /* * FUNCTION * * _gu_db_enter_ process entry point to user function * * SYNOPSIS * * VOID _gu_db_enter_ (_func_, _file_, _line_, * _sfunc_, _sfile_, _slevel_, _sframep_) * char *_func_; points to current function name * char *_file_; points to current file name * int _line_; called from source line number * char **_sfunc_; save previous _func_ * char **_sfile_; save previous _file_ * int *_slevel_; save previous nesting level * char ***_sframep_; save previous frame pointer * * DESCRIPTION * * Called at the beginning of each user function to tell * the debugger that a new function has been entered. * Note that the pointers to the previous user function * name and previous user file name are stored on the * caller's stack (this is why the ENTER macro must be * the first "executable" code in a function, since it * allocates these storage locations). The previous nesting * level is also stored on the callers stack for internal * self consistency checks. * * Also prints a trace line if tracing is enabled and * increments the current function nesting depth. * * Note that this mechanism allows the debugger to know * what the current user function is at all times, without * maintaining an internal stack for the function names. * */ void _gu_db_enter_(const char *_func_, const char *_file_, uint _line_, const char **_sfunc_, const char **_sfile_, uint * _slevel_, char ***_sframep_ __attribute__ ((unused))) { register CODE_STATE *state; if (!_gu_no_db_) { int save_errno = errno; state = code_state(); *_sfunc_ = state->func; *_sfile_ = state->file; state->func = (char *) _func_; state->file = (char *) _file_; /* BaseName takes time !! */ *_slevel_ = ++state->level; #ifndef THREAD *_sframep_ = state->framep; state->framep = (char **) _sframep_; if (DoProfile()) { long stackused; if (*state->framep == NULL) { stackused = 0; } else { stackused = ((long) (*state->framep)) - ((long) (state->framep)); stackused = stackused > 0 ? stackused : -stackused; } (void) fprintf(_gu_db_pfp_, PROF_EFMT, Clock(), state->func); #ifdef AUTOS_REVERSE (void) fprintf(_gu_db_pfp_, PROF_SFMT, state->framep, stackused, *_sfunc_); #else (void) fprintf(_gu_db_pfp_, PROF_SFMT, (ulong) state->framep, stackused, state->func); #endif (void) fflush(_gu_db_pfp_); } #endif if (DoTrace(state)) { if (!state->locked) pthread_mutex_lock(&_gu_db_mutex); DoPrefix(_line_); Indent(state->level); (void) fprintf(_gu_db_fp_, ">%s\n", state->func); dbug_flush(state); /* This does a unlock */ } #ifdef SAFEMALLOC if (_gu_db_stack->flags & SANITY_CHECK_ON) if (_sanity(_file_, _line_)) /* Check of my_malloc */ _gu_db_stack->flags &= ~SANITY_CHECK_ON; #endif errno = save_errno; } } /* * FUNCTION * * _gu_db_return_ process exit from user function * * SYNOPSIS * * VOID _gu_db_return_ (_line_, _sfunc_, _sfile_, _slevel_) * int _line_; current source line number * char **_sfunc_; where previous _func_ is to be retrieved * char **_sfile_; where previous _file_ is to be retrieved * int *_slevel_; where previous level was stashed * * DESCRIPTION * * Called just before user function executes an explicit or implicit * return. Prints a trace line if trace is enabled, decrements * the current nesting level, and restores the current function and * file names from the defunct function's stack. * */ void _gu_db_return_(uint _line_, const char **_sfunc_, const char **_sfile_, uint * _slevel_) { CODE_STATE *state; if (!_gu_no_db_) { int save_errno = errno; if (!(state = code_state())) return; /* Only happens at end of program */ if (_gu_db_stack->flags & (TRACE_ON | DEBUG_ON | PROFILE_ON)) { if (!state->locked) pthread_mutex_lock(&_gu_db_mutex); if (state->level != (int) *_slevel_) (void) fprintf(_gu_db_fp_, ERR_MISSING_RETURN, _gu_db_process_, state->func); else { #ifdef SAFEMALLOC if (_gu_db_stack->flags & SANITY_CHECK_ON) if (_sanity(*_sfile_, _line_)) _gu_db_stack->flags &= ~SANITY_CHECK_ON; #endif #ifndef THREAD if (DoProfile()) (void) fprintf(_gu_db_pfp_, PROF_XFMT, Clock(), state->func); #endif if (DoTrace(state)) { DoPrefix(_line_); Indent(state->level); (void) fprintf(_gu_db_fp_, "<%s\n", state->func); } } dbug_flush(state); } state->level = *_slevel_ - 1; state->func = *_sfunc_; state->file = *_sfile_; #ifndef THREAD if (state->framep != NULL) state->framep = (char **) *state->framep; #endif errno = save_errno; code_state_cleanup(state); } } /* * FUNCTION * * _gu_db_pargs_ log arguments for subsequent use by _gu_db_doprnt_() * * SYNOPSIS * * VOID _gu_db_pargs_ (_line_, keyword) * int _line_; * char *keyword; * * DESCRIPTION * * The new universal printing macro GU_DBUG_PRINT, which replaces * all forms of the GU_DBUG_N macros, needs two calls to runtime * support routines. The first, this function, remembers arguments * that are used by the subsequent call to _gu_db_doprnt_(). * */ void _gu_db_pargs_(uint _line_, const char *keyword) { CODE_STATE *state = code_state(); state->u_line = _line_; state->u_keyword = (char *) keyword; } /* * FUNCTION * * _gu_db_doprnt_ handle print of debug lines * * SYNOPSIS * * VOID _gu_db_doprnt_ (format, va_alist) * char *format; * va_dcl; * * DESCRIPTION * * When invoked via one of the GU_DBUG macros, tests the current keyword * set by calling _gu_db_pargs_() to see if that macro has been selected * for processing via the debugger control string, and if so, handles * printing of the arguments via the format string. The line number * of the GU_DBUG macro in the source is found in u_line. * * Note that the format string SHOULD NOT include a terminating * newline, this is supplied automatically. * */ #include void _gu_db_doprnt_(const char *format, ...) { va_list args; CODE_STATE *state; state = code_state(); va_start(args, format); if (_gu_db_keyword_(state->u_keyword)) { int save_errno = errno; if (!state->locked) pthread_mutex_lock(&_gu_db_mutex); DoPrefix(state->u_line); if (TRACING) { Indent(state->level + 1); } else { (void) fprintf(_gu_db_fp_, "%s: ", state->func); } (void) fprintf(_gu_db_fp_, "%s: ", state->u_keyword); (void) vfprintf(_gu_db_fp_, format, args); va_end(args); (void) fputc('\n', _gu_db_fp_); dbug_flush(state); errno = save_errno; } va_end(args); code_state_cleanup(state); } /* * FUNCTION * * _gu_db_dump_ dump a string until '\0' is found * * SYNOPSIS * * void _gu_db_dump_ (_line_,keyword,memory,length) * int _line_; current source line number * char *keyword; * char *memory; Memory to print * int length; Bytes to print * * DESCRIPTION * Dump N characters in a binary array. * Is used to examine corrputed memory or arrays. */ void _gu_db_dump_(uint _line_, const char *keyword, const char *memory, uint length) { int pos; char dbuff[90]; CODE_STATE *state; state = code_state(); if (_gu_db_keyword_((char *) keyword)) { if (!state->locked) pthread_mutex_lock(&_gu_db_mutex); DoPrefix(_line_); if (TRACING) { Indent(state->level + 1); pos = min(max(state->level - _gu_db_stack->sub_level, 0) * INDENT, 80); } else { fprintf(_gu_db_fp_, "%s: ", state->func); } sprintf(dbuff, "%s: Memory: %lx Bytes: (%d)\n", keyword, (ulong) memory, length); (void) fputs(dbuff, _gu_db_fp_); pos = 0; while (length-- > 0) { uint tmp = *((unsigned char *) memory++); if ((pos += 3) >= 80) { fputc('\n', _gu_db_fp_); pos = 3; } fputc(_gu_dig_vec[((tmp >> 4) & 15)], _gu_db_fp_); fputc(_gu_dig_vec[tmp & 15], _gu_db_fp_); fputc(' ', _gu_db_fp_); } (void) fputc('\n', _gu_db_fp_); dbug_flush(state); } code_state_cleanup(state); } /* * FUNCTION * * ListParse parse list of modifiers in debug control string * * SYNOPSIS * * static struct link *ListParse (ctlp) * char *ctlp; * * DESCRIPTION * * Given pointer to a comma separated list of strings in "cltp", * parses the list, building a list and returning a pointer to it. * The original comma separated list is destroyed in the process of * building the linked list, thus it had better be a duplicate * if it is important. * * Note that since each link is added at the head of the list, * the final list will be in "reverse order", which is not * significant for our usage here. * */ static struct link * ListParse(char *ctlp) { REGISTER char *start; REGISTER struct link *new_malloc; REGISTER struct link *head; head = NULL; while (*ctlp != EOS) { start = ctlp; while (*ctlp != EOS && *ctlp != ',') { ctlp++; } if (*ctlp == ',') { *ctlp++ = EOS; } new_malloc = (struct link *) DbugMalloc(sizeof(struct link)); new_malloc->str = StrDup(start); new_malloc->next_link = head; head = new_malloc; } return (head); } /* * FUNCTION * * InList test a given string for member of a given list * * SYNOPSIS * * static BOOLEAN InList (linkp, cp) * struct link *linkp; * char *cp; * * DESCRIPTION * * Tests the string pointed to by "cp" to determine if it is in * the list pointed to by "linkp". Linkp points to the first * link in the list. If linkp is NULL then the string is treated * as if it is in the list (I.E all strings are in the null list). * This may seem rather strange at first but leads to the desired * operation if no list is given. The net effect is that all * strings will be accepted when there is no list, and when there * is a list, only those strings in the list will be accepted. * */ static BOOLEAN InList(struct link *linkp, const char *cp) { REGISTER struct link *scan; REGISTER BOOLEAN result; if (linkp == NULL) { result = TRUE; } else { result = FALSE; for (scan = linkp; scan != NULL; scan = scan->next_link) { if (STREQ(scan->str, cp)) { result = TRUE; break; } } } return (result); } /* * FUNCTION * * PushState push current state onto stack and set up new one * * SYNOPSIS * * static VOID PushState () * * DESCRIPTION * * Pushes the current state on the state stack, and inits * a new state. The only parameter inherited from the previous * state is the function nesting level. This action can be * inhibited if desired, via the "r" flag. * * The state stack is a linked list of states, with the new * state added at the head. This allows the stack to grow * to the limits of memory if necessary. * */ static void PushState() { REGISTER struct state *new_malloc; new_malloc = (struct state *) DbugMalloc(sizeof(struct state)); new_malloc->flags = 0; new_malloc->delay = 0; new_malloc->maxdepth = MAXDEPTH; new_malloc->sub_level = 0; new_malloc->out_file = stderr; new_malloc->prof_file = (FILE *) 0; new_malloc->functions = NULL; new_malloc->p_functions = NULL; new_malloc->keywords = NULL; new_malloc->processes = NULL; new_malloc->next_state = _gu_db_stack; _gu_db_stack = new_malloc; } /* * FUNCTION * * DoTrace check to see if tracing is current enabled * * SYNOPSIS * * static BOOLEAN DoTrace (stack) * * DESCRIPTION * * Checks to see if tracing is enabled based on whether the * user has specified tracing, the maximum trace depth has * not yet been reached, the current function is selected, * and the current process is selected. Returns TRUE if * tracing is enabled, FALSE otherwise. * */ static BOOLEAN DoTrace(CODE_STATE * state) { register BOOLEAN trace = FALSE; if (TRACING && state->level <= _gu_db_stack->maxdepth && InList(_gu_db_stack->functions, state->func) && InList(_gu_db_stack->processes, _gu_db_process_)) trace = TRUE; return (trace); } /* * FUNCTION * * DoProfile check to see if profiling is current enabled * * SYNOPSIS * * static BOOLEAN DoProfile () * * DESCRIPTION * * Checks to see if profiling is enabled based on whether the * user has specified profiling, the maximum trace depth has * not yet been reached, the current function is selected, * and the current process is selected. Returns TRUE if * profiling is enabled, FALSE otherwise. * */ #ifndef THREAD static BOOLEAN DoProfile() { REGISTER BOOLEAN profile; CODE_STATE *state; state = code_state(); profile = FALSE; if (PROFILING && state->level <= _gu_db_stack->maxdepth && InList(_gu_db_stack->p_functions, state->func) && InList(_gu_db_stack->processes, _gu_db_process_)) profile = TRUE; return (profile); } #endif /* * FUNCTION * * _gu_db_keyword_ test keyword for member of keyword list * * SYNOPSIS * * BOOLEAN _gu_db_keyword_ (keyword) * char *keyword; * * DESCRIPTION * * Test a keyword to determine if it is in the currently active * keyword list. As with the function list, a keyword is accepted * if the list is null, otherwise it must match one of the list * members. When debugging is not on, no keywords are accepted. * After the maximum trace level is exceeded, no keywords are * accepted (this behavior subject to change). Additionally, * the current function and process must be accepted based on * their respective lists. * * Returns TRUE if keyword accepted, FALSE otherwise. * */ BOOLEAN _gu_db_keyword_(const char *keyword) { REGISTER BOOLEAN result; CODE_STATE *state; state = code_state(); result = FALSE; if (DEBUGGING && state->level <= _gu_db_stack->maxdepth && InList(_gu_db_stack->functions, state->func) && InList(_gu_db_stack->keywords, keyword) && InList(_gu_db_stack->processes, _gu_db_process_)) result = TRUE; return (result); } /* * FUNCTION * * Indent indent a line to the given indentation level * * SYNOPSIS * * static VOID Indent (indent) * int indent; * * DESCRIPTION * * Indent a line to the given level. Note that this is * a simple minded but portable implementation. * There are better ways. * * Also, the indent must be scaled by the compile time option * of character positions per nesting level. * */ static void Indent(int indent) { REGISTER int count; indent = max(indent - 1 - _gu_db_stack->sub_level, 0) * INDENT; for (count = 0; count < indent; count++) { if ((count % INDENT) == 0) fputc('|', _gu_db_fp_); else fputc(' ', _gu_db_fp_); } } /* * FUNCTION * * FreeList free all memory associated with a linked list * * SYNOPSIS * * static VOID FreeList (linkp) * struct link *linkp; * * DESCRIPTION * * Given pointer to the head of a linked list, frees all * memory held by the list and the members of the list. * */ static void FreeList(struct link *linkp) { REGISTER struct link *old; while (linkp != NULL) { old = linkp; linkp = linkp->next_link; if (old->str != NULL) { free(old->str); } free((char *) old); } } /* * FUNCTION * * StrDup make a duplicate of a string in new memory * * SYNOPSIS * * static char *StrDup (my_string) * char *string; * * DESCRIPTION * * Given pointer to a string, allocates sufficient memory to make * a duplicate copy, and copies the string to the newly allocated * memory. Failure to allocated sufficient memory is immediately * fatal. * */ static char * StrDup(const char *str) { register char *new_malloc; new_malloc = DbugMalloc((int) strlen(str) + 1); (void) strcpy(new_malloc, str); return (new_malloc); } /* * FUNCTION * * DoPrefix print debugger line prefix prior to indentation * * SYNOPSIS * * static VOID DoPrefix (_line_) * int _line_; * * DESCRIPTION * * Print prefix common to all debugger output lines, prior to * doing indentation if necessary. Print such information as * current process name, current source file name and line number, * and current function nesting depth. * */ static void DoPrefix(uint _line_) { CODE_STATE *state; state = code_state(); state->lineno++; if (_gu_db_stack->flags & PID_ON) { #ifdef THREAD (void) fprintf(_gu_db_fp_, "%5d:(thread %lu):", (int)getpid(), (unsigned long)pthread_self()); #else (void) fprintf(_gu_db_fp_, "%5d: ", (int) getpid()); #endif /* THREAD */ } if (_gu_db_stack->flags & NUMBER_ON) { (void) fprintf(_gu_db_fp_, "%5d: ", state->lineno); } if (_gu_db_stack->flags & PROCESS_ON) { (void) fprintf(_gu_db_fp_, "%s: ", _gu_db_process_); } if (_gu_db_stack->flags & FILE_ON) { (void) fprintf(_gu_db_fp_, "%14s: ", BaseName(state->file)); } if (_gu_db_stack->flags & LINE_ON) { (void) fprintf(_gu_db_fp_, "%5d: ", _line_); } if (_gu_db_stack->flags & DEPTH_ON) { (void) fprintf(_gu_db_fp_, "%4d: ", state->level); } } /* * FUNCTION * * GU_DBUGOpenFile open new output stream for debugger output * * SYNOPSIS * * static VOID GU_DBUGOpenFile (name) * char *name; * * DESCRIPTION * * Given name of a new file (or "-" for stdout) opens the file * and sets the output stream to the new file. * */ static void GU_DBUGOpenFile(const char *name, int append) { REGISTER FILE *fp; REGISTER BOOLEAN newfile; if (name != NULL) { strcpy(_gu_db_stack->name, name); if (strlen(name) == 1 && name[0] == '-') { _gu_db_fp_ = stdout; _gu_db_stack->out_file = _gu_db_fp_; _gu_db_stack->flags |= FLUSH_ON_WRITE; } else { if (!Writable((char *) name)) { (void) fprintf(stderr, ERR_OPEN, _gu_db_process_, name); perror(""); fflush(stderr); } else { newfile = !EXISTS(name); if (!(fp = fopen(name, append ? "a+" : "w"))) { (void) fprintf(stderr, ERR_OPEN, _gu_db_process_, name); perror(""); fflush(stderr); } else { _gu_db_fp_ = fp; _gu_db_stack->out_file = fp; if (newfile) { ChangeOwner(name); } } } } } } /* * FUNCTION * * OpenProfile open new output stream for profiler output * * SYNOPSIS * * static FILE *OpenProfile (name) * char *name; * * DESCRIPTION * * Given name of a new file, opens the file * and sets the profiler output stream to the new file. * * It is currently unclear whether the prefered behavior is * to truncate any existing file, or simply append to it. * The latter behavior would be desirable for collecting * accumulated runtime history over a number of separate * runs. It might take some changes to the analyzer program * though, and the notes that Binayak sent with the profiling * diffs indicated that append was the normal mode, but this * does not appear to agree with the actual code. I haven't * investigated at this time [fnf; 24-Jul-87]. */ #ifndef THREAD static FILE * OpenProfile(const char *name) { REGISTER FILE *fp; REGISTER BOOLEAN newfile; fp = 0; if (!Writable(name)) { (void) fprintf(_gu_db_fp_, ERR_OPEN, _gu_db_process_, name); perror(""); dbug_flush(0); (void) Delay(_gu_db_stack->delay); } else { newfile = !EXISTS(name); if (!(fp = fopen(name, "w"))) { (void) fprintf(_gu_db_fp_, ERR_OPEN, _gu_db_process_, name); perror(""); dbug_flush(0); } else { _gu_db_pfp_ = fp; _gu_db_stack->prof_file = fp; if (newfile) { ChangeOwner(name); } } } return fp; } #endif /* * FUNCTION * * CloseFile close the debug output stream * * SYNOPSIS * * static VOID CloseFile (fp) * FILE *fp; * * DESCRIPTION * * Closes the debug output stream unless it is standard output * or standard error. * */ static void CloseFile(FILE * fp) { if (fp != stderr && fp != stdout) { if (fclose(fp) == EOF) { pthread_mutex_lock(&_gu_db_mutex); (void) fprintf(_gu_db_fp_, ERR_CLOSE, _gu_db_process_); perror(""); dbug_flush(0); } } } /* * FUNCTION * * DbugExit print error message and exit * * SYNOPSIS * * static VOID DbugExit (why) * char *why; * * DESCRIPTION * * Prints error message using current process name, the reason for * aborting (typically out of memory), and exits with status 1. * This should probably be changed to use a status code * defined in the user's debugger include file. * */ static void DbugExit(const char *why) { (void) fprintf(stderr, ERR_ABORT, _gu_db_process_, why); (void) fflush(stderr); exit(1); } /* * FUNCTION * * DbugMalloc allocate memory for debugger runtime support * * SYNOPSIS * * static long *DbugMalloc (size) * int size; * * DESCRIPTION * * Allocate more memory for debugger runtime support functions. * Failure to to allocate the requested number of bytes is * immediately fatal to the current process. This may be * rather unfriendly behavior. It might be better to simply * print a warning message, freeze the current debugger state, * and continue execution. * */ static char * DbugMalloc(int size) { register char *new_malloc; if (!(new_malloc = (char *) malloc((unsigned int) size))) DbugExit("out of memory"); return (new_malloc); } /* * As strtok but two separators in a row are changed to one * separator (to allow directory-paths in dos). */ static char * static_strtok(char *s1, char separator) { static char *end = NULL; register char *rtnval, *cpy; rtnval = NULL; if (s1 != NULL) end = s1; if (end != NULL && *end != EOS) { rtnval = cpy = end; do { if ((*cpy++ = *end++) == separator) { if (*end != separator) { cpy--; /* Point at separator */ break; } end++; /* Two separators in a row, skipp one */ } } while (*end != EOS); *cpy = EOS; /* Replace last separator */ } return (rtnval); } /* * FUNCTION * * BaseName strip leading pathname components from name * * SYNOPSIS * * static char *BaseName (pathname) * char *pathname; * * DESCRIPTION * * Given pointer to a complete pathname, locates the base file * name at the end of the pathname and returns a pointer to * it. * */ static char * BaseName(const char *pathname) { register const char *base; base = strrchr(pathname, FN_LIBCHAR); // if (base++ == NullS) - this doesn't make sense if (NULL == base || '\0' == base[1]) base = pathname; return ((char *) base); } /* * FUNCTION * * Writable test to see if a pathname is writable/creatable * * SYNOPSIS * * static BOOLEAN Writable (pathname) * char *pathname; * * DESCRIPTION * * Because the debugger might be linked in with a program that * runs with the set-uid-bit (suid) set, we have to be careful * about opening a user named file for debug output. This consists * of checking the file for write access with the real user id, * or checking the directory where the file will be created. * * Returns TRUE if the user would normally be allowed write or * create access to the named file. Returns FALSE otherwise. * */ #ifndef Writable static BOOLEAN Writable(char *pathname) { REGISTER BOOLEAN granted; REGISTER char *lastslash; granted = FALSE; if (EXISTS(pathname)) { if (WRITABLE(pathname)) { granted = TRUE; } } else { lastslash = strrchr(pathname, '/'); if (lastslash != NULL) { *lastslash = EOS; } else { pathname = "."; } if (WRITABLE(pathname)) { granted = TRUE; } if (lastslash != NULL) { *lastslash = '/'; } } return (granted); } #endif /* * FUNCTION * * ChangeOwner change owner to real user for suid programs * * SYNOPSIS * * static VOID ChangeOwner (pathname) * * DESCRIPTION * * For unix systems, change the owner of the newly created debug * file to the real owner. This is strictly for the benefit of * programs that are running with the set-user-id bit set. * * Note that at this point, the fact that pathname represents * a newly created file has already been established. If the * program that the debugger is linked to is not running with * the suid bit set, then this operation is redundant (but * harmless). * */ #ifndef ChangeOwner static void ChangeOwner(char *pathname) { if (chown(pathname, getuid(), getgid()) == -1) { (void) fprintf(stderr, ERR_CHOWN, _gu_db_process_, pathname); perror(""); (void) fflush(stderr); } } #endif /* * FUNCTION * * _gu_db_setjmp_ save debugger environment * * SYNOPSIS * * VOID _gu_db_setjmp_ () * * DESCRIPTION * * Invoked as part of the user's GU_DBUG_SETJMP macro to save * the debugger environment in parallel with saving the user's * environment. * */ #ifdef HAVE_LONGJMP void _gu_db_setjmp_() { CODE_STATE *state; state = code_state(); state->jmplevel = state->level; state->jmpfunc = state->func; state->jmpfile = state->file; } /* * FUNCTION * * _gu_db_longjmp_ restore previously saved debugger environment * * SYNOPSIS * * VOID _gu_db_longjmp_ () * * DESCRIPTION * * Invoked as part of the user's GU_DBUG_LONGJMP macro to restore * the debugger environment in parallel with restoring the user's * previously saved environment. * */ void _gu_db_longjmp_() { CODE_STATE *state; state = code_state(); state->level = state->jmplevel; if (state->jmpfunc) { state->func = state->jmpfunc; } if (state->jmpfile) { state->file = state->jmpfile; } } #endif /* * FUNCTION * * DelayArg convert D flag argument to appropriate value * * SYNOPSIS * * static int DelayArg (value) * int value; * * DESCRIPTION * * Converts delay argument, given in tenths of a second, to the * appropriate numerical argument used by the system to delay * that that many tenths of a second. For example, on the * amiga, there is a system call "Delay()" which takes an * argument in ticks (50 per second). On unix, the sleep * command takes seconds. Thus a value of "10", for one * second of delay, gets converted to 50 on the amiga, and 1 * on unix. Other systems will need to use a timing loop. * */ #ifdef AMIGA #define HZ (50) /* Probably in some header somewhere */ #endif static int DelayArg(int value) { uint delayarg = 0; #if (unix || xenix) delayarg = value / 10; /* Delay is in seconds for sleep () */ #endif #ifdef AMIGA delayarg = (HZ * value) / 10; /* Delay in ticks for Delay () */ #endif return (delayarg); } /* * A dummy delay stub for systems that do not support delays. * With a little work, this can be turned into a timing loop. */ #if ! defined(Delay) && ! defined(AMIGA) static int Delay(int ticks) { return ticks; } #endif /* * FUNCTION * * perror perror simulation for systems that don't have it * * SYNOPSIS * * static VOID perror (s) * char *s; * * DESCRIPTION * * Perror produces a message on the standard error stream which * provides more information about the library or system error * just encountered. The argument string s is printed, followed * by a ':', a blank, and then a message and a newline. * * An undocumented feature of the unix perror is that if the string * 's' is a null string (NOT a NULL pointer!), then the ':' and * blank are not printed. * * This version just complains about an "unknown system error". * */ /* flush dbug-stream, free mutex lock & wait delay */ /* This is because some systems (MSDOS!!) dosn't flush fileheader */ /* and dbug-file isn't readable after a system crash !! */ static void dbug_flush(CODE_STATE * state) { #ifndef THREAD if (_gu_db_stack->flags & FLUSH_ON_WRITE) #endif { #if defined(MSDOS) || defined(__WIN__) if (_gu_db_fp_ != stdout && _gu_db_fp_ != stderr) { if (!(freopen(_gu_db_stack->name, "a", _gu_db_fp_))) { (void) fprintf(stderr, ERR_OPEN, _gu_db_process_,_gu_db_stack->name); fflush(stderr); _gu_db_fp_ = stdout; _gu_db_stack->out_file = _gu_db_fp_; _gu_db_stack->flags |= FLUSH_ON_WRITE; } } else #endif { (void) fflush(_gu_db_fp_); if (_gu_db_stack->delay) (void) Delay(_gu_db_stack->delay); } } if (!state || !state->locked) pthread_mutex_unlock(&_gu_db_mutex); } /* dbug_flush */ void _gu_db_lock_file() { CODE_STATE *state; state = code_state(); pthread_mutex_lock(&_gu_db_mutex); state->locked = 1; } void _gu_db_unlock_file() { CODE_STATE *state; state = code_state(); state->locked = 0; pthread_mutex_unlock(&_gu_db_mutex); } /* * Here we need the definitions of the clock routine. Add your * own for whatever system that you have. */ #ifndef THREAD #if defined(HAVE_GETRUSAGE) #include #include /* extern int getrusage(int, struct rusage *); */ /* * Returns the user time in milliseconds used by this process so * far. */ static unsigned long Clock() { struct rusage ru; (void) getrusage(RUSAGE_SELF, &ru); return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000)); } #elif defined(MSDOS) || defined(__WIN__) || defined(OS2) static ulong Clock() { return clock() * (1000 / Cmy_pthread_mutex_lockS_PER_SEC); } #elif defined (amiga) struct DateStamp { /* Yes, this is a hack, but doing it right */ long ds_Days; /* is incredibly ugly without splitting this */ long ds_Minute; /* off into a separate file */ long ds_Tick; }; static int first_clock = TRUE; static struct DateStamp begin; static struct DateStamp elapsed; static unsigned long Clock() { register struct DateStamp *now; register unsigned long millisec = 0; extern VOID *AllocMem(); now = (struct DateStamp *) AllocMem((long) sizeof(struct DateStamp), 0L); if (now != NULL) { if (first_clock == TRUE) { first_clock = FALSE; (void) DateStamp(now); begin = *now; } (void) DateStamp(now); millisec = 24 * 3600 * (1000 / HZ) * (now->ds_Days - begin.ds_Days); millisec += 60 * (1000 / HZ) * (now->ds_Minute - begin.ds_Minute); millisec += (1000 / HZ) * (now->ds_Tick - begin.ds_Tick); (void) FreeMem(now, (long) sizeof(struct DateStamp)); } return (millisec); } #else static unsigned long Clock() { return (0); } #endif /* RUSAGE */ #endif /* THREADS */ #ifdef NO_VARARGS /* * Fake vfprintf for systems that don't support it. If this * doesn't work, you are probably SOL... */ static int vfprintf(stream, format, ap) FILE *stream; char *format; va_list ap; { int rtnval; ARGS_DCL; ARG0 = va_arg(ap, ARGS_TYPE); ARG1 = va_arg(ap, ARGS_TYPE); ARG2 = va_arg(ap, ARGS_TYPE); ARG3 = va_arg(ap, ARGS_TYPE); ARG4 = va_arg(ap, ARGS_TYPE); ARG5 = va_arg(ap, ARGS_TYPE); ARG6 = va_arg(ap, ARGS_TYPE); ARG7 = va_arg(ap, ARGS_TYPE); ARG8 = va_arg(ap, ARGS_TYPE); ARG9 = va_arg(ap, ARGS_TYPE); rtnval = fprintf(stream, format, ARGS_LIST); return (rtnval); } #endif /* NO_VARARGS */ char _gu_dig_vec[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_fdesc.hpp0000644000175000017500000000254213136555240025154 0ustar jenkinsjenkins/* * Copyright (C) 2009-2016 Codership Oy * * $Id$ */ #ifndef __GU_FDESC_HPP__ #define __GU_FDESC_HPP__ #include "gu_exception.hpp" #include "gu_types.hpp" // for off_t, byte_t #include namespace gu { class FileDescriptor { public: /* open existing file */ FileDescriptor (const std::string& fname, bool sync = true); /* (re)create file */ FileDescriptor (const std::string& fname, size_t length, bool allocate = true, bool sync = true); ~FileDescriptor (); int get() const { return fd_; } const std::string& name() const { return name_; } off_t size() const { return size_; } void sync() const; void unlink() const { ::unlink (name_.c_str()); } private: std::string const name_; int const fd_; off_t const size_; bool const sync_; // sync on close bool write_byte (off_t offset); void write_file (off_t start = 0); void prealloc (off_t start = 0); void constructor_common(); FileDescriptor (const FileDescriptor&); FileDescriptor& operator = (const FileDescriptor); }; } /* namespace gu */ #endif /* __GU_FDESC_HPP__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_progress.hpp0000644000175000017500000000626513136555240025742 0ustar jenkinsjenkins/* * Copyright (C) 2016-2017 Codership Oy */ #ifndef __GU_PROGRESS__ #define __GU_PROGRESS__ #include "gu_logger.hpp" #include "gu_datetime.hpp" #include #include #include namespace gu { template class Progress { std::string const prefix_; std::string const units_; gu::datetime::Period const time_interval_; T const unit_interval_; T const total_; T current_; T last_size_; gu::datetime::Date last_time_; unsigned char const total_digits_; void report(gu::datetime::Date const now) { log_info << prefix_ << "..." << std::fixed << std::setprecision(1) << std::setw(5) << (double(current_)/total_ * 100) << "% (" << std::setw(total_digits_) << current_ << '/' << total_ << units_ << ") complete."; last_time_ = now; } static std::string const DEFAULT_INTERVAL; // see definition below public: /* * Creates progress context and logs the beginning of the progress (0%) * * @param p prefix to be printed in each report * (include trailing space) * @param u units to be printed next to numbers (empty string - no units) * (include space between number and units) * @param t total amount of work in units * @param ui minimal unit interval to report progress * @param ti minimal time interval to report progress */ Progress(const std::string& p, const std::string& u, T const t, T const ui, const std::string& ti = DEFAULT_INTERVAL) : prefix_ (p), units_ (u), time_interval_(ti), unit_interval_(ui), total_ (t), current_ (0), last_size_ (current_), last_time_ (), total_digits_ (::ceil(::log10(total_ + 1))) { report(gu::datetime::Date::monotonic()); } /* Increments progress by @increment. * If time limit is reached, logs the total progress */ void update(T const increment) { current_ += increment; if (current_ - last_size_ >= unit_interval_ /* don't log too close to the end */ && total_ - current_ > unit_interval_) { gu::datetime::Date const now(gu::datetime::Date::monotonic()); if (now - last_time_ >= time_interval_) report(now); last_size_ = current_; /* last_time_ is updated in report() */ } } /* Logs the end of the progress (100%) */ void finish() { current_ = total_; report(gu::datetime::Date::monotonic()); } }; /* class Progress */ template std::string const Progress::DEFAULT_INTERVAL = "PT10S"; /* 10 sec */ } /* namespace gu */ #endif /* __GU_PROGRESS__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_mmh3.h0000644000175000017500000002461113136555240024375 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /** * @file MurmurHash3 header * * This code is based on the refrence C++ MurMurHash3 implementation by its * author Austin Appleby, who released it to public domain. * * $Id$ */ #ifndef _gu_mmh3_h_ #define _gu_mmh3_h_ #include "gu_byteswap.h" #include // for memset() and memcpy() #ifdef __cplusplus extern "C" { #endif //----------------------------------------------------------------------------- // Finalization mix - force all bits of a hash block to avalanche static GU_FORCE_INLINE uint32_t _mmh3_fmix32 (uint32_t h) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; h ^= h >> 16; return h; } static GU_FORCE_INLINE uint64_t _mmh3_fmix64 (uint64_t k) { k ^= k >> 33; k *= GU_ULONG_LONG(0xff51afd7ed558ccd); k ^= k >> 33; k *= GU_ULONG_LONG(0xc4ceb9fe1a85ec53); k ^= k >> 33; return k; } //----------------------------------------------------------------------------- static uint32_t const _mmh3_32_c1 = 0xcc9e2d51; static uint32_t const _mmh3_32_c2 = 0x1b873593; static GU_FORCE_INLINE void _mmh3_block_32 (uint32_t k1, uint32_t* h1) { k1 *= _mmh3_32_c1; k1 = GU_ROTL32(k1,15); k1 *= _mmh3_32_c2; *h1 ^= k1; *h1 = GU_ROTL32(*h1,13); *h1 *= 5; *h1 += 0xe6546b64; } static GU_FORCE_INLINE void _mmh3_blocks_32 (const uint32_t* const blocks,size_t const nblocks,uint32_t* h1) { //---------- // body size_t i; for (i = 0; i < nblocks; i++) { //----------------------------------------------------------------------------- // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here _mmh3_block_32 (gu_le32(blocks[i]), h1);/* convert from little-endian */ } } static GU_FORCE_INLINE uint32_t _mmh3_tail_32 (const uint8_t* const tail, size_t const len, uint32_t h1) { //---------- // tail #if 0 /* Reference implementation */ uint32_t k1 = 0; switch(len & 3) { case 3: k1 ^= tail[2] << 16; case 2: k1 ^= tail[1] << 8; case 1: k1 ^= tail[0]; k1 *= _mmh3_32_c1; k1 = GU_ROTL32(k1,15); k1 *= _mmh3_32_c2; h1 ^= k1; }; #else /* Optimized implementation */ size_t const shift = (len & 3) << 3; if (shift) { uint32_t k1 = gu_le32(((uint32_t*)tail)[0]) & (0x00ffffff>>(24-shift)); k1 *= _mmh3_32_c1; k1 = GU_ROTL32(k1,15); k1 *= _mmh3_32_c2; h1 ^= k1; } #endif /* Optimized implementation */ //---------- // finalization h1 ^= len; h1 = _mmh3_fmix32(h1); return h1; } static GU_FORCE_INLINE uint32_t _mmh32_seed (const void* key, size_t const len, uint32_t seed) { size_t const nblocks = len >> 2; const uint32_t* const blocks = (const uint32_t*)key; const uint8_t* const tail = (const uint8_t*)(blocks + nblocks); _mmh3_blocks_32 (blocks, nblocks, &seed); return _mmh3_tail_32 (tail, len, seed); } // same as FNV32 seed static uint32_t const GU_MMH32_SEED = GU_ULONG(2166136261); /*! A function to hash buffer in one go */ #define gu_mmh32(_buf, _len) \ _mmh32_seed (_buf, _len, GU_MMH32_SEED); /* * 128-bit MurmurHash3 */ static uint64_t const _mmh3_128_c1 = GU_ULONG_LONG(0x87c37b91114253d5); static uint64_t const _mmh3_128_c2 = GU_ULONG_LONG(0x4cf5ad432745937f); static GU_FORCE_INLINE void _mmh3_128_block (uint64_t k1, uint64_t k2, uint64_t* h1, uint64_t* h2) { k1 *= _mmh3_128_c1; k1 = GU_ROTL64(k1,31); k1 *= _mmh3_128_c2; *h1 ^= k1; *h1 = GU_ROTL64(*h1,27); *h1 += *h2; *h1 *= 5; *h1 += 0x52dce729; k2 *= _mmh3_128_c2; k2 = GU_ROTL64(k2,33); k2 *= _mmh3_128_c1; *h2 ^= k2; *h2 = GU_ROTL64(*h2,31); *h2 += *h1; *h2 *= 5; *h2 += 0x38495ab5; } static GU_FORCE_INLINE void _mmh3_128_blocks (const uint64_t* const blocks, size_t const nblocks, uint64_t* h1, uint64_t* h2) { //---------- // body size_t i; for(i = 0; i < nblocks; i++) { //----------------------------------------------------------------------------- // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here uint64_t k1 = gu_le64(blocks[i]); i++; uint64_t k2 = gu_le64(blocks[i]); _mmh3_128_block (k1, k2, h1, h2); } } static GU_FORCE_INLINE void _mmh3_128_tail (const uint8_t* const tail, size_t const len, uint64_t h1, uint64_t h2, uint64_t* const out) { //---------- // tail uint64_t k1 = 0; uint64_t k2 = 0; switch(len & 15) { case 15: k2 ^= ((uint64_t)tail[14]) << 48; case 14: k2 ^= ((uint64_t)tail[13]) << 40; case 13: k2 ^= ((uint64_t)tail[12]) << 32; case 12: k2 ^= ((uint64_t)tail[11]) << 24; case 11: k2 ^= ((uint64_t)tail[10]) << 16; case 10: k2 ^= ((uint64_t)tail[ 9]) << 8; case 9: k2 ^= ((uint64_t)tail[ 8]) << 0; k2 *= _mmh3_128_c2; k2 = GU_ROTL64(k2,33); k2 *= _mmh3_128_c1; h2 ^= k2; k1 = gu_le64(((uint64_t*)tail)[0]); k1 *= _mmh3_128_c1; k1 = GU_ROTL64(k1,31); k1 *= _mmh3_128_c2; h1 ^= k1; break; case 8: k1 ^= ((uint64_t)tail[ 7]) << 56; case 7: k1 ^= ((uint64_t)tail[ 6]) << 48; case 6: k1 ^= ((uint64_t)tail[ 5]) << 40; case 5: k1 ^= ((uint64_t)tail[ 4]) << 32; case 4: k1 ^= ((uint64_t)tail[ 3]) << 24; case 3: k1 ^= ((uint64_t)tail[ 2]) << 16; case 2: k1 ^= ((uint64_t)tail[ 1]) << 8; case 1: k1 ^= ((uint64_t)tail[ 0]) << 0; k1 *= _mmh3_128_c1; k1 = GU_ROTL64(k1,31); k1 *= _mmh3_128_c2; h1 ^= k1; }; //---------- // finalization h1 ^= len; h2 ^= len; h1 += h2; h2 += h1; h1 = _mmh3_fmix64(h1); h2 = _mmh3_fmix64(h2); h1 += h2; h2 += h1; out[0] = h1; out[1] = h2; } static GU_FORCE_INLINE void _mmh3_128_seed (const void* const key, size_t const len, uint64_t s1, uint64_t s2, uint64_t* const out) { size_t const nblocks = (len >> 4) << 1; /* using 64-bit half-blocks */ const uint64_t* const blocks = (const uint64_t*)(key); const uint8_t* const tail = (const uint8_t*)(blocks + nblocks); _mmh3_128_blocks (blocks, nblocks, &s1, &s2); _mmh3_128_tail (tail, len, s1, s2, out); } // same as FNV128 seed static uint64_t const GU_MMH128_SEED1 = GU_ULONG_LONG(0x6C62272E07BB0142); static uint64_t const GU_MMH128_SEED2 = GU_ULONG_LONG(0x62B821756295C58D); /* returns hash in the canonical byte order, as a byte array */ static GU_FORCE_INLINE void gu_mmh128 (const void* const msg, size_t const len, void* const out) { _mmh3_128_seed (msg, len, GU_MMH128_SEED1, GU_MMH128_SEED2, (uint64_t*)out); uint64_t* const res = (uint64_t*)out; res[0] = gu_le64(res[0]); res[1] = gu_le64(res[1]); } /* returns hash as an integer, in host byte-order */ static GU_FORCE_INLINE uint64_t gu_mmh128_64 (const void* const msg, size_t len) { uint64_t res[2]; _mmh3_128_seed (msg, len, GU_MMH128_SEED1, GU_MMH128_SEED2, res); return res[0]; } /* returns hash as an integer, in host byte-order */ static GU_FORCE_INLINE uint32_t gu_mmh128_32 (const void* const msg, size_t len) { uint64_t res[2]; _mmh3_128_seed (msg, len, GU_MMH128_SEED1, GU_MMH128_SEED2, res); return (uint32_t)res[0]; } /* * Functions to hash message by parts * (only 128-bit version, 32-bit is not relevant any more) */ typedef struct gu_mmh128_ctx { uint64_t hash[2]; uint64_t tail[2]; size_t length; } gu_mmh128_ctx_t; /*! Initialize/reset MMH context with a particular seed. * The seed is two 8-byte _integers_, obviously in HOST BYTE ORDER. * Should not be used directly. */ static GU_INLINE void _mmh128_init_seed (gu_mmh128_ctx_t* const mmh, uint64_t const s1, uint64_t const s2) { memset (mmh, 0, sizeof(*mmh)); mmh->hash[0] = s1; mmh->hash[1] = s2; } /*! Initialize MMH context with a default Galera seed. */ #define gu_mmh128_init(_mmh) \ _mmh128_init_seed (_mmh, GU_MMH128_SEED1, GU_MMH128_SEED2); /*! Apeend message part to hash context */ static GU_INLINE void gu_mmh128_append (gu_mmh128_ctx_t* const mmh, const void* part, size_t len) { size_t tail_len = mmh->length & 15; mmh->length += len; if (tail_len) /* there's something in the tail */// do we need this if()? { size_t const to_fill = 16 - tail_len; void* const tail_end = (uint8_t*)mmh->tail + tail_len; if (len >= to_fill) /* we can fill a full block */ { memcpy (tail_end, part, to_fill); _mmh3_128_block (gu_le64(mmh->tail[0]), gu_le64(mmh->tail[1]), &mmh->hash[0], &mmh->hash[1]); part = ((char*)part) + to_fill; len -= to_fill; } else { memcpy (tail_end, part, len); return; } } size_t const nblocks = (len >> 4) << 1; /* using 64-bit half-blocks */ const uint64_t* const blocks = (const uint64_t*)(part); _mmh3_128_blocks (blocks, nblocks, &mmh->hash[0], &mmh->hash[1]); /* save possible trailing bytes to tail */ memcpy (mmh->tail, blocks + nblocks, len & 15); } /*! Get the accumulated message hash (does not change the context) */ static GU_INLINE void gu_mmh128_get (const gu_mmh128_ctx_t* const mmh, void* const res) { uint64_t* const r = (uint64_t*)res; _mmh3_128_tail ((const uint8_t*)mmh->tail, mmh->length, mmh->hash[0], mmh->hash[1], r); r[0] = gu_le64(r[0]); r[1] = gu_le64(r[1]); } static GU_INLINE uint64_t gu_mmh128_get64 (const gu_mmh128_ctx_t* const mmh) { uint64_t res[2]; _mmh3_128_tail ((const uint8_t*)mmh->tail, mmh->length, mmh->hash[0], mmh->hash[1], res); return res[0]; } static GU_INLINE uint32_t gu_mmh128_get32 (const gu_mmh128_ctx_t* const mmh) { uint64_t res[2]; _mmh3_128_tail ((const uint8_t*)mmh->tail, mmh->length, mmh->hash[0], mmh->hash[1], res); return (uint32_t)res[0]; } /* * Below are fuctions with reference signatures for implementation verification */ extern void gu_mmh3_32 (const void* key, int len, uint32_t seed, void* out); #if 0 /* x86 variant is faulty and unsuitable for short keys, ignore */ extern void gu_mmh3_x86_128 (const void* key, int len, uint32_t seed, void* out); #endif /* 0 */ extern void gu_mmh3_x64_128 (const void* key, int len, uint32_t seed, void* out); #ifdef __cplusplus } #endif #endif /* _gu_mmh3_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_rset.hpp0000644000175000017500000002622313136555240025047 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy */ /*! * @file common RecordSet interface * * Record set is a collection of serialized records of the same type. * * It stores them in an iovec-like collection of buffers before sending * and restores from a single buffer when receiving. * * $Id$ */ #ifndef _GU_RSET_HPP_ #define _GU_RSET_HPP_ #include "gu_vector.hpp" #include "gu_alloc.hpp" #include "gu_digest.hpp" #ifdef GU_RSET_CHECK_SIZE # include "gu_throw.hpp" #endif #include namespace gu { class RecordSet { public: enum Version { EMPTY = 0, VER1 }; static Version const MAX_VERSION = VER1; enum CheckType { CHECK_NONE = 0, CHECK_MMH32, CHECK_MMH64, CHECK_MMH128 }; /*! return total size of a RecordSet */ size_t size() const { return size_; } /*! return number of records in the record set */ int count() const { return count_; } typedef gu::Vector GatherVector; protected: ssize_t size_; int count_; Version version_; CheckType check_type_; /* ctor for RecordSetOut */ RecordSet (Version const version, CheckType const ct); /* ctor for RecordSetIn */ RecordSet () : size_(0), count_(0), version_(EMPTY), check_type_(CHECK_NONE) {} void init (const byte_t* buf, ssize_t size); ~RecordSet() {} }; #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic push # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic ignored "-Weffc++" #endif /*! class to store records in buffer(s) to send out */ class RecordSetOutBase : public RecordSet { public: typedef Allocator::BaseName BaseName; /*! return number of disjoint pages in the record set */ ssize_t page_count() const { return bufs_->size(); } /*! return vector of RecordSet fragments in adjusent order */ ssize_t gather (GatherVector& out); protected: RecordSetOutBase() : RecordSet() {} RecordSetOutBase (byte_t* reserved, size_t reserved_size, const BaseName& base_name, /* basename for on-disk * allocator */ CheckType ct, Version version = MAX_VERSION #ifdef GU_RSET_CHECK_SIZE ,ssize_t max_size = 0x7fffffff #endif ); /* this is to emulate partial specialization of function template through * overloading by parameter */ template struct HasPtr{}; /* variant for classes that don't provide ptr() method and need to be * explicitly serialized to internal storage */ template void process (const R& record, const byte_t*& ptr, bool& new_page, size_t const size, bool, HasPtr) { byte_t* const dst(alloc_.alloc (size, new_page)); new_page = (new_page || !prev_stored_); ptr = dst; #ifdef NDEBUG record.serialize_to (dst, size); #else size_t const ssize (record.serialize_to (dst, size)); assert (ssize == size); #endif } /* variant for classes that have ptr() method and can be either serialized * or referenced */ template void process (const R& record, const byte_t*& ptr, bool& new_page, size_t const size, bool const store, HasPtr) { if (store) { process (record, ptr, new_page, size, true, HasPtr()); } else { ptr = record.ptr(); new_page = true; } } template std::pair append_base (const R& record, bool const store = true, bool const new_record = true) { ssize_t const size (record.serial_size()); #ifdef GU_RSET_CHECK_SIZE if (gu_unlikely(size > max_size_ - size_)) gu_throw_error(EMSGSIZE); #endif bool new_page; const byte_t* ptr; process (record, ptr, new_page, size, store, HasPtr()); prev_stored_ = store; // make sure there is at least one record count_ += new_record || (0 == count_); post_append (new_page, ptr, size); return std::pair(ptr, size); } private: #ifdef GU_RSET_CHECK_SIZE ssize_t const max_size_; #endif Allocator alloc_; Hash check_; Vector bufs_; bool prev_stored_; void post_alloc (bool const new_page, const byte_t* const ptr, ssize_t const size); void post_append (bool const new_page, const byte_t* const ptr, ssize_t const size); int header_size () const; int header_size_max () const; /* Writes the header to the end of provided buffer, returns header * offset from ptr */ ssize_t write_header (byte_t* ptr, ssize_t size); }; /*! This is a small wrapper template for RecordSetOutBase to avoid templating * the whole thing instead of just the two append methods. */ template class RecordSetOut : public RecordSetOutBase { public: typedef RecordSetOutBase::BaseName BaseName; RecordSetOut() : RecordSetOutBase() {} RecordSetOut (byte_t* reserved, size_t reserved_size, const BaseName& base_name, CheckType ct, Version version = MAX_VERSION #ifdef GU_RSET_CHECK_SIZE ,ssize_t max_size = 0x7fffffff #endif ) : RecordSetOutBase (reserved, reserved_size, base_name, ct, version #ifdef GU_RSET_CHECK_SIZE ,max_size #endif ) {} std::pair append (const R& r) { return append_base (r); // return append_base (r); old append_base() method } std::pair append (const void* const src, ssize_t const size, bool const store = true, bool const new_record = true) { assert (src); assert (size); BufWrap bw (src, size); return append_base (bw, store, new_record); // return append_base (src, size, store); - old append_base() method } private: /*! a wrapper class to represent ptr and size as a serializable object: * simply defines serial_size(), ptr() and serialize_to() methods */ class BufWrap { const byte_t* const ptr_; size_t const size_; public: BufWrap (const void* const ptr, size_t const size) : ptr_(reinterpret_cast(ptr)), size_(size) {} size_t serial_size() const { return size_; } const byte_t* ptr() const { return ptr_; } size_t serialize_to (byte_t* const dst, size_t) const { ::memcpy (dst, ptr_, size_); return size_; } }; RecordSetOut (const RecordSetOut&); RecordSetOut& operator = (const RecordSetOut&); }; /*! class to recover records from a buffer */ class RecordSetInBase : public RecordSet { public: RecordSetInBase (const byte_t* buf,/* pointer to the beginning of buffer */ size_t size, /* total size of buffer */ bool check_now = true); /* checksum now */ /* this is a "delayed constructor", for the object created empty */ void init (const byte_t* buf, /* pointer to the beginning of buffer */ size_t size, /* total size of buffer */ bool check_now = true); /* checksum now */ void rewind() const { next_ = begin_; } void checksum() const; // throws if checksum fails uint64_t get_checksum() const; gu::Buf buf() const { gu::Buf ret = { head_, size_ }; return ret; } protected: template void next_base (Buf& n) const { if (gu_likely (next_ < size_)) { size_t const next_size(R::serial_size(head_ + next_, size_ -next_)); /* sanity check */ if (gu_likely (next_ + next_size <= size_t(size_))) { n.ptr = head_ + next_; n.size = next_size; next_ += next_size; return; } throw_error (E_FAULT); } assert (next_ == size_); throw_error (E_PERM); } template R next_base () const { if (gu_likely (next_ < size_)) { R const rec(head_ + next_, size_ - next_); size_t const tmp_size(rec.serial_size()); /* sanity check */ if (gu_likely (next_ + tmp_size <= size_t(size_))) { next_ += tmp_size; return rec; } throw_error (E_FAULT); } assert (next_ == size_); throw_error (E_PERM); } private: const byte_t* head_; /* pointer to header */ ssize_t mutable next_; /* offset to next record */ short begin_; /* offset to first record */ /* size_ from parent class is offset past all records */ /* takes total size of the supplied buffer */ void parse_header_v1 (size_t size); enum Error { E_PERM, E_FAULT }; GU_NORETURN void throw_error (Error code) const; /* shallow copies here - we're not allocating anything */ RecordSetInBase (const RecordSetInBase& r) : RecordSet (r), head_ (r.head_), next_ (r.next_), begin_ (r.begin_) {} RecordSetInBase& operator= (const RecordSetInBase r); #if 0 { std::swap(head_, r.head_); std::swap(next_, r.next_); std::swap(begin, r.begin_); } #endif }; /* class RecordSetInBase */ /*! This is a small wrapper template for RecordSetInBase to avoid templating * the whole thing instead of just the two next methods. */ template class RecordSetIn : public RecordSetInBase { public: RecordSetIn (const void* buf,/* pointer to the beginning of buffer */ size_t size, /* total size of buffer */ bool check_first = true) /* checksum now */ : RecordSetInBase (reinterpret_cast(buf), size, check_first) {} RecordSetIn () : RecordSetInBase (NULL, 0, false) {} void next (Buf& n) const { next_base (n); } R next () const { return next_base (); } }; /* class RecordSetIn */ #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic pop # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) #endif } /* namespace gu */ #endif /* _GU_RSET_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_hexdump.c0000644000175000017500000000362313136555240025176 0ustar jenkinsjenkins// Copyright (C) 2012-2013 Codership Oy /** * @file Functions to dump buffer contents in a readable form * * $Id$ */ #include "gu_hexdump.h" #include "gu_macros.h" #define GU_ASCII_0 0x30 #define GU_ASCII_10 0x3a #define GU_ASCII_A 0x41 #define GU_ASCII_a 0x61 #define GU_ASCII_A_10 (GU_ASCII_A - GU_ASCII_10) #define GU_ASCII_a_10 (GU_ASCII_a - GU_ASCII_10) static GU_FORCE_INLINE int _hex_code (uint8_t const x) { return (x + GU_ASCII_0 + (x > 9)*GU_ASCII_a_10); } static GU_FORCE_INLINE void _write_byte_binary (char* const str, uint8_t const byte) { str[0] = _hex_code(byte >> 4); str[1] = _hex_code(byte & 0x0f); } static GU_FORCE_INLINE void _write_byte_alpha (char* const str, uint8_t const byte) { str[0] = (char)byte; str[1] = '.'; } #define GU_ASCII_ALPHA_START 0x20U /* ' ' */ #define GU_ASCII_ALPHA_END 0x7eU /* '~' */ #define GU_ASCII_ALPHA_INTERVAL (GU_ASCII_ALPHA_END - GU_ASCII_ALPHA_START) static GU_FORCE_INLINE bool _byte_is_alpha (uint8_t const byte) { return (byte - GU_ASCII_ALPHA_START <= GU_ASCII_ALPHA_INTERVAL); } /*! Dumps contents of the binary buffer into a readable form */ void gu_hexdump(const void* buf, ssize_t const buf_size, char* str, ssize_t str_size, bool alpha) { const uint8_t* b = (uint8_t*)buf; ssize_t i; str_size--; /* reserve a space for \0 */ for (i = 0; i < buf_size && str_size > 1;) { if (alpha && _byte_is_alpha (b[i])) _write_byte_alpha (str, b[i]); else _write_byte_binary (str, b[i]); str += 2; str_size -= 2; i++; if (0 == (i % 4) && str_size > 0 && i < buf_size) { /* insert space after every 4 bytes and newline after every 32 */ str[0] = (i % GU_HEXDUMP_BYTES_PER_LINE) ? ' ' : '\n'; str_size--; str++; } } str[0] = '\0'; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_int128.h0000644000175000017500000001252313136555240024555 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /** * @file 128-bit arithmetic macros. This is so far needed only for FNV128 * hash algorithm * * $Id$ */ #ifndef _gu_int128_h_ #define _gu_int128_h_ #include "gu_arch.h" #include "gu_byteswap.h" #include #if defined(__SIZEOF_INT128__) typedef int __attribute__((__mode__(__TI__))) int128_t; typedef unsigned int __attribute__((__mode__(__TI__))) uint128_t; typedef int128_t gu_int128_t; typedef uint128_t gu_uint128_t; #define GU_SET128(_a, hi64, lo64) _a = (((uint128_t)hi64) << 64) + lo64 #define GU_MUL128_INPLACE(_a, _b) _a *= _b #define GU_IMUL128_INPLACE(_a, _b) GU_MUL128_INPLACE(_a, _b) #define GU_EQ128(_a, _b) (_a == _b) #else /* Uncapable of 16-byte integer arythmetic */ #if defined(GU_LITTLE_ENDIAN) #define GU_64LO 0 #define GU_64HI 1 #define GU_32LO 0 #define GU_32HI 3 #define GU_32_0 0 #define GU_32_1 1 #define GU_32_2 2 #define GU_32_3 3 typedef union gu_int128 { uint64_t u64[2]; uint32_t u32[4]; struct {uint32_t lo; uint64_t mid; int32_t hi;}__attribute__((packed)) m; #ifdef __cplusplus gu_int128() : m() {} gu_int128(int64_t hi, uint64_t lo) : m() { u64[0] = lo; u64[1] = hi; } #endif } gu_int128_t; typedef union gu_uint128 { uint64_t u64[2]; uint32_t u32[4]; struct {uint32_t lo; uint64_t mid; uint32_t hi;}__attribute__((packed)) m; #ifdef __cplusplus gu_uint128() : m() {} gu_uint128(uint64_t hi, uint64_t lo) : m() { u64[0] = lo; u64[1] = hi; } #endif } gu_uint128_t; #ifdef __cplusplus #define GU_SET128(_a, hi64, lo64) _a = gu_uint128(hi64, lo64) #else #define GU_SET128(_a, hi64, lo64) _a = { .u64 = { lo64, hi64 } } #endif #define GU_MUL128_INPLACE(_a,_b) { \ uint64_t m00 = (uint64_t)(_a).u32[0] * (_b).u32[0]; \ uint64_t m10 = (uint64_t)(_a).u32[1] * (_b).u32[0]; \ uint64_t m20 = (uint64_t)(_a).u32[2] * (_b).u32[0]; \ uint64_t m01 = (uint64_t)(_a).u32[0] * (_b).u32[1]; \ uint64_t m02 = (uint64_t)(_a).u32[0] * (_b).u32[2]; \ uint64_t m11 = (uint64_t)(_a).u32[1] * (_b).u32[1]; \ uint32_t m30 = (_a).u32[3] * (_b).u32[0]; \ uint32_t m21 = (_a).u32[2] * (_b).u32[1]; \ uint32_t m12 = (_a).u32[1] * (_b).u32[2]; \ uint32_t m03 = (_a).u32[0] * (_b).u32[3]; \ (_a).u64[GU_64LO] = m00; (_a).u64[GU_64HI] = 0; \ (_a).m.mid += m10; (_a).m.hi += ((_a).m.mid < m10); \ (_a).m.mid += m01; (_a).m.hi += ((_a).m.mid < m01); \ (_a).u64[GU_64HI] += m20 + m11 + m02; \ (_a).u32[GU_32HI] += m30 + m21 + m12 + m03; \ } #else /* Big-Endian */ #define GU_64HI 0 #define GU_64LO 1 #define GU_32HI 0 #define GU_32LO 3 typedef union gu_int128 { uint64_t u64[2]; uint32_t u32[4]; struct {int32_t hi; uint64_t mid; uint32_t lo;}__attribute__((packed)) m; #ifdef __cplusplus gu_int128() {} gu_int128(int64_t hi, uint64_t lo) { u64[0] = hi; u64[1] = lo; } #endif } gu_int128_t; typedef union gu_uint128 { uint64_t u64[2]; uint32_t u32[4]; struct {uint32_t hi; uint64_t mid; uint32_t lo;}__attribute__((packed)) m; #ifdef __cplusplus gu_uint128() {} gu_uint128(uint64_t hi, uint64_t lo) { u64[0] = hi; u64[1] = lo; } #endif } gu_uint128_t; #ifdef __cplusplus #define GU_SET128(_a, hi64, lo64) _a = gu_uint128(hi64, lo64) #else #define GU_SET128(_a, hi64, lo64) _a = { .u64 = { hi64, lo64 } } #endif #define GU_MUL128_INPLACE(_a,_b) { \ uint64_t m33 = (uint64_t)_a.u32[3] * _b.u32[3]; \ uint64_t m23 = (uint64_t)_a.u32[2] * _b.u32[3]; \ uint64_t m13 = (uint64_t)_a.u32[1] * _b.u32[3]; \ uint64_t m32 = (uint64_t)_a.u32[3] * _b.u32[2]; \ uint64_t m31 = (uint64_t)_a.u32[3] * _b.u32[1]; \ uint64_t m22 = (uint64_t)_a.u32[2] * _b.u32[2]; \ uint32_t m30 = _a.u32[3] * _b.u32[0]; \ uint32_t m21 = _a.u32[2] * _b.u32[1]; \ uint32_t m12 = _a.u32[1] * _b.u32[2]; \ uint32_t m03 = _a.u32[0] * _b.u32[3]; \ _a.u64[GU_64LO] = m00; _a.u64[GU_64HI] = 0; \ _a.m.mid += m23; _a.m.hi += (_a.m.mid < m23); \ _a.m.mid += m32; _a.m.hi += (_a.m.mid < m32); \ _a.u64[GU_64HI] += m13 + m22 + m31; \ _a.u32[GU_32HI] += m30 + m21 + m12 + m03; \ } #endif /* Big-Endian */ #define GU_IMUL128_INPLACE(_a, _b) { \ uint32_t sign = ((_a).u32[GU_32HI] ^ (_b).u32[GU_32HI]) & 0x80000000UL; \ GU_MUL128_INPLACE (_a, _b); \ (_a).u32[GU_32HI] |= sign; \ } #define GU_EQ128(_a, _b) (!memcmp(&_a,&_b,sizeof(_a))) #endif /* __SIZEOF_INT128__ */ /* Not sure how to make it both portable, efficient and still follow the * signature of other byteswap functions at the same time. * So this one does inplace conversion. */ #ifdef __cplusplus extern "C" { #endif static inline void gu_bswap128 (gu_uint128_t* const arg) { uint64_t* x = (uint64_t*)arg; uint64_t tmp = gu_bswap64(x[0]); x[0] = gu_bswap64(x[1]); x[1] = tmp; } #ifdef __cplusplus } #endif #ifdef GU_LITTLE_ENDIAN # define gu_le128(x) {} # define gu_be128(x) gu_bswap128(x) #else # define gu_le128(x) gu_bswap128(x) # define gu_be128(x) {} #endif /* GU_LITTLE_ENDIAN */ #define htog128(x) gu_le128(x) #define gtoh128(x) htog128(x) #endif /* _gu_int128_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_string_utils.hpp0000644000175000017500000000176613136555240026625 0ustar jenkinsjenkins// Copyright (C) 2009-2010 Codership Oy #ifndef __GU_STRING_UTILS_HPP__ #define __GU_STRING_UTILS_HPP__ #include #include namespace gu { /*! * @brief Split string into tokens using given separator * * @param sep token separator */ std::vector strsplit(const std::string& s, char sep = ' '); /*! * @brief Split string into tokens using given separator and escape. * * @param sep token separator * @param esc separator escape sequence ('\0' to disable escapes) * @param empty whether to return empty tokens */ std::vector tokenize(const std::string& s, char sep = ' ', char esc = '\\', bool empty = false); /*! Remove non-alnum symbols from the beginning and end of string */ void trim (std::string& s); } #endif /* __GU_STRING_UTILS_HPP__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_to.h0000644000175000017500000001040413136555240024146 0ustar jenkinsjenkins/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /*! * @file gu_to.h Public TO monitor API */ #ifndef _gu_to_h_ #define _gu_to_h_ #ifdef __cplusplus extern "C" { #endif #include #include #include /*! @typedef @brief Sequence number type. */ typedef int64_t gu_seqno_t; /*! Total Order object */ typedef struct gu_to gu_to_t; /*! @brief Creates TO object. * TO object can be used to serialize access to application * critical section using sequence number. * * @param len A length of the waiting queue. Should be no less than the * possible maximum number of threads competing for the resource, * but should not be too high either. Perhaps 1024 is good enough * for most applications. * @param seqno A starting sequence number * (the first to be used by gu_to_grab()). * @return Pointer to TO object or NULL in case of error. */ extern gu_to_t* gu_to_create (int len, gu_seqno_t seqno); /*! @brief Destroys TO object. * * @param to A pointer to TO object to be destroyed * @return 0 in case of success, negative code in case of error. * In particular -EBUSY means the object is used by other threads. */ extern long gu_to_destroy (gu_to_t** to); /*! @brief Grabs TO resource in the specified order. * On successful return the mutex associated with specified TO is locked. * Must be released gu_to_release(). @see gu_to_release * * @param to TO resource to be acquired. * @param seqno The order at which TO resouce should be aquired. For any N * gu_to_grab (to, N) will return exactly after * gu_to_release (to, N-1). * @return 0 in case of success, negative code in case of error. * -EAGAIN means that there are too many threads waiting for TO * already. It is safe to try again later. * -ECANCEL if waiter was canceled, seqno is skipped in TO * -EINTR if wait was interrupted, must retry grabbing later */ extern long gu_to_grab (gu_to_t* to, gu_seqno_t seqno); /*! @brief Releases TO specified resource. * On succesful return unlocks the mutex associated with TO. * TO must be previously acquired with gu_to_grab(). @see gu_to_grab * * @param to TO resource that was previously acquired with gu_to_grab(). * @param seqno The same number with which gu_to_grab() was called. * @return 0 in case of success, negative code in case of error. Any error * here is an application error - attempt to release TO resource * out of order (not paired with gu_to_grab()). */ extern long gu_to_release (gu_to_t* to, gu_seqno_t seqno); /*! @brief The last sequence number that had been used to access TO object. * Note that since no locks are held, it is a conservative estimation. * It is guaranteed however that returned seqno is no longer in use. * * @param to A pointer to TO object. * @return GCS sequence number. Since GCS TO sequence starts with 1, this * sequence can start with 0. */ extern gu_seqno_t gu_to_seqno (gu_to_t* to); /*! @brief cancels a TO monitor waiter making it return immediately * It is assumed that the caller is currenly holding the TO. * The to-be-cancelled waiter can be some later transaction but also * some earlier transaction. Tests have shown that the latter case * can also happen. * * @param to A pointer to TO object. * @param seqno Seqno of the waiter object to be cancelled * @return 0 for success and -ERANGE, if trying to cancel an earlier * transaction */ extern long gu_to_cancel (gu_to_t *to, gu_seqno_t seqno); /*! * Self cancel to without attempting to enter critical secion */ extern long gu_to_self_cancel(gu_to_t *to, gu_seqno_t seqno); /*! @brief interrupts from TO monitor waiting state. * Seqno remains valid in the queue and later seqnos still need to * wait for this seqno to be released. * * The caller can (and must) later try gu_to_grab() again or cancel * the seqno with gu_to_self_cancel(). * * @param to A pointer to TO object. * @param seqno Seqno of the waiter object to be interrupted * @return 0 for success and -ERANGE, if trying to interrupt an already * used transaction */ extern long gu_to_interrupt (gu_to_t *to, gu_seqno_t seqno); #ifdef __cplusplus } #endif #endif // _gu_to_h_ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_hexdump.h0000644000175000017500000000177613136555240025212 0ustar jenkinsjenkins// Copyright (C) 2012-2013 Codership Oy /** * @file Functions to dump binary buffer contents in a readable form * * $Id$ */ #ifndef _gu_hexdump_h_ #define _gu_hexdump_h_ #include "gu_types.h" #ifdef __cplusplus extern "C" { #endif /* This makes it 32*2 + 7 spaces = 71 character per line - just short of 80 */ #define GU_HEXDUMP_BYTES_PER_LINE 32 /*! Dumps contents of the binary buffer in a readable form to a 0-terminated * string of length not exeeding str_size - 1 * @param buf input binary buffer * @param but_size size of the input buffer * @param str target string buffer (will be always 0-terminated) * @param str_size string buffer size (including terminating 0) * @param alpha dump alphanumeric characters as they are, padded with '.' * (e.g. D.u.m.p.) */ extern void gu_hexdump(const void* buf, ssize_t buf_size, char* str, ssize_t str_size, bool alpha); #ifdef __cplusplus } #endif #endif /* _gu_hexdump_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_config.cpp0000644000175000017500000002673413136555240025341 0ustar jenkinsjenkins// Copyright (C) 2010-2014 Codership Oy /** * @file * Configuration management implementation * * $Id$ */ #include "gu_config.h" #include "gu_config.hpp" #include "gu_logger.hpp" #include "gu_assert.hpp" const char gu::Config::PARAM_SEP = ';'; // parameter separator const char gu::Config::KEY_VALUE_SEP = '='; // key-value separator const char gu::Config::ESCAPE = '\\'; // escape symbol void gu::Config::parse ( std::vector >& params_vector, const std::string& param_list) { assert(params_vector.empty()); // we probably want a clean list if (param_list.empty()) return; std::vector pv = gu::tokenize (param_list, PARAM_SEP, ESCAPE); for (size_t i = 0; i < pv.size(); ++i) { std::vector kvv = gu::tokenize (pv[i], KEY_VALUE_SEP, ESCAPE, true); assert(kvv.size() > 0); gu::trim(kvv[0]); const std::string& key = kvv[0]; if (!key.empty()) { if (kvv.size() == 1) { gu_throw_error(EINVAL) <<"Key without value: '" << key <<"' at position '" << i << "' in parameter list."; } if (kvv.size() > 2) { gu_throw_error(EINVAL) <<"More than one value for key '" << key <<"' at '" << pv[i] << "' in parameter list."; } gu::trim(kvv[1]); std::string& value = kvv[1]; params_vector.push_back(std::make_pair(key, value)); } else if (kvv.size() > 1) { gu_throw_error(EINVAL) << "Empty key at '" << pv[i] << "' in parameter list."; } } } void gu::Config::parse (const std::string& param_list) { if (param_list.empty()) return; std::vector > pv; parse (pv, param_list); bool not_found(false); for (size_t i = 0; i < pv.size(); ++i) { const std::string& key (pv[i].first); const std::string& value(pv[i].second); try { set(key, value); } catch (NotFound& e) { log_error << "Unrecognized parameter '" << key << '\''; /* Throw later so that all invalid parameters get logged.*/ not_found = true; } log_debug << "Set parameter '" << key << "' = '" << value << "'"; } if (not_found) throw gu::NotFound(); } gu::Config::Config() : params_() {} void gu::Config::set_longlong (const std::string& key, long long val) { const char* num_mod = ""; /* Shift preserves sign! */ if (val != 0) { if (!(val & ((1LL << 40) - 1))) { val >>= 40; num_mod = "T"; } else if (!(val & ((1 << 30) - 1))) { val >>= 30; num_mod = "G"; } else if (!(val & ((1 << 20) - 1))) { val >>= 20; num_mod = "M"; } else if (!(val & ((1 << 10) - 1))) { val >>= 10; num_mod = "K"; } } std::ostringstream ost; ost << val << num_mod; set (key, ost.str()); } void gu::Config::check_conversion (const char* str, const char* endptr, const char* type, bool range_error) { if (endptr == str || endptr[0] != '\0' || range_error) { gu_throw_error(EINVAL) << "Invalid value '" << str << "' for " << type << " type."; } } char gu::Config::overflow_char(long long ret) { if (ret >= CHAR_MIN && ret <= CHAR_MAX) return ret; gu_throw_error(EOVERFLOW) << "Value " << ret << " too large for requested type (char)."; } short gu::Config::overflow_short(long long ret) { if (ret >= SHRT_MIN && ret <= SHRT_MAX) return ret; gu_throw_error(EOVERFLOW) << "Value " << ret << " too large for requested type (short)."; } int gu::Config::overflow_int(long long ret) { if (ret >= INT_MIN && ret <= INT_MAX) return ret; gu_throw_error(EOVERFLOW) << "Value " << ret << " too large for requested type (int)."; } void gu::Config::print (std::ostream& os, bool const notset) const { struct _print_param { void operator() (std::ostream& os, bool const notset, param_map_t::const_iterator& pi) { const Parameter& p(pi->second); if (p.is_set() || notset) { os << pi->first << " = " << p.value() << "; "; } } } print_param; for (param_map_t::const_iterator pi(params_.begin()); pi != params_.end(); ++pi) { print_param(os, notset, pi); } } std::ostream& gu::operator<<(std::ostream& ost, const gu::Config& c) { c.print(ost); return ost; } gu_config_t* gu_config_create (void) { try { return (reinterpret_cast(new gu::Config())); } catch (gu::Exception& e) { log_error << "Failed to create configuration object: " << e.what(); return 0; } } void gu_config_destroy (gu_config_t* cnf) { if (cnf) { gu::Config* conf = reinterpret_cast(cnf); delete conf; } else { log_error << "Null configuration object in " << __FUNCTION__; assert (0); } } static int config_check_set_args (gu_config_t* cnf, const char* key, const char* func) { if (cnf && key && key[0] != '\0') return 0; if (!cnf) { log_fatal << "Null configuration object in " << func; } if (!key) { log_fatal << "Null key in " << func; } else if (key[0] == '\0') { log_fatal << "Empty key in " << func; } assert (0); return -EINVAL; } static int config_check_get_args (gu_config_t* cnf, const char* key, const void* val_ptr, const char* func) { if (cnf && key && key[0] != '\0' && val_ptr) return 0; if (!cnf) { log_error << "Null configuration object in " << func; } if (!key) { log_error << "Null key in " << func; } else if (key[0] == '\0') { log_error << "Empty key in " << func; } if (!val_ptr) { log_error << "Null value pointer in " << func; } assert (0); return -EINVAL; } bool gu_config_has (gu_config_t* cnf, const char* key) { if (config_check_set_args (cnf, key, __FUNCTION__)) return false; gu::Config* conf = reinterpret_cast(cnf); return (conf->has (key)); } bool gu_config_is_set (gu_config_t* cnf, const char* key) { if (config_check_set_args (cnf, key, __FUNCTION__)) return false; gu::Config* conf = reinterpret_cast(cnf); return (conf->is_set (key)); } int gu_config_add (gu_config_t* cnf, const char* key, const char* const val) { if (config_check_set_args (cnf, key, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { if (val != NULL) conf->add (key, val); else conf->add (key); return 0; } catch (std::exception& e) { log_error << "Error adding parameter '" << key << "': " << e.what(); return -1; } catch (...) { log_error << "Unknown exception adding parameter '" << key << "'"; return -1; } } int gu_config_get_string (gu_config_t* cnf, const char* key, const char** val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key).c_str(); return 0; } catch (gu::NotFound&) { return 1; } } int gu_config_get_int64 (gu_config_t* cnf, const char* key, int64_t* val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key); return 0; } catch (gu::NotFound&) { return 1; } catch (gu::NotSet&) { return 1; } catch (gu::Exception& e) { log_error << "Failed to parse parameter '" << key << "': " << e.what(); return -e.get_errno(); } } int gu_config_get_double (gu_config_t* cnf, const char* key, double* val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key); return 0; } catch (gu::NotFound&) { return 1; } catch (gu::NotSet&) { return 1; } catch (gu::Exception& e) { log_error << "Failed to parse parameter '" << key << "': " << e.what(); return -e.get_errno(); } } int gu_config_get_ptr (gu_config_t* cnf, const char* key, void** val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key); return 0; } catch (gu::NotFound&) { return 1; } catch (gu::NotSet&) { return 1; } catch (gu::Exception& e) { log_error << "Failed to parse parameter '" << key << "': " << e.what(); return -e.get_errno(); } } int gu_config_get_bool (gu_config_t* cnf, const char* key, bool* val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key); return 0; } catch (gu::NotFound&) { return 1; } catch (gu::NotSet&) { return 1; } catch (gu::Exception& e) { log_error << "Failed to parse parameter '" << key << "': " << e.what(); return -e.get_errno(); } } #include void gu_config_set_string (gu_config_t* cnf, const char* key, const char* val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); assert (cnf); gu::Config* conf = reinterpret_cast(cnf); conf->set (key, val); } void gu_config_set_int64 (gu_config_t* cnf, const char* key, int64_t val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); gu::Config* conf = reinterpret_cast(cnf); conf->set (key, val); } void gu_config_set_double (gu_config_t* cnf, const char* key, double val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); gu::Config* conf = reinterpret_cast(cnf); conf->set(key, val); } void gu_config_set_ptr (gu_config_t* cnf, const char* key, const void* val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); gu::Config* conf = reinterpret_cast(cnf); conf->set(key, val); } void gu_config_set_bool (gu_config_t* cnf, const char* key, bool val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); gu::Config* conf = reinterpret_cast(cnf); conf->set(key, val); } ssize_t gu_config_print (gu_config_t* cnf, char* buf, ssize_t buf_len) { std::ostringstream os; os << *(reinterpret_cast(cnf)); const std::string& str = os.str(); strncpy (buf, str.c_str(), buf_len - 1); buf[buf_len - 1] = '\0'; return str.length(); } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_time.h0000644000175000017500000000570513136555240024472 0ustar jenkinsjenkins// Copyright (C) 2008 Codership Oy /** * @file time manipulation functions/macros * * $Id$ */ #ifndef _gu_time_h_ #define _gu_time_h_ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** Returns seconds */ static inline double gu_timeval_diff (struct timeval* left, struct timeval* right) { long long diff = left->tv_sec; diff = ((diff - right->tv_sec)*1000000LL) + left->tv_usec - right->tv_usec; return (((double)diff) * 1.0e-06); } static inline void gu_timeval_add (struct timeval* t, double s) { double ret = (double)t->tv_sec + ((double)t->tv_usec) * 1.0e-06 + s; t->tv_sec = (long)ret; t->tv_usec = (long)((ret - (double)t->tv_sec) * 1.0e+06); } static const double SEC_PER_CLOCK = ((double)1.0)/CLOCKS_PER_SEC; /** Returns seconds */ static inline double gu_clock_diff (clock_t left, clock_t right) { return ((double)(left - right)) * SEC_PER_CLOCK; } #include /** * New time interface * * All funcitons return nanoseconds. */ /* Maximum date representable by long long and compatible with timespec */ #define GU_TIME_ETERNITY 9223372035999999999LL #if defined(__APPLE__) /* synced with linux/time.h */ # define CLOCK_REALTIME 0 # define CLOCK_MONOTONIC 1 typedef int clockid_t; int clock_gettime (clockid_t clk_id, struct timespec * tp); #endif /* __APPLE__ */ static inline long long gu_time_getres() { #if _POSIX_TIMERS > 0 struct timespec tmp; clock_getres (CLOCK_REALTIME, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else return 1000LL; // assumed resolution of gettimeofday() in nanoseconds #endif } static inline long long gu_time_calendar() { #if _POSIX_TIMERS > 0 || defined(__APPLE__) struct timespec tmp; clock_gettime (CLOCK_REALTIME, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else struct timeval tmp; gettimeofday (&tmp, NULL); return ((tmp.tv_sec * 1000000000LL) + (tmp.tv_usec * 1000LL)); #endif } static inline long long gu_time_monotonic() { #if defined(_POSIX_MONOTONIC_CLOCK) || defined(__APPLE__) struct timespec tmp; clock_gettime (CLOCK_MONOTONIC, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else struct timeval tmp; gettimeofday (&tmp, NULL); return ((tmp.tv_sec * 1000000000LL) + (tmp.tv_usec * 1000LL)); #endif } #ifdef CLOCK_PROCESS_CPUTIME_ID static inline long long gu_time_process_cputime() { #if _POSIX_TIMERS > 0 struct timespec tmp; clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else return -1; #endif } #endif /* CLOCK_PROCESS_CPUTIME_ID */ static inline long long gu_time_thread_cputime() { #if _POSIX_TIMERS > 0 struct timespec tmp; clock_gettime (CLOCK_THREAD_CPUTIME_ID, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else return -1; #endif } #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _gu_time_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_types.hpp0000644000175000017500000000042413136555240025231 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @file Location of some "standard" types definitions * * $Id$ */ #ifndef _GU_TYPES_HPP_ #define _GU_TYPES_HPP_ #include "gu_types.h" namespace gu { typedef gu_byte_t byte_t; } #endif /* _GU_TYPES_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/SConscript0000644000175000017500000000701613136555240024677 0ustar jenkinsjenkinsImport('env', 'x86', 'sysname') libgalerautils_env = env.Clone() # Include paths libgalerautils_env.Append(CPPPATH = Split(''' # ''')) # C part libgalerautils_sources = [ 'gu_abort.c', 'gu_dbug.c', 'gu_fifo.c', 'gu_lock_step.c', 'gu_log.c', 'gu_mem.c', 'gu_mmh3.c', 'gu_spooky.c', 'gu_crc32c.c', 'gu_rand.c', 'gu_threads.c', 'gu_hexdump.c', 'gu_to.c', 'gu_utils.c', 'gu_uuid.c', 'gu_backtrace.c', 'gu_limits.c', 'gu_time.c', 'gu_init.c' ] libgalerautils_objs = libgalerautils_env.SharedObject(libgalerautils_sources) crc32c_sources = [ '#/www.evanjones.ca/crc32c.c' ] crc32c_env = env.Clone() crc32c_env.Append(CPPPATH = [ '#' ]) crc32c_env.Append(CPPFLAGS = ' -DWITH_GALERA') crc32c_sources = [ '#/www.evanjones.ca/crc32c.c' ] crc32c_objs = crc32c_env.SharedObject(crc32c_sources) if x86: crc32c_env.Append(CFLAGS = ' -msse4.2') if sysname == 'sunos': # Ideally we want to simply strip SSE4.2 flag from the resulting # crc32.pic.o # (see http://ffmpeg.org/pipermail/ffmpeg-user/2013-March/013977.html) # but that requires some serious scons-fu, so we just don't # compile hardware support in if host CPU does not have it. from subprocess import check_call try: check_call("isainfo -v | grep sse4.2 >/dev/null 2>&1", shell=True); except: libgalerautils_env.Append(CPPFLAGS = ' -DCRC32C_NO_HARDWARE') crc32c_env.Append(CPPFLAGS = ' -DCRC32C_NO_HARDWARE') libgalerautils_env.StaticLibrary('galerautils', libgalerautils_objs + crc32c_objs) env.Append(LIBGALERA_OBJS = libgalerautils_objs + crc32c_objs) #env.Append(LIBGALERA_OBJS = libgalerautils_env.SharedObject( # libgalerautils_sources)) #env.Append(LIBGALERA_OBJS = crc32c_objs) libgalerautilsxx_env = env.Clone() # Include paths libgalerautilsxx_env.Append(CPPPATH = Split(''' # #/common ''')) # disable old style cast warnings libgalerautilsxx_env.Append(CXXFLAGS = ' -Wno-old-style-cast') # C++ part libgalerautilsxx_sources = [ 'gu_vlq.cpp', 'gu_datetime.cpp', 'gu_exception.cpp', 'gu_logger.cpp', 'gu_prodcons.cpp', 'gu_regex.cpp', 'gu_string_utils.cpp', 'gu_uri.cpp', 'gu_buffer.cpp', 'gu_utils++.cpp', 'gu_config.cpp', 'gu_fdesc.cpp', 'gu_mmap.cpp', 'gu_alloc.cpp', 'gu_rset.cpp', 'gu_resolver.cpp', 'gu_histogram.cpp', 'gu_stats.cpp', 'gu_asio.cpp', 'gu_debug_sync.cpp', 'gu_thread.cpp' ] #libgalerautilsxx_objs = libgalerautilsxx_env.Object( # libgalerautilsxx_sources) libgalerautilsxx_sobjs = libgalerautilsxx_env.SharedObject( libgalerautilsxx_sources) #hexdump_obj = libgalerautilsxx_env.Object('gu_hexdump++','gu_hexdump.cpp') hexdump_sobj = libgalerautilsxx_env.SharedObject('gu_hexdump++','gu_hexdump.cpp') #libgalerautilsxx_objs += hexdump_obj libgalerautilsxx_sobjs += hexdump_sobj #if '-DGALERA_USE_GU_NETWORK' in libgalerautils_env['CPPFLAGS']: # libgalerautilsxx_sources = [libgalerautilsxx_sources, # 'gu_resolver.cpp'] libgalerautilsxx_env.StaticLibrary('galerautils++', libgalerautilsxx_sobjs) env.Append(LIBGALERA_OBJS = libgalerautilsxx_sobjs) percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_crc32c.c0000644000175000017500000000133313136555240024577 0ustar jenkinsjenkins/* * Copyright (C) 2013 Codership Oy * * $Id$ */ #include "gu_crc32c.h" #include "gu_log.h" #include CRC32CFunctionPtr gu_crc32c_func = crc32cSlicingBy8; // some sensible default void gu_crc32c_configure() { gu_crc32c_func = detectBestCRC32C(); #if !defined(CRC32C_NO_HARDWARE) if (gu_crc32c_func == crc32cHardware64 || gu_crc32c_func == crc32cHardware32) { gu_info ("CRC-32C: using hardware acceleration."); } else #endif /* !CRC32C_NO_HARDWARE */ if (gu_crc32c_func == crc32cSlicingBy8) { gu_info ("CRC-32C: using \"slicing-by-8\" algorithm."); } else { gu_fatal ("unexpected CRC-32C implementation."); abort(); } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_fifo.h0000644000175000017500000000523213136555240024452 0ustar jenkinsjenkins/* * Copyright (C) 2008-2013 Codership Oy * * Queue (FIFO) class definition * * The driving idea behind this class is avoiding malloc()'s * at all costs on one hand, on the other - make it almost * as infinite as an ordinary linked list. FIFO properties * help to achieve that. * * When needed this FIFO can be made very big, holding * millions or even billions of items while taking up * minimum space when there are few items in the queue. * malloc()'s do happen, but once per thousand of pushes and * allocate multiples of pages, thus reducing memory fragmentation. */ #ifndef _gu_fifo_h_ #define _gu_fifo_h_ #include typedef struct gu_fifo gu_fifo_t; /*! constructor */ extern gu_fifo_t* gu_fifo_create (size_t length, size_t unit); /*! puts FIFO into closed state, waking up waiting threads */ extern void gu_fifo_close (gu_fifo_t *queue); /*! (re)opens FIFO */ extern void gu_fifo_open (gu_fifo_t *queue); /*! destructor - would block until all members are dequeued */ extern void gu_fifo_destroy (gu_fifo_t *queue); /*! for logging purposes */ extern char* gu_fifo_print (gu_fifo_t *queue); /*! Lock FIFO */ extern void gu_fifo_lock (gu_fifo_t *q); /*! Release FIFO */ extern void gu_fifo_release (gu_fifo_t *q); /*! Lock FIFO and get pointer to head item * @param err contains error code if retval is NULL (otherwise - undefined): -ENODATA - queue closed, -ECANCELED - gets were canceled on the queue * @retval pointer to head item or NULL if error occured */ extern void* gu_fifo_get_head (gu_fifo_t* q, int* err); /*! Advance FIFO head pointer and release FIFO. */ extern void gu_fifo_pop_head (gu_fifo_t* q); /*! Lock FIFO and get pointer to tail item */ extern void* gu_fifo_get_tail (gu_fifo_t* q); /*! Advance FIFO tail pointer and release FIFO. */ extern void gu_fifo_push_tail (gu_fifo_t* q); /*! Return how many items are in the queue (unprotected) */ extern long gu_fifo_length (gu_fifo_t* q); /*! Returns the maximum number of items allowed in the queue (unprotected) */ extern long gu_fifo_max_length(gu_fifo_t* q); /*! Return how many items were in the queue on average per push_tail() */ extern void gu_fifo_stats_get (gu_fifo_t* q, int* q_len, int* q_len_max, int* q_len_min, double* q_len_avg); /*! Flush stats counters */ extern void gu_fifo_stats_flush(gu_fifo_t* q); /*! Cancel getters (must be called while holding a FIFO lock) */ extern int gu_fifo_cancel_gets (gu_fifo_t* q); /*! Resume get operations */ extern int gu_fifo_resume_gets (gu_fifo_t* q); #ifndef NDEBUG extern bool gu_fifo_locked (gu_fifo_t* q); #endif #endif // _gu_fifo_h_ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_asio.hpp0000644000175000017500000001355613136555240025032 0ustar jenkinsjenkins// // Copyright (C) 2014 Codership Oy // // // Common ASIO methods and configuration options for Galera // #ifndef GU_ASIO_HPP #define GU_ASIO_HPP #include "gu_macros.h" // gu_likely() #include "common.h" // // Make GCC to treat this as the system header to suppress compiler // warnings #pragma GCC system_header // Turn off some compiler warnings which are known to break the // build. #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic push # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) // Ignore possibly unknown warning flags # pragma GCC diagnostic ignored "-Wpragmas" # pragma GCC diagnostic ignored "-Weffc++" # pragma GCC diagnostic ignored "-Wold-style-cast" # pragma GCC diagnostic ignored "-Wunused-local-typedef" # pragma GCC diagnostic ignored "-Wunused-variable" #endif // __GNUG__ #ifdef ASIO_HPP #error asio.hpp is already included before gu_asio.hpp, can't customize asio.hpp #endif // ASIO_HPP #include "asio/version.hpp" // ASIO does not interact well with kqueue before ASIO 1.10.5, see // https://readlist.com/lists/freebsd.org/freebsd-current/23/119264.html // http://think-async.com/Asio/asio-1.10.6/doc/asio/history.html#asio.history.asio_1_10_5 #if ASIO_VERSION < 101005 # define ASIO_DISABLE_KQUEUE #endif // ASIO_VERSION < 101005 #include "asio.hpp" #include "asio/ssl.hpp" #include #include namespace gu { // URI schemes for networking namespace scheme { const std::string tcp("tcp"); /// TCP scheme const std::string udp("udp"); /// UDP scheme const std::string ssl("ssl"); /// SSL scheme const std::string def("tcp"); /// default scheme (TCP) } // // SSL // // Configuration options for sockets namespace conf { /// Enable SSL explicitly const std::string use_ssl("socket.ssl"); /// SSL cipher list const std::string ssl_cipher("socket.ssl_cipher"); /// SSL compression algorithm const std::string ssl_compression("socket.ssl_compression"); /// SSL private key file const std::string ssl_key("socket.ssl_key"); /// SSL certificate file const std::string ssl_cert("socket.ssl_cert"); /// SSL CA file const std::string ssl_ca("socket.ssl_ca"); /// SSL password file const std::string ssl_password_file("socket.ssl_password_file"); } // Return the cipher in use template static const char* cipher(asio::ssl::stream& socket) { return SSL_get_cipher_name(socket.impl()->ssl); } // Return the compression algorithm in use template static const char* compression(asio::ssl::stream& socket) { return SSL_COMP_get_name( SSL_get_current_compression(socket.impl()->ssl)); } // register ssl parameters to config void ssl_register_params(gu::Config&); // initialize defaults, verify set options void ssl_init_options(gu::Config&); // prepare asio::ssl::context using parameters from config void ssl_prepare_context(const gu::Config&, asio::ssl::context&, bool verify_peer_cert = true); // // Address manipulation helpers // // Return any address string. static inline std::string any_addr(const asio::ip::address& addr) { if (gu_likely(addr.is_v4() == true)) { return addr.to_v4().any().to_string(); } else { return addr.to_v6().any().to_string(); } } // Escape address string. Surrounds IPv6 address with []. // IPv4 addresses not affected. static inline std::string escape_addr(const asio::ip::address& addr) { if (gu_likely(addr.is_v4() == true)) { return addr.to_v4().to_string(); } else { return "[" + addr.to_v6().to_string() + "]"; } } // Unescape address string. Remove [] from around the address if found. static inline std::string unescape_addr(const std::string& addr) { std::string ret(addr); size_t pos(ret.find('[')); if (pos != std::string::npos) ret.erase(pos, 1); pos = ret.find(']'); if (pos != std::string::npos) ret.erase(pos, 1); return ret; } // // Error handling // // Exclude some errors which are generated by the SSL library. extern "C" { static inline bool exclude_ssl_error(const asio::error_code& ec) { switch (ERR_GET_REASON(ec.value())) { #ifdef SSL_R_SHORT_READ case SSL_R_SHORT_READ: // Short read error seems to be generated quite frequently // by SSL library, probably because broken connections. return true; #endif /* SSL_R_SHORT_READ */ default: return false; } } } // Return low level error info for asio::error_code if available. static inline const std::string extra_error_info(const asio::error_code& ec) { std::ostringstream os; if (ec.category() == asio::error::get_ssl_category()) { char errstr[120] = {0, }; ERR_error_string_n(ec.value(), errstr, sizeof(errstr)); os << ec.value() << ": '" << errstr << "'"; } return os.str(); } // // Misc utilities // // Set common socket options template void set_fd_options(S& socket) { long flags(FD_CLOEXEC); if (fcntl(socket.native(), F_SETFD, flags) == -1) { gu_throw_error(errno) << "failed to set FD_CLOEXEC"; } } } #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic pop # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) #endif #endif // GU_ASIO_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/galerautils.h0000644000175000017500000000132413136555240025346 0ustar jenkinsjenkins// Copyright (C) 2007-2017 Codership Oy /** * @file GaleraUtils main header file * * $Id$ */ #ifndef _galerautils_h_ #define _galerautils_h_ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #include "gu_macros.h" #include "gu_limits.h" #include "gu_byteswap.h" #include "gu_time.h" #include "gu_log.h" #include "gu_conf.h" #include "gu_assert.h" #include "gu_mem.h" #include "gu_threads.h" #include "gu_dbug.h" #include "gu_fifo.h" #include "gu_uuid.h" #include "gu_to.h" #include "gu_lock_step.h" #include "gu_utils.h" #include "gu_config.h" #include "gu_abort.h" #include "gu_errno.h" #include "gu_atomic.h" #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _galerautils_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_string.hpp0000644000175000017500000001721513136555240025401 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /*! * @file string class template that allows to allows to allocate initial storage * to hold string data together with the object. If storage is exhausted, * it transparently overflows to heap. */ #ifndef _GU_STRING_HPP_ #define _GU_STRING_HPP_ #include "gu_vector.hpp" #include #include // std::bad_alloc #include #include // realloc() #include // strlen(), strcmp() #include // snprintf() #include #include "gu_macros.h" // gu_likely() namespace gu { /* container for a printf()-like format */ struct Fmt { explicit Fmt(const char* f) : fmt_(f) {} const char* const fmt_; }; template class StringBase { public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef size_t size_type; size_type size() const { return size_; } size_type length()const { return size(); } pointer c_str() { return str_; } const_pointer c_str() const { return str_; } StringBase& operator<< (const Fmt& f) { fmt_ = f.fmt_; return *this; } StringBase& operator<< (const StringBase& s) { size_type const n(s.size()); append_string (s.c_str(), n); return *this; } StringBase& operator<< (const char* s) { size_type const n(::strlen(s)); append_string (s, n); return *this; } StringBase& operator<< (const std::string& s) { append_string (s.c_str(), s.length()); return *this; } StringBase& operator<< (const bool& b) { // following std::boolalpha if (b) append_string ("true", 4); else append_string ("false", 5); return *this; } StringBase& operator<< (const double& d) { convert ("%f", std::numeric_limits::digits10, d); return *this; } StringBase& operator<< (const void* const ptr) { /* not using %p here seeing that it may be not universally supported */ static size_type const ptr_len(sizeof(ptr) == 4 ? 11 : 19 ); static const char* const fmt(sizeof(ptr) == 4 ? "0x%08lx":"0x%016lx"); convert (fmt, ptr_len, reinterpret_cast(ptr)); return *this; } StringBase& operator<< (const long long &i) { convert ("%lld", 21, i); return *this; } StringBase& operator<< (const unsigned long long &i) { convert ("%llu", 20, i); return *this; } StringBase& operator<< (const int &i) { convert ("%d", 11, i); return *this; } StringBase& operator<< (const unsigned int &i) { convert ("%u", 10, i); return *this; } StringBase& operator<< (const short &i) { convert ("%hd", 6, i); return *this; } StringBase& operator<< (const unsigned short &i) { convert ("%hu", 5, i); return *this; } StringBase& operator<< (const char &c) { convert ("%c", 1, c); return *this; } StringBase& operator<< (const unsigned char &c) { convert ("%hhu", 3, c); return *this; } template StringBase& operator+= (const X& x) { return operator<<(x); } bool operator== (const StringBase& other) { return (size() == other.size() && !::strcmp(c_str(), other.c_str())); } bool operator== (const std::string& other) { return (size() == other.size() && !::strcmp(c_str(), other.c_str())); } bool operator== (const char* s) { size_type const s_size(::strlen(s)); return (size() == s_size && !::strcmp(c_str(), s)); } template bool operator!= (const X& x) { return !operator==(x); } void clear() { derived_clear(); }; StringBase& operator= (const StringBase& other) { clear(); append_string (other.c_str(), other.size()); return *this; } StringBase& operator= (const char* const other) { clear(); append_string (other, ::strlen(other)); return *this; } protected: pointer str_; // points to an adequately sized memory area const char* fmt_; size_type size_; virtual void reserve (size_type n) = 0; virtual void derived_clear() = 0; // real clear must happen in derived class void append_string (const_pointer const s, size_type const n) { reserve(size_ + n + 1); std::copy(s, s + n, &str_[size_]); size_ += n; str_[size_] = 0; } template void convert (const char* const format, size_type max_len, const X& x) { ++max_len; // add null termination reserve(size_ + max_len); int const n(snprintf(&str_[size_], max_len, fmt_ ? fmt_ : format, x)); assert(n > 0); assert(size_type(n) < max_len); if (gu_likely(n > 0)) size_ += n; str_[size_] = 0; // null-terminate even if snprintf() failed. fmt_ = NULL; } StringBase(pointer init_buf) : str_(init_buf), fmt_(NULL), size_(0) {} virtual ~StringBase() {} private: StringBase(const StringBase&); }; /* class StringBase */ template std::ostream& operator<< (std::ostream& os, const gu::StringBase& s) { os << s.c_str(); return os; } template class String : public StringBase { public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef size_t size_type; String() : StringBase(buf_), reserved_(capacity), buf_() { buf_[0] = 0; } explicit String(const StringBase& s) : StringBase(buf_), reserved_(capacity), buf_() { append_string (s.c_str(), s.size()); } String(const T* s, size_type n) : StringBase(buf_), reserved_(capacity), buf_() { append_string (s, n); } explicit String(const char* s) : StringBase(buf_), reserved_(capacity), buf_() { size_type const n(strlen(s)); append_string (s, n); } explicit String(const std::string& s) : StringBase(buf_), reserved_(capacity), buf_() { append_string (s.c_str(), s.length()); } #if 0 String& operator= (String other) { using namespace std; swap(other); return *this; } #endif template String& operator= (const X& x) { base::operator=(x); return *this; } ~String() { if (base::str_ != buf_) ::free(base::str_); } private: size_type reserved_; value_type buf_[capacity]; typedef StringBase base; void reserve (size_type const n) { if (n <= reserved_) return; assert (n > capacity); bool const overflow(buf_ == base::str_); pointer const tmp (static_cast (::realloc(overflow ? NULL : base::str_, n * sizeof(value_type)))); if (NULL == tmp) throw std::bad_alloc(); if (overflow) std::copy(buf_, buf_ + base::size_, tmp); base::str_ = tmp; reserved_ = n; } void derived_clear() { if (base::str_ != buf_) ::free(base::str_); base::str_ = buf_; base::size_ = 0; buf_[0] = 0; reserved_ = capacity; } void append_string (const_pointer s, size_type n) { base::append_string(s, n); } }; /* class String */ } /* namespace gu */ #endif /* _GU_STRING_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_exception.cpp0000644000175000017500000000071413136555240026060 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy * */ #include #include "gu_utils.hpp" #include "gu_exception.hpp" namespace gu { void Exception::trace (const char* file, const char* func, int line) { msg.reserve (msg.length() + ::strlen(file) + ::strlen(func) + 15); msg += "\n\t at "; msg += file; msg += ':'; msg += func; msg += "():"; msg += to_string(line); } } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_digest.hpp0000644000175000017500000001027513136555240025351 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @file Message digest interface. * * $Id$ */ #ifndef GU_DIGEST_HPP #define GU_DIGEST_HPP #include "gu_hash.h" #include "gu_vec16.h" #include "gu_byteswap.hpp" #include "gu_serializable.hpp" #include "gu_macros.hpp" namespace gu { /* Just making MMH3 not derive from Digest reduced TrxHandle size from * 4560 bytes to 4256. 304 bytes of vtable pointers... */ class MMH3 { public: MMH3 () : ctx_() { gu_mmh128_init (&ctx_); } ~MMH3 () {} template static int digest (const void* const in, size_t size, T& out) { byte_t tmp[16]; gu_mmh128(in, size, tmp); int const s(std::min(sizeof(T), sizeof(tmp))); ::memcpy (&out, tmp, s); return s; } /* experimental */ template static T digest (const void* const in, size_t size) { switch (sizeof(T)) { case 1: return gu_mmh128_32(in, size); case 2: return gu_mmh128_32(in, size); case 4: return gu_mmh128_32(in, size); case 8: return gu_mmh128_64(in, size); } throw; } void append (const void* const buf, size_t const size) { gu_mmh128_append (&ctx_, buf, size); } template int gather (void* const buf) const { GU_COMPILE_ASSERT(size >= 16, wrong_buf_size); gather16 (buf); return 16; } int gather (void* const buf, size_t const size) const { byte_t tmp[16]; gather16(tmp); int const s(std::min(size, sizeof(tmp))); ::memcpy (buf, tmp, s); return s; } void gather16 (void* const buf) const { gu_mmh128_get (&ctx_, buf); } uint64_t gather8() const { return gu_mmh128_get64 (&ctx_); } uint32_t gather4() const { return gu_mmh128_get32 (&ctx_); } // a questionable feature template int operator() (T& out) const { return gather(&out); } private: gu_mmh128_ctx_t ctx_; }; /* class MMH3 */ template <> inline int MMH3::digest (const void* const in, size_t size, uint8_t& out) { out = gu_mmh128_32(in, size); return sizeof(out); } template <> inline int MMH3::digest (const void* const in, size_t size, uint16_t& out) { out = gu_mmh128_32(in, size); return sizeof(out); } template <> inline int MMH3::digest (const void* const in, size_t size, uint32_t& out) { out = gu_mmh128_32(in, size); return sizeof(out); } template <> inline int MMH3::digest (const void* const in, size_t size, uint64_t& out) { out = gu_mmh128_64(in, size); return sizeof(out); } template <> inline int MMH3::gather<8> (void* const out) const { *(static_cast(out)) = gather8(); return 8; } template <> inline int MMH3::gather<4> (void* const out) const { *(static_cast(out)) = gather4(); return 4; } typedef MMH3 Hash; class FastHash { public: template static int digest (const void* const in, size_t size, T& out) { byte_t tmp[16]; gu_fast_hash128(in, size, tmp); int const s(std::min(sizeof(T), sizeof(tmp))); ::memcpy (&out, tmp, s); return s; } /* experimental */ template static T digest (const void* const in, size_t size) { switch (sizeof(T)) { case 1: return gu_fast_hash32(in, size); case 2: return gu_fast_hash32(in, size); case 4: return gu_fast_hash32(in, size); case 8: return gu_fast_hash64(in, size); } throw; } }; /* FastHash */ template <> inline int FastHash::digest (const void* const in, size_t size, uint8_t& out) { out = gu_fast_hash32(in, size); return sizeof(out); } template <> inline int FastHash::digest (const void* const in, size_t size, uint16_t& out) { out = gu_fast_hash32(in, size); return sizeof(out); } template <> inline int FastHash::digest (const void* const in, size_t size, uint32_t& out) { out = gu_fast_hash32(in, size); return sizeof(out); } template <> inline int FastHash::digest (const void* const in, size_t size, uint64_t& out) { out = gu_fast_hash64(in, size); return sizeof(out); } } /* namespace gu */ #endif /* GU_DIGEST_HPP */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_rand.h0000644000175000017500000000124313136555240024451 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy /** * @file routines to generate "random" seeds for RNGs by collecting some easy * entropy. * * gu_rand_seed_long() goes for srand48() * * gu_rand_seed_int() goes for srand() and rand_r() * * $Id$ */ #ifndef _gu_rand_h_ #define _gu_rand_h_ #include "gu_arch.h" #include // for pid_t extern long int gu_rand_seed_long (long long time, const void* heap_ptr, pid_t pid); #if GU_WORDSIZE == 32 extern unsigned int gu_rand_seed_int (long long time, const void* heap_ptr, pid_t pid); #else #define gu_rand_seed_int gu_rand_seed_long #endif /* GU_WORDSIZE */ #endif /* _gu_rand_h_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_alloc.hpp0000644000175000017500000001233113136555240025157 0ustar jenkinsjenkins/* Copyright (C) 2013-2016 Codership Oy */ /*! * @file Continuous buffer allocator for RecordSet * * $Id$ */ #ifndef _GU_ALLOC_HPP_ #define _GU_ALLOC_HPP_ #include "gu_string.hpp" #include "gu_fdesc.hpp" #include "gu_mmap.hpp" #include "gu_buf.hpp" #include "gu_vector.hpp" #include "gu_macros.h" // gu_likely() #include // realloc(), free() #include #include namespace gu { class Allocator { public: class BaseName { public: virtual void print(std::ostream& os) const = 0; virtual ~BaseName() {} }; // this questionable optimization reduces Allocator size by 8 // probably not worth the loss of generality. typedef unsigned int page_size_type; // max page size typedef page_size_type heap_size_type; // max heap store size explicit Allocator (const BaseName& base_name = BASE_NAME_DEFAULT, byte_t* reserved = NULL, page_size_type reserved_size = 0, heap_size_type max_heap = (1U << 22), /* 4M */ page_size_type disk_page_size = (1U << 26)); /* 64M */ ~Allocator (); /*! @param new_page - true if not adjucent to previous allocation */ byte_t* alloc (page_size_type const size, bool& new_page); /* Total allocated size */ size_t size () const { return size_; } /* Total count of pages */ size_t count() const { return pages_->size(); } #ifdef GU_ALLOCATOR_DEBUG /* appends own vector of Buf structures to the passed one, * should be called only after all allocations have been made. * returns sum of all appended buffers' sizes (same as size()) */ size_t gather (std::vector& out) const; #endif /* GU_ALLOCATOR_DEBUG */ /* After we allocated 3 heap pages, spilling vector into heap should not * be an issue. */ static size_t const INITIAL_VECTOR_SIZE = 4; private: class Page /* base class for memory and file pages */ { public: Page (byte_t* ptr, size_t size) : base_ptr_(ptr), ptr_ (base_ptr_), left_ (size) {} virtual ~Page() {}; byte_t* alloc (size_t size) { byte_t* ret = NULL; if (gu_likely(size <= left_)) { ret = ptr_; ptr_ += size; left_ -= size; } return ret; } const byte_t* base() const { return base_ptr_; } ssize_t size() const { return ptr_ - base_ptr_; } protected: byte_t* base_ptr_; byte_t* ptr_; page_size_type left_; Page& operator=(const Page&); Page (const Page&); }; class HeapPage : public Page { public: HeapPage (page_size_type max_size); ~HeapPage () { free (base_ptr_); } }; class FilePage : public Page { public: FilePage (const std::string& name, page_size_type size); ~FilePage () { fd_.unlink(); } private: FileDescriptor fd_; MMap mmap_; }; class PageStore { public: Page* new_page (page_size_type size) { return my_new_page(size); } protected: virtual ~PageStore() {} private: virtual Page* my_new_page (page_size_type size) = 0; }; class HeapStore : public PageStore { public: HeapStore (heap_size_type max) : PageStore(), left_(max) {} ~HeapStore () {} private: heap_size_type left_; Page* my_new_page (page_size_type const size); }; class FileStore : public PageStore { public: FileStore (const BaseName& base_name, page_size_type page_size) : PageStore(), base_name_(base_name), page_size_(page_size), n_ (0) {} ~FileStore() {} const BaseName& base_name() const { return base_name_; } int size() const { return n_; } private: const BaseName& base_name_; page_size_type const page_size_; int n_; Page* my_new_page (page_size_type const size); FileStore (const FileStore&); FileStore& operator= (const FileStore&); }; Page first_page_; Page* current_page_; HeapStore heap_store_; FileStore file_store_; PageStore* current_store_; gu::Vector pages_; #ifdef GU_ALLOCATOR_DEBUG gu::Vector bufs_; void add_current_to_bufs(); #endif /* GU_ALLOCATOR_DEBUG */ size_t size_; Allocator(const gu::Allocator&); const Allocator& operator=(const gu::Allocator&); class BaseNameDefault : public BaseName { public: BaseNameDefault() {} // this is seemingly required by the standard void print(std::ostream& os) const { os << "alloc"; } }; static BaseNameDefault const BASE_NAME_DEFAULT; }; /* class Allocator */ inline std::ostream& operator<< (std::ostream& os, const Allocator::BaseName& bn) { bn.print(os); return os; } } /* namespace gu */ #endif /* _GU_ALLOC_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_utils++.cpp0000644000175000017500000000203213136555240025343 0ustar jenkinsjenkins// Copyright (C) 2009-2011 Codership Oy /** * @file General-purpose functions and templates * * $Id$ */ #include "gu_utils.hpp" #include "gu_string_utils.hpp" #include namespace gu { bool _to_bool (const std::string& s) { std::istringstream iss(s); bool ret; if ((iss >> ret).fail()) { /* if 1|0 didn't work, try true|false */ iss.clear(); iss.seekg(0); if ((iss >> std::boolalpha >> ret).fail()) { /* try on/off and yes/no */ std::string tmp(s); gu::trim(tmp); if (tmp.length() >=2 && tmp.length() <= 3) { std::transform (tmp.begin(), tmp.end(), tmp.begin(), static_cast(std::tolower)); if (tmp == "yes" || tmp == "on") return true; if (tmp == "off" || tmp == "no") return false; } throw NotFound(); } } return ret; } } // namespace gu percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_crc32c.h0000644000175000017500000000211013136555240024576 0ustar jenkinsjenkins/* * Copyright (C) 2013 Codership Oy * * @file Interface to CRC-32C implementation from www.evanjones.ca * * $Id$ */ #ifndef _GU_CRC32C_H_ #define _GU_CRC32C_H_ #if defined(__cplusplus) extern "C" { #endif #include "www.evanjones.ca/crc32c.h" #include "gu_macros.h" #include "gu_byteswap.h" /*! Call this to configure CRC32C to use the best available implementation */ extern void gu_crc32c_configure(); extern CRC32CFunctionPtr gu_crc32c_func; typedef uint32_t gu_crc32c_t; static gu_crc32c_t const GU_CRC32C_INIT = 0xFFFFFFFF; static GU_FORCE_INLINE void gu_crc32c_init (gu_crc32c_t* crc) { *crc = GU_CRC32C_INIT; } static GU_FORCE_INLINE void gu_crc32c_append (gu_crc32c_t* crc, const void* data, size_t size) { *crc = gu_crc32c_func (*crc, data, size); } static GU_FORCE_INLINE uint32_t gu_crc32c_get (gu_crc32c_t crc) { return (~(crc)); } static GU_FORCE_INLINE uint32_t gu_crc32c (const void* data, size_t size) { return (~(gu_crc32c_func (GU_CRC32C_INIT, data, size))); } #if defined(__cplusplus) } #endif #endif /* _GU_CRC32C_H_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_rset.cpp0000644000175000017500000002702513136555240025043 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy */ /*! * @file common RecordSet implementation * * Record set is a collection of serialized records of the same type. * * It stores them in an iovec-like collection of buffers before sending * and restores from a single buffer when receiving. * * $Id$ */ #include "gu_rset.hpp" #include "gu_vlq.hpp" #include "gu_hexdump.hpp" #include "gu_throw.hpp" #include "gu_logger.hpp" #include "gu_hash.h" #include namespace gu { void RecordSetOutBase::post_alloc (bool const new_page, const byte_t* const ptr, ssize_t const size) { if (new_page) { Buf b = { ptr, size }; bufs_->push_back (b); } else { bufs_->back().size += size; } size_ += size; } void RecordSetOutBase::post_append (bool const new_page, const byte_t* const ptr, ssize_t const size) { check_.append (ptr, size); post_alloc (new_page, ptr, size); } static int check_size (RecordSet::CheckType const ct) { switch (ct) { case RecordSet::CHECK_NONE: return 0; case RecordSet::CHECK_MMH32: return 4; case RecordSet::CHECK_MMH64: return 8; case RecordSet::CHECK_MMH128: return 16; #define MAX_CHECKSUM_SIZE 16 } log_fatal << "Non-existing RecordSet::CheckType value: " << ct; abort(); } #define VER1_CRC_SIZE sizeof(uint32_t) static int header_size_max_v0() { return 1 + /* version + checksum type */ 9 + /* max payload size in vlq format */ 9 + /* max record count in vlq format */ VER1_CRC_SIZE; /* header checksum */ } int RecordSetOutBase::header_size_max() const { switch (version_) { case EMPTY: assert (0); break; case VER1: return header_size_max_v0(); } log_fatal << "Unsupported RecordSet::Version value: " << version_; abort(); } static int header_size_v1(ssize_t size, ssize_t const count) { int hsize = header_size_max_v0(); assert (size > hsize); assert (count > 0); /* need to converge on the header size as it depends on the total size */ do { int new_hsize = 1 + /* version + checksum type */ uleb128_size(size) + /* size in vlq format */ uleb128_size(count) + /* count in vlq format */ VER1_CRC_SIZE; /* header checksum */ assert (new_hsize <= hsize); if (new_hsize == hsize) break; size -= hsize - new_hsize; hsize = new_hsize; } while (true); assert (hsize > 0); assert (size > hsize); return hsize; } int RecordSetOutBase::header_size() const { switch (version_) { case EMPTY: assert(0); break; case VER1: return header_size_v1 (size_, count_); } log_fatal << "Unsupported RecordSet::Version value: " << version_; abort(); } ssize_t RecordSetOutBase::write_header (byte_t* const buf, ssize_t const size) { int const csize(check_size(check_type_)); assert (header_size_max() + csize <= size); ssize_t const hdr_offset(header_size_max() - header_size()); assert (hdr_offset >= 0); size_ -= hdr_offset; int off(hdr_offset); buf[off] = (static_cast(version_) << 4) | /* upper 4 bytes: ver */ (static_cast(check_type_) & 0x0f); off += 1; off += uleb128_encode(size_, buf + off, size - off); off += uleb128_encode(count_, buf + off, size - off); /* write header CRC */ uint32_t const crc(gu_fast_hash32(buf + hdr_offset, off - hdr_offset)); *(reinterpret_cast(buf + off)) = htog(crc); off += VER1_CRC_SIZE; /* append payload checksum */ if (check_type_ != CHECK_NONE) { assert (csize <= size - off); check_.append (buf + hdr_offset, off - hdr_offset); /* append header */ check_.gather (buf + off, csize); } return hdr_offset; } ssize_t RecordSetOutBase::gather (GatherVector& out) { if (count_) { byte_t* const ptr = reinterpret_cast(const_cast(bufs_->front().ptr)); ssize_t const offset = write_header (ptr, bufs_->front().size); bufs_->front().ptr = ptr + offset; bufs_->front().size -= offset; // size_ is taken care of in write_header() out->insert (out->end(), bufs_->begin(), bufs_->end()); return size_; } else { return 0; } } RecordSet::RecordSet (Version ver, CheckType const ct) : size_ (0), count_ (0), version_ (ver), check_type_(ct) { if (gu_unlikely(uint(version_) > MAX_VERSION)) { gu_throw_error (EPROTO) << "Unsupported header version: " << version_; } } RecordSetOutBase::RecordSetOutBase (byte_t* reserved, size_t reserved_size, const BaseName& base_name, CheckType const ct, Version const version #ifdef GU_RSET_CHECK_SIZE ,ssize_t const max_size #endif ) : RecordSet (version, ct), #ifdef GU_RSET_CHECK_SIZE max_size_ (max_size), #endif alloc_ (base_name, reserved, reserved_size), check_ (), bufs_ (), prev_stored_(true) { /* reserve space for header */ size_ = header_size_max() + check_size(check_type_); bool unused; byte_t* ptr = alloc_.alloc (size_, unused); Buf b = { ptr, size_ }; bufs_->push_back (b); } static inline RecordSet::Version header_version (const byte_t* buf, ssize_t const size) { assert (NULL != buf); assert (size > 0); uint const ver((buf[0] & 0xf0) >> 4); assert (ver > 0); if (gu_likely(ver <= RecordSet::MAX_VERSION)) return static_cast(ver); gu_throw_error (EPROTO) << "Unsupported RecordSet version: " << ver; } static inline RecordSet::CheckType ver1_check_type (const byte_t* buf, ssize_t const size) { assert (size > 0); int const ct(buf[0] & 0x0f); switch (ct) { case RecordSet::CHECK_NONE: return RecordSet::CHECK_NONE; case RecordSet::CHECK_MMH32: return RecordSet::CHECK_MMH32; case RecordSet::CHECK_MMH64: return RecordSet::CHECK_MMH64; case RecordSet::CHECK_MMH128: return RecordSet::CHECK_MMH128; } gu_throw_error (EPROTO) << "Unsupported RecordSet checksum type: " << ct; } static inline RecordSet::CheckType header_check_type(RecordSet::Version ver, const byte_t* ptr, ssize_t const size) { assert (size > 0); switch (ver) { case RecordSet::EMPTY: assert(0); return RecordSet::CHECK_NONE; case RecordSet::VER1: return ver1_check_type (ptr, size); } gu_throw_error (EPROTO) << "Unsupported RecordSet version: " << ver; } void RecordSet::init (const byte_t* const ptr, ssize_t const size) { assert (EMPTY == version_); assert (size >= 0); assert (NULL != ptr || 0 == size); assert (NULL == ptr || 0 != size); if (gu_likely ((ptr && size))) { version_ = header_version (ptr, size); check_type_ = header_check_type (version_, ptr, size); } } void RecordSetInBase::parse_header_v1 (size_t const size) { assert (size > 1); int off = 1; off += uleb128_decode (head_ + off, size - off, size_); if (gu_unlikely(static_cast(size_) > static_cast(size))) { gu_throw_error (EPROTO) << "RecordSet size " << size_ << " exceeds buffer size " << size << "\nfirst 4 bytes: " << gu::Hexdump(head_, 4); } off += uleb128_decode (head_ + off, size - off, count_); if (gu_unlikely(static_cast(size_) < static_cast(count_))) { gu_throw_error (EPROTO) << "Corrupted RecordSet header: count " << count_ << " exceeds size " << size_; } /* verify header CRC */ uint32_t const crc_comp(gu_fast_hash32(head_, off)); uint32_t const crc_orig( gtoh(*(reinterpret_cast(head_ + off)))); if (gu_unlikely(crc_comp != crc_orig)) { gu_throw_error (EPROTO) << "RecordSet header CRC mismatch: " << std::showbase << std::internal << std::hex << std::setfill('0') << std::setw(10) << "\ncomputed: " << crc_comp << "\nfound: " << crc_orig << std::dec; } off += VER1_CRC_SIZE; /* checksum is between header and records */ begin_ = off + check_size(check_type_); } /* returns false if checksum matched and true if failed */ void RecordSetInBase::checksum() const { int const cs(check_size(check_type_)); if (cs > 0) /* checksum records */ { Hash check; check.append (head_ + begin_, size_ - begin_); /* records */ check.append (head_, begin_ - cs); /* header */ assert(cs <= MAX_CHECKSUM_SIZE); byte_t result[MAX_CHECKSUM_SIZE]; check.gather(result); const byte_t* const stored_checksum(head_ + begin_ - cs); if (gu_unlikely(memcmp (result, stored_checksum, cs))) { gu_throw_error(EINVAL) << "RecordSet checksum does not match:" << "\ncomputed: " << gu::Hexdump(result, cs) << "\nfound: " << gu::Hexdump(stored_checksum, cs); } } } uint64_t RecordSetInBase::get_checksum() const { unsigned int const checksum_size(check_size(check_type_)); const void* const stored_checksum(head_ + begin_ - checksum_size); uint64_t ret(0); if (checksum_size >= sizeof(uint64_t)) ret = *(static_cast(stored_checksum)); else if (checksum_size >= sizeof(uint32_t)) ret = *(static_cast(stored_checksum)); else if (checksum_size >= sizeof(uint16_t)) ret = *(static_cast(stored_checksum)); else if (checksum_size >= sizeof(uint8_t)) ret = *(static_cast(stored_checksum)); return gu::gtoh(ret); } RecordSetInBase::RecordSetInBase (const byte_t* const ptr, size_t const size, bool const check_now) : RecordSet (), head_ (), next_ (), begin_ () { init (ptr, size, check_now); } void RecordSetInBase::init (const byte_t* const ptr, size_t const size, bool const check_now) { assert (EMPTY == version_); RecordSet::init (ptr, size); head_ = ptr; switch (version_) { case EMPTY: return; case VER1: parse_header_v1(size); // should set begin_ } if (check_now) checksum(); next_ = begin_; assert (size_ > 0); assert (count_ >= 0); assert (count_ <= size_); assert (begin_ > 0); assert (begin_ <= size_); assert (next_ == begin_); } void RecordSetInBase::throw_error (Error code) const { switch (code) { case E_PERM: gu_throw_error (EPERM) << "Access beyond record set end."; case E_FAULT: gu_throw_error (EFAULT) << "Corrupted record set: record extends " << next_ << " beyond set boundary " << size_; } log_fatal << "Unknown error in RecordSetIn."; abort(); } } /* namespace gu */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_stats.hpp0000644000175000017500000000174113136555240025226 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #ifndef _gu_stats_hpp_ #define _gu_stats_hpp_ #include namespace gu { class Stats { public: Stats():n_(0), old_m_(), new_m_(), old_s_(), new_s_(), min_(), max_() {} void insert(const double); void clear() { n_ = 0; } unsigned int times() const { return n_; } double min() const; double max() const; double mean() const; double variance() const; double std_dev() const; friend std::ostream& operator<<(std::ostream&, const Stats&); std::string to_string() const; private: unsigned int n_; double old_m_; double new_m_; double old_s_; double new_s_; double min_; double max_; }; std::ostream& operator<<(std::ostream&, const Stats&); } #endif // _gu_stats_hpp_ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_stats.cpp0000644000175000017500000000321113136555240025213 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #include #include #include #include "gu_macros.h" #include "gu_stats.hpp" // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance // http://www.johndcook.com/standard_deviation.html void gu::Stats::insert(const double val) { n_++; if (gu_unlikely(n_ == 1)) { old_m_ = new_m_ = val; old_s_ = new_s_ = 0.0; min_ = val; max_ = val; } else { new_m_ = old_m_ + (val - old_m_) / n_; new_s_ = old_s_ + (val - old_m_) * (val - new_m_); old_m_ = new_m_; old_s_ = new_s_; min_ = std::min(min_, val); max_ = std::max(max_, val); } } // I guess it's okay to assign 0.0 if no data. double gu::Stats::min() const { return gu_likely(n_ > 0) ? min_ : 0.0; } double gu::Stats::max() const { return gu_likely(n_ > 0) ? max_ : 0.0; } double gu::Stats::mean() const { return gu_likely(n_ > 0) ? new_m_ : 0.0; } double gu::Stats::variance() const { // n_ > 1 ? new_s_ / (n_ - 1) : 0.0; // is to compute unbiased sample variance // not population variance. return gu_likely(n_ > 0) ? new_s_ / n_ : 0.0; } double gu::Stats::std_dev() const { return sqrt(variance()); } std::string gu::Stats::to_string() const { std::ostringstream os; os << *this; return os.str(); } std::ostream& gu::operator<<(std::ostream& os, const gu::Stats& stats) { return (os << stats.min() << "/" << stats.mean() << "/" << stats.max() << "/" << stats.std_dev() << "/" << stats.times()); } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_uri.cpp0000644000175000017500000002035713136555240024666 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy * * $Id$ */ /*! @todo: scheme and host parts should be normalized to lower case except for * %-encodings, which should go upper-case */ #include #include #include #include "gu_assert.h" #include "gu_throw.hpp" #include "gu_logger.hpp" #include "gu_string_utils.hpp" // strsplit() #include "gu_uri.hpp" using std::string; using std::vector; using std::multimap; static void parse_authority (const string& auth, gu::RegEx::Match& user, gu::RegEx::Match& host, gu::RegEx::Match& port) { size_t pos1, pos2; pos1 = auth.find_first_of ('@'); if (pos1 != string::npos) { user = gu::RegEx::Match (auth.substr(0, pos1)); pos1 += 1; // pos1 now points past the first occurence of @, // which may be past the end of the string. } else { pos1 = 0; } if (auth[pos1] == '[') { size_t close_bracket = auth.find_first_of(']', pos1); if (close_bracket == string::npos) { gu_throw_error (EINVAL) << "Expected ']' in " << auth; } pos2 = string::npos; if (close_bracket < auth.length() && auth[close_bracket + 1] == ':') { pos2 = close_bracket + 1; } } else { pos2 = auth.find_last_of (':'); if (auth.find_first_of (':') != pos2) { pos2 = string::npos; } } if (pos2 != string::npos && pos2 >= pos1) { host = gu::RegEx::Match (auth.substr (pos1, pos2 - pos1)); // according to RFC 3986 empty port (nothing after :) should be treated // as unspecified, so make sure that it is not 0-length. if ((pos2 + 1) < auth.length()) { port = gu::RegEx::Match (auth.substr (pos2 + 1)); if ((port.str().find_first_not_of ("0123456789") != string::npos) || // @todo: possible port range is not determined in RFC 3986 (65535 < gu::from_string (port.str()))) { log_debug << "\n\tauth: '" << auth << "'" << "\n\thost: '" << host.str() << "'" << "\n\tport: '" << port.str() << "'" << "\n\tpos1: " << pos1 << ", pos2: " << pos2; gu_throw_error (EINVAL) << "Can't parse port number from '" << port.str() << "'"; } } } else { host = gu::RegEx::Match (auth.substr (pos1)); } } static gu::URIQueryList extract_query_list(const string& s, const string& query) { gu::URIQueryList ret; // scan all key=value pairs vector qlist = gu::strsplit(query, '&'); for (vector::const_iterator i = qlist.begin(); i != qlist.end(); ++i) { vector kvlist = gu::strsplit(*i, '='); if (kvlist.size() != 2) { gu_throw_error (EINVAL) << "Invalid URI query part: '" << *i << "'"; } ret.insert(make_pair(kvlist[0], kvlist[1])); } return ret; } gu::URI::URI(const string& uri_str, bool const strict) : modified_ (true), // recompose to normalize on the first call to_string() str_ (uri_str), scheme_ (), authority_ (), path_ (), fragment_ (), query_list_() { parse(uri_str, strict); } /*! regexp suggested by RFC 3986 to parse URI into 5 canonical parts */ const char* const gu::URI::uri_regex_ = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; /* 12 3 4 5 6 7 8 9 */ /*! positions of URI components as matched by the above pattern */ enum { SCHEME = 2, AUTHORITY = 4, PATH = 5, QUERY = 7, FRAGMENT = 9, NUM_PARTS }; gu::RegEx const gu::URI::regex_(uri_regex_); static string const UNSET_SCHEME("unset://"); void gu::URI::parse (const string& uri_str, bool const strict) { log_debug << "URI: " << uri_str; vector parts; if (!strict && uri_str.find("://") == std::string::npos) { string tmp = UNSET_SCHEME + uri_str; parts = regex_.match (tmp, NUM_PARTS); } else { parts = regex_.match (uri_str, NUM_PARTS); scheme_ = parts[SCHEME]; //set scheme only if it was explicitly provided } if (strict && (!scheme_.is_set() || !scheme_.str().length())) { gu_throw_error (EINVAL) << "URI '" << uri_str << "' has empty scheme"; } try { std::vector auth_list( strsplit(parts[AUTHORITY].str(), ',')); for (size_t i(0); i < auth_list.size(); ++i) { Authority auth; parse_authority (auth_list[i], auth.user_, auth.host_, auth.port_); authority_.push_back(auth); } } catch (NotSet&) { authority_.push_back(Authority()); } path_ = parts[PATH]; if (!parts[AUTHORITY].is_set() && !path_.is_set()) { gu_throw_error (EINVAL) << "URI '" << uri_str << "' has no hierarchical part"; } try { query_list_ = extract_query_list(str_, parts[QUERY].str()); } catch (NotSet&) {} fragment_ = parts[FRAGMENT]; #if 0 try { log_debug << "Base URI: " << scheme.str() << "://" << get_authority(); } catch (NotSet&) {} #endif } std::string gu::URI::get_authority(const gu::URI::Authority& authority) const { const RegEx::Match& user(authority.user_); const RegEx::Match& host(authority.host_); const RegEx::Match& port(authority.port_); if (!user.is_set() && !host.is_set()) throw NotSet(); size_t auth_len = 0; if (user.is_set()) auth_len += user.str().length() + 1; if (host.is_set()) { auth_len += host.str().length(); if (port.is_set()) auth_len += port.str().length() + 1; } string auth; auth.reserve (auth_len); if (user.is_set()) { auth += user.str(); auth += '@'; } if (host.is_set()) { auth += host.str(); if (port.is_set()) { auth += ':'; auth += port.str(); } } return auth; } string gu::URI::get_authority() const { if (authority_.empty()) return ""; return get_authority(authority_.front()); } void gu::URI::recompose() const { size_t l = str_.length(); str_.clear (); str_.reserve (l); // resulting string length will be close to this if (scheme_.is_set()) { str_ += scheme_.str(); str_ += ':'; } str_ += "//"; for (AuthorityList::const_iterator i(authority_.begin()); i != authority_.end(); ++i) { AuthorityList::const_iterator i_next(i); ++i_next; try { string auth = get_authority(*i); str_ += auth; } catch (NotSet&) {} if (i_next != authority_.end()) str_ += ","; } if (path_.is_set()) str_ += path_.str(); if (query_list_.size() > 0) { str_ += '?'; } URIQueryList::const_iterator i = query_list_.begin(); while (i != query_list_.end()) { str_ += i->first + '=' + i->second; URIQueryList::const_iterator i_next = i; ++i_next; if (i_next != query_list_.end()) { str_ += '&'; } i = i_next; } if (fragment_.is_set()) { str_ += '#'; str_ += fragment_.str(); } } void gu::URI::set_query_param(const string& key, const string& val, bool override) { if (override == false) { query_list_.insert(make_pair(key, val)); } else { URIQueryList::iterator i(query_list_.find(key)); if (i == query_list_.end()) { query_list_.insert(make_pair(key, val)); } else { i->second = val; } } modified_ = true; } const std::string& gu::URI::get_option (const std::string& name) const { gu::URIQueryList::const_iterator i = query_list_.find(name); if (i == query_list_.end()) throw NotFound(); return i->second; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_utils.hpp0000644000175000017500000000764113136555240025235 0ustar jenkinsjenkins// Copyright (C) 2009-2010 Codership Oy /** * @file General-purpose functions and templates * * $Id$ */ #ifndef _gu_utils_hpp_ #define _gu_utils_hpp_ #include #include #include #include #include "gu_exception.hpp" namespace gu { /* * String conversion functions for primitive types */ /*! Generic to_string() template function */ template inline std::string to_string(const T& x, std::ios_base& (*f)(std::ios_base&) = std::dec) { std::ostringstream out; out << std::showbase << f << x; return out.str(); } /*! Specialized template: make bool translate into 'true' or 'false' */ template <> inline std::string to_string(const bool& x, std::ios_base& (*f)(std::ios_base&)) { std::ostringstream out; out << std::boolalpha << x; return out.str(); } /*! Specialized template: make double to print with full precision */ template <> inline std::string to_string(const double& x, std::ios_base& (*f)(std::ios_base&)) { const int sigdigits = std::numeric_limits::digits10; // or perhaps std::numeric_limits::max_digits10? std::ostringstream out; out << std::setprecision(sigdigits) << x; return out.str(); } /*! Generic from_string() template. Default base is decimal. * @throws NotFound */ template inline T from_string(const std::string& s, std::ios_base& (*f)(std::ios_base&) = std::dec) { std::istringstream iss(s); T ret; try { if ((iss >> f >> ret).fail()) throw NotFound(); } catch (gu::Exception& e) { throw NotFound(); } return ret; } /*! Specialized template for reading strings. This is to avoid throwing * NotFound in case of empty string. */ template <> inline std::string from_string(const std::string& s, std::ios_base& (*f)(std::ios_base&)) { return s; } /*! Specialized template for reading pointers. Default base is hex. * @throws NotFound */ template <> inline void* from_string(const std::string& s, std::ios_base& (*f)(std::ios_base&)) { std::istringstream iss(s); void* ret; if ((iss >> std::hex >> ret).fail()) throw NotFound(); return ret; } extern "C" const char* gu_str2bool (const char* str, bool* bl); /*! Specialized template for reading bool. Tries both 1|0 and true|false * @throws NotFound */ template <> inline bool from_string (const std::string& s, std::ios_base& (*f)(std::ios_base&)) { bool ret; const char* const str(s.c_str()); const char* const endptr(gu_str2bool(str, &ret)); if (endptr == str || endptr == 0 || *endptr != '\0') throw NotFound(); return ret; } /*! * Substitute for the Variable Length Array on the stack from C99. * Provides automatic deallocation when out of scope: * * void foo(size_t n) { VLA bar(n); bar[0] = 5; throw; } */ template class VLA { T* array; VLA (const VLA&); VLA& operator= (const VLA&); public: VLA (size_t n) : array(new T[n]) {} ~VLA () { delete[] array; } T* operator& () { return array; } T& operator[] (size_t i) { return array[i]; } }; /*! * Object deletion operator. Convenient with STL containers containing * pointers. Example: * * @code * void cleanup() * { * for_each(container.begin(), container.end(), DeleteObject()); * container.clear(); * } * * @endcode */ class DeleteObject { public: template void operator()(T* t) { delete t; } }; /*! swap method for arrays, which does't seem to be built in all compilers */ template inline void swap_array(T (&a)[N], T (&b)[N]) { for (size_t n(0); n < N; ++n) std::swap(a[n], b[n]); } } // namespace gu #endif /* _gu_utils_hpp_ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/src/gu_to.c0000644000175000017500000002651413136555240024152 0ustar jenkinsjenkins/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /*! \file \brief Total order access "class" implementation. * Although gcs_repl() and gcs_recv() calls return sequence * numbers in total order, there are concurrency issues between * application threads and they can grab critical section * mutex out of order. Wherever total order access to critical * section is required, these functions can be used to do this. */ #include #include #include #include // abort() #include "gu_log.h" #include "gu_assert.h" #include "gu_mem.h" #include "gu_threads.h" #include "gu_to.h" #define TO_USE_SIGNAL 1 typedef enum { HOLDER = 0, //!< current TO holder WAIT, //!< actively waiting in the queue CANCELED, //!< Waiter has canceled its to request INTERRUPTED,//!< marked to be interrupted RELEASED, //!< has been released, free entry now } waiter_state_t; typedef struct { #ifdef TO_USE_SIGNAL gu_cond_t cond; #else pthread_mutex_t mtx; // have to use native pthread for double locking #endif waiter_state_t state; } to_waiter_t; struct gu_to { volatile gu_seqno_t seqno; size_t used; /* number of active waiters */ ssize_t qlen; size_t qmask; to_waiter_t* queue; gu_mutex_t lock; }; /** Returns pointer to the waiter with the given seqno */ static inline to_waiter_t* to_get_waiter (gu_to_t* to, gu_seqno_t seqno) { // Check for queue overflow. Tell application that it should wait. if (seqno >= to->seqno + to->qlen) { return NULL; } return (to->queue + (seqno & to->qmask)); } gu_to_t *gu_to_create (int len, gu_seqno_t seqno) { gu_to_t *ret; assert (seqno >= 0); if (len <= 0) { gu_error ("Negative length parameter: %d", len); return NULL; } ret = GU_CALLOC (1, gu_to_t); if (ret) { /* Make queue length a power of 2 */ ret->qlen = 1; while (ret->qlen < len) { // unsigned, can be bigger than any integer ret->qlen = ret->qlen << 1; } ret->qmask = ret->qlen - 1; ret->seqno = seqno; ret->queue = GU_CALLOC (ret->qlen, to_waiter_t); if (ret->queue) { ssize_t i; for (i = 0; i < ret->qlen; i++) { to_waiter_t *w = ret->queue + i; #ifdef TO_USE_SIGNAL gu_cond_init (&w->cond, NULL); #else pthread_mutex_init (&w->mtx, NULL); #endif w->state = RELEASED; } gu_mutex_init (&ret->lock, NULL); return ret; } gu_free (ret); } return NULL; } long gu_to_destroy (gu_to_t** to) { gu_to_t *t = *to; long ret; ssize_t i; gu_mutex_lock (&t->lock); if (t->used) { gu_mutex_unlock (&t->lock); return -EBUSY; } for (i = 0; i < t->qlen; i++) { to_waiter_t *w = t->queue + i; #ifdef TO_USE_SIGNAL if (gu_cond_destroy (&w->cond)) { // @todo: what if someone is waiting? gu_warn ("Failed to destroy condition %d. Should not happen", i); } #else if (pthread_mutex_destroy (&w->mtx)) { // @todo: what if someone is waiting? gu_warn ("Failed to destroy mutex %d. Should not happen", i); } #endif } t->qlen = 0; gu_mutex_unlock (&t->lock); /* What else can be done here? */ ret = gu_mutex_destroy (&t->lock); if (ret) return -ret; // application can retry gu_free (t->queue); gu_free (t); *to = NULL; return 0; } long gu_to_grab (gu_to_t* to, gu_seqno_t seqno) { long err; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock(&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } if (seqno < to->seqno) { gu_mutex_unlock(&to->lock); return -ECANCELED; } if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); return -EAGAIN; } /* we have a valid waiter now */ switch (w->state) { case INTERRUPTED: w->state = RELEASED; err = -EINTR; break; case CANCELED: err = -ECANCELED; break; case RELEASED: if (seqno == to->seqno) { w->state = HOLDER; } else if (seqno < to->seqno) { gu_error("Trying to grab outdated seqno"); err = -ECANCELED; } else { /* seqno > to->seqno, wait for my turn */ w->state = WAIT; to->used++; #ifdef TO_USE_SIGNAL gu_cond_wait(&w->cond, &to->lock); #else pthread_mutex_lock (&w->mtx); pthread_mutex_unlock (&to->lock); pthread_mutex_lock (&w->mtx); // wait for unlock by other thread pthread_mutex_lock (&to->lock); pthread_mutex_unlock (&w->mtx); #endif to->used--; switch (w->state) { case WAIT:// should be most probable assert (seqno == to->seqno); w->state = HOLDER; break; case INTERRUPTED: w->state = RELEASED; err = -EINTR; break; case CANCELED: err = -ECANCELED; break; case RELEASED: /* this waiter has been cancelled */ assert(seqno < to->seqno); err = -ECANCELED; break; default: gu_fatal("Invalid cond wait exit state %d, seqno %llu(%llu)", w->state, seqno, to->seqno); abort(); } } break; default: gu_fatal("TO queue over wrap"); abort(); } gu_mutex_unlock(&to->lock); return err; } static inline long to_wake_waiter (to_waiter_t* w) { long err = 0; if (w->state == WAIT) { #ifdef TO_USE_SIGNAL err = gu_cond_signal (&w->cond); #else err = pthread_mutex_unlock (&w->mtx); #endif if (err) { gu_fatal ("gu_cond_signal failed: %d", err); } } return err; } static inline void to_release_and_wake_next (gu_to_t* to, to_waiter_t* w) { w->state = RELEASED; /* * Iterate over CANCELED waiters and set states as RELEASED * We look for waiter in the head of queue, which guarantees that * to_get_waiter() will always return a valid waiter pointer */ for (to->seqno++; (w = to_get_waiter(to, to->seqno)) && w && w->state == CANCELED; to->seqno++) { w->state = RELEASED; } to_wake_waiter (w); } long gu_to_release (gu_to_t *to, gu_seqno_t seqno) { long err; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock(&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); return -EAGAIN; } /* we have a valid waiter now */ if (seqno == to->seqno) { to_release_and_wake_next (to, w); } else if (seqno > to->seqno) { if (w->state != CANCELED) { gu_fatal("Illegal state in premature release: %d", w->state); abort(); } /* Leave state CANCELED so that real releaser can iterate */ } else { /* */ if (w->state != RELEASED) { gu_fatal("Outdated seqno and state not RELEASED: %d", w->state); abort(); } } gu_mutex_unlock(&to->lock); return err; } gu_seqno_t gu_to_seqno (gu_to_t* to) { return to->seqno - 1; } long gu_to_cancel (gu_to_t *to, gu_seqno_t seqno) { long err; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock (&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } // Check for queue overflow. This is totally unrecoverable. Abort. if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); abort(); } /* we have a valid waiter now */ if ((seqno > to->seqno) || (seqno == to->seqno && w->state != HOLDER)) { err = to_wake_waiter (w); w->state = CANCELED; } else if (seqno == to->seqno && w->state == HOLDER) { gu_warn("tried to cancel current TO holder, state %d seqno %llu", w->state, seqno); err = -ECANCELED; } else { gu_warn("trying to cancel used seqno: state %d cancel seqno = %llu, " "TO seqno = %llu", w->state, seqno, to->seqno); err = -ECANCELED; } gu_mutex_unlock (&to->lock); return err; } long gu_to_self_cancel(gu_to_t *to, gu_seqno_t seqno) { long err = 0; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock (&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); return -EAGAIN; } /* we have a valid waiter now */ if (seqno > to->seqno) { // most probable case w->state = CANCELED; } else if (seqno == to->seqno) { // have to wake the next waiter as if we grabbed and now releasing TO to_release_and_wake_next (to, w); } else { // (seqno < to->seqno) // This waiter must have been canceled or even released by preceding // waiter. Do nothing. } gu_mutex_unlock(&to->lock); return err; } long gu_to_interrupt (gu_to_t *to, gu_seqno_t seqno) { long rcode = 0; long err; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock (&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } if (seqno >= to->seqno) { if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); return -EAGAIN; } /* we have a valid waiter now */ switch (w->state) { case HOLDER: gu_debug ("trying to interrupt in use seqno: seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); /* gu_mutex_unlock (&to->lock); */ rcode = -ERANGE; break; case CANCELED: gu_debug ("trying to interrupt canceled seqno: seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); /* gu_mutex_unlock (&to->lock); */ rcode = -ERANGE; break; case WAIT: gu_debug ("signaling to interrupt wait seqno: seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); rcode = to_wake_waiter (w); case RELEASED: w->state = INTERRUPTED; break; case INTERRUPTED: gu_debug ("TO waiter interrupt already seqno: seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); break; } } else { gu_debug ("trying to interrupt used seqno: cancel seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); /* gu_mutex_unlock (&to->lock); */ rcode = -ERANGE; } gu_mutex_unlock (&to->lock); return rcode; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/doc/0000755000175000017500000000000013136555240022637 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/galerautils/doc/Doxyfile0000644000175000017500000014366713136555240024366 0ustar jenkinsjenkins# Doxyfile 1.4.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = GCS # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 0.2.3 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = ./ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../src # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.c *.h *.hpp # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that a graph may be further truncated if the graph's # image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH # and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), # the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO percona-xtradb-cluster-galera-3.x-3.21/galerautils/README0000644000175000017500000000112013136555240022744 0ustar jenkinsjenkinslibgalerautils is a library of utilities commonly used by Galera project. Current release includes logging, mutex and malloc debug functions and convenience macros. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, to the extent permitted by law; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. libgalerautils is free software. Please see the file COPYING for details. For documentation, please see the files in the doc subdirectory. For building and installation instructions please see the INSTALL file. percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/0000755000175000017500000000000013136555240023234 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_utils_test.c0000644000175000017500000000570613136555240026302 0ustar jenkinsjenkins// Copyright (C) 2010 Codership Oy // $Id$ #include #include "gu_utils_test.h" #include "../src/gu_utils.h" #include #include START_TEST (gu_strconv_test) { long long llret; const char* strret; strret = gu_str2ll ("-1a", &llret); fail_if (strret[0] != 'a'); fail_if (-1 != llret); strret = gu_str2ll ("1K", &llret); fail_if (strret[0] != '\0'); fail_if ((1 << 10) != llret); strret = gu_str2ll ("-1m", &llret); fail_if (strret[0] != '\0'); fail_if (-(1 << 20) != llret); strret = gu_str2ll ("354G0", &llret); fail_if (strret[0] != '0'); fail_if ((354LL << 30) != llret); strret = gu_str2ll ("0m", &llret); fail_if (strret[0] != '\0'); fail_if (0 != llret); strret = gu_str2ll ("-999999999999999g", &llret); fail_if (strret[0] != '\0'); fail_if (LLONG_MIN != llret); bool b; strret = gu_str2bool ("-1a", &b); fail_if (strret[0] != '-'); fail_if (false != b); strret = gu_str2bool ("-1", &b); fail_if (strret[0] != '-'); fail_if (false != b); strret = gu_str2bool ("1a", &b); fail_if (strret[0] != '1'); fail_if (false != b); strret = gu_str2bool ("35", &b); fail_if (strret[0] != '3'); fail_if (false != b); strret = gu_str2bool ("0k", &b); fail_if (strret[0] != '0'); fail_if (false != b); strret = gu_str2bool ("1", &b); fail_if (strret[0] != '\0'); fail_if (true != b); strret = gu_str2bool ("0", &b); fail_if (strret[0] != '\0'); fail_if (false != b); strret = gu_str2bool ("Onn", &b); fail_if (strret[0] != 'O'); fail_if (false != b); strret = gu_str2bool ("oFf", &b); fail_if (strret[0] != '\0'); fail_if (false != b); strret = gu_str2bool ("offt", &b); fail_if (strret[0] != 'o'); fail_if (false != b); strret = gu_str2bool ("On", &b); fail_if (strret[0] != '\0'); fail_if (true != b); strret = gu_str2bool ("tru", &b); fail_if (strret[0] != 't'); fail_if (false != b); strret = gu_str2bool ("trUE", &b); fail_if (strret[0] != '\0'); fail_if (true != b); strret = gu_str2bool ("truEth", &b); fail_if (strret[0] != 't'); fail_if (false != b); strret = gu_str2bool (" fALsE", &b); fail_if (strret[0] != ' '); fail_if (false != b); strret = gu_str2bool ("fALsE", &b); fail_if (strret[0] != '\0'); fail_if (false != b); strret = gu_str2bool ("fALsEth", &b); fail_if (strret[0] != 'f'); fail_if (false != b); void* ptr; strret = gu_str2ptr ("-01234abc", &ptr); fail_if (strret[0] != '\0'); fail_if (-0x1234abcLL != (intptr_t)ptr, "Expected %lld, got %lld", -0x1234abcLL, (intptr_t)ptr); } END_TEST Suite *gu_utils_suite(void) { Suite *s = suite_create("Galera misc utils functions"); TCase *tc = tcase_create("gu_utils"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_strconv_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_mem_test.h0000644000175000017500000000026313136555240025716 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_mem_test__ #define __gu_mem_test__ extern Suite *gu_mem_suite(void); #endif /* __gu_mem_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_mem_pool_test.cpp0000644000175000017500000000230113136555240027275 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy // $Id$ #define TEST_SIZE 1024 #include "gu_mem_pool.hpp" #include "gu_mem_pool_test.hpp" START_TEST (unsafe) { gu::MemPoolUnsafe mp(10, 1, "unsafe"); void* const buf0(mp.acquire()); fail_if(NULL == buf0); void* const buf1(mp.acquire()); fail_if(NULL == buf1); fail_if(buf0 == buf1); mp.recycle(buf0); void* const buf2(mp.acquire()); fail_if(NULL == buf2); fail_if(buf0 != buf2); log_info << mp; mp.recycle(buf1); mp.recycle(buf2); } END_TEST START_TEST (safe) { gu::MemPoolSafe mp(10, 1, "safe"); void* const buf0(mp.acquire()); fail_if(NULL == buf0); void* const buf1(mp.acquire()); fail_if(NULL == buf1); fail_if(buf0 == buf1); mp.recycle(buf0); void* const buf2(mp.acquire()); fail_if(NULL == buf2); fail_if(buf0 != buf2); log_info << mp; mp.recycle(buf1); mp.recycle(buf2); } END_TEST Suite *gu_mem_pool_suite(void) { Suite *s = suite_create("gu::MemPool"); TCase *tc_mem = tcase_create("gu_mem_pool"); suite_add_tcase (s, tc_mem); tcase_add_test(tc_mem, unsafe); tcase_add_test(tc_mem, safe); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_net_test.hpp0000644000175000017500000000030713136555240026265 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_net_test__ #define __gu_net_test__ #include extern Suite *gu_net_suite(void); #endif /* __gu_net_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_config_test.hpp0000644000175000017500000000032313136555240026742 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy // $Id$ #ifndef __gu_config_test__ #define __gu_config_test__ #include extern Suite *gu_config_suite(void); #endif /* __gu_config_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_lock_step_test.c0000644000175000017500000000703213136555240027117 0ustar jenkinsjenkins/* * Copyright (C) 2008-2017 Codership Oy * * $Id$ */ #include #include // usleep() #include // strerror() #include "../src/gu_log.h" #include "../src/gu_lock_step.h" #include "gu_lock_step_test.h" #define TEST_USLEEP 1000 // 1ms #define WAIT_FOR(cond) \ { int count = 1000; while (--count && !(cond)) { usleep (TEST_USLEEP); }} gu_lock_step_t LS; static void* lock_step_thread (void* arg) { gu_lock_step_wait (&LS); return NULL; } START_TEST (gu_lock_step_test) { const long timeout = 500; // 500 ms long ret; gu_thread_t thr1, thr2; gu_lock_step_init (&LS); fail_if (LS.wait != 0); fail_if (LS.enabled != false); // first try with lock-stepping disabled ret = gu_thread_create (&thr1, NULL, lock_step_thread, NULL); fail_if (ret != 0); WAIT_FOR(0 == LS.wait); // 10ms fail_if (LS.wait != 0); // by default lock-step is disabled ret = gu_thread_join (thr1, NULL); fail_if (ret != 0, "gu_thread_join() failed: %ld (%s)", ret, strerror(ret)); ret = gu_lock_step_cont (&LS, timeout); fail_if (-1 != ret); // enable lock-step gu_lock_step_enable (&LS, true); fail_if (LS.enabled != true); ret = gu_lock_step_cont (&LS, timeout); fail_if (0 != ret); // nobody's waiting ret = gu_thread_create (&thr1, NULL, lock_step_thread, NULL); fail_if (ret != 0); WAIT_FOR(1 == LS.wait); // 10ms fail_if (LS.wait != 1); ret = gu_thread_create (&thr2, NULL, lock_step_thread, NULL); fail_if (ret != 0); WAIT_FOR(2 == LS.wait); // 10ms fail_if (LS.wait != 2); ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 2); // there were 2 waiters fail_if (LS.wait != 1); // 1 waiter remains ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 1); fail_if (LS.wait != 0); // 0 waiters remain ret = gu_thread_join (thr1, NULL); fail_if (ret != 0, "gu_thread_join() failed: %ld (%s)", ret, strerror(ret)); ret = gu_thread_join (thr2, NULL); fail_if (ret != 0, "gu_thread_join() failed: %ld (%s)", ret, strerror(ret)); ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 0); // there were 0 waiters fail_if (LS.wait != 0, "Expected LS.wait to be 0, found: %ld", LS.wait); gu_lock_step_destroy (&LS); } END_TEST #define RACE_ITERATIONS 1000 static void* lock_step_race (void* arg) { long i; for (i = 0; i < RACE_ITERATIONS; i++) gu_lock_step_wait (&LS); return NULL; } START_TEST (gu_lock_step_race) { const long timeout = 500; // 500 ms long ret, i; gu_thread_t thr1; gu_lock_step_init (&LS); gu_lock_step_enable (&LS, true); fail_if (LS.enabled != true); ret = gu_thread_create (&thr1, NULL, lock_step_race, NULL); fail_if (ret != 0); for (i = 0; i < RACE_ITERATIONS; i++) { ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 1, "No waiter at iteration: %ld", i); } fail_if (LS.wait != 0); // 0 waiters remain ret = gu_thread_join (thr1, NULL); fail_if (ret != 0, "gu_thread_join() failed: %ld (%s)", ret, strerror(ret)); ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 0); } END_TEST Suite *gu_lock_step_suite(void) { Suite *suite = suite_create("Galera LOCK_STEP utils"); TCase *tcase = tcase_create("gu_lock_step"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gu_lock_step_test); tcase_add_test (tcase, gu_lock_step_race); return suite; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_spooky_test.c0000644000175000017500000001743013136555240026463 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /*! * Original Bob Jenkins' test implementation: * http://www.burtleburtle.net/bob/c/testspooky.cpp * * $Id$ */ #include "gu_spooky_test.h" #include "../src/gu_spooky.h" #include "../src/gu_hexdump.h" #define BUFSIZE 512 static uint64_t const expected[BUFSIZE] = { 0xa24295ec, 0xfe3a05ce, 0x257fd8ef, 0x3acd5217, 0xfdccf85c, 0xc7b5f143, 0x3b0c3ff0, 0x5220f13c, 0xa6426724, 0x4d5426b4, 0x43e76b26, 0x051bc437, 0xd8f28a02, 0x23ccc30e, 0x811d1a2d, 0x039128d4, 0x9cd96a73, 0x216e6a8d, 0x97293fe8, 0xe4fc6d09, 0x1ad34423, 0x9722d7e4, 0x5a6fdeca, 0x3c94a7e1, 0x81a9a876, 0xae3f7c0e, 0x624b50ee, 0x875e5771, 0x0095ab74, 0x1a7333fb, 0x056a4221, 0xa38351fa, 0x73f575f1, 0x8fded05b, 0x9097138f, 0xbd74620c, 0x62d3f5f2, 0x07b78bd0, 0xbafdd81e, 0x0638f2ff, 0x1f6e3aeb, 0xa7786473, 0x71700e1d, 0x6b4625ab, 0xf02867e1, 0xb2b2408f, 0x9ce21ce5, 0xa62baaaf, 0x26720461, 0x434813ee, 0x33bc0f14, 0xaaab098a, 0x750af488, 0xc31bf476, 0x9cecbf26, 0x94793cf3, 0xe1a27584, 0xe80c4880, 0x1299f748, 0x25e55ed2, 0x405e3feb, 0x109e2412, 0x3e55f94f, 0x59575864, 0x365c869d, 0xc9852e6a, 0x12c30c62, 0x47f5b286, 0xb47e488d, 0xa6667571, 0x78220d67, 0xa49e30b9, 0x2005ef88, 0xf6d3816d, 0x6926834b, 0xe6116805, 0x694777aa, 0x464af25b, 0x0e0e2d27, 0x0ea92eae, 0x602c2ca9, 0x1d1d79c5, 0x6364f280, 0x939ee1a4, 0x3b851bd8, 0x5bb6f19f, 0x80b9ed54, 0x3496a9f1, 0xdf815033, 0x91612339, 0x14c516d6, 0xa3f0a804, 0x5e78e975, 0xf408bcd9, 0x63d525ed, 0xa1e459c3, 0xfde303af, 0x049fc17f, 0xe7ed4489, 0xfaeefdb6, 0x2b1b2fa8, 0xc67579a6, 0x5505882e, 0xe3e1c7cb, 0xed53bf30, 0x9e628351, 0x8fa12113, 0x7500c30f, 0xde1bee00, 0xf1fefe06, 0xdc759c00, 0x4c75e5ab, 0xf889b069, 0x695bf8ae, 0x47d6600f, 0xd2a84f87, 0xa0ca82a9, 0x8d2b750c, 0xe03d8cd7, 0x581fea33, 0x969b0460, 0x36c7b7de, 0x74b3fd20, 0x2bb8bde6, 0x13b20dec, 0xa2dcee89, 0xca36229d, 0x06fdb74e, 0x6d9a982d, 0x02503496, 0xbdb4e0d9, 0xbd1f94cf, 0x6d26f82d, 0xcf5e41cd, 0x88b67b65, 0x3e1b3ee4, 0xb20e5e53, 0x1d9be438, 0xcef9c692, 0x299bd1b2, 0xb1279627, 0x210b5f3d, 0x5569bd88, 0x9652ed43, 0x7e8e0f8c, 0xdfa01085, 0xcd6d6343, 0xb8739826, 0xa52ce9a0, 0xd33ef231, 0x1b4d92c2, 0xabfa116d, 0xcdf47800, 0x3a4eefdc, 0xd01f3bcf, 0x30a32f46, 0xfb54d851, 0x06a98f67, 0xbdcd0a71, 0x21a00949, 0xfe7049c9, 0x67ef46d2, 0xa1fabcbc, 0xa4c72db4, 0x4a8a910d, 0x85a890ad, 0xc37e9454, 0xfc3d034a, 0x6f46cc52, 0x742be7a8, 0xe94ecbc5, 0x5f993659, 0x98270309, 0x8d1adae9, 0xea6e035e, 0x293d5fae, 0x669955b3, 0x5afe23b5, 0x4c74efbf, 0x98106505, 0xfbe09627, 0x3c00e8df, 0x5b03975d, 0x78edc83c, 0x117c49c6, 0x66cdfc73, 0xfa55c94f, 0x5bf285fe, 0x2db49b7d, 0xfbfeb8f0, 0xb7631bab, 0x837849f3, 0xf77f3ae5, 0x6e5db9bc, 0xfdd76f15, 0x545abf92, 0x8b538102, 0xdd5c9b65, 0xa5adfd55, 0xecbd7bc5, 0x9f99ebdd, 0x67500dcb, 0xf5246d1f, 0x2b0c061c, 0x927a3747, 0xc77ba267, 0x6da9f855, 0x6240d41a, 0xe9d1701d, 0xc69f0c55, 0x2c2c37cf, 0x12d82191, 0x47be40d3, 0x165b35cd, 0xb7db42e1, 0x358786e4, 0x84b8fc4e, 0x92f57c28, 0xf9c8bbd7, 0xab95a33d, 0x11009238, 0xe9770420, 0xd6967e2a, 0x97c1589f, 0x2ee7e7d3, 0x32cc86da, 0xe47767d1, 0x73e9b61e, 0xd35bac45, 0x835a62bb, 0x5d9217b0, 0x43f3f0ed, 0x8a97911e, 0x4ec7eb55, 0x4b5a988c, 0xb9056683, 0x45456f97, 0x1669fe44, 0xafb861b8, 0x8e83a19c, 0x0bab08d6, 0xe6a145a9, 0xc31e5fc2, 0x27621f4c, 0x795692fa, 0xb5e33ab9, 0x1bc786b6, 0x45d1c106, 0x986531c9, 0x40c9a0ec, 0xff0fdf84, 0xa7359a42, 0xfd1c2091, 0xf73463d4, 0x51b0d635, 0x1d602fb4, 0xc56b69b7, 0x6909d3f7, 0xa04d68f4, 0x8d1001a7, 0x8ecace50, 0x21ec4765, 0x3530f6b0, 0x645f3644, 0x9963ef1e, 0x2b3c70d5, 0xa20c823b, 0x8d26dcae, 0x05214e0c, 0x1993896d, 0x62085a35, 0x7b620b67, 0x1dd85da2, 0x09ce9b1d, 0xd7873326, 0x063ff730, 0xf4ff3c14, 0x09a49d69, 0x532062ba, 0x03ba7729, 0xbd9a86cc, 0xe26d02a7, 0x7ccbe5d3, 0x4f662214, 0x8b999a66, 0x3d0b92b4, 0x70b210f0, 0xf5b8f16f, 0x32146d34, 0x430b92bf, 0x8ab6204c, 0x35e6e1ff, 0xc2f6c2fa, 0xa2df8a1a, 0x887413ec, 0x7cb7a69f, 0x7ac6dbe6, 0x9102d1cb, 0x8892a590, 0xc804fe3a, 0xdfc4920a, 0xfc829840, 0x8910d2eb, 0x38a210fd, 0x9d840cc9, 0x7b9c827f, 0x3444ca0c, 0x071735ab, 0x5e9088e4, 0xc995d60e, 0xbe0bb942, 0x17b089ae, 0x050e1054, 0xcf4324f7, 0x1e3e64dd, 0x436414bb, 0xc48fc2e3, 0x6b6b83d4, 0x9f6558ac, 0x781b22c5, 0x7147cfe2, 0x3c221b4d, 0xa5602765, 0x8f01a4f0, 0x2a9f14ae, 0x12158cb8, 0x28177c50, 0x1091a165, 0x39e4e4be, 0x3e451b7a, 0xd965419c, 0x52053005, 0x0798aa53, 0xe6773e13, 0x1207f671, 0xd2ef998b, 0xab88a38f, 0xc77a8482, 0xa88fb031, 0x5199e0cd, 0x01b30536, 0x46eeb0ef, 0x814259ff, 0x9789a8cf, 0x376ec5ac, 0x7087034a, 0x948b6bdd, 0x4281e628, 0x2c848370, 0xd76ce66a, 0xe9b6959e, 0x24321a8e, 0xdeddd622, 0xb890f960, 0xea26c00a, 0x55e7d8b2, 0xeab67f09, 0x9227fb08, 0xeebbed06, 0xcac1b0d1, 0xb6412083, 0x05d2b0e7, 0x9037624a, 0xc9702198, 0x2c8d1a86, 0x3e7d416e, 0xc3f1a39f, 0xf04bdce4, 0xc88cdb61, 0xbdc89587, 0x4d29b63b, 0x6f24c267, 0x4b529c87, 0x573f5a53, 0xdb3316e9, 0x288eb53b, 0xd2c074bd, 0xef44a99a, 0x2b404d2d, 0xf6706464, 0xfe824f4c, 0xc3debaf8, 0x12f44f98, 0x03135e76, 0xb4888e7f, 0xb6b2325d, 0x3a138259, 0x513c83ec, 0x2386d214, 0x94555500, 0xfbd1522d, 0xda2af018, 0x15b054c0, 0x5ad654e6, 0xb6ed00aa, 0xa2f2180e, 0x5f662825, 0xecd11366, 0x1de5e99d, 0x07afd2ad, 0xcf457b04, 0xe631e10b, 0x83ae8a21, 0x709f0d59, 0x3e278bf9, 0x246816db, 0x9f5e8fd3, 0xc5b5b5a2, 0xd54a9d5c, 0x4b6f2856, 0x2eb5a666, 0xfc68bdd4, 0x1ed1a7f8, 0x98a34b75, 0xc895ada9, 0x2907cc69, 0x87b0b455, 0xddaf96d9, 0xe7da15a6, 0x9298c82a, 0x72bd5cab, 0x2e2a6ad4, 0x7f4b6bb8, 0x525225fe, 0x985abe90, 0xac1fd6e1, 0xb8340f23, 0x92985159, 0x7d29501d, 0xe75dc744, 0x687501b4, 0x92077dc3, 0x58281a67, 0xe7e8e9be, 0xd0e64fd1, 0xb2eb0a30, 0x0e1feccd, 0xc0dc4a9e, 0x5c4aeace, 0x2ca5b93c, 0xee0ec34f, 0xad78467b, 0x0830e76e, 0x0df63f8b, 0x2c2dfd95, 0x9b41ed31, 0x9ff4cddc, 0x1590c412, 0x2366fc82, 0x7a83294f, 0x9336c4de, 0x2343823c, 0x5b681096, 0xf320e4c2, 0xc22b70e2, 0xb5fbfb2a, 0x3ebc2fed, 0x11af07bd, 0x429a08c5, 0x42bee387, 0x58629e33, 0xfb63b486, 0x52135fbe, 0xf1380e60, 0x6355de87, 0x2f0bb19a, 0x167f63ac, 0x507224cf, 0xf7c99d00, 0x71646f50, 0x74feb1ca, 0x5f9abfdd, 0x278f7d68, 0x70120cd7, 0x4281b0f2, 0xdc8ebe5c, 0x36c32163, 0x2da1e884, 0x61877598, 0xbef04402, 0x304db695, 0xfa8e9add, 0x503bac31, 0x0fe04722, 0xf0d59f47, 0xcdc5c595, 0x918c39dd, 0x0cad8d05, 0x6b3ed1eb, 0x4d43e089, 0x7ab051f8, 0xdeec371f, 0x0f4816ae, 0xf8a1a240, 0xd15317f6, 0xb8efbf0b, 0xcdd05df8, 0x4fd5633e, 0x7cf19668, 0x25d8f422, 0x72d156f2, 0x2a778502, 0xda7aefb9, 0x4f4f66e8, 0x19db6bff, 0x74e468da, 0xa754f358, 0x7339ec50, 0x139006f6, 0xefbd0b91, 0x217e9a73, 0x939bd79c }; START_TEST (gu_spooky_test) { uint8_t buf[BUFSIZE]; size_t i; for (i = 0; i < BUFSIZE; ++i) { uint32_t res; buf[i] = i+128; /* It looks like values for messages under bufSize are for the "short" * algorithm, incompatible with the real one. */ if (i < _spooky_bufSize) { /* using 128-bit version */ uint64_t h[2]; gu_spooky_short (buf, i, h); res = (uint32_t)gu_le64(h[0]); } else { /* using 32-bit version */ res = gu_spooky32 (buf, i); } if (res != expected[i]) { fail ("%d: expected: 0x%.8lX, found: 0x%.8lX", i, expected[i], res); } } } END_TEST Suite *gu_spooky_suite(void) { Suite *s = suite_create("Spooky hash"); TCase *tc = tcase_create("gu_spooky"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_spooky_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_thread_test.cpp0000644000175000017500000000266513136555240026752 0ustar jenkinsjenkins// // Copyright (C) 2016-2017 Codership Oy // #include "gu_thread.hpp" #include #include "gu_thread_test.hpp" START_TEST(check_thread_schedparam_parse) { gu::ThreadSchedparam sp_other(SCHED_OTHER, 0); std::ostringstream oss; oss << sp_other; fail_unless(oss.str() == "other:0", "'%s'", oss.str().c_str()); oss.str(""); gu::ThreadSchedparam sp_fifo(SCHED_FIFO, 95); oss << sp_fifo; fail_unless(oss.str() == "fifo:95", "'%s'", oss.str().c_str()); oss.str(""); gu::ThreadSchedparam sp_rr(SCHED_RR, 96); oss << sp_rr; fail_unless(oss.str() == "rr:96", "'%s'", oss.str().c_str()); } END_TEST START_TEST(check_thread_schedparam_system_default) { gu::ThreadSchedparam sp(gu::thread_get_schedparam(gu_thread_self())); std::ostringstream sp_oss; sp_oss << sp; std::ostringstream system_default_oss; system_default_oss << gu::ThreadSchedparam::system_default; fail_unless(sp == gu::ThreadSchedparam::system_default, "sp '%s' != system default '%s'", sp_oss.str().c_str(), system_default_oss.str().c_str()); } END_TEST Suite* gu_thread_suite() { Suite* s(suite_create("galerautils Thread")); TCase* tc(tcase_create("schedparam")); suite_add_tcase(s, tc); tcase_add_test(tc, check_thread_schedparam_parse); tcase_add_test(tc, check_thread_schedparam_system_default); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_vec_test.h0000644000175000017500000000031413136555240025712 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_vec_test__ #define __gu_vec_test__ #include extern Suite *gu_vec_suite(void); #endif /* __gu_vec_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_alloc_test.hpp0000644000175000017500000000031713136555240026572 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy // $Id$ #ifndef __gu_alloc_test__ #define __gu_alloc_test__ #include extern Suite *gu_alloc_suite(void); #endif /* __gu_alloc_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_histogram_test.hpp0000644000175000017500000000033213136555240027472 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #ifndef __gu_histogram_test__ #define __gu_histogram_test__ #include extern Suite *gu_histogram_suite(void); #endif // __gu_histogram_test__ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_tests++.hpp0000644000175000017500000000221113136555240025724 0ustar jenkinsjenkins// Copyright (C) 2009-2014 Codership Oy // $Id$ /*! * @file: package specific part of the main test file. */ #ifndef __gu_testspp_hpp__ #define __gu_testspp_hpp__ #define LOG_FILE "gu_tests++.log" #include "gu_atomic_test.hpp" #include "gu_vector_test.hpp" #include "gu_string_test.hpp" #include "gu_vlq_test.hpp" #include "gu_digest_test.hpp" #include "gu_mem_pool_test.hpp" #include "gu_alloc_test.hpp" #include "gu_rset_test.hpp" #include "gu_string_utils_test.hpp" #include "gu_uri_test.hpp" #include "gu_config_test.hpp" #include "gu_net_test.hpp" #include "gu_datetime_test.hpp" #include "gu_histogram_test.hpp" #include "gu_stats_test.hpp" #include "gu_thread_test.hpp" typedef Suite *(*suite_creator_t)(void); static suite_creator_t suites[] = { gu_atomic_suite, gu_vector_suite, gu_string_suite, gu_vlq_suite, gu_digest_suite, gu_mem_pool_suite, gu_alloc_suite, gu_rset_suite, gu_string_utils_suite, gu_uri_suite, gu_config_suite, gu_net_suite, gu_datetime_suite, gu_histogram_suite, gu_stats_suite, gu_thread_suite, 0 }; #endif /* __gu_testspp_hpp__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_crc32c_test.h0000644000175000017500000000033313136555240026215 0ustar jenkinsjenkins/* * Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_crc32c_test_h__ #define __gu_crc32c_test_h__ #include Suite* gu_crc32c_suite(void); #endif /* __gu_crc32c_test_h__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_lock_step_test.h0000644000175000017500000000032413136555240027121 0ustar jenkinsjenkins/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gu_lock_step_test__ #define __gu_lock_step_test__ extern Suite *gu_lock_step_suite(void); #endif /* __gu_lock_step_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_config_test.cpp0000644000175000017500000000354513136555240026746 0ustar jenkinsjenkins// Copyright (C) 2013-2014 Codership Oy // $Id$ #include "../src/gu_config.hpp" #include "gu_config_test.hpp" static std::string const key("test_key"); static std::string const another_key("another_key"); static std::string const str_value("123"); static long long const int_value( 123 ); START_TEST (gu_config_test) { gu::Config cnf; std::string svalue; long long ivalue; fail_if(cnf.has(key)); try { cnf.is_set(key); fail("gu::NotFound expected"); } catch(gu::NotFound&) {} cnf.add(key); fail_unless(cnf.has(key)); fail_if(cnf.is_set(key)); #define SUFFIX_CHECK(_suf_,_shift_) \ svalue = str_value + _suf_; \ cnf.set(key, svalue); \ fail_unless(cnf.is_set(key)); \ fail_unless(cnf.get(key) == svalue); \ ivalue = cnf.get(key); \ fail_if(ivalue != (int_value << _shift_)); SUFFIX_CHECK('T', 40); // check overflow checks try { ivalue = cnf.get(key); fail("gu::Exception expected"); } catch (gu::Exception&) {} try { ivalue = cnf.get(key); fail("gu::Exception expected"); } catch (gu::Exception&) {} try { ivalue = cnf.get(key); fail("gu::Exception expected"); } catch (gu::Exception&) {} SUFFIX_CHECK('G', 30); SUFFIX_CHECK('M', 20); SUFFIX_CHECK('K', 10); // try { cnf.add(key, str_value); fail("gu::Exception expected"); } // catch (gu::Exception& e) {} cnf.add(another_key, str_value); fail_unless(cnf.is_set(another_key)); ivalue = cnf.get(another_key); fail_if(ivalue != int_value); } END_TEST Suite *gu_config_suite(void) { Suite *s = suite_create("gu::Config"); TCase *tc = tcase_create("gu_config_test"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_config_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_fifo_test.h0000644000175000017500000000026013136555240026060 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_fifo_test__ #define __gu_fifo_test__ Suite *gu_fifo_suite(void); #endif /* __gu_fifo_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_stats_test.hpp0000644000175000017500000000031213136555240026631 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #ifndef __gu_stats_test__ #define __gu_stats_test__ #include extern Suite *gu_stats_suite(void); #endif // __gu_stats_test__ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_digest_test.cpp0000644000175000017500000002171013136555240026752 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /* * This unit test is mostly to check that Galera hash definitions didn't change: * correctness of hash algorithms definitions is checked in respective unit * tests. * * By convention checks are made against etalon byte arrays, so integers must be * converted to little-endian. * * $Id$ */ #include "../src/gu_digest.hpp" #include "gu_digest_test.hpp" #include "../src/gu_hexdump.hpp" #include "../src/gu_logger.hpp" /* checks equivalence of two buffers, returns true if check fails and logs * buffer contents. */ static bool check (const void* const exp, const void* const got, ssize_t size) { if (memcmp (exp, got, size)) { log_info << "expected hash value:\n" << gu::Hexdump(exp, size) << "\nfound:\n" << gu::Hexdump(got, size) << "\n"; return true; } return false; } static const char test_msg[2048] = { 0, }; #define GU_HASH_TEST_LENGTH 43 /* some random prime */ static const uint8_t gu_hash128_check[16] = { 0xFA,0x2C,0x78,0x67,0x35,0x99,0xD9,0x84,0x73,0x41,0x3F,0xA5,0xEB,0x27,0x40,0x2F }; static const uint8_t gu_hash64_check[8] = { 0xFA,0x2C,0x78,0x67,0x35,0x99,0xD9,0x84 }; static const uint8_t gu_hash32_check[4] = { 0xFA,0x2C,0x78,0x67 }; /* Tests partial hashing functions */ START_TEST (gu_hash_test) { gu::Hash hash_one; hash_one.append(test_msg, GU_HASH_TEST_LENGTH); uint8_t res128_one[16]; hash_one.gather(res128_one); fail_if (check (gu_hash128_check, res128_one, sizeof(res128_one)), "gu::Hash::gather() failed in single mode."); gu::Hash::digest(test_msg, GU_HASH_TEST_LENGTH, res128_one); fail_if (check (gu_hash128_check, res128_one, sizeof(res128_one)), "gu::Hash::digest() failed."); gu::Hash hash_multi; int off = 0; hash_multi.append(test_msg, 16); off += 16; hash_multi.append(test_msg + off, 15); off += 15; hash_multi.append(test_msg + off, 7); off += 7; hash_multi.append(test_msg + off, 5); off += 5; fail_if (off != GU_HASH_TEST_LENGTH); uint8_t res128_multi[16]; hash_multi.gather(res128_multi); fail_if (check (gu_hash128_check, res128_multi, sizeof(res128_multi)), "gu::Hash::gather() failed in multi mode."); uint64_t res64; hash_multi.gather(&res64); uint64_t const res(gu_hash64(test_msg, GU_HASH_TEST_LENGTH)); fail_if (res != res64, "got 0x%0llx, expected 0x%llx", res64, res); res64 = gu_le64(res64); fail_if (check (gu_hash64_check, &res64, sizeof(res64)), "gu::Hash::gather() failed."); uint32_t res32; hash_one(res32); fail_if (gu_hash32(test_msg, GU_HASH_TEST_LENGTH) != res32); res32 = gu_le32(res32); fail_if (check (gu_hash32_check, &res32, sizeof(res32)), "gu::Hash::gather() failed."); } END_TEST static const uint8_t fast_hash128_check0 [16] = { 0xA9,0xCE,0x5A,0x56,0x0C,0x0B,0xF7,0xD6,0x63,0x4F,0x6F,0x81,0x0E,0x0B,0xF2,0x0A }; static const uint8_t fast_hash128_check511 [16] = { 0xC6,0x7F,0x4C,0xE7,0x6F,0xE0,0xDA,0x14,0xCC,0x9F,0x21,0x76,0xAF,0xB5,0x12,0x1A }; static const uint8_t fast_hash128_check512 [16] = { 0x38,0x8D,0x2B,0x90,0xC8,0x7F,0x11,0x53,0x3F,0xB4,0x32,0xC1,0xD7,0x2B,0x04,0x39 }; static const uint8_t fast_hash128_check2011[16] = { 0xB7,0xCE,0x75,0xC7,0xB4,0x31,0xBC,0xC8,0x95,0xB3,0x41,0xB8,0x5B,0x8E,0x77,0xF9 }; static const uint8_t fast_hash64_check0 [8] = { 0x6C, 0x55, 0xB8, 0xA1, 0x02, 0xC6, 0x21, 0xCA }; static const uint8_t fast_hash64_check15 [8] = { 0x28, 0x49, 0xE8, 0x34, 0x7A, 0xAB, 0x49, 0x34 }; static const uint8_t fast_hash64_check16 [8] = { 0x44, 0x40, 0x2C, 0x82, 0xD3, 0x8D, 0xAA, 0xFE }; static const uint8_t fast_hash64_check511 [8] = { 0xC6, 0x7F, 0x4C, 0xE7, 0x6F, 0xE0, 0xDA, 0x14 }; static const uint8_t fast_hash64_check512 [8] = { 0x38, 0x8D, 0x2B, 0x90, 0xC8, 0x7F, 0x11, 0x53 }; static const uint8_t fast_hash64_check2011[8] = { 0xB7, 0xCE, 0x75, 0xC7, 0xB4, 0x31, 0xBC, 0xC8 }; static const uint8_t fast_hash32_check0 [4] = { 0x0B, 0x7C, 0x3E, 0xAB }; static const uint8_t fast_hash32_check31 [4] = { 0x1E, 0xFF, 0x48, 0x38 }; static const uint8_t fast_hash32_check32 [4] = { 0x63, 0xC2, 0x53, 0x0D }; static const uint8_t fast_hash32_check511 [4] = { 0xC6, 0x7F, 0x4C, 0xE7 }; static const uint8_t fast_hash32_check512 [4] = { 0x38, 0x8D, 0x2B, 0x90 }; static const uint8_t fast_hash32_check2011[4] = { 0xB7, 0xCE, 0x75, 0xC7 }; /* Tests fast hash functions */ START_TEST (gu_fast_hash_test) { uint8_t res128[16]; gu::FastHash::digest (test_msg, 0, res128); fail_if (check (fast_hash128_check0, res128, sizeof(res128))); gu::FastHash::digest (test_msg, 511, res128); fail_if (check (fast_hash128_check511, res128, sizeof(res128))); gu::FastHash::digest (test_msg, 512, res128); fail_if (check (fast_hash128_check512, res128, sizeof(res128))); gu::FastHash::digest (test_msg, 2011, res128); fail_if (check (fast_hash128_check2011, res128, sizeof(res128))); uint64_t res64; res64 = gu::FastHash::digest(test_msg, 0); res64 = gu_le64(res64); fail_if (check (fast_hash64_check0, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,15); res64 = gu_le64(res64); fail_if (check (fast_hash64_check15, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,16); res64 = gu_le64(res64); fail_if (check (fast_hash64_check16, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,511); res64 =gu_le64(res64); fail_if (check (fast_hash64_check511, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,512); res64 =gu_le64(res64); fail_if (check (fast_hash64_check512, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,2011);res64 =gu_le64(res64); fail_if (check (fast_hash64_check2011, &res64, sizeof(res64))); uint32_t res32; res32 = gu::FastHash::digest(test_msg, 0); res32 = gu_le32(res32); fail_if (check (fast_hash32_check0, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,31); res32 = gu_le32(res32); fail_if (check (fast_hash32_check31, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,32); res32 = gu_le32(res32); fail_if (check (fast_hash32_check32, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,511); res32 =gu_le32(res32); fail_if (check (fast_hash32_check511, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,512); res32 =gu_le32(res32); fail_if (check (fast_hash32_check512, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,2011); res32=gu_le32(res32); fail_if (check (fast_hash32_check2011, &res32, sizeof(res32))); } END_TEST #if SKIP_TABLE_FUNCTIONS /* Tests table hash functions: * - for 64-bit platforms table hash should be identical to fast 64-bit hash, * - for 32-bit platforms table hash is different. */ #if GU_WORDSIZE == 64 START_TEST (gu_table_hash_test) { size_t res; fail_if (sizeof(res) > 8); res = gu_table_hash (test_msg, 0); res = gu_le64(res); fail_if (check (fast_hash64_check0, &res, sizeof(res))); res = gu_table_hash (test_msg, 15); res = gu_le64(res); fail_if (check (fast_hash64_check15, &res, sizeof(res))); res = gu_table_hash (test_msg, 16); res = gu_le64(res); fail_if (check (fast_hash64_check16, &res, sizeof(res))); res = gu_table_hash (test_msg, 511); res = gu_le64(res); fail_if (check (fast_hash64_check511, &res, sizeof(res))); res = gu_table_hash (test_msg, 512); res = gu_le64(res); fail_if (check (fast_hash64_check512, &res, sizeof(res))); res = gu_table_hash (test_msg, 2011); res = gu_le64(res); fail_if (check (fast_hash64_check2011, &res, sizeof(res))); } END_TEST #elif GU_WORDSIZE == 32 static const uint8_t table_hash32_check0 [4] = { 0x0B, 0x7C, 0x3E, 0xAB }; static const uint8_t table_hash32_check32 [4] = { 0x65, 0x16, 0x17, 0x42 }; static const uint8_t table_hash32_check2011[4] = { 0xF9, 0xBC, 0xEF, 0x7A }; START_TEST (gu_table_hash_test) { size_t res; fail_if (sizeof(res) > 4); res = gu_table_hash (test_msg, 0); res = gu_le32(res); fail_if (check (table_hash32_check0, &res, sizeof(res))); res = gu_table_hash (test_msg, 32); res = gu_le32(res); fail_if (check (table_hash32_check32, &res, sizeof(res))); res = gu_table_hash (test_msg, 2011); res = gu_le32(res); fail_if (check (table_hash32_check2011, &res, sizeof(res))); } END_TEST #else /* GU_WORDSIZE == 32 */ # error "Unsupported word size" #endif #endif // SKIP_TABLE_FUNCTIONS Suite *gu_digest_suite(void) { Suite *s = suite_create("gu::Hash"); TCase *tc = tcase_create("gu_hash"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_hash_test); tcase_add_test (tc, gu_fast_hash_test); // tcase_add_test (tc, gu_table_hash_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_tests.c0000644000175000017500000000364113136555240025241 0ustar jenkinsjenkins// Copyright (C) 2007-2017 Codership Oy // $Id$ #include // printf() #include // strcmp() #include // EXIT_SUCCESS | EXIT_FAILURE #include // unlink() #include #include "../src/gu_conf.h" #include "gu_mem_test.h" #include "gu_vec_test.h" #include "gu_bswap_test.h" #include "gu_fnv_test.h" #include "gu_mmh3_test.h" #include "gu_spooky_test.h" #include "gu_crc32c_test.h" #include "gu_hash_test.h" #include "gu_dbug_test.h" #include "gu_time_test.h" #include "gu_fifo_test.h" #include "gu_uuid_test.h" #include "gu_lock_step_test.h" #include "gu_str_test.h" #include "gu_utils_test.h" typedef Suite *(*suite_creator_t)(void); static suite_creator_t suites[] = { gu_mem_suite, gu_vec_suite, gu_bswap_suite, gu_fnv_suite, gu_mmh3_suite, gu_spooky_suite, gu_crc32c_suite, gu_hash_suite, gu_dbug_suite, gu_time_suite, gu_fifo_suite, gu_uuid_suite, gu_lock_step_suite, gu_str_suite, gu_utils_suite, NULL }; #define LOG_FILE "gu_tests.log" int main(int argc, char* argv[]) { int no_fork = ((argc > 1) && !strcmp(argv[1], "nofork")) ? 1 : 0; int i = 0; int failed = 0; FILE* log_file = NULL; if (!no_fork) { log_file = fopen (LOG_FILE, "w"); if (!log_file) return EXIT_FAILURE; gu_conf_set_log_file (log_file); } gu_conf_debug_on(); while (suites[i]) { SRunner* sr = srunner_create(suites[i]()); if (no_fork) srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all (sr, CK_NORMAL); failed += srunner_ntests_failed (sr); srunner_free (sr); i++; } if (log_file) { fclose (log_file); } if (0 == failed && NULL != log_file) unlink(LOG_FILE); printf ("Total tests failed: %d\n", failed); return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_datetime_test.cpp0000644000175000017500000000657213136555240027300 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy * * $Id$ */ #include "gu_datetime.hpp" #include "gu_logger.hpp" #include "gu_utils.hpp" #include "gu_datetime_test.hpp" using namespace gu; using namespace gu::datetime; START_TEST(test_units) { fail_unless(NSec == 1LL); fail_unless(USec == 1000LL); fail_unless(MSec == 1000LL*1000LL); fail_unless(Sec == 1000LL*1000LL*1000LL); fail_unless(Min == 60LL*1000LL*1000LL*1000LL); fail_unless(Hour == 60LL*60LL*1000LL*1000LL*1000LL); fail_unless(Day == 24LL*60LL*60LL*1000LL*1000LL*1000LL); fail_unless(Month == 30LL*24LL*60LL*60LL*1000LL*1000LL*1000LL); fail_unless(Year == 12LL*30LL*24LL*60LL*60LL*1000LL*1000LL*1000LL); } END_TEST START_TEST(test_period) { // Zero periods fail_unless(Period("").get_nsecs() == 0); fail_unless(Period("P").get_nsecs() == 0); fail_unless(Period("PT").get_nsecs() == 0); // Year-mon-day fail_unless(Period("P3Y").get_nsecs() == 3*Year); fail_unless(Period("P5M").get_nsecs() == 5*Month); fail_unless(Period("P37D").get_nsecs() == 37*Day); fail_unless(Period("P3Y17M").get_nsecs() == 3*Year + 17*Month); fail_unless(Period("P5Y66D").get_nsecs() == 5*Year + 66*Day); fail_unless(Period("P37M44D").get_nsecs() == 37*Month + 44*Day); fail_unless(Period("P3YT").get_nsecs() == 3*Year); fail_unless(Period("P5MT").get_nsecs() == 5*Month); fail_unless(Period("P37DT").get_nsecs() == 37*Day); fail_unless(Period("P3Y17MT").get_nsecs() == 3*Year + 17*Month); fail_unless(Period("P5Y66DT").get_nsecs() == 5*Year + 66*Day); fail_unless(Period("P37M44DT").get_nsecs() == 37*Month + 44*Day); // Hour-min-sec fail_unless(Period("PT3H").get_nsecs() == 3*Hour); fail_unless(Period("PT5M").get_nsecs() == 5*Min); fail_unless(Period("P37S").get_nsecs() == 37*Sec); // fail_unless(Period("PT3.578777S").get_nsecs() == 3*Sec + 578*MSec + 777*USec); fail_unless(Period("PT0.5S").get_nsecs() == 500*MSec); // fail_unless(Period("PT5H7M3.578777S").get_nsecs() == 5*Hour + 7*Min + 3*Sec + 578*MSec + 777*USec); // @todo these should fail fail_unless(Period("PT.S").get_nsecs() == 0); fail_unless(Period("PT.D").get_nsecs() == 0); } END_TEST START_TEST(test_date) { Date d1(Date::now()); Date d2 = d1 + Period("PT6S"); fail_unless(d2.get_utc() == d1.get_utc() + 6*Sec); fail_unless(d2 - Period("PT6S") == d1); Date max(Date::max()); fail_unless(d1 < max); } END_TEST START_TEST(test_trac_712) { try { Period p; p = gu::from_string("0x3"); // used to throw gu::Exception } catch (gu::NotFound& nf) { } } END_TEST Suite* gu_datetime_suite() { Suite* s = suite_create("gu::datetime"); TCase* tc; tc = tcase_create("test_units"); tcase_add_test(tc, test_units); suite_add_tcase(s, tc); tc = tcase_create("test_period"); tcase_add_test(tc, test_period); suite_add_tcase(s, tc); tc = tcase_create("test_date"); tcase_add_test(tc, test_date); suite_add_tcase(s, tc); tc = tcase_create("test_trac_712"); tcase_add_test(tc, test_trac_712); suite_add_tcase(s, tc); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_mmh3_test.c0000644000175000017500000002167013136555240026004 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy // $Id$ #include "gu_mmh3_test.h" #include "../src/gu_mmh3.h" #include "../src/gu_log.h" #include "../src/gu_hexdump.h" /* This is to verify all tails plus block + all tails. Max block is 16 bytes */ static const char test_input[] = "0123456789ABCDEF0123456789abcde"; typedef struct hash32 { uint8_t h[4]; } hash32_t; #define NUM_32_TESTS 8 /* 0 to 7 bytes */ static const hash32_t test_output32[NUM_32_TESTS] = { {{ 0x0b, 0x7c, 0x3e, 0xab }}, /* '' */ {{ 0xba, 0xeb, 0x75, 0x97 }}, /* '0' */ {{ 0x5d, 0x5c, 0x21, 0x60 }}, /* '01' */ {{ 0x4b, 0xff, 0x61, 0x41 }}, /* '012' */ {{ 0x35, 0x3b, 0x57, 0xca }}, /* '0123' */ {{ 0x09, 0xdd, 0x77, 0xf9 }}, /* '01234' */ {{ 0x1f, 0x3c, 0x29, 0x7b }}, /* '012345' */ {{ 0xe1, 0xbe, 0x2d, 0xce }} /* '0123456' */ }; typedef struct hash128 { uint8_t h[16]; } hash128_t; #define NUM_128_TESTS 32 /* 0 to 31 bytes */ static const hash128_t test_output128[NUM_128_TESTS] = { {{ 0xa9,0xce,0x5a,0x56,0x0c,0x0b,0xf7,0xd6,0x63,0x4f,0x6f,0x81,0x0e,0x0b,0xf2,0x0a }}, {{ 0x72,0xa1,0x46,0xa3,0x73,0x03,0x49,0x85,0x30,0xb9,0x52,0xaa,0x3b,0x00,0xad,0x23 }}, {{ 0x4f,0x32,0xa2,0x15,0x91,0x00,0xea,0xaa,0x59,0x90,0x48,0x30,0xe5,0x86,0x50,0xee }}, {{ 0x55,0xfe,0x86,0x3b,0x9c,0x67,0xc6,0xee,0x5c,0x06,0x34,0xd0,0xe5,0x15,0xfb,0xdd }}, {{ 0x3a,0x50,0x35,0xe5,0x72,0x75,0xa5,0x5e,0x46,0x3d,0x0e,0x23,0xbb,0x17,0x5a,0x66 }}, {{ 0x3b,0xff,0xb5,0x1a,0x93,0x0c,0x77,0x9a,0x40,0x5f,0x62,0x0c,0x40,0x15,0x0b,0x6e }}, {{ 0x7c,0xf8,0xf9,0xd2,0xfa,0x5a,0x8b,0x51,0x65,0x3c,0xa5,0x0e,0xa2,0xca,0x0a,0x87 }}, {{ 0x95,0x69,0x33,0x98,0xe4,0xb2,0x2a,0x21,0xd4,0x23,0x21,0x80,0xb1,0x00,0x46,0xbb }}, {{ 0x92,0xca,0xd3,0xbb,0x39,0x16,0x96,0xb5,0x3a,0x61,0x58,0x53,0xbb,0xf8,0xc4,0xb0 }}, {{ 0x36,0xf0,0xa3,0xc8,0xdc,0x5e,0x46,0x20,0x12,0xcf,0xad,0x3f,0xda,0xd5,0x95,0x7a }}, {{ 0xb9,0x71,0x76,0x54,0xd3,0x74,0x9b,0x31,0x93,0xb2,0xd9,0xbf,0xad,0x78,0x49,0x7e }}, {{ 0x39,0x75,0xc6,0x34,0x38,0x65,0x60,0x32,0xb1,0xa3,0x02,0xd2,0xba,0x47,0x0b,0xc3 }}, {{ 0x37,0xcd,0xe3,0x34,0x7d,0x2d,0xa4,0xdc,0xf3,0x51,0xd1,0x1e,0x46,0xb8,0x1a,0xd4 }}, {{ 0xa0,0xf6,0xff,0xc6,0xcd,0x50,0xdf,0xa2,0x59,0x36,0x8d,0xdf,0x09,0x57,0x14,0x7b }}, {{ 0xeb,0x58,0x42,0xca,0x56,0xb5,0x94,0x16,0x10,0x86,0x38,0x5b,0x2c,0x4a,0x13,0x84 }}, {{ 0x5d,0xee,0x3a,0x5b,0x45,0x5f,0x92,0x7d,0x42,0x91,0x8a,0x7b,0xb6,0xc7,0xde,0xd9 }}, {{ 0x63,0xff,0xe5,0x55,0x38,0x3d,0xd6,0x5d,0xa4,0xad,0xcb,0xf6,0x0a,0xc3,0xd9,0x12 }}, {{ 0x86,0x15,0xd3,0x5a,0x47,0x81,0x3f,0xea,0x6b,0xbc,0x3b,0x82,0xd0,0x49,0xda,0x5d }}, {{ 0xb7,0x41,0xc9,0xf5,0x94,0x3f,0x91,0xa5,0x56,0x68,0x9c,0x12,0xc7,0xa1,0xd9,0x45 }}, {{ 0xb7,0x7c,0x2f,0x60,0xe3,0x2b,0x6a,0xd6,0x5e,0x24,0x6c,0xaf,0x8c,0x83,0x99,0xc7 }}, {{ 0x62,0xdb,0xad,0xab,0xda,0x51,0x82,0x0b,0x04,0xe6,0x7a,0x88,0xaa,0xae,0xfd,0xce }}, {{ 0x70,0x89,0xd2,0x6a,0x35,0x80,0x19,0xa4,0x71,0x0e,0x5c,0x68,0x33,0xf5,0x0c,0x67 }}, {{ 0x05,0xb3,0x50,0x50,0xbe,0x8d,0xaa,0x6e,0x32,0x02,0x1b,0x5e,0xe6,0xb7,0x5f,0x72 }}, {{ 0x85,0x60,0x7c,0x7a,0xdf,0xaa,0x67,0xc6,0xed,0x3e,0x7e,0x13,0x84,0x2c,0xd4,0x28 }}, {{ 0x51,0x4a,0xe3,0x56,0xe0,0x5f,0x7d,0x42,0xfb,0x41,0xec,0xfe,0xff,0xa4,0x74,0x13 }}, {{ 0xb8,0xc0,0xc1,0x01,0xc2,0x74,0xbb,0x84,0xc8,0xca,0x16,0x9c,0x6b,0xf3,0x3e,0x4d }}, {{ 0xab,0xd0,0x4a,0xc5,0xa4,0xc8,0xce,0xf4,0xf2,0xf5,0x2f,0xdc,0x22,0x4f,0x20,0xda }}, {{ 0x36,0x25,0x28,0x74,0xf0,0x4c,0x36,0x38,0xd2,0x9a,0x64,0xf8,0x11,0xcf,0xaf,0x28 }}, {{ 0x8b,0x79,0x18,0x09,0x14,0x19,0x3c,0xa0,0x5b,0x62,0x4d,0x09,0x18,0xdd,0x6a,0x89 }}, {{ 0xc0,0xae,0x4f,0x67,0x45,0x01,0x00,0xb7,0x75,0xc5,0x1c,0x56,0xdf,0x55,0x7c,0x04 }}, {{ 0xcd,0x5a,0xda,0xea,0xbc,0xfb,0x8d,0xc7,0x8a,0xd3,0xc6,0x70,0x12,0x34,0x82,0x84 }}, {{ 0x69,0x53,0x0d,0xc3,0x4d,0xd4,0x33,0xe9,0x00,0x1b,0x27,0x06,0x27,0x7f,0x48,0xf7 }} }; typedef void (*hash_f_t) (const void* key, int len, uint32_t seed, void* out); /* Verification code from the original SMHasher test suite */ static void smhasher_verification (hash_f_t hash, size_t const hashbytes, uint32_t* const res) { ssize_t const n_tests = 256; uint8_t key[n_tests]; uint8_t hashes[hashbytes * n_tests]; uint8_t final[hashbytes]; /* Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as * the seed */ ssize_t i; for(i = 0; i < n_tests; i++) { key[i] = (uint8_t)i; hash (key, i, n_tests - i, &hashes[i * hashbytes]); } /* Then hash the result array */ hash (hashes, hashbytes * n_tests, 0, final); memcpy (res, final, sizeof(*res)); } static hash32_t smhasher_checks[3] = { {{ 0xE3, 0x7E, 0xF5, 0xB0 }}, /* mmh3_32 */ {{ 0x2A, 0xE6, 0xEC, 0xB3 }}, /* mmh3_x86_128 */ {{ 0x69, 0xBA, 0x84, 0x63 }} /* mmh3_x64_128 */ }; /* returns true if check fails */ static bool check (const void* const exp, const void* const got, ssize_t size) { if (memcmp (exp, got, size)) { ssize_t str_size = size * 2.2 + 1; char c[str_size], r[str_size]; gu_hexdump (exp, size, c, sizeof(c), false); gu_hexdump (got, size, r, sizeof(r), false); gu_info ("expected MurmurHash3:\n%s\nfound:\n%s\n", c, r); return true; } return false; } START_TEST (gu_mmh32_test) { int i; uint32_t out; smhasher_verification (gu_mmh3_32, sizeof(out), &out); fail_if (check (&smhasher_checks[0], &out, sizeof(out)), "gu_mmh3_32 failed."); for (i = 0; i < NUM_32_TESTS; i++) { uint32_t res = gu_mmh32 (test_input, i); res = gu_le32(res); fail_if(check (&test_output32[i], &res, sizeof(res)), "gu_mmh32() failed at step %d",i); } } END_TEST #if 0 /* x86 variant is faulty and unsuitable for short keys, ignore */ START_TEST (gu_mmh128_x86_test) { int i; uint32_t out32; smhasher_verification (gu_mmh3_x86_128, sizeof(hash128_t), &out32); fail_if (check (&smhasher_checks[1], &out32, sizeof(out32)), "gu_mmh3_x86_128 failed."); for (i = 0; i < NUM_128_TESTS; i++) { hash128_t out; gu_mmh3_x86_128 (test_input, i, GU_MMH32_SEED, &out); check (&test_output128[i], &out, sizeof(out)); } } END_TEST #endif /* 0 */ START_TEST (gu_mmh128_x64_test) { int i; uint32_t out32; smhasher_verification (gu_mmh3_x64_128, sizeof(hash128_t), &out32); fail_if (check (&smhasher_checks[2], &out32, sizeof(out32)), "gu_mmh3_x64_128 failed."); for (i = 0; i < NUM_128_TESTS; i++) { hash128_t out; gu_mmh128 (test_input, i, &out); fail_if(check (&test_output128[i], &out, sizeof(out)), "gu_mmh128() failed at step %d", i); } } END_TEST /* Tests partial hashing functions */ START_TEST (gu_mmh128_partial) { hash128_t part; gu_mmh128_ctx_t ctx; gu_mmh128_init (&ctx); gu_mmh128_append (&ctx, test_input, 31); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[31], &part, sizeof(part)), "gu_mmh128_get() failed at one go"); gu_mmh128_init (&ctx); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[0], &part, sizeof(part)), "gu_mmh128_get() failed at init"); gu_mmh128_append (&ctx, test_input + 0, 0); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[0], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 0); gu_mmh128_append (&ctx, test_input + 0, 1); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[1], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 1); gu_mmh128_append (&ctx, test_input + 1, 2); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[3], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 3); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[3], &part, sizeof(part)), "gu_mmh128_get() failed at length %d again", 3); gu_mmh128_append (&ctx, test_input + 3, 20); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[23], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 23); gu_mmh128_append (&ctx, test_input + 23, 0); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[23], &part, sizeof(part)), "gu_mmh128_get() failed at length %d again", 23); gu_mmh128_append (&ctx, test_input + 23, 3); gu_mmh128_append (&ctx, test_input + 26, 3); gu_mmh128_append (&ctx, test_input + 29, 2); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[31], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 31); } END_TEST Suite *gu_mmh3_suite(void) { Suite *s = suite_create("MurmurHash3"); TCase *tc = tcase_create("gu_mmh3"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_mmh32_test); // tcase_add_test (tc, gu_mmh128_x86_test); tcase_add_test (tc, gu_mmh128_x64_test); tcase_add_test (tc, gu_mmh128_partial); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_atomic_test.hpp0000644000175000017500000000031413136555240026751 0ustar jenkinsjenkins// Copyright (C) 2014 Codership Oy // $Id$ #ifndef __gu_atomic_test__ #define __gu_atomic_test__ #include Suite *gu_atomic_suite(void); #endif /* __gu_atomic_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_vec_test.c0000644000175000017500000000171513136555240025713 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy * * $Id$ */ #include "gu_vec_test.h" #include "../src/gu_vec16.h" START_TEST (vec16_test) { gu_vec16_t v1 = gu_vec16_from_byte (0); gu_vec16_t v2 = gu_vec16_from_byte (0); gu_vec16_t v3 = gu_vec16_from_byte (7); fail_if (!gu_vec16_eq(v1, v2)); fail_if (gu_vec16_eq(v1, v3)); unsigned char a1[16], a2[16], a3[16]; fail_if (sizeof(v1) != sizeof(a1)); unsigned int i; for (i = 0; i < sizeof(a1); i++) { a1[i] = i; a2[i] = i * i; a3[i] = a1[i] ^ a2[i]; } v1 = gu_vec16_from_ptr (a1); v2 = gu_vec16_from_ptr (a2); fail_if (gu_vec16_eq(v1, v2)); v3 = gu_vec16_xor (v1, v2); fail_if (memcmp (&v3, a3, sizeof(a3))); } END_TEST Suite* gu_vec_suite(void) { TCase* t = tcase_create ("vec16"); tcase_add_test (t, vec16_test); Suite* s = suite_create ("Vector math"); suite_add_tcase (s, t); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_str_test.c0000644000175000017500000000467413136555240025755 0ustar jenkinsjenkins #include "gu_str.h" #include START_TEST(test_append) { const char* strs[3] = { "t", "ttt", "tttttttt" }; char* str = NULL; size_t off = 0; size_t i; for (i = 0; i < 3; ++i) { str = gu_str_append(str, &off, strs[i], strlen(strs[i])); } free(str); } END_TEST START_TEST(test_scan) { const char* strs[5] = { "1", "234", "56789abc", "4657777777777", "345" }; char* str = NULL; size_t off = 0; size_t len = 0; size_t i; const char* ptr; for (i = 0; i < 5; ++i) { str = gu_str_append(str, &off, strs[i], strlen(strs[i])); len += strlen(strs[i]) + 1; } ptr = str; for (i = 0; i < 5; ++i) { fail_unless(strcmp(ptr, strs[i]) == 0); ptr = gu_str_next(ptr); } fail_unless(ptr == len + str); for (i = 0; i < 5; ++i) { ptr = gu_str_advance(str, i); fail_unless(strcmp(ptr, strs[i]) == 0); } free(str); } END_TEST START_TEST(test_str_table) { size_t n_cols = 5; char const* col_names[5] = { "col1", "column2", "foo", "bar", "zzz" }; size_t n_rows = 255; const char* row[5] = {"dddd", "asdfasdf", "sadfdf", "", "a"}; const char* name = "test_table"; char* str = NULL; size_t off = 0; size_t i; str = gu_str_table_set_name(str, &off, name); fail_unless(strcmp(gu_str_table_get_name(str), name) == 0); str = gu_str_table_set_n_cols(str, &off, n_cols); fail_unless(gu_str_table_get_n_cols(str) == n_cols); str = gu_str_table_set_n_rows(str, &off, n_rows); fail_unless(gu_str_table_get_n_rows(str) == n_rows); str = gu_str_table_set_cols(str, &off, n_cols, col_names); for (i = 0; i < n_rows; ++i) { str = gu_str_table_append_row(str, &off, n_cols, row); } mark_point(); FILE* tmp = fopen("/dev/null", "w"); fail_if (NULL == tmp); gu_str_table_print(tmp, str); fclose(tmp); free(str); } END_TEST Suite* gu_str_suite() { Suite* s = suite_create("Galera Str util suite"); TCase* tc; tc = tcase_create("test_append"); tcase_add_test(tc, test_append); suite_add_tcase(s, tc); tc = tcase_create("test_scan"); tcase_add_test(tc, test_scan); suite_add_tcase(s, tc); tc = tcase_create("test_str_table"); tcase_add_test(tc, test_str_table); suite_add_tcase(s, tc); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_vector_test.cpp0000644000175000017500000000246513136555240027003 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy * * $Id$ */ #include "../src/gu_vector.hpp" #include "gu_vector_test.hpp" START_TEST (simple_test) { // we are not to test the whole vector functionality, it is provided // by incorporated std::vector. We just need to see that allocator // works as expected gu::Vector v1; v1->reserve(12); fail_if (v1->size() != 0); v1->push_back(12); fail_if (v1->size() != 1); v1->resize(11); fail_if (v1->size() != 11); fail_if (v1.in_heap() != false); v1[10]=1; fail_if (v1[10] != v1()[10]); gu::Vector v2(v1); fail_if (v2->size() != v1->size()); fail_if (v1[10] != v2[10]); fail_if (&v1[10] == &v2[10]); v2[10]=2; fail_if (v1[10] == v2[10]); v2() = v1(); fail_if (v1[10] != v2[10]); fail_if (&v1[0] == &v2[0]); fail_if (v2.in_heap() != false); v2->resize(32); fail_if (v2.in_heap() != true); fail_if (v1.in_heap() != false); v2[25]=1; v1->resize(32); fail_if (v1.in_heap() != true); v1[25]=2; fail_if (v1[25] == v2[25]); } END_TEST Suite* gu_vector_suite(void) { TCase* t = tcase_create ("simple_test"); tcase_add_test (t, simple_test); Suite* s = suite_create ("gu::Vector"); suite_add_tcase (s, t); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_uuid_test.h0000644000175000017500000000030013136555240026076 0ustar jenkinsjenkins/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gu_uuid_test__ #define __gu_uuid_test__ extern Suite *gu_uuid_suite(void); #endif /* __gu_uuid_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_tests++.cpp0000644000175000017500000000200413136555240025717 0ustar jenkinsjenkins// Copyright (C) 2009-2017 Codership Oy #include #include #include #include extern "C" { #include "../src/gu_conf.h" } #include "gu_tests++.hpp" int main(int argc, char* argv[]) { bool no_fork = (argc >= 2 && std::string(argv[1]) == "nofork"); FILE* log_file = 0; if (!no_fork) { log_file = fopen (LOG_FILE, "w"); if (!log_file) return EXIT_FAILURE; gu_conf_set_log_file (log_file); } gu_conf_debug_on(); int failed = 0; for (int i = 0; suites[i] != 0; ++i) { SRunner* sr = srunner_create(suites[i]()); if (no_fork) srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all(sr, CK_NORMAL); failed += srunner_ntests_failed(sr); srunner_free(sr); } if (log_file != 0) fclose(log_file); printf ("Total tests failed: %d\n", failed); if (0 == failed && 0 != log_file) ::unlink(LOG_FILE); return failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_hash_test.h0000644000175000017500000000031313136555240026057 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_hash_test__ #define __gu_hash_test__ #include extern Suite *gu_hash_suite(void); #endif /* __gu_hash_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_hash_test.c0000644000175000017500000001771113136555240026064 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy /* * This unit test is mostly to check that Galera hash definitions didn't change: * correctness of hash algorithms definitions is checked in respective unit * tests. * * By convention checks are made against etalon byte arrays, so integers must be * converted to little-endian. * * $Id$ */ #include "gu_hash_test.h" #include "../src/gu_hash.h" #include "../src/gu_log.h" #include "../src/gu_hexdump.h" /* checks equivalence of two buffers, returns true if check fails and logs * buffer contents. */ static bool check (const void* const exp, const void* const got, ssize_t size) { if (memcmp (exp, got, size)) { ssize_t str_size = size * 2.2 + 1; char c[str_size], r[str_size]; gu_hexdump (exp, size, c, sizeof(c), false); gu_hexdump (got, size, r, sizeof(r), false); gu_info ("expected hash value:\n%s\nfound:\n%s\n", c, r); return true; } return false; } static const char test_msg[2048] = { 0, }; #define GU_HASH_TEST_LENGTH 43 /* some random prime */ static const uint8_t gu_hash128_check[16] = { 0xFA,0x2C,0x78,0x67,0x35,0x99,0xD9,0x84,0x73,0x41,0x3F,0xA5,0xEB,0x27,0x40,0x2F }; static const uint8_t gu_hash64_check[8] = { 0xFA,0x2C,0x78,0x67,0x35,0x99,0xD9,0x84 }; static const uint8_t gu_hash32_check[4] = { 0xFA,0x2C,0x78,0x67 }; /* Tests partial hashing functions */ START_TEST (gu_hash_test) { gu_hash_t h; gu_hash_init(&h); gu_hash_append(&h, test_msg, GU_HASH_TEST_LENGTH); uint8_t res128[16]; gu_hash_get128 (&h, res128); fail_if (check (gu_hash128_check, res128, sizeof(res128)), "gu_hash_get128() failed."); uint64_t res64 = gu_hash_get64(&h); fail_if (gu_hash64(test_msg, GU_HASH_TEST_LENGTH) != res64); res64 = gu_le64(res64); fail_if (check (gu_hash64_check, &res64, sizeof(res64)), "gu_hash_get64() failed."); uint32_t res32 = gu_hash_get32(&h); fail_if (gu_hash32(test_msg, GU_HASH_TEST_LENGTH) != res32); res32 = gu_le32(res32); fail_if (check (gu_hash32_check, &res32, sizeof(res32)), "gu_hash_get32() failed."); } END_TEST static const uint8_t fast_hash128_check0 [16] = { 0xA9,0xCE,0x5A,0x56,0x0C,0x0B,0xF7,0xD6,0x63,0x4F,0x6F,0x81,0x0E,0x0B,0xF2,0x0A }; static const uint8_t fast_hash128_check511 [16] = { 0xC6,0x7F,0x4C,0xE7,0x6F,0xE0,0xDA,0x14,0xCC,0x9F,0x21,0x76,0xAF,0xB5,0x12,0x1A }; static const uint8_t fast_hash128_check512 [16] = { 0x38,0x8D,0x2B,0x90,0xC8,0x7F,0x11,0x53,0x3F,0xB4,0x32,0xC1,0xD7,0x2B,0x04,0x39 }; static const uint8_t fast_hash128_check2011[16] = { 0xB7,0xCE,0x75,0xC7,0xB4,0x31,0xBC,0xC8,0x95,0xB3,0x41,0xB8,0x5B,0x8E,0x77,0xF9 }; static const uint8_t fast_hash64_check0 [8] = { 0x6C, 0x55, 0xB8, 0xA1, 0x02, 0xC6, 0x21, 0xCA }; static const uint8_t fast_hash64_check15 [8] = { 0x28, 0x49, 0xE8, 0x34, 0x7A, 0xAB, 0x49, 0x34 }; static const uint8_t fast_hash64_check16 [8] = { 0x44, 0x40, 0x2C, 0x82, 0xD3, 0x8D, 0xAA, 0xFE }; static const uint8_t fast_hash64_check511 [8] = { 0xC6, 0x7F, 0x4C, 0xE7, 0x6F, 0xE0, 0xDA, 0x14 }; static const uint8_t fast_hash64_check512 [8] = { 0x38, 0x8D, 0x2B, 0x90, 0xC8, 0x7F, 0x11, 0x53 }; static const uint8_t fast_hash64_check2011[8] = { 0xB7, 0xCE, 0x75, 0xC7, 0xB4, 0x31, 0xBC, 0xC8 }; static const uint8_t fast_hash32_check0 [4] = { 0x0B, 0x7C, 0x3E, 0xAB }; static const uint8_t fast_hash32_check31 [4] = { 0x1E, 0xFF, 0x48, 0x38 }; static const uint8_t fast_hash32_check32 [4] = { 0x63, 0xC2, 0x53, 0x0D }; static const uint8_t fast_hash32_check511 [4] = { 0xC6, 0x7F, 0x4C, 0xE7 }; static const uint8_t fast_hash32_check512 [4] = { 0x38, 0x8D, 0x2B, 0x90 }; static const uint8_t fast_hash32_check2011[4] = { 0xB7, 0xCE, 0x75, 0xC7 }; /* Tests fast hash functions */ START_TEST (gu_fast_hash_test) { uint8_t res128[16]; gu_fast_hash128 (test_msg, 0, res128); fail_if (check (fast_hash128_check0, res128, sizeof(res128))); gu_fast_hash128 (test_msg, 511, res128); fail_if (check (fast_hash128_check511, res128, sizeof(res128))); gu_fast_hash128 (test_msg, 512, res128); fail_if (check (fast_hash128_check512, res128, sizeof(res128))); gu_fast_hash128 (test_msg, 2011, res128); fail_if (check (fast_hash128_check2011, res128, sizeof(res128))); uint64_t res64; res64 = gu_fast_hash64 (test_msg, 0); res64 = gu_le64(res64); fail_if (check (fast_hash64_check0, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 15); res64 = gu_le64(res64); fail_if (check (fast_hash64_check15, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 16); res64 = gu_le64(res64); fail_if (check (fast_hash64_check16, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 511); res64 = gu_le64(res64); fail_if (check (fast_hash64_check511, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 512); res64 = gu_le64(res64); fail_if (check (fast_hash64_check512, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 2011); res64 = gu_le64(res64); fail_if (check (fast_hash64_check2011, &res64, sizeof(res64))); uint32_t res32; res32 = gu_fast_hash32 (test_msg, 0); res32 = gu_le32(res32); fail_if (check (fast_hash32_check0, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 31); res32 = gu_le32(res32); fail_if (check (fast_hash32_check31, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 32); res32 = gu_le32(res32); fail_if (check (fast_hash32_check32, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 511); res32 = gu_le32(res32); fail_if (check (fast_hash32_check511, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 512); res32 = gu_le32(res32); fail_if (check (fast_hash32_check512, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 2011); res32 = gu_le32(res32); fail_if (check (fast_hash32_check2011, &res32, sizeof(res32))); } END_TEST /* Tests table hash functions: * - for 64-bit platforms table hash should be identical to fast 64-bit hash, * - for 32-bit platforms table hash is different. */ #if GU_WORDSIZE == 64 START_TEST (gu_table_hash_test) { size_t res; fail_if (sizeof(res) > 8); res = gu_table_hash (test_msg, 0); res = gu_le64(res); fail_if (check (fast_hash64_check0, &res, sizeof(res))); res = gu_table_hash (test_msg, 15); res = gu_le64(res); fail_if (check (fast_hash64_check15, &res, sizeof(res))); res = gu_table_hash (test_msg, 16); res = gu_le64(res); fail_if (check (fast_hash64_check16, &res, sizeof(res))); res = gu_table_hash (test_msg, 511); res = gu_le64(res); fail_if (check (fast_hash64_check511, &res, sizeof(res))); res = gu_table_hash (test_msg, 512); res = gu_le64(res); fail_if (check (fast_hash64_check512, &res, sizeof(res))); res = gu_table_hash (test_msg, 2011); res = gu_le64(res); fail_if (check (fast_hash64_check2011, &res, sizeof(res))); } END_TEST #elif GU_WORDSIZE == 32 static const uint8_t table_hash32_check0 [4] = { 0x0B, 0x7C, 0x3E, 0xAB }; static const uint8_t table_hash32_check32 [4] = { 0x65, 0x16, 0x17, 0x42 }; static const uint8_t table_hash32_check2011[4] = { 0xF9, 0xBC, 0xEF, 0x7A }; START_TEST (gu_table_hash_test) { size_t res; fail_if (sizeof(res) > 4); res = gu_table_hash (test_msg, 0); res = gu_le32(res); fail_if (check (table_hash32_check0, &res, sizeof(res))); res = gu_table_hash (test_msg, 32); res = gu_le32(res); fail_if (check (table_hash32_check32, &res, sizeof(res))); res = gu_table_hash (test_msg, 2011); res = gu_le32(res); fail_if (check (table_hash32_check2011, &res, sizeof(res))); } END_TEST #else /* GU_WORDSIZE == 32 */ # error "Unsupported word size" #endif Suite *gu_hash_suite(void) { Suite *s = suite_create("Galera hash"); TCase *tc = tcase_create("gu_hash"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_hash_test); tcase_add_test (tc, gu_fast_hash_test); tcase_add_test (tc, gu_table_hash_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_utils_test.h0000644000175000017500000000026413136555240026301 0ustar jenkinsjenkins// Copyright (C) 2010 Codership Oy // $Id$ #ifndef __gu_utils_test__ #define __gu_utils_test__ Suite *gu_utils_suite(void); #endif /* __gu_utils_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_mmh3_test.h0000644000175000017500000000031313136555240026000 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_mmh3_test__ #define __gu_mmh3_test__ #include extern Suite *gu_mmh3_suite(void); #endif /* __gu_mmh3_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_uri_test.cpp0000644000175000017500000003473513136555240026305 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #include #include #include "../src/gu_uri.hpp" #include "../src/gu_exception.hpp" #include "../src/gu_logger.hpp" #include "gu_uri_test.hpp" using std::string; using std::pair; using gu::URI; using gu::URIQueryList; using gu::NotSet; using gu::NotFound; using gu::Exception; START_TEST (uri_test1) // checking normal URI { const string scheme("scheme"); const string user ("user:pswd"); const string host ("[::ffff:192.168.0.1]"); // IPv4 over IPv6 const string port ("4567"); const string path ("/path1/path2"); const string opt1 ("opt1"); const string val1 ("val1"); const string opt2 ("opt2"); const string val2 ("val2"); const string query (opt1 + '=' + val1 + '&' + opt2 + '=' + val2); const string frag ("frag"); string auth = user + "@" + host + ":" + port; string uri_str = scheme + "://" + auth + path + "?" + query + "#" + frag; try { URI uri(uri_str); try { fail_if (scheme != uri.get_scheme(), "Scheme '%s' != '%s'", scheme.c_str(), uri.get_scheme().c_str()); } catch (NotSet&) { fail ("Scheme not set in '%s'", uri_str.c_str()); } try { fail_if (user != uri.get_user(), "User info '%s' != '%s'", user.c_str(), uri.get_user().c_str()); } catch (NotSet&) { fail ("User info not set in '%s'", uri_str.c_str()); } try { fail_if (host != uri.get_host(), "Host '%s' != '%s'", host.c_str(), uri.get_host().c_str()); } catch (NotSet&) { fail ("Host not set in '%s'", uri_str.c_str()); } try { fail_if (port != uri.get_port(), "Port '%s' != '%s'", port.c_str(), uri.get_port().c_str()); } catch (NotSet&) { fail ("Port not set in '%s'", uri_str.c_str()); } try { fail_if (path != uri.get_path(), "Path '%s' != '%s'", path.c_str(), uri.get_path().c_str()); } catch (NotSet&) { fail ("Path not set in '%s'", uri_str.c_str()); } try { fail_if (frag != uri.get_fragment(), "Fragment '%s' != '%s'", frag.c_str(), uri.get_fragment().c_str()); } catch (NotSet&) { fail ("Fragment not set in '%s'", uri_str.c_str()); } try { fail_if (auth != uri.get_authority(), "Authority '%s' != '%s'", auth.c_str(), uri.get_authority().c_str()); } catch (NotSet&) { fail ("Authority not set in '%s'", uri_str.c_str()); } URIQueryList ql = uri.get_query_list(); fail_if (ql.size() != 2, "Query list size %zu, expected 2", ql.size()); URIQueryList::const_iterator i = ql.begin(); fail_if (i->first != opt1, "got option '%s', expected '%s'", i->first.c_str(), opt1.c_str()); fail_if (i->second != val1, "got value '%s', expected '%s'", i->second.c_str(), val1.c_str()); ++i; fail_if (i->first != opt2, "got option '%s', expected '%s'", i->first.c_str(), opt2.c_str()); fail_if (i->second != val2, "got value '%s', expected '%s'", i->second.c_str(), val2.c_str()); fail_if (val1 != uri.get_option(opt1)); fail_if (val2 != uri.get_option(opt2)); try { uri.get_option("xxx"); fail ("Expected NotFound exception"); } catch (NotFound&) {} URI simple ("gcomm+pc://192.168.0.1"); } catch (Exception& e) { fail (e.what()); } } END_TEST START_TEST (uri_test2) // checking corner cases { #ifdef NDEBUG try { URI uri(""); fail ("URI should have failed."); } catch (Exception& e) {} #endif mark_point(); try { URI uri("scheme:"); } catch (Exception& e) { fail ("URI should be valid."); } mark_point(); #ifdef NDEBUG try { URI uri(":path"); fail ("URI should have failed."); } catch (Exception& e) {} #endif mark_point(); try { URI uri("a://b:c?d=e#f"); fail ("URI should have failed."); } catch (Exception& e) {} mark_point(); try { URI uri("a://b:99999?d=e#f"); fail ("URI should have failed."); } catch (Exception& e) {} mark_point(); #ifdef NDEBUG try { URI uri("?query"); fail ("URI should have failed."); } catch (Exception& e) {} #endif mark_point(); try { URI uri("scheme:path"); try { uri.get_user(); fail ("User should be unset"); } catch (NotSet&) {} try { uri.get_host(); fail ("Host should be unset"); } catch (NotSet&) {} try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} try { uri.get_authority(); fail ("Authority should be unset"); } catch (NotSet&) {} try { uri.get_fragment(); fail ("Fragment should be unset"); } catch (NotSet&) {} fail_if (uri.get_query_list().size() != 0, "Query list must be empty"); } catch (Exception& e) { fail (e.what()); } mark_point(); try { URI uri("scheme:///path"); try { fail_if (uri.get_authority() != ""); } catch (NotSet&) { fail ("Authority should be set"); } try { uri.get_host(); fail("Host should be unset"); } catch (NotSet&) { } try { uri.get_user(); fail ("User should be unset"); } catch (NotSet&) {} try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} try { fail_if (uri.get_path().length() != 5); } catch (NotSet&) { fail ("Path should be 5 characters long"); } } catch (Exception& e) { fail (e.what()); } mark_point(); try { URI uri("scheme://@/path"); try { fail_if (uri.get_authority() != "@"); } catch (NotSet&) { fail ("Authority should be set"); } try { fail_if (uri.get_user() != ""); } catch (NotSet&) { fail ("User should be set"); } try { fail_if (uri.get_host() != ""); } catch (NotSet&) { fail ("Host should be set"); } try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} } catch (Exception& e) { fail (e.what()); } mark_point(); try { URI uri("scheme://@:/path"); try { fail_if (uri.get_authority() != "@"); } catch (NotSet&) { fail ("Authority should be set"); } try { fail_if (uri.get_user() != ""); } catch (NotSet&) { fail ("User should be set"); } try { fail_if (uri.get_host() != ""); } catch (NotSet&) { fail ("Host should be set"); } try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} } catch (Exception& e) { fail (e.what()); } mark_point(); try { URI uri("scheme://"); try { fail_if (uri.get_authority() != ""); } catch (NotSet&) { fail ("Authority should be set"); } try { uri.get_user(); fail ("User should be unset"); } catch (NotSet&) {} try { uri.get_host(); fail("Host should be unset"); } catch (NotSet&) { } try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} // According to http://tools.ietf.org/html/rfc3986#section-3.3 try { fail_if (uri.get_path() != ""); } catch (NotSet&) { fail ("Path should be set to empty"); } } catch (Exception& e) { fail (e.what()); } } END_TEST START_TEST (uri_test3) // Test from gcomm { #ifdef NDEBUG try { URI too_simple("http"); fail("too simple accepted"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } #endif URI empty_auth("http://"); fail_unless(empty_auth.get_scheme() == "http"); fail_unless(empty_auth.get_authority() == ""); URI simple_valid1("http://example.com"); fail_unless(simple_valid1.get_scheme() == "http"); fail_unless(simple_valid1.get_authority() == "example.com"); fail_unless(simple_valid1.get_path() == ""); fail_unless(simple_valid1.get_query_list().size() == 0); URI with_path("http://example.com/path/to/file.html"); fail_unless(with_path.get_scheme() == "http"); fail_unless(with_path.get_authority() == "example.com"); fail_unless(with_path.get_path() == "/path/to/file.html"); fail_unless(with_path.get_query_list().size() == 0); URI with_query("http://example.com?key1=val1&key2=val2"); fail_unless(with_query.get_scheme() == "http"); fail_unless(with_query.get_authority() == "example.com"); fail_unless(with_query.get_path() == ""); const URIQueryList& qlist = with_query.get_query_list(); fail_unless(qlist.size() == 2); URIQueryList::const_iterator i; i = qlist.find("key1"); fail_unless(i != qlist.end() && i->second == "val1"); i = qlist.find("key2"); fail_unless(i != qlist.end() && i->second == "val2"); URI with_uri_in_query("gcomm+gmcast://localhost:10001?gmcast.node=gcomm+tcp://localhost:10002&gmcast.node=gcomm+tcp://localhost:10003"); fail_unless(with_uri_in_query.get_scheme() == "gcomm+gmcast"); fail_unless(with_uri_in_query.get_authority() == "localhost:10001"); const URIQueryList& qlist2 = with_uri_in_query.get_query_list(); fail_unless(qlist2.size() == 2); pair ii; ii = qlist2.equal_range("gmcast.node"); fail_unless(ii.first != qlist2.end()); for (i = ii.first; i != ii.second; ++i) { fail_unless(i->first == "gmcast.node"); URI quri(i->second); fail_unless(quri.get_scheme() == "gcomm+tcp"); fail_unless(quri.get_authority().substr(0, string("localhost:1000").size()) == "localhost:1000"); } try { URI invalid1("http://example.com/?key1"); fail("invalid query accepted"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } } END_TEST START_TEST(uri_non_strict) { std::string const ip("1.2.3.4"); std::string const port("789"); std::string const addr(ip + ':' + port); try { URI u(ip); fail("Strict mode passed without scheme"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL, "Expected errno %d, got %d", EINVAL, e.get_errno()); } try { URI u(addr, false); fail_if (u.get_host() != ip); fail_if (u.get_port() != port); try { u.get_scheme(); fail("Scheme is '%s', should be unset", u.get_scheme().c_str()); } catch (gu::NotSet&) {} } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } } END_TEST START_TEST(uri_test_multihost) { try { gu::URI uri("tcp://host1,host2"); fail_unless(uri.get_authority_list().size() == 2); try { uri.get_authority_list()[0].user(); fail("User should not be set"); } catch (NotSet&) { } fail_unless(uri.get_authority_list()[0].host() == "host1"); try { uri.get_authority_list()[0].port(); fail("Port should not be set"); } catch (NotSet&) { } fail_unless(uri.get_authority_list()[1].host() == "host2"); } catch (gu::Exception& e) { fail(e.what()); } try { gu::URI uri("tcp://host1:1234,host2:,host3:3456"); fail_unless(uri.get_authority_list().size() == 3); try { uri.get_authority_list()[0].user(); fail("User should not be set"); } catch (NotSet&) { } fail_unless(uri.get_authority_list()[0].host() == "host1"); fail_unless(uri.get_authority_list()[0].port() == "1234"); fail_unless(uri.get_authority_list()[1].host() == "host2"); } catch (gu::Exception& e) { fail(e.what()); } } END_TEST START_TEST(uri_IPv6) { std::string const ip("[2001:db8:85a3::8a2e:370:7334]"); std::string const ip_unescaped("2001:db8:85a3::8a2e:370:7334"); std::string const port("789"); std::string const addr(ip + ':' + port); std::string const localhost("[::1]"); std::string const localhost_unescaped("::1"); std::string const default_unescaped("::"); std::string const invalid("[2001:db8:85a3::8a2e:370:7334[:789"); try { URI u(ip, false); fail_unless (u.get_host() == ip); } catch (gu::Exception& e) { fail(e.what()); } try { URI u(ip_unescaped, false); fail_unless (u.get_host() == ip_unescaped); } catch (gu::Exception& e) { fail(e.what()); } try { URI u(addr, false); fail_unless (u.get_host() == ip); fail_unless (u.get_port() == port); } catch (gu::Exception& e) { fail(e.what()); } try { URI u(localhost, false); fail_unless (u.get_host() == localhost); } catch (gu::Exception& e) { fail(e.what()); } try { URI u(localhost_unescaped, false); fail_unless (u.get_host() == localhost_unescaped); log_info << "host: " << u.get_host(); } catch (gu::Exception& e) { fail(e.what()); } try { URI u(default_unescaped, false); fail_unless (u.get_host() == default_unescaped); } catch (gu::Exception& e) { fail(e.what()); } try { URI u(invalid, false); fail("invalid uri accepted"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } } END_TEST Suite *gu_uri_suite(void) { Suite *s = suite_create("galerautils++ URI"); TCase *tc = tcase_create("URI"); suite_add_tcase (s, tc); tcase_add_test (tc, uri_test1); tcase_add_test (tc, uri_test2); tcase_add_test (tc, uri_test3); tcase_add_test (tc, uri_non_strict); tcase_add_test (tc, uri_test_multihost); tcase_add_test (tc, uri_IPv6); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_thread_test.hpp0000644000175000017500000000031113136555240026741 0ustar jenkinsjenkins// // Copyright (C) 2016 Codership Oy // #ifndef GU_THREAD_TEST_HPP #define GU_THREAD_TEST_HPP #include extern Suite *gu_thread_suite(); #endif // GU_THREAD_TEST_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_uri_test.hpp0000644000175000017500000000030713136555240026276 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_uri_test__ #define __gu_uri_test__ #include extern Suite *gu_uri_suite(void); #endif /* __gu_uri_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_str_test.h0000644000175000017500000000025413136555240025750 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy #ifndef __gu_str_test__ #define __gu_str_test__ extern Suite *gu_str_suite(void); #endif /* __gu_str_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_bswap_test.c0000644000175000017500000000267513136555240026260 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #include #include #include "gu_bswap_test.h" #include "../src/gu_byteswap.h" START_TEST (gu_bswap_test) { // need volatile to prevent compile-time optimization volatile uint16_t s = 0x1234; volatile uint32_t i = 0x12345678; volatile uint64_t l = 0x1827364554637281LL; uint16_t sle, sbe; uint32_t ile, ibe; uint64_t lle, lbe; // first conversion sle = gu_le16(s); sbe = gu_be16(s); ile = gu_le32(i); ibe = gu_be32(i); lle = gu_le64(l); lbe = gu_be64(l); #if __BYTE_ORDER == __LITTLE_ENDIAN fail_if (s != sle); fail_if (i != ile); fail_if (l != lle); fail_if (s == sbe); fail_if (i == ibe); fail_if (l == lbe); #else fail_if (s == sle); fail_if (i == ile); fail_if (l == lle); fail_if (s != sbe); fail_if (i != ibe); fail_if (l != lbe); #endif /* __BYTE_ORDER */ // second conversion sle = gu_le16(sle); sbe = gu_be16(sbe); ile = gu_le32(ile); ibe = gu_be32(ibe); lle = gu_le64(lle); lbe = gu_be64(lbe); fail_if (s != sle); fail_if (i != ile); fail_if (l != lle); fail_if (s != sbe); fail_if (i != ibe); fail_if (l != lbe); } END_TEST Suite *gu_bswap_suite(void) { Suite *s = suite_create("Galera byteswap functions"); TCase *tc = tcase_create("gu_bswap"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_bswap_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_to_test.c0000644000175000017500000002206113136555240025555 0ustar jenkinsjenkins/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include #include // printf() #include // strerror() #include // strtol(), exit(), EXIT_SUCCESS, EXIT_FAILURE #include // errno #include // gettimeofday() #include // usleep() #include #include struct thread_ctx { gu_thread_t thread; long thread_id; long stat_grabs; // how many times gcs_to_grab() was successful long stat_cancels;// how many times gcs_to_cancel() was called long stat_fails; // how many times gcs_to_grab() failed long stat_self; // how many times gcs_self_cancel() was called }; /* returns a semirandom number (hash) from seqno */ static inline ulong my_rnd (uint64_t x) { x = 2654435761U * x; // http://www.concentric.net/~Ttwang/tech/inthash.htm return (ulong)(x ^ (x >> 32)); // combine upper and lower halfs for better // randomness } /* whether to cancel self */ static inline ulong self_cancel (ulong rnd) { return !(rnd & 0xf); // will return TRUE once in 16 } /* how many other seqnos to cancel */ static inline ulong cancel (ulong rnd) { #if 0 // this causes probablity of conflict 88% // and average conflicts per seqno 3.5. Reveals a lot of corner cases return (rnd & 0x70) >> 4; // returns 0..7 #else // this is more realistic. // probability of conflict 25%, conflict rate 0.375 ulong ret = (rnd & 0x70) >> 4; // returns 0,0,0,0,0,0,1,2 if (gu_likely(ret < 5)) return 0; else return (ret - 5); #endif } /* offset of seqnos to cancel */ static inline ulong cancel_offset (ulong rnd) { return ((rnd & 0x700) >> 8) + 1; // returns 1 - 8 } static gu_to_t* to = NULL; static ulong thread_max = 16; // default number of threads static gu_seqno_t seqno_max = 1<<20; // default number of seqnos to check /* mutex to synchronize threads start */ static gu_mutex_t start = GU_MUTEX_INITIALIZER; static const unsigned int t = 10; // optimal sleep time static const struct timespec tsleep = { 0, 10000000 }; // 10 ms void* run_thread(void* ctx) { struct thread_ctx* thd = ctx; gu_seqno_t seqno = thd->thread_id; // each thread starts with own offset // to guarantee uniqueness of seqnos // without having to lock mutex gu_mutex_lock (&start); // wait for start signal gu_mutex_unlock (&start); while (seqno < seqno_max) { long ret; ulong rnd = my_rnd(seqno); if (gu_unlikely(self_cancel(rnd))) { // printf("Self-cancelling %8llu\n", (unsigned long long)seqno); while ((ret = gu_to_self_cancel(to, seqno)) == -EAGAIN) usleep (t); if (gu_unlikely(ret)) { fprintf (stderr, "gu_to_self_cancel(%llu) returned %ld (%s)\n", (unsigned long long)seqno, ret, strerror(-ret)); exit (EXIT_FAILURE); } else { // printf ("Self-cancel success (%llu)\n", (unsigned long long)seqno); thd->stat_self++; } } else { // printf("Grabbing %8llu\n", (unsigned long long)seqno); while ((ret = gu_to_grab (to, seqno)) == -EAGAIN) nanosleep (&tsleep, NULL); if (gu_unlikely(ret)) { if (gu_likely(-ECANCELED == ret)) { // printf ("canceled (%llu)\n", (unsigned long long)seqno); thd->stat_fails++; } else { fprintf (stderr, "gu_to_grab(%llu) returned %ld (%s)\n", (unsigned long long)seqno, ret, strerror(-ret)); exit (EXIT_FAILURE); } } else { long cancels = cancel(rnd); // printf ("success (%llu), cancels = %ld\n", (unsigned long long)seqno, cancels); if (gu_likely(cancels)) { long offset = cancel_offset (rnd); gu_seqno_t cancel_seqno = seqno + offset; while (cancels-- && (cancel_seqno < seqno_max)) { ret = gu_to_cancel(to, cancel_seqno); if (gu_unlikely(ret)) { fprintf (stderr, "gu_to_cancel(%llu) by %llu " "failed: %s\n", (unsigned long long)cancel_seqno, (unsigned long long)seqno, strerror (-ret)); exit (EXIT_FAILURE); } else { // printf ("%llu canceled %llu\n", // seqno, cancel_seqno); cancel_seqno += offset; thd->stat_cancels++; } } } thd->stat_grabs++; ret = gu_to_release(to, seqno); if (gu_unlikely(ret)) { fprintf (stderr, "gu_to_release(%llu) failed: %ld(%s)\n", (unsigned long long)seqno, ret, strerror(-ret)); exit (EXIT_FAILURE); } } } seqno += thread_max; // this together with unique starting point // guarantees that seqnos are unique } // printf ("Thread %ld exiting. Last seqno = %llu\n", // thd->thread_id, (unsigned long long)(seqno - thread_max)); return NULL; } int main (int argc, char* argv[]) { // minimum to length required by internal logic ulong to_len = cancel(0xffffffff) * cancel_offset(0xffffffff); errno = 0; if (argc > 1) seqno_max = (1 << atol(argv[0])); if (argc > 2) thread_max = (1 << atol(argv[1])); if (errno) { fprintf (stderr, "Usage: %s [seqno [threads]]\nBoth seqno and threads" "are exponents of 2^n.\n", argv[0]); exit(errno); } printf ("Starting with %lu threads and %llu maximum seqno.\n", thread_max, (unsigned long long)seqno_max); /* starting with 0, enough space for all threads and cancels */ // 4 is a magic number to get it working without excessive sleep on amd64 to_len = to_len > thread_max ? to_len : thread_max; to_len *= 4; to = gu_to_create (to_len, 0); if (to != NULL) { printf ("Created TO monitor of length %lu\n", to_len); } else { exit (-ENOMEM); } /* main block */ { long i, ret; clock_t start_clock, stop_clock; double time_spent; struct thread_ctx thread[thread_max]; gu_mutex_lock (&start); { /* initialize threads */ for (i = 0; (ulong)i < thread_max; i++) { thread[i].thread_id = i; thread[i].stat_grabs = 0; thread[i].stat_cancels = 0; thread[i].stat_fails = 0; thread[i].stat_self = 0; ret = pthread_create(&(thread[i].thread), NULL, run_thread, &thread[i]); if (ret) { fprintf (stderr, "Failed to create thread %ld: %s", i, strerror(ret)); exit (EXIT_FAILURE); } } start_clock = clock(); } gu_mutex_unlock (&start); // release threads /* wait for threads to complete and accumulate statistics */ gu_thread_join (thread[0].thread, NULL); for (i = 1; (ulong)i < thread_max; i++) { pthread_join (thread[i].thread, NULL); thread[0].stat_grabs += thread[i].stat_grabs; thread[0].stat_cancels += thread[i].stat_cancels; thread[0].stat_fails += thread[i].stat_fails; thread[0].stat_self += thread[i].stat_self; } stop_clock = clock(); time_spent = gu_clock_diff (stop_clock,start_clock); /* print statistics */ printf ("%llu seqnos in %.3f seconds (%.3f seqno/sec)\n", (unsigned long long)seqno_max, time_spent, ((double) seqno_max)/time_spent); printf ("Overhead at 10000 actions/second: %.2f%%\n", (time_spent * 10000 * 100/* for % */)/seqno_max); printf ("Grabbed: %9lu\n" "Failed: %9lu\n" "Self-cancelled: %9lu\n" "Canceled: %9lu (can exceed total number of seqnos)\n", thread[0].stat_grabs, thread[0].stat_fails, thread[0].stat_self, thread[0].stat_cancels ); if (seqno_max != (thread[0].stat_grabs+thread[0].stat_fails+thread[0].stat_self)) { fprintf (stderr, "Error: total number of grabbed, failed and " "self-cancelled waiters does not match total seqnos.\n"); exit (EXIT_FAILURE); } } return 0; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_mem_test.c0000644000175000017500000000351513136555240025714 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #define DEBUG_MALLOC // turn on the debugging code #define TEST_SIZE 1024 #include #include #include #include #include "gu_mem_test.h" #include "../src/galerautils.h" START_TEST (gu_mem_test) { void* ptr1; void* ptr2; int res; int i; ptr1 = gu_malloc (0); fail_if (NULL != ptr1, "Zero memory allocated, non-NULL pointer returned"); mark_point(); ptr1 = gu_malloc (TEST_SIZE); fail_if (NULL == ptr1, "NULL pointer returned for allocation" " errno: %s", strerror (errno)); mark_point(); ptr2 = memset (ptr1, 0xab, TEST_SIZE); fail_if (ptr2 != ptr1, "Memset changed pointer"); ptr2 = NULL; mark_point(); ptr2 = gu_realloc (ptr2, TEST_SIZE); fail_if (NULL == ptr2, "NULL pointer returned for reallocation" " errno: %s", strerror (errno)); memcpy (ptr2, ptr1, TEST_SIZE); mark_point(); ptr1 = gu_realloc (ptr1, TEST_SIZE + TEST_SIZE); res = memcmp (ptr1, ptr2, TEST_SIZE); fail_if (res != 0, "Realloc changed the contents of the memory"); mark_point(); ptr1 = gu_realloc (ptr1, 0); fail_if (res != 0, "Realloc to 0 didn't return NULL"); mark_point(); ptr1 = gu_calloc (1, TEST_SIZE); fail_if (NULL == ptr1, "NULL pointer returned for allocation" " errno: %s", strerror (errno)); for (i = 0; i < TEST_SIZE; i++) { res = ((char*)ptr1)[i]; if (res != 0) break; } fail_if (res != 0, "Calloc didn't clear up the memory"); mark_point(); gu_free (ptr1); mark_point(); gu_free (ptr2); } END_TEST Suite *gu_mem_suite(void) { Suite *s = suite_create("Galera memory utils"); TCase *tc_mem = tcase_create("gu_mem"); suite_add_tcase (s, tc_mem); tcase_add_test(tc_mem, gu_mem_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_spooky_test.h0000644000175000017500000000032313136555240026461 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_spooky_test__ #define __gu_spooky_test__ #include extern Suite *gu_spooky_suite(void); #endif /* __gu_spooky_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_string_utils_test.hpp0000644000175000017500000000035313136555240030226 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_string_utils_test__ #define __gu_string_utils_test__ #include extern Suite* gu_string_utils_suite(void); #endif /* __gu_string_utils_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_vector_test.hpp0000644000175000017500000000033113136555240026776 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_vector_test__ #define __gu_vector_test__ #include extern Suite *gu_vector_suite(void); #endif /* __gu_vector_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_datetime_test.hpp0000644000175000017500000000034113136555240027271 0ustar jenkinsjenkins/* * Copyright (C) 2009 Codership Oy * * $Id$ */ #ifndef __gu_datetime_test_hpp__ #define __gu_datetime_test_hpp__ #include Suite* gu_datetime_suite(); #endif // __gu_datetime_test_hpp__ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_string_test.hpp0000644000175000017500000000033113136555240027002 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_string_test__ #define __gu_string_test__ #include extern Suite *gu_string_suite(void); #endif /* __gu_string_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_alloc_test.cpp0000644000175000017500000000426313136555240026571 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy // $Id$ #include "../src/gu_alloc.hpp" #include "gu_alloc_test.hpp" class TestBaseName : public gu::Allocator::BaseName { std::string str_; public: TestBaseName(const char* name) : str_(name) {} void print(std::ostream& os) const { os << str_; } }; START_TEST (basic) { ssize_t const extra_size(1 << 12); /* extra size to force new page */ gu::byte_t reserved[extra_size]; const char test0[] = "test0"; ssize_t const test0_size(sizeof(test0)); const char test1[] = "test1"; ssize_t const test1_size(sizeof(test1) + extra_size); TestBaseName test_name("gu_alloc_test"); gu::Allocator a(test_name, reserved, sizeof(reserved), sizeof(test1), 1 << 16); mark_point(); void* p; size_t r, s = 0; bool n; r = 0; s += r; mark_point(); p = a.alloc(r, n); fail_if (p != 0); fail_if (n); fail_if (a.size() != s); r = test0_size; s += r; mark_point(); p = a.alloc(r, n); fail_if (0 == p); fail_if (n); fail_if (a.size() != s); strcpy (reinterpret_cast(p), test0); r = test1_size; s += r; mark_point(); p = a.alloc(r, n); fail_if (0 == p); fail_if (!n); /* new page must be allocated */ fail_if (a.size() != s); strcpy (reinterpret_cast(p), test1); r = 0; s += r; mark_point(); p = a.alloc(r, n); fail_if (p != 0); fail_if (n); fail_if (a.size() != s); #ifdef GU_ALLOCATOR_DEBUG std::vector out; out.reserve (a.count()); mark_point(); size_t out_size = a.gather (out); fail_if (out_size != test0_size + test1_size); fail_if (out.size() != 2); fail_if (out[0].size != test0_size); fail_if (strcmp(reinterpret_cast(out[0].ptr), test0)); fail_if (out[1].size != test1_size); fail_if (strcmp(reinterpret_cast(out[1].ptr), test1)); #endif /* GU_ALLOCATOR_DEBUG */ } END_TEST Suite* gu_alloc_suite () { TCase* t = tcase_create ("Allocator"); tcase_add_test (t, basic); Suite* s = suite_create ("gu::Allocator"); suite_add_tcase (s, t); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_stats_test.cpp0000644000175000017500000000242413136555240026632 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #include "../src/gu_stats.hpp" #include "gu_stats_test.hpp" #include #include using namespace gu; static inline bool double_equal(double a, double b) { return (std::fabs(a - b) <= std::fabs(a + b) * std::numeric_limits::epsilon()); } START_TEST(test_stats) { Stats st; st.insert(10.0); st.insert(20.0); st.insert(30.0); fail_if(!double_equal(st.mean(), 20.0)); fail_if(!double_equal(st.variance() * 3, 200.0), "%e != 0", st.variance()*3-200.0); fail_if(!double_equal(st.min(), 10.0)); fail_if(!double_equal(st.max(), 30.0)); st.clear(); st.insert(10.0); fail_if(!double_equal(st.mean(), 10.0)); fail_if(!double_equal(st.variance(), 0.0)); fail_if(!double_equal(st.min(), 10.0)); fail_if(!double_equal(st.max(), 10.0)); st.clear(); fail_if(!double_equal(st.mean(), 0.0)); fail_if(!double_equal(st.variance(), 0.0)); fail_if(!double_equal(st.min(), 0.0)); fail_if(!double_equal(st.max(), 0.0)); } END_TEST Suite* gu_stats_suite() { TCase* t = tcase_create ("test_stats"); tcase_add_test (t, test_stats); Suite* s = suite_create ("gu::Stats"); suite_add_tcase (s, t); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_time_test.c0000644000175000017500000000157413136555240026077 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #include #include #include "gu_time_test.h" #include "../src/gu_time.h" START_TEST (gu_time_test) { struct timeval left = { 1, 900000 }; // 1.9 sec struct timeval right = { 5, 400000 }; // 5.4 sec double diff, tolerance = 1.0e-15; // double precision tolerance diff = gu_timeval_diff (&left, &right); fail_if (fabs(3.5 + diff) > tolerance, "Expected %f, got %f, delta: %e", -3.5, diff, 3.5 + diff); diff = gu_timeval_diff (&right, &left); fail_if (fabs(3.5 - diff) > tolerance, "Expected %f, got %f, delta: %e", 3.5, diff, 3.5 - diff); } END_TEST Suite *gu_time_suite(void) { Suite *s = suite_create("Galera time functions"); TCase *tc = tcase_create("gu_time"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_time_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_dbug_test.c0000644000175000017500000000317713136555240026063 0ustar jenkinsjenkins// Copyright (C) 2008-2017 Codership Oy // $Id$ /* Pthread yield */ #define _GNU_SOURCE 1 #include #include #include #include "gu_dbug_test.h" #include "../src/gu_dbug.h" #include "../src/gu_threads.h" static void cf() { GU_DBUG_ENTER("cf"); GU_DBUG_PRINT("galera", ("hello from cf")); sched_yield(); GU_DBUG_VOID_RETURN; } static void bf() { GU_DBUG_ENTER("bf"); GU_DBUG_PRINT("galera", ("hello from bf")); sched_yield(); cf(); GU_DBUG_VOID_RETURN; } static void af() { GU_DBUG_ENTER("af"); GU_DBUG_PRINT("galera", ("hello from af")); sched_yield(); bf(); GU_DBUG_VOID_RETURN; } static time_t stop = 0; static void *dbg_thr(void *arg) { while (time(NULL) < stop) { af(); } gu_thread_exit(NULL); } START_TEST(gu_dbug_test) { int i; #define N_THREADS 10 gu_thread_t th[N_THREADS]; /* Log > /dev/null */ GU_DBUG_FILE = fopen("/dev/null", "a+"); /* These should not produce output yet */ af(); af(); af(); /* Start logging */ GU_DBUG_PUSH("d:t:i"); GU_DBUG_PRINT("galera", ("Start logging")); af(); af(); af(); /* Run few threads concurrently */ stop = time(NULL) + 2; for (i = 0; i < N_THREADS; i++) gu_thread_create(&th[i], NULL, &dbg_thr, NULL); for (i = 0; i < N_THREADS; i++) gu_thread_join(th[i], NULL); } END_TEST Suite *gu_dbug_suite(void) { Suite *s = suite_create("Galera dbug functions"); TCase *tc = tcase_create("gu_dbug"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_dbug_test); tcase_set_timeout(tc, 60); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_vlq_test.hpp0000644000175000017500000000026613136555240026305 0ustar jenkinsjenkins// // Copyright (C) 2011 Codership Oy // #ifndef GU_VLQ_TEST_HPP #define GU_VLQ_TEST_HPP #include Suite* gu_vlq_suite(); #endif // GU_VLQ_TEST_HPP percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_mem_pool_test.hpp0000644000175000017500000000033313136555240027305 0ustar jenkinsjenkins// Copyright (C) 2013 Codership Oy // $Id$ #ifndef __gu_mem_pool_test__ #define __gu_mem_pool_test__ #include extern Suite *gu_mem_pool_suite(void); #endif /* __gu_mem_pool_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_histogram_test.cpp0000644000175000017500000000134113136555240027466 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #include "../src/gu_histogram.hpp" #include "../src/gu_logger.hpp" #include #include "gu_histogram_test.hpp" using namespace gu; START_TEST(test_histogram) { Histogram hs("0.0,0.0005,0.001,0.002,0.005,0.01,0.02,0.05,0.1,0.5,1.,5."); hs.insert(0.001); log_info << hs; for (size_t i = 0; i < 1000; ++i) { hs.insert(double(::rand())/RAND_MAX); } log_info << hs; hs.clear(); log_info << hs; } END_TEST Suite* gu_histogram_suite() { TCase* t = tcase_create ("test_histogram"); tcase_add_test (t, test_histogram); Suite* s = suite_create ("gu::Histogram"); suite_add_tcase (s, t); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/avalanche.c0000644000175000017500000000510113136555240025317 0ustar jenkinsjenkins/* * Copyright (c) 2012 Codership Oy * * This program is to measure avalanche effect of different hash * implementations, for that it uses 1M of random 8-byte keys. * Use #define macro below to define the implementation to test. * * Compilation: g++ -DHAVE_ENDIAN_H -DHAVE_BYTESWAP_H -O3 -Wall -Wno-unused avalanche.c \ gu_mmh3.c gu_spooky.c -o avalanche && time ./avalanche * Visualization in gnuplot: unset cbtics set xrange [-0.5:64.5] set yrange [-0.5:64.5] set cbrange [0.0:1.0] set xlabel 'Hash bit' set ylabel 'Flipped bit in message' set cblabel 'Hash bit flip probability [0.0 - 1.0]' set palette rgbformula 7,7,7 plot 'avalanche.out' matrix with image */ #include "gu_hash.h" #include #include #include uint64_t flip_count[64*64] = { 0, }; //#define HASH gu_mmh128_64 #define HASH gu_fast_hash64 int main (int argc, char* argv[]) { int n_keys = 1 << 20; int i, j, k; /* collect statistics */ for (k = 0; k < n_keys; k++) { uint64_t key_part = rand(); uint64_t const key = (key_part << 32) + rand(); uint64_t const hash = HASH (&key, sizeof(key)); for (j = 0; j < 64; j++) { uint64_t const flipped_key = key ^ (GU_LONG_LONG(0x01) << j); uint64_t const flipped_hash = HASH (&flipped_key, sizeof(flipped_key)); uint64_t flipped_bits = hash ^ flipped_hash; for (i = 0; i < 64; i++) { int const idx = j * 64 + i; flip_count[idx] += flipped_bits & GU_LONG_LONG(0x01); flipped_bits >>= 1; } } } /* print statistics */ char out_name [256] = { 0, }; snprintf(out_name, sizeof(out_name) - 1, "%s.out", argv[0]); FILE* const out = fopen(out_name, "w"); if (!out) { fprintf (stderr, "Could not open file for writing: '%s': %d (%s)", out_name, errno, strerror(errno)); return errno; } uint64_t base = n_keys; double min_stat = 1.0; double max_stat = 0.0; for (j = 0; j < 64; j++) { for (i = 0; i < 64; i++) { int const idx = j * 64 + i; double stat = (((double)(flip_count[idx]))/base); min_stat = min_stat > stat ? stat : min_stat; max_stat = max_stat < stat ? stat : max_stat; fprintf (out, "%6.4f%c", stat, 63 == i ? '\n' : '\t'); } } fclose(out); printf ("%6.4f : %6.4f (delta: %6.4f)\n", min_stat, max_stat, max_stat - min_stat); return 0; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_fnv_test.h0000644000175000017500000000030713136555240025730 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_fnv_test__ #define __gu_fnv_test__ #include extern Suite *gu_fnv_suite(void); #endif /* __gu_fnv_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_atomic_test.cpp0000644000175000017500000001027713136555240026755 0ustar jenkinsjenkins/* * Copyright (C) 2014 Codership Oy */ #include "../src/gu_atomic.hpp" #include "gu_atomic_test.hpp" #include "gu_limits.h" #include START_TEST(test_sanity_c) { int64_t i, j, k; i = 1; j = 0; k = 3; gu_atomic_set(&i, &j); fail_if(j != 0); fail_if(i != 0); gu_atomic_get(&i, &k); fail_if(i != 0); fail_if(k != 0); j = gu_atomic_fetch_and_add (&i, 7); fail_if(j != 0); fail_if(i != 7); j = gu_atomic_fetch_and_sub (&i, 10); fail_if(j != 7); fail_if(i != -3); j = gu_atomic_fetch_and_or (&i, 15); fail_if(j != -3); fail_if(i != -1); j = gu_atomic_fetch_and_and (&i, 5); fail_if(j != -1); fail_if(i != 5); j = gu_atomic_fetch_and_xor (&i, 3); fail_if(j != 5); fail_if(i != 6); j = gu_atomic_fetch_and_nand(&i, 15); fail_if(j != 6); fail_if(i != -7); j = gu_atomic_add_and_fetch (&i, 7); fail_if(j != 0); fail_if(i != 0); j = gu_atomic_sub_and_fetch (&i, -2); fail_if(j != 2); fail_if(i != 2); j = gu_atomic_or_and_fetch (&i, 5); fail_if(j != 7); fail_if(i != 7); j = gu_atomic_and_and_fetch (&i, 13); fail_if(j != 5); fail_if(i != 5); j = gu_atomic_xor_and_fetch (&i, 15); fail_if(j != 10); fail_if(i != 10); j = gu_atomic_nand_and_fetch(&i, 7); fail_if(j != -3); fail_if(i != -3); } END_TEST START_TEST(test_sanity_cxx) { gu::Atomic i(1); int64_t const k(3); fail_if(i() != 1); fail_if(i() == k); fail_if((i = k) != k); fail_if(i() != k); fail_if(i.fetch_and_zero() != k); fail_if(i() != 0); fail_if(i.fetch_and_add(5) != 0); fail_if(i() != 5); fail_if(i.add_and_fetch(3) != 8); fail_if(i() != 8); fail_if((++i)() != 9); fail_if(i() != 9); fail_if((--i)() != 8); fail_if(i() != 8); i += 3; fail_if(i() != 11); } END_TEST // we want it sufficiently long to test above least 4 bytes, but sufficiently // short to avoid overflow static long long const increment(333333333333LL); // number of add/sub thread pairs static int const n_threads(8); // maximum iterations number (to guarantee no overflow) static int const max_iter(GU_LLONG_MAX/increment/n_threads); // number of iterations capped at 1M, just in case static int const iterations(max_iter > 1000000 ? 1000000 : max_iter); static void* add_loop(void* arg) { int64_t* const var(static_cast(arg)); for (int i(iterations); --i;) { gu_atomic_fetch_and_add(var, increment); } return NULL; } static void* sub_loop(void* arg) { int64_t* const var(static_cast(arg)); for (int i(iterations); --i;) { gu_atomic_fetch_and_sub(var, increment); } return NULL; } static int start_threads(pthread_t* threads, int64_t* var) { for (int i(0); i < n_threads; ++i) { pthread_t* const add_thr(&threads[i * 2]); pthread_t* const sub_thr(add_thr + 1); int const add_err(pthread_create(add_thr, NULL, add_loop, var)); int const sub_err(pthread_create(sub_thr, NULL, sub_loop, var)); if (add_err != 0) return add_err; if (sub_err != 0) return sub_err; } return 0; } static int join_threads(pthread_t* threads) { for (int i(0); i < n_threads; ++i) { pthread_t* const add_thr(&threads[i * 2]); pthread_t* const sub_thr(add_thr + 1); int const add_err(pthread_join(*add_thr, NULL)); int const sub_err(pthread_join(*sub_thr, NULL)); if (add_err != 0) return add_err; if (sub_err != 0) return sub_err; } return 0; } // This may not catch concurrency problems every time. But sometimes it should // (if there are any). START_TEST(test_concurrency) { fail_if(iterations < 1000000); int64_t var(0); pthread_t threads[n_threads * 2]; fail_if(start_threads(threads, &var)); fail_if(join_threads(threads)); fail_if(0 != var); } END_TEST Suite* gu_atomic_suite() { TCase* t1 = tcase_create ("sanity"); tcase_add_test (t1, test_sanity_c); tcase_add_test (t1, test_sanity_cxx); TCase* t2 = tcase_create ("concurrency"); tcase_add_test (t2, test_concurrency); tcase_set_timeout(t2, 60); Suite* s = suite_create ("gu::Atomic"); suite_add_tcase (s, t1); suite_add_tcase (s, t2); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_string_test.cpp0000644000175000017500000000532613136555240027006 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy * * $Id$ */ #include "../src/gu_string.hpp" #include "gu_string_test.hpp" START_TEST (ctor_test) { gu::String<8> str1; // default fail_if (str1.size() != 0); fail_if (strlen(str1.c_str()) != 0); const char* const test_string1("test"); gu::String<8> str2(test_string1); // from char* fail_if (str2.size() != strlen(test_string1)); fail_if (strcmp(str2.c_str(), test_string1)); gu::String<2> str3(str2); // copy ctor fail_if (str3.size() != str2.size()); fail_if (strcmp(str2.c_str(), str3.c_str())); std::string const std_string(str3.c_str()); gu::String<4> str4(std_string); // from std::string fail_if (str4.size() != strlen(test_string1)); fail_if (strcmp(str4.c_str(), test_string1)); gu::String<5> str5(test_string1, 2); fail_if (str5.size() != 2); fail_if (strncmp(str5.c_str(), test_string1, 2)); } END_TEST START_TEST (func_test) { gu::String<16> str; fail_if (str.size() != 0); fail_if (strlen(str.c_str()) != 0); const char* const buf_ptr(str.c_str()); str = "one"; str << std::string("two") << gu::String<8>("three"); fail_if (strcmp(str.c_str(), "onetwothree")); fail_if (str.c_str() != buf_ptr); str += "blast!"; // this should spill to heap fail_if (strcmp(str.c_str(), "onetwothreeblast!"), "expected 'onetwothreeblast!' got '%s'", str.c_str()); fail_if (str.c_str() == buf_ptr); str = gu::String<2>("back to stack"); fail_if (str != "back to stack"); fail_if (str != gu::String<>("back to stack")); fail_if (str != std::string("back to stack")); fail_if (str.c_str() != buf_ptr); typedef void* pointer; // conversions fail_if ((gu::String<>() << true) != "true"); fail_if ((gu::String<>() << 0.0123) != "0.012300"); if (sizeof(pointer) == 4) fail_if ((gu::String<>() << pointer(0xdeadbeef))!="0xdeadbeef"); else fail_if ((gu::String<>() << pointer(0xdeadbeef))!="0x00000000deadbeef"); fail_if ((gu::String<>() << 1234567890) != "1234567890"); fail_if ((gu::String<>() << 12345U) != "12345"); fail_if ((gu::String<>() << 'a') != "a"); fail_if ((gu::String<>() << 0xdeadbeef) != "3735928559"); fail_if ((gu::String<>() << gu::Fmt("%010x") << 0xdeadbeef) !="00deadbeef"); } END_TEST Suite* gu_string_suite(void) { Suite* s = suite_create ("gu::String"); TCase* t = tcase_create ("ctor_test"); tcase_add_test (t, ctor_test); suite_add_tcase (s, t); t = tcase_create ("func_test"); tcase_add_test (t, func_test); suite_add_tcase (s, t); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_fnv_test.c0000644000175000017500000000334613136555240025731 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy // $Id$ #include "gu_fnv_test.h" #include static const char* const test_buf = "chongo /\\../\\"; // enable normal FNV mode for reference hash checking #define GU_FNV_NORMAL #include "../src/gu_fnv.h" START_TEST (gu_fnv32_test) { uint32_t ret = 0; gu_fnv32a_internal (test_buf, strlen(test_buf), &ret); fail_if (GU_FNV32_SEED != ret, "FNV32 failed: expected %"PRIu32", got %"PRIu32, GU_FNV32_SEED, ret); } END_TEST START_TEST (gu_fnv64_test) { uint64_t ret = 0; gu_fnv64a_internal (test_buf, strlen(test_buf), &ret); fail_if (GU_FNV64_SEED != ret, "FNV64 failed: expected %"PRIu64", got %"PRIu64, GU_FNV64_SEED, ret); } END_TEST START_TEST (gu_fnv128_test) { gu_uint128_t GU_SET128(ret, 0, 0); gu_fnv128a_internal (test_buf, strlen(test_buf), &ret); #if defined(__SIZEOF_INT128__) fail_if (!GU_EQ128(GU_FNV128_SEED, ret), "FNV128 failed: expected %"PRIx64" %"PRIx64", got %"PRIx64" %"PRIx64, (uint64_t)(GU_FNV128_SEED >> 64), (uint64_t)GU_FNV128_SEED, (uint64_t)(ret >> 64), (uint64_t)ret); #else fail_if (!GU_EQ128(GU_FNV128_SEED, ret), "FNV128 failed: expected %"PRIx64" %"PRIx64", got %"PRIx64" %"PRIx64, GU_FNV128_SEED.u64[GU_64HI], GU_FNV128_SEED.u64[GU_64LO], ret.u64[GU_64HI], ret.u64[GU_64LO]); #endif } END_TEST Suite *gu_fnv_suite(void) { Suite *s = suite_create("FNV hash"); TCase *tc_fnv = tcase_create("gu_fnv"); suite_add_tcase (s, tc_fnv); tcase_add_test(tc_fnv, gu_fnv32_test); tcase_add_test(tc_fnv, gu_fnv64_test); tcase_add_test(tc_fnv, gu_fnv128_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_dbug_test.h0000644000175000017500000000026013136555240026056 0ustar jenkinsjenkins// Copyright (C) 2008 Codership Oy // $Id$ #ifndef __gu_dbug_test__ #define __gu_dbug_test__ Suite *gu_dbug_suite(void); #endif /* __gu_dbug_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_bswap_test.h0000644000175000017500000000026413136555240026255 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_bswap_test__ #define __gu_bswap_test__ Suite *gu_bswap_suite(void); #endif /* __gu_bswap_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_time_test.h0000644000175000017500000000026013136555240026073 0ustar jenkinsjenkins// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_time_test__ #define __gu_time_test__ Suite *gu_time_suite(void); #endif /* __gu_time_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_fifo_test.c0000644000175000017500000001700113136555240026054 0ustar jenkinsjenkins// Copyright (C) 2007-2017 Codership Oy // $Id$ #include #include "gu_fifo_test.h" #include "../src/galerautils.h" #define FIFO_LENGTH 10000L START_TEST (gu_fifo_test) { gu_fifo_t* fifo; long i; size_t* item; long used; fifo = gu_fifo_create (0, 1); fail_if (fifo != NULL); fifo = gu_fifo_create (1, 0); fail_if (fifo != NULL); fifo = gu_fifo_create (1, 1); fail_if (fifo == NULL); gu_fifo_close (fifo); mark_point(); gu_fifo_destroy (fifo); mark_point(); fifo = gu_fifo_create (FIFO_LENGTH, sizeof(i)); fail_if (fifo == NULL); fail_if (gu_fifo_length(fifo) != 0, "fifo->used is %lu for an empty FIFO", gu_fifo_length(fifo)); fail_if (gu_fifo_max_length(fifo) < FIFO_LENGTH); // fill FIFO for (i = 0; i < FIFO_LENGTH; i++) { item = gu_fifo_get_tail (fifo); fail_if (item == NULL, "could not get item %ld", i); *item = i; gu_fifo_push_tail (fifo); } used = i; fail_if (gu_fifo_length(fifo) != used, "used is %zu, expected %zu", used, gu_fifo_length(fifo)); // test pop for (i = 0; i < used; i++) { int err; item = gu_fifo_get_head (fifo, &err); fail_if (item == NULL, "could not get item %ld", i); fail_if (*item != (ulong)i, "got %ld, expected %ld", *item, i); gu_fifo_pop_head (fifo); } fail_if (gu_fifo_length(fifo) != 0, "gu_fifo_length() for empty queue is %ld", gu_fifo_length(fifo)); gu_fifo_close (fifo); int err; item = gu_fifo_get_head (fifo, &err); fail_if (item != NULL); fail_if (err != -ENODATA); gu_fifo_destroy (fifo); } END_TEST static gu_mutex_t sync_mtx = GU_MUTEX_INITIALIZER; static gu_cond_t sync_cond = GU_COND_INITIALIZER; #define ITEM 12345 static void* cancel_thread (void* arg) { gu_fifo_t* q = arg; /* sync with parent */ gu_mutex_lock (&sync_mtx); gu_cond_signal (&sync_cond); gu_mutex_unlock (&sync_mtx); size_t* item; int err; /* try to get from non-empty queue */ item = gu_fifo_get_head (q, &err); fail_if (NULL != item, "Got item %p: %zu", item, item ? *item : 0); fail_if (-ECANCELED != err); /* signal end of the first gu_fifo_get_head() */ gu_mutex_lock (&sync_mtx); gu_cond_signal (&sync_cond); /* wait until gets are resumed */ gu_cond_wait (&sync_cond, &sync_mtx); item = gu_fifo_get_head (q, &err); fail_if (NULL == item); fail_if (ITEM != *item); gu_fifo_pop_head (q); /* signal end of the 2nd gu_fifo_get_head() */ gu_cond_signal (&sync_cond); gu_mutex_unlock (&sync_mtx); /* try to get from empty queue (should block) */ item = gu_fifo_get_head (q, &err); fail_if (NULL != item); fail_if (-ECANCELED != err); /* signal end of the 3rd gu_fifo_get_head() */ gu_mutex_lock (&sync_mtx); gu_cond_signal (&sync_cond); /* wait until fifo is closed */ gu_cond_wait (&sync_cond, &sync_mtx); item = gu_fifo_get_head (q, &err); fail_if (NULL != item); fail_if (-ECANCELED != err); /* signal end of the 4th gu_fifo_get_head() */ gu_cond_signal (&sync_cond); /* wait until fifo is resumed */ gu_cond_wait (&sync_cond, &sync_mtx); gu_mutex_unlock (&sync_mtx); item = gu_fifo_get_head (q, &err); fail_if (NULL != item); fail_if (-ENODATA != err); return NULL; } START_TEST(gu_fifo_cancel_test) { gu_fifo_t* q = gu_fifo_create (FIFO_LENGTH, sizeof(size_t)); size_t* item = gu_fifo_get_tail (q); fail_if (item == NULL); *item = ITEM; gu_fifo_push_tail (q); gu_mutex_lock (&sync_mtx); gu_thread_t thread; gu_thread_create (&thread, NULL, cancel_thread, q); /* sync with child thread */ gu_fifo_lock (q); gu_cond_wait (&sync_cond, &sync_mtx); int err; err = gu_fifo_cancel_gets (q); fail_if (0 != err); err = gu_fifo_cancel_gets (q); fail_if (-EBADFD != err); /* allow the first gu_fifo_get_head() */ gu_fifo_release (q); mark_point(); /* wait for the first gu_fifo_get_head() to complete */ gu_cond_wait (&sync_cond, &sync_mtx); mark_point(); err = gu_fifo_resume_gets (q); fail_if (0 != err); err = gu_fifo_resume_gets (q); fail_if (-EBADFD != err); /* signal that now gets are resumed */ gu_cond_signal (&sync_cond); /* wait for the 2nd gu_fifo_get_head() to complete */ gu_cond_wait (&sync_cond, &sync_mtx); /* wait a bit to make sure 3rd gu_fifo_get_head() is blocked * (even if it is not - still should work)*/ usleep (100000 /* 0.1s */); gu_fifo_lock(q); err = gu_fifo_cancel_gets (q); gu_fifo_release(q); fail_if (0 != err); /* wait for the 3rd gu_fifo_get_head() to complete */ gu_cond_wait (&sync_cond, &sync_mtx); gu_fifo_close (q); // closes for puts, but the q still must be canceled gu_cond_signal (&sync_cond); /* wait for the 4th gu_fifo_get_head() to complete */ gu_cond_wait (&sync_cond, &sync_mtx); gu_fifo_resume_gets (q); // resumes gets gu_cond_signal (&sync_cond); gu_mutex_unlock (&sync_mtx); mark_point(); gu_thread_join(thread, NULL); } END_TEST /* Test the functionality when a row gets deleted if the head reaches the end of a row (we have to ensure that the tail is in the same row). */ START_TEST(gu_fifo_wrap_around_test) { gu_fifo_t* fifo; long i; size_t* item; long used; #define FIFO_WRAP_LENGTH 2048 fifo = gu_fifo_create (FIFO_WRAP_LENGTH, sizeof(i)); fail_if (fifo == NULL); fail_if (gu_fifo_length(fifo) != 0, "fifo->used is %lu for an empty FIFO", gu_fifo_length(fifo)); /* fill FIFO */ for (i = 0; i < FIFO_WRAP_LENGTH; i++) { item = gu_fifo_get_tail (fifo); fail_if (item == NULL, "could not get item %ld", i); *item = 0xCCCC; gu_fifo_push_tail (fifo); } used = i; fail_if (gu_fifo_length(fifo) != used, "used is %zu, expected %zu", used, gu_fifo_length(fifo)); /* run through the queue (ensure that we do gu_fifo_pop_head() at the * end of a row) */ for (i = 0; i < FIFO_WRAP_LENGTH*2; i++) { int err; item = gu_fifo_get_head (fifo, &err); fail_if (item == NULL, "could not get item %ld", i); fail_if (*item != (ulong)0xCCCC, "got %ld, expected %lx", *item, 0xCCCC); gu_fifo_pop_head (fifo); item = gu_fifo_get_tail (fifo); fail_if (item == NULL, "could not get item %ld", i); *item = 0xCCCC; gu_fifo_push_tail (fifo); } /* drain the queue */ used = gu_fifo_length(fifo); for (i = 0; i < used; i++) { int err; item = gu_fifo_get_head (fifo, &err); fail_if (item == NULL, "could not get item %ld", i); fail_if (*item != (ulong)0xCCCC, "got %ld, expected %lx", *item, 0xCCCC); gu_fifo_pop_head (fifo); } fail_if (gu_fifo_length(fifo) != 0, "gu_fifo_length() for empty queue is %lx", gu_fifo_length(fifo)); gu_fifo_close (fifo); int err; item = gu_fifo_get_head (fifo, &err); fail_if (item != NULL); fail_if (err != -ENODATA); gu_fifo_destroy (fifo); } END_TEST Suite *gu_fifo_suite(void) { Suite *s = suite_create("Galera FIFO functions"); TCase *tc = tcase_create("gu_fifo"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_fifo_test); tcase_add_test (tc, gu_fifo_cancel_test); tcase_add_test (tc, gu_fifo_wrap_around_test); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_uuid_test.c0000644000175000017500000000214713136555240026104 0ustar jenkinsjenkins/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include #include #include #include "../src/gu_log.h" #include "../src/gu_uuid.h" #include "gu_uuid_test.h" START_TEST (gu_uuid_test) { size_t uuid_num = 10; gu_uuid_t uuid[uuid_num]; size_t i; uuid[0] = GU_UUID_NIL; gu_uuid_generate (&uuid[0], NULL, 0); fail_if (!memcmp (&uuid[0], &GU_UUID_NIL, sizeof(gu_uuid_t))); fail_if (!gu_uuid_compare(&uuid[0], &GU_UUID_NIL)); for (i = 1; i < uuid_num; i++) { uuid[i] = GU_UUID_NIL; gu_uuid_generate (&uuid[i], NULL, 0); fail_if (!gu_uuid_compare(&uuid[i], &GU_UUID_NIL)); fail_if (!gu_uuid_compare(&uuid[i], &uuid[i - 1])); fail_if (1 != gu_uuid_older (&uuid[i - 1], &uuid[i])); fail_if (-1 != gu_uuid_older (&uuid[i], &uuid[i - 1])); } } END_TEST Suite *gu_uuid_suite(void) { Suite *suite = suite_create("Galera UUID utils"); TCase *tcase = tcase_create("gu_uuid"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gu_uuid_test); return suite; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_vlq_test.cpp0000644000175000017500000002016013136555240026273 0ustar jenkinsjenkins// // Copyright (C) 2011 Codership Oy // #include "gu_vlq.hpp" #include "gu_vlq_test.hpp" #include "gu_logger.hpp" #include #include #include #include #include static struct valval { const unsigned long long val; const size_t size; } valarr[] = { {0x00 , 1}, {0x01 , 1}, {0x7fULL , 1}, {0x80ULL , 2}, {0x3fffULL , 2}, {0x4000ULL , 3}, {0x1fffffULL , 3}, {0x200000ULL , 4}, {0x0fffffffULL , 4}, {0x10000000ULL , 5}, {0x07ffffffffULL , 5}, {0x0800000000ULL , 6}, {0x03ffffffffffULL , 6}, {0x040000000000ULL , 7}, {0x01ffffffffffffULL , 7}, {0x02000000000000ULL , 8}, {0x00ffffffffffffffULL, 8}, {0x0100000000000000ULL, 9}, {0x7fffffffffffffffULL, 9}, {0x8000000000000000ULL, 10}, {0xffffffffffffffffULL, 10} }; // http://www.cplusplus.com/faq/sequences/arrays/sizeof-array/ template inline size_t SizeOfArray( const T(&)[ N ] ) { return N; } START_TEST(test_uleb128_size) { for (size_t i(0); i < SizeOfArray(valarr); ++i) { size_t size(gu::uleb128_size(valarr[i].val)); fail_unless(size == valarr[i].size, "got size %z, expected %z for value 0x%llx", size, valarr[i].size, valarr[i].val); } } END_TEST START_TEST(test_uleb128_encode) { std::vector buf; for (size_t i(0); i < SizeOfArray(valarr); ++i) { buf.resize(valarr[i].size); size_t offset(gu::uleb128_encode(valarr[i].val, &buf[0], buf.size(), 0)); fail_unless(offset == valarr[i].size, "got offset %zu, expected %zu for value 0x%llx", offset, valarr[i].size, valarr[i].val); } } END_TEST START_TEST(test_uleb128_decode) { std::vector buf; for (size_t i(0); i < SizeOfArray(valarr); ++i) { buf.resize(valarr[i].size); size_t offset(gu::uleb128_encode(valarr[i].val, &buf[0], buf.size(), 0)); unsigned long long val; try { offset = gu::uleb128_decode(&buf[0], buf.size(), 0, val); fail_unless(offset == valarr[i].size, "got offset %zu, expected %zu for value 0x%llx", offset, valarr[i].size, valarr[i].val); fail_unless(val == valarr[i].val, "got value 0x%llx, expected 0x%llx", val, valarr[i].val); } catch (gu::Exception& e) { fail("Exception in round %zu for encoding of size %zu: %s", i, valarr[i].size, e.what()); } } } END_TEST START_TEST(test_uleb128_misc) { std::vector buf(10); // check uint8_t whole range for (size_t i(0); i <= std::numeric_limits::max(); ++i) { (void)gu::uleb128_encode(static_cast(i), &buf[0], buf.size(), 0); uint8_t val; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val); if (i != val) fail("0x%x != 0x%x", i, val); } // check uint16_t whole range for (size_t i(0); i <= std::numeric_limits::max(); ++i) { (void)gu::uleb128_encode(static_cast(i), &buf[0], buf.size(), 0); uint16_t val; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val); if (i != val) fail("0x%x != 0x%x", i, val); } // check uint32_t: 0 -> 1^20 for (size_t i(0); i < (1 << 20); ++i) { (void)gu::uleb128_encode(static_cast(i), &buf[0], buf.size(), 0); uint32_t val; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val); if (i != val) fail("0x%x != 0x%x", i, val); } // check uin32_t: max - 1^20 -> max for (uint64_t i(std::numeric_limits::max() - (1 << 20)); i <= std::numeric_limits::max(); ++i) { (void)gu::uleb128_encode(static_cast(i), &buf[0], buf.size(), 0); uint32_t val; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val); if (i != val) fail("0x%x != 0x%x", i, val); } // uint64_t is tested for representation byte boundaries earlier, // run test just for random values for (size_t i(0); i < (1 << 16); ++i) { unsigned long long val(static_cast(rand()) * static_cast(rand())); (void)gu::uleb128_encode(val, &buf[0], buf.size(), 0); unsigned long long val2; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val2); if (val != val2) fail("0x%llx != 0x%llx", val, val2); } { // check that exception is thrown if target type is not // wide enough // uint8_t uint64_t val(static_cast(std::numeric_limits::max()) + 1); buf.resize(gu::uleb128_size(val)); (void)gu::uleb128_encode(val, &buf[0], buf.size(), 0); try { uint8_t cval; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } // uint16_t val = static_cast(std::numeric_limits::max()) + 1; buf.resize(gu::uleb128_size(val)); (void)gu::uleb128_encode(val, &buf[0], buf.size(), 0); try { uint16_t cval; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } // uint32_t val = static_cast(std::numeric_limits::max()) + 1; buf.resize(gu::uleb128_size(val)); (void)gu::uleb128_encode(val, &buf[0], buf.size(), 0); try { uint32_t cval; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } // check that exception is thrown if terminating byte is missing buf.resize(buf.size() - 1); try { uint64_t cval; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } // finally check the representation that cannot be stored with // uint64_t gu::byte_t b[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // <--- up here 9 * 7 = 63 bits 0x02}; // <--- requires two additional bits try { uint64_t cval; (void)gu::uleb128_decode(b, SizeOfArray(b), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } } } END_TEST Suite* gu_vlq_suite() { Suite* s(suite_create("gu::vlq")); TCase* tc; tc = tcase_create("test_uleb128_size"); tcase_add_test(tc, test_uleb128_size); suite_add_tcase(s, tc); tc = tcase_create("test_uleb128_encode"); tcase_add_test(tc, test_uleb128_encode); suite_add_tcase(s, tc); tc = tcase_create("test_uleb128_decode"); tcase_add_test(tc, test_uleb128_decode); suite_add_tcase(s, tc); tc = tcase_create("test_uleb128_misc"); tcase_add_test(tc, test_uleb128_misc); suite_add_tcase(s, tc); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_crc32c_test.c0000644000175000017500000000641213136555240026214 0ustar jenkinsjenkins/* * Copyright (C) 2013-2014 Codership Oy * * $Id$ */ #include "../src/gu_crc32c.h" #include "gu_crc32c_test.h" #include #define long_input \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" #define long_output 0x7e5806b3 struct test_pair { const char* input; uint32_t output; }; //#define test_vector_length 6 /* * boost::crc_optimal<32, 0x1EDC6F41, 0, 0, true, true> crc; */ static struct test_pair test_vector[] = { { "", 0x00000000 }, { "1", 0x90f599e3 }, { "22", 0x47b26cf9 }, { "333", 0x4cb6e5c8 }, { "4444", 0xfb8150f7 }, { "55555", 0x23874b2f }, { "666666", 0xfad65244 }, { "7777777", 0xe4cbaa36 }, { "88888888", 0xda8901c2 }, { "123456789", 0xe3069283 }, // taken from SCTP mailing list { "My", 0xc7600404 }, // taken from { "test", 0x86a072c0 }, // http://www.zorc.breitbandkatze.de/crc.html { "vector", 0xa0b8f38a }, { long_input, long_output}, { NULL, 0x0 } }; static void test_function(void) { int i; for (i = 0; test_vector[i].input != NULL; i++) { const char* const input = test_vector[i].input; uint32_t const output = test_vector[i].output; uint32_t ret = gu_crc32c(input, strlen(input)); fail_if(ret != output, "Input '%s' resulted in %#08x, expected %#08x\n", input, ret, output); } const char* const input = long_input; uint32_t const output = long_output; int const size = strlen(input); int offset = 0; gu_crc32c_t crc; gu_crc32c_init(&crc); #define CRC_APPEND(x) gu_crc32c_append(&crc, &input[offset], x); offset += x; CRC_APPEND(1); CRC_APPEND(3); CRC_APPEND(5); CRC_APPEND(7); CRC_APPEND(13); CRC_APPEND(15); mark_point(); CRC_APPEND(0); CRC_APPEND(27); CRC_APPEND(43); CRC_APPEND(64); int tail = size - offset; fail_if (tail < 0); CRC_APPEND(tail); uint32_t ret = gu_crc32c_get (crc); fail_if (ret != output, "Generated %#08x, expected %#08x\n", ret, output); } START_TEST(test_Sarwate) { gu_crc32c_func = crc32cSarwate; test_function(); } END_TEST START_TEST(test_SlicingBy4) { gu_crc32c_func = crc32cSlicingBy4; test_function(); } END_TEST START_TEST(test_SlicingBy8) { gu_crc32c_func = crc32cSlicingBy8; test_function(); } END_TEST // will run a hardware test, if available START_TEST(test_hardware) { gu_crc32c_configure(); test_function(); } END_TEST Suite *gu_crc32c_suite(void) { Suite *suite = suite_create("CRC32C implementation"); TCase *sw = tcase_create("test_sw"); suite_add_tcase (suite, sw); tcase_add_test (sw, test_Sarwate); tcase_add_test (sw, test_SlicingBy4); tcase_add_test (sw, test_SlicingBy8); TCase *hw = tcase_create("test_hw"); suite_add_tcase (suite, hw); tcase_add_test (hw, test_hardware); return suite; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_string_utils_test.cpp0000644000175000017500000000533613136555240030227 0ustar jenkinsjenkins// Copyright (C) 2009-2010 Codership Oy #include "gu_string_utils.hpp" #include "gu_string_utils_test.hpp" using std::string; using std::vector; START_TEST(test_strsplit) { string str = "foo bar baz"; vector vec = gu::strsplit(str, ' '); fail_unless(vec.size() == 3); fail_unless(vec[0] == "foo"); fail_unless(vec[1] == "bar"); fail_unless(vec[2] == "baz"); } END_TEST START_TEST(test_tokenize) { vector vec = gu::tokenize("", 'a', 'b', false); fail_unless(vec.size() == 0); vec = gu::tokenize("", 'a', 'b', true); fail_unless(vec.size() == 1); fail_unless(vec[0] == ""); vec = gu::tokenize("a", 'a', 'b', false); fail_unless(vec.size() == 0); vec = gu::tokenize("a", 'a', 'b', true); fail_unless(vec.size() == 2); fail_unless(vec[0] == ""); fail_unless(vec[1] == ""); vec = gu::tokenize("foo bar baz"); fail_unless(vec.size() == 3); fail_unless(vec[0] == "foo"); fail_unless(vec[1] == "bar"); fail_unless(vec[2] == "baz"); vec = gu::tokenize("foo\\ bar baz"); fail_unless(vec.size() == 2); fail_unless(vec[0] == "foo bar", "expected 'foo bar', found '%s'", vec[0].c_str()); fail_unless(vec[1] == "baz"); vec = gu::tokenize("foo\\;;bar;;baz;", ';', '\\', false); fail_unless(vec.size() == 3); fail_unless(vec[0] == "foo;"); fail_unless(vec[1] == "bar"); fail_unless(vec[2] == "baz"); vec = gu::tokenize("foo\\;;bar;;baz;", ';', '\\', true); fail_unless(vec.size() == 5, "vetor length %zu, expected 5", vec.size()); fail_unless(vec[0] == "foo;"); fail_unless(vec[1] == "bar"); fail_unless(vec[2] == ""); fail_unless(vec[3] == "baz"); fail_unless(vec[4] == ""); } END_TEST START_TEST(test_trim) { string full1 = ".,wklerf joweji"; string full2 = full1; gu::trim (full2); fail_if (full1 != full2); string part = " part "; gu::trim (part); fail_if (part.length() != 4); fail_if (0 != part.compare("part")); string empty; gu::trim (empty); fail_if (!empty.empty()); empty += ' '; empty += '\t'; empty += '\n'; empty += '\f'; fail_if (empty.empty()); gu::trim (empty); fail_if (!empty.empty(), "string contents: '%s', expected empty", empty.c_str()); } END_TEST Suite* gu_string_utils_suite(void) { Suite* s = suite_create("String Utils"); TCase* tc; tc = tcase_create("strsplit"); tcase_add_test(tc, test_strsplit); suite_add_tcase(s, tc); tc = tcase_create("tokenize"); tcase_add_test(tc, test_tokenize); suite_add_tcase(s, tc); tc = tcase_create("trim"); tcase_add_test(tc, test_trim); suite_add_tcase(s, tc); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_digest_test.hpp0000644000175000017500000000032313136555240026754 0ustar jenkinsjenkins// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_digest_test__ #define __gu_digest_test__ #include extern Suite *gu_digest_suite(void); #endif /* __gu_digest_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/SConscript0000644000175000017500000000514113136555240025247 0ustar jenkinsjenkins Import('check_env') env = check_env.Clone() # Include paths env.Append(CPPPATH = Split(''' # #/galerautils/src ''')) env.Prepend(LIBS=File('#/galerautils/src/libgalerautils.a')) env.Prepend(LIBS=File('#/galerautils/src/libgalerautils++.a')) gu_tests = env.Program(target = 'gu_tests', source = Split(''' gu_tests.c gu_mem_test.c gu_vec_test.c gu_bswap_test.c gu_fnv_test.c gu_mmh3_test.c gu_spooky_test.c gu_crc32c_test.c gu_hash_test.c gu_time_test.c gu_fifo_test.c gu_uuid_test.c gu_dbug_test.c gu_lock_step_test.c gu_str_test.c gu_utils_test.c ''')) env.Test("gu_tests.passed", gu_tests) env.Alias("test", "gu_tests.passed") Clean(gu_tests, '#/gu_tests.log') gu_testspp = env.Program(target = 'gu_tests++', source = Split(''' gu_atomic_test.cpp gu_vector_test.cpp gu_string_test.cpp gu_vlq_test.cpp gu_digest_test.cpp gu_mem_pool_test.cpp gu_alloc_test.cpp gu_rset_test.cpp gu_string_utils_test.cpp gu_uri_test.cpp gu_config_test.cpp gu_net_test.cpp gu_datetime_test.cpp gu_histogram_test.cpp gu_stats_test.cpp gu_thread_test.cpp gu_tests++.cpp ''')) env.Test("gu_tests++.passed", gu_testspp) env.Alias("test", "gu_tests++.passed") Clean(gu_testspp, '#/gu_tests++.log') gu_to_test = env.Program(target = 'gu_to_test', source = Split(''' gu_to_test.c ''')) avalanche = env.Program(target = 'avalanche', source = Split(''' avalanche.c ''')) percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_rset_test.hpp0000644000175000017500000000031213136555240026450 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_rset_test__ #define __gu_rset_test__ #include Suite *gu_rset_suite(void); #endif /* __gu_rset_test__ */ percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_rset_test.cpp0000644000175000017500000002731713136555240026461 0ustar jenkinsjenkins/* Copyright (C) 2013 Codership Oy * * $Id$ */ #undef NDEBUG #include "../src/gu_rset.hpp" #include "gu_rset_test.hpp" #include "gu_logger.hpp" #include "gu_hexdump.hpp" class TestBaseName : public gu::Allocator::BaseName { std::string str_; public: TestBaseName(const char* name) : str_(name) {} void print(std::ostream& os) const { os << str_; } }; class TestRecord : public gu::Serializable { public: TestRecord (size_t size, const char* str) : Serializable(), size_(size), buf_(reinterpret_cast(::malloc(size_))), str_(reinterpret_cast(buf_ + sizeof(uint32_t))), own_(true) { fail_if (size_ > 0x7fffffff); if (0 == buf_) throw std::runtime_error("failed to allocate record"); gu::byte_t* tmp = const_cast(buf_); *reinterpret_cast(tmp) = htog32(size_); ::strncpy (const_cast(str_), str, size_ - 4); } TestRecord (const gu::byte_t* const buf, ssize_t const size) : Serializable(), size_(TestRecord::serial_size(buf, size)), buf_(buf), str_(reinterpret_cast(buf_ + sizeof(uint32_t))), own_(false) {} TestRecord (const TestRecord& t) : size_(t.size_), buf_(t.buf_), str_(t.str_), own_(false) {} virtual ~TestRecord () { if (own_) free (const_cast(buf_)); } const gu::byte_t* buf() const { return buf_; } const char* c_str() const { return str_; } ssize_t serial_size() const { return my_serial_size(); } static ssize_t serial_size(const gu::byte_t* const buf, ssize_t const size) { check_buf (buf, size, 1); return gtoh32 (*reinterpret_cast(buf)); } bool operator!= (const TestRecord& t) const { return (::strcmp(str_, t.str_)); } bool operator== (const TestRecord& t) const { return (!(*this != t)); } private: size_t const size_; const gu::byte_t* const buf_; const char* const str_; bool const own_; ssize_t my_serial_size () const { return size_; }; ssize_t my_serialize_to (void* buf, ssize_t size) const { check_buf (buf, size, size_); ::memcpy (buf, buf_, size_); return size_; } static void check_buf (const void* const buf, ssize_t const size, ssize_t min_size) { if (gu_unlikely (buf == 0 || size < min_size)) throw std::length_error("buffer too short"); } TestRecord& operator= (const TestRecord&); }; START_TEST (ver0) { size_t const MB = 1 << 20; // the choice of sizes below is based on default allocator memory store size // of 4MB. If it is changed, these need to be changed too. TestRecord rout0(120, "abc0"); fail_if (rout0.serial_size() != 120); fail_if (gtoh32(*reinterpret_cast(rout0.buf())) != 120); TestRecord rout1(121, "abc1"); TestRecord rout2(122, "012345"); TestRecord rout3(123, "defghij"); TestRecord rout4(3*MB, "klm"); TestRecord rout5(1*MB, "qpr"); std::vector records; records.push_back (&rout0); records.push_back (&rout1); records.push_back (&rout2); records.push_back (&rout3); records.push_back (&rout4); records.push_back (&rout5); gu::byte_t reserved[1024]; TestBaseName str("gu_rset_test"); gu::RecordSetOut rset_out(reserved, sizeof(reserved), str, gu::RecordSet::CHECK_MMH64, gu::RecordSet::VER1); size_t offset(rset_out.size()); fail_if (1 != rset_out.page_count()); std::pair rp; int rsize; const void* rout_ptrs[7]; // this should be allocated inside current page rp = rset_out.append (rout0); rout_ptrs[0] = rp.first; rsize = rp.second; fail_if (rsize != rout0.serial_size()); fail_if (rsize < 0); fail_if (rsize != TestRecord::serial_size(rp.first, rsize)); offset += rsize; fail_if (rset_out.size() != offset); fail_if (1 != rset_out.page_count()); // this should trigger new page since not stored rp = rset_out.append (rout1.buf(), rout1.serial_size(), false); rout_ptrs[1] = rp.first; rsize = rp.second; fail_if (rsize != rout1.serial_size()); offset += rsize; fail_if (rset_out.size() != offset); fail_if (2 != rset_out.page_count()); // this should trigger new page since previous one was not stored rp = rset_out.append (rout2); rout_ptrs[2] = rp.first; rsize = rp.second; fail_if (rsize != rout2.serial_size()); fail_if (rsize < 0); fail_if (rsize != TestRecord::serial_size(rp.first, rsize)); offset += rsize; fail_if (rset_out.size() != offset); fail_if (3 != rset_out.page_count(), "Expected %d pages, found %zu", 3, rset_out.page_count()); //***** test partial record appending *****// // this should be allocated inside the current page. rp = rset_out.append (rout3.buf(), 3); // rout_ptrs[2] = rp.first; rsize = rp.second; offset += rp.second; fail_if (3 != rset_out.page_count()); // this should trigger a new page, since not stored rp = rset_out.append (rout3.buf() + 3, rout3.serial_size() - 3, false, false); rout_ptrs[3] = rp.first; rsize += rp.second; fail_if (rsize != rout3.serial_size()); offset += rp.second; fail_if (rset_out.size() != offset); fail_if (4 != rset_out.page_count()); // this should trigger new page, because won't fit in the current page rp = rset_out.append (rout4); rout_ptrs[4] = rp.first; rsize = rp.second; fail_if (rsize != rout4.serial_size()); offset += rsize; fail_if (rset_out.size() != offset); fail_if (5 != rset_out.page_count()); // this should trigger new page, because 4MB RAM limit exceeded rp = rset_out.append (rout5); rout_ptrs[5] = rp.first; rsize = rp.second; fail_if (rsize != rout5.serial_size()); offset += rsize; fail_if (rset_out.size() != offset); fail_if (6 != rset_out.page_count(), "Expected %d pages, found %zu", 5, rset_out.page_count()); fail_if (records.size() != size_t(rset_out.count())); gu::RecordSet::GatherVector out_bufs; out_bufs->reserve (rset_out.page_count()); size_t min_out_size(0); for (size_t i = 0; i < records.size(); ++i) { min_out_size += records[i]->serial_size(); } size_t const out_size (rset_out.gather (out_bufs)); fail_if (out_size <= min_out_size || out_size > offset); fail_if (out_bufs->size() != static_cast(rset_out.page_count()), "Expected %zu buffers, got: %zd", rset_out.page_count(), out_bufs->size()); /* concatenate all buffers into one */ std::vector in_buf; in_buf.reserve(out_size); mark_point(); for (size_t i = 0; i < out_bufs->size(); ++i) { // 0th fragment starts with header, so it it can't be used in this check fail_if (i > 0 && rout_ptrs[i] != out_bufs[i].ptr, "Record pointers don't mathch after gather(). " "old: %p, new: %p", rout_ptrs[i],out_bufs[i].ptr); ssize_t size = gtoh32( *reinterpret_cast(out_bufs[i].ptr)); const char* str = reinterpret_cast(out_bufs[i].ptr) + sizeof(uint32_t); // 0th fragment starts with header, so it it can't be used in this check fail_if (i > 0 && size <= ssize_t(sizeof(uint32_t)), "Expected size > 4, got %zd(%#010zx). i = %zu, buf = %s", size, size, i, str); // the above variables make have sense only on certain pages // hence ifs below size_t k = i; switch (i) { case 3: break; // 4th page is partial 4th record case 1: case 2: fail_if (::strcmp(str, records[k]->c_str()), "Buffer %zu: appending '%s', expected '%s'", i, str, records[k]->c_str()); } if (i == 1 || i == 4) { fail_if (size != records[k]->serial_size(), "Buffer %zu: appending size %zd, expected %zd", i, size, records[k]->serial_size()); } log_info << "\nadding buf " << i << ": " << gu::Hexdump(out_bufs[i].ptr, std::min(out_bufs[i].size, 24), true); size_t old_size = in_buf.size(); const gu::byte_t* const begin (reinterpret_cast(out_bufs[i].ptr)); in_buf.insert (in_buf.end(), begin, begin + out_bufs[i].size); fail_if (old_size + out_bufs[i].size != in_buf.size()); } fail_if (in_buf.size() != out_size, "Sent buf size: %zu, recvd buf size: %zu", out_size, in_buf.size()); log_info << "Resulting RecordSet buffer:\n" << gu::Hexdump(in_buf.data(), 32, false) << '\n' << gu::Hexdump(in_buf.data(), 32, true); gu::RecordSetIn const rset_in(in_buf.data(), in_buf.size()); fail_if (rset_in.size() != rset_out.size()); fail_if (rset_in.count() != rset_out.count()); for (ssize_t i = 0; i < rset_in.count(); ++i) { TestRecord const rin(rset_in.next()); fail_if (rin != *records[i], "Record %d failed: expected %s, found %s", i, records[i]->c_str(), rin.c_str()); } /* Test checksum method: */ try { rset_in.checksum(); } catch (std::exception& e) { fail("%s", e.what()); } /* test buf() method */ gu::RecordSetIn const rset_in_buf(rset_in.buf().ptr, rset_in.buf().size); fail_if(rset_in.count() != rset_in_buf.count()); fail_if(rset_in.size() != rset_in_buf.size()); fail_if (rset_in.buf().ptr != rset_in_buf.buf().ptr); for (ssize_t i = 0; i < rset_in_buf.count(); ++i) { TestRecord const rin(rset_in_buf.next()); fail_if (rin != *records[i], "Record %d failed: expected %s, found %s", i, records[i]->c_str(), rin.c_str()); } /* test empty RecordSetIn creation with subsequent initialization */ gu::RecordSetIn rset_in_empty; fail_if (rset_in_empty.size() != 0); fail_if (rset_in_empty.count() != 0); try { TestRecord const rin(rset_in_empty.next()); fail ("next() succeeded on an empty writeset"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EPERM); } rset_in_empty.init(in_buf.data(), in_buf.size(), true); fail_if (rset_in_empty.size() != rset_out.size()); fail_if (rset_in_empty.count() != rset_out.count()); /* Try some data corruption: swap a bit */ in_buf[10] ^= 1; try { rset_in.checksum(); fail("checksum() didn't throw on corrupted set"); } catch (std::exception& e) {} try { rset_in_empty.checksum(); fail("checksum() didn't throw on corrupted set"); } catch (std::exception& e) {} } END_TEST START_TEST (empty) { gu::RecordSetIn const rset_in(0, 0); fail_if (0 != rset_in.size()); fail_if (0 != rset_in.count()); try { rset_in.checksum(); } catch (std::exception& e) { fail("%s", e.what()); } } END_TEST Suite* gu_rset_suite () { TCase* t = tcase_create ("RecordSet"); tcase_add_test (t, ver0); tcase_add_test (t, empty); tcase_set_timeout(t, 60); Suite* s = suite_create ("gu::RecordSet"); suite_add_tcase (s, t); return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/tests/gu_net_test.cpp0000644000175000017500000000403313136555240026260 0ustar jenkinsjenkins// Copyright (C) 2009 Codership Oy #include #include #include #include #include #include #include #include #include "gu_logger.hpp" #include "gu_uri.hpp" #include "gu_resolver.hpp" #include "gu_lock.hpp" #include "gu_prodcons.hpp" #include "gu_net_test.hpp" using std::vector; using std::string; using std::deque; using std::mem_fun; using std::for_each; using namespace gu; using namespace gu::net; using namespace gu::prodcons; START_TEST(test_resolver) { std::string tcp_lh4("tcp://127.0.0.1:2002"); Addrinfo tcp_lh4_ai(resolve(tcp_lh4)); fail_unless(tcp_lh4_ai.get_family() == AF_INET); fail_unless(tcp_lh4_ai.get_socktype() == SOCK_STREAM); fail_unless(tcp_lh4_ai.to_string() == tcp_lh4, "%s != %s", tcp_lh4_ai.to_string().c_str(), tcp_lh4.c_str()); std::string tcp_lh6("tcp://[::1]:2002"); Addrinfo tcp_lh6_ai(resolve(tcp_lh6)); fail_unless(tcp_lh6_ai.get_family() == AF_INET6); fail_unless(tcp_lh6_ai.get_socktype() == SOCK_STREAM); fail_unless(tcp_lh6_ai.to_string() == tcp_lh6, "%s != %s", tcp_lh6_ai.to_string().c_str(), tcp_lh6.c_str()); std::string lh("tcp://localhost:2002"); Addrinfo lh_ai(resolve(lh)); fail_unless(lh_ai.to_string() == "tcp://127.0.0.1:2002" || lh_ai.to_string() == "tcp://[::1]:2002"); } END_TEST START_TEST(trac_288) { try { string url("tcp://do-not-resolve:0"); (void)resolve(url); } catch (Exception& e) { log_debug << "exception was " << e.what(); } } END_TEST Suite* gu_net_suite() { Suite* s = suite_create("galerautils++ Networking"); TCase* tc; tc = tcase_create("test_resolver"); tcase_add_test(tc, test_resolver); tcase_set_timeout(tc, 30); suite_add_tcase(s, tc); tc = tcase_create("trac_288"); tcase_add_test(tc, trac_288); #if 0 /* bogus test, commenting out for now */ suite_add_tcase(s, tc); #endif return s; } percona-xtradb-cluster-galera-3.x-3.21/galerautils/SConscript0000644000175000017500000000014013136555240024077 0ustar jenkinsjenkins# SConscript for building galerautils SConscript(Split('''src/SConscript tests/SConscript''')) percona-xtradb-cluster-galera-3.x-3.21/galerautils/ChangeLog0000644000175000017500000000270213136555240023645 0ustar jenkinsjenkins2009-09-20 Alex Added RegEx class for matching strings with POSIX regular expressions. Renamed URL class to URI to better reflect what it does. Added get_host(), get_user() and get_port() methods and a unit test. Modularized galerautils++ unit tests. Version 0.3.5 2009-09-17 Alex Added gu_utils.hpp to hold general-purpose templates and functions (now with to_string() template functions). Logger class cleanups. Exception class cleanups. Added stack tracing macro. New Throw class for composing verbose exception messages. Version 0.3.4 2009-09-01 Alex Added a simple option line parser. Some optimizations and cleanups. Version 0.3.3 2009-07-07 Alex Slightly changed gu_fifo interface. Added gu_lock_step object. Version 0.3.2. 2009-06-21 Alex Moved TO monitor module from GCS to galerautils. Version 0.3.1. 2009-06-08 Alex Started galerautils++ project. Added galerautils.hpp and C++-style logger and assert variants. Version 0.3.0. 2008-11-16 Alex Added gu_fifo_t class for mallocless FIFO queue. Version 0.2.9. 2008-03-23 Alex Added gu_timeval_diff() and gu_clock_diff() functions. Bumped interface version. 2008-02-21 Teemu Made DBUG thread safe. 2007-11-01 Alex Fixed thread safe compilation without MySQL Tagged release 0.2.5 2007-10-18 Alex Fixed compilation. Added gtohl/htogl/gtohs/htogs functions. Tagged release 0.2.4 percona-xtradb-cluster-galera-3.x-3.21/garb/0000755000175000017500000000000013136555240020471 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/garb/files/0000755000175000017500000000000013136555240021573 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/garb/files/garb.service0000644000175000017500000000065113136555240024072 0ustar jenkinsjenkins# Systemd service file for garbd [Unit] Description=Galera Arbitrator Daemon After=network.target syslog.target [Install] WantedBy=multi-user.target Alias=garbd.service [Service] User=nobody EnvironmentFile=/etc/sysconfig/garb ExecStart=/usr/bin/garb-systemd start # Use SIGINT because with the default SIGTERM # garbd fails to reliably transition to 'destroyed' state KillSignal=SIGINT TimeoutSec=2m PrivateTmp=false percona-xtradb-cluster-galera-3.x-3.21/garb/files/freebsd/0000755000175000017500000000000013136555240023205 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/garb/files/freebsd/garb.sh0000644000175000017500000000577613136555240024473 0ustar jenkinsjenkins#!/bin/sh # # garb.sh for rc.d usage (c) 2013 Codership Oy # $Id$ # PROVIDE: garb # REQUIRE: LOGIN # KEYWORD: shutdown # # Add the following line to /etc/rc.conf to enable Galera Arbitrator Daemon (garbd): # garb_enable (bool): Set to "NO" by default. # Set it to "YES" to enable Galera Arbitrator Daemon. # garb_galera_nodes (str): A space-separated list of node addresses (address[:port]) in the cluster # (default empty). # garb_galera_group (str): Galera cluster name, should be the same as on the rest of the nodes. # (default empty). # Optional: # garb_galera_options (str): Optional Galera internal options string (e.g. SSL settings) # see http://www.codership.com/wiki/doku.php?id=galera_parameters # (default empty). # garb_log_file (str): Log file for garbd (default empty). Optional, by default logs to syslog # garb_pid_file (str): Custum PID file path and name. # Default to "/var/run/garb.pid". # . /etc/rc.subr name="garb" rcvar=garb_enable load_rc_config $name # set defaults : ${garb_enable="NO"} : ${garb_galera_nodes=""} : ${garb_galera_group=""} : ${garb_galera_options=""} : ${garb_log_file=""} : ${garb_pid_file="/var/run/garb.pid"} procname="/usr/local/bin/garbd" command="/usr/sbin/daemon" command_args="-c -f -u nobody -p $garb_pid_file $procname" start_precmd="${name}_prestart" #start_cmd="${name}_start" start_postcmd="${name}_poststart" stop_precmd="${name}_prestop" #stop_cmd="${name}_stop" #stop_postcmd="${name}_poststop" #extra_commands="reload" #reload_cmd="${name}_reload" export LD_LIBRARY_PATH=/usr/local/lib/gcc44 garb_prestart() { [ "$(id -ur)" != "0" ] && err 4 "root rights are required to start $name" [ -r "$garb_pid_file" ] && err 0 "$procname is already running with PID $(cat $garb_pid_file)" [ -x "$procname" ] || err 5 "$procname is not found" # check that node addresses are configured [ -z "$garb_galera_nodes" ] && err 6 "List of garb_galera_nodes is not configured" [ -z "$garb_galera_group" ] && err 6 "garb_galera_group name is not configured" GALERA_PORT=${GALERA_PORT:-4567} # Concatenate all nodes in the list (for backward compatibility) ADDRESS= for NODE in ${garb_galera_nodes}; do [ -z "$ADDRESS" ] && ADDRESS="$NODE" || ADDRESS="$ADDRESS,$NODE" done command_args="$command_args -a gcomm://$ADDRESS" [ -n "$garb_galera_group" ] && command_args="$command_args -g $garb_galera_group" [ -n "$garb_galera_options" ] && command_args="$command_args -o $garb_galera_options" [ -n "$garb_log_file" ] && command_args="$command_args -l $garb_log_file" return 0 } garb_poststart() { local timeout=15 while [ ! -f "$garb_pid_file" -a $timeout -gt 0 ]; do timeout=$(( timeout - 1 )) sleep 1 done return 0 } garb_prestop() { [ "$(id -ur)" != "0" ] && err 4 "root rights are required to stop $name" [ -r $garb_pid_file ] || err 0 "" return 0 } run_rc_command "$1" percona-xtradb-cluster-galera-3.x-3.21/garb/files/garb.cnf0000644000175000017500000000114613136555240023200 0ustar jenkinsjenkins# Copyright (C) 2012 Codership Oy # This config file is to be sourced by garb service script. # REMOVE THIS AFTER CONFIGURATION # A comma-separated list of node addresses (address[:port]) in the cluster # GALERA_NODES="" # Galera cluster name, should be the same as on the rest of the nodes. # GALERA_GROUP="" # Optional Galera internal options string (e.g. SSL settings) # see http://galeracluster.com/documentation-webpages/galeraparameters.html # GALERA_OPTIONS="" # Log file for garbd. Optional, by default logs to syslog # Deprecated for CentOS7, use journalctl to query the log for garbd # LOG_FILE="" percona-xtradb-cluster-galera-3.x-3.21/garb/files/garb-systemd0000755000175000017500000000203513136555240024122 0ustar jenkinsjenkins#!/bin/bash -ue # config=/etc/sysconfig/garb log_failure() { echo " ERROR! $@" } program_start() { echo "Starting garbd" /usr/bin/garbd "$@" } start() { if grep -q -E '^# REMOVE' $config;then log_failure "Garbd config $config is not configured yet" return 0 fi # Check that node addresses are configured if [[ -z "${GALERA_NODES:-}" ]]; then log_failure "List of GALERA_NODES is not configured" return 6 fi if [[ -z "${GALERA_GROUP:-}" ]]; then log_failure "GALERA_GROUP name is not configured" return 6 fi GALERA_PORT=${GALERA_PORT:-4567} OPTIONS="-a gcomm://${GALERA_NODES// /,}" # substitute space with comma for backward compatibility [ -n "${GALERA_GROUP:-}" ] && OPTIONS="$OPTIONS -g '$GALERA_GROUP'" [ -n "${GALERA_OPTIONS:-}" ] && OPTIONS="$OPTIONS -o '$GALERA_OPTIONS'" [ -n "${LOG_FILE:-}" ] && OPTIONS="$OPTIONS -l '$LOG_FILE'" eval program_start $OPTIONS } # See how we were called. case "$1" in start) start ;; *) echo $"Usage: $0 {start}" exit 2 esac exit $? percona-xtradb-cluster-galera-3.x-3.21/garb/files/garb.sh0000755000175000017500000001155613136555240023055 0ustar jenkinsjenkins#!/bin/bash # # Copyright (C) 2012-2015 Codership Oy # # init.d script for garbd # # chkconfig: - 99 01 # config: /etc/sysconfig/garb | /etc/default/garb # ### BEGIN INIT INFO # Provides: garb # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Should-Start: $network $named $time # Should-Stop: $network $named $time # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Galera Arbitrator Daemon # Description: The Galera Arbitrator is used as part of clusters # that have only two real Galera servers and need an # extra node to arbitrate split brain situations. ### END INIT INFO # On Debian Jessie, avoid redirecting calls to this script to 'systemctl start' _SYSTEMCTL_SKIP_REDIRECT=true # Source function library. if [ -f /etc/redhat-release ]; then . /etc/init.d/functions . /etc/sysconfig/network config=/etc/sysconfig/garb else . /lib/lsb/init-functions config=/etc/default/garbd fi log_failure() { if [ -f /etc/redhat-release ]; then echo -n $* failure "$*" echo else log_failure_msg "$*" fi } if grep -q -E '^# REMOVE' $config; then log_failure "Garbd config $config is not configured yet" exit 0 fi PIDFILE=/var/run/garbd prog="/usr/bin/garbd" program_start() { local rcode local gpid if [ -f /etc/redhat-release ]; then if [ -r $PIDFILE ];then gpid=$(cat $PIDFILE) echo -n $"Stale pid file found at $PIDFILE" if [[ -n ${gpid:-} ]] && kill -0 $gpid;then echo -n $"Garbd already running wiht PID $gpid" exit 17 else echo -n $"Removing stale pid file $PIDFILE" rm -f $PIDFILE fi fi echo -n $"Starting $prog: " runuser nobody -s /bin/sh -c "$prog $*" >/dev/null rcode=$? sleep 2 [ $rcode -eq 0 ] && pidof $prog > $PIDFILE \ && echo_success || echo_failure echo else if [ -r $PIDFILE ];then gpid=$(cat $PIDFILE) log_daemon_msg "Stale pid file found at $PIDFILE" if [[ -n ${gpid:-} ]] && kill -0 $gpid;then log_daemon_msg "Garbd already running wiht PID $gpid" exit 17 else log_daemon_msg "Removing stale pid file $PIDFILE" rm -f $PIDFILE fi fi if [ -r $PIDFILE ];then log_daemon_msg "Stale pid file with $(cat $PIDFILE)" fi log_daemon_msg "Starting $prog: " start-stop-daemon --start --quiet -c nobody --background \ --exec $prog -- "$@" rcode=$? # Hack: sleep a bit to give garbd some time to fork sleep 1 if [ $rcode -eq 0 ]; then pidof $prog > $PIDFILE || rcode=$? fi log_end_msg $rcode fi return $rcode } program_stop() { local rcode if [ -f /etc/redhat-release ]; then echo -n $"Shutting down $prog: " killproc -p $PIDFILE rcode=$? [ $rcode -eq 0 ] && echo_success || echo_failure else start-stop-daemon --stop --quiet --oknodo --retry TERM/30/KILL/5 \ --pidfile $PIDFILE rcode=$? log_end_msg $rcode fi [ $rcode -eq 0 ] && rm -f $PIDFILE return $rcode } program_status() { if [ -f /etc/redhat-release ]; then status $prog else status_of_proc -p $PIDFILE "$prog" garb fi } start() { [ "$EUID" != "0" ] && return 4 [ "$NETWORKING" = "no" ] && return 1 if [ -r $PIDFILE ]; then local PID=$(cat ${PIDFILE}) if ps -p $PID >/dev/null 2>&1; then log_failure "$prog is already running with PID $PID" return 3 # ESRCH else rm -f $PIDFILE fi fi [ -x $prog ] || return 5 [ -f $config ] && . $config # Check that node addresses are configured if [ -z "$GALERA_NODES" ]; then log_failure "List of GALERA_NODES is not configured" return 6 fi if [ -z "$GALERA_GROUP" ]; then log_failure "GALERA_GROUP name is not configured" return 6 fi GALERA_PORT=${GALERA_PORT:-4567} OPTIONS="-d -a gcomm://${GALERA_NODES// /,}" # substitute space with comma for backward compatibility [ -n "$GALERA_GROUP" ] && OPTIONS="$OPTIONS -g '$GALERA_GROUP'" [ -n "$GALERA_OPTIONS" ] && OPTIONS="$OPTIONS -o '$GALERA_OPTIONS'" [ -n "$LOG_FILE" ] && OPTIONS="$OPTIONS -l '$LOG_FILE'" eval program_start $OPTIONS } stop() { [ "$EUID" != "0" ] && return 4 [ -r $PIDFILE ] || return 3 # ESRCH program_stop } restart() { stop start } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) program_status exit ;; restart|reload|force-reload) restart ;; condrestart) if status $prog > /dev/null; then stop start fi ;; *) echo $"Usage: $0 {start|stop|status|restart|reload}" exit 2 esac percona-xtradb-cluster-galera-3.x-3.21/garb/garb_main.cpp0000644000175000017500000000455013136555240023120 0ustar jenkinsjenkins/* Copyright (C) 2011 Codership Oy */ #include "garb_config.hpp" #include "garb_recv_loop.hpp" #include #include #include // exit() #include // setsid(), chdir() #include // open() namespace garb { void become_daemon () { if (pid_t pid = fork()) { if (pid > 0) // parent { exit(0); } else { // I guess we want this to go to stderr as well; std::cerr << "Failed to fork daemon process: " << errno << " (" << strerror(errno) << ")"; gu_throw_error(errno) << "Failed to fork daemon process"; } } // child if (setsid()<0) // become a new process leader, detach from terminal { gu_throw_error(errno) << "setsid() failed"; } if (chdir("/")) // detach from potentially removable block devices { gu_throw_error(errno) << "chdir(\"/\") failed"; } // umask(0); // A second fork ensures the process cannot acquire a controlling // terminal. if (pid_t pid = fork()) { if (pid > 0) { exit(0); } else { gu_throw_error(errno) << "Second fork failed"; } } // Close the standard streams. This decouples the daemon from the // terminal that started it. close(0); close(1); close(2); // Bind standard fds (0, 1, 2) to /dev/null for (int fd = 0; fd < 3; ++fd) { if (open("/dev/null", O_RDONLY) < 0) { gu_throw_error(errno) << "Unable to open /dev/null for fd " << fd; } } } int main (int argc, char* argv[]) { Config config(argc, argv); if (config.exit()) return 0; log_info << "Read config: " << config << std::endl; if (config.daemon()) become_daemon(); try { RecvLoop loop (config); return 0; } catch (std::exception& e) { log_fatal << "Exception in creating receive loop: " << e.what(); } catch (...) { log_fatal << "Exception in creating receive loop."; } return EXIT_FAILURE; } } /* namespace garb */ int main (int argc, char* argv[]) { try { return garb::main (argc, argv); } catch (std::exception& e) { log_fatal << e.what(); return 1; } } percona-xtradb-cluster-galera-3.x-3.21/garb/garb_recv_loop.hpp0000644000175000017500000000177413136555240024176 0ustar jenkinsjenkins/* Copyright (C) 2011-2014 Codership Oy */ #ifndef _GARB_RECV_LOOP_HPP_ #define _GARB_RECV_LOOP_HPP_ #include "garb_gcs.hpp" #include "garb_config.hpp" #include #include #include namespace garb { class RecvLoop { public: RecvLoop (const Config&); ~RecvLoop () {} private: void loop(); const Config& config_; gu::Config gconf_; struct RegisterParams { RegisterParams(gu::Config& cnf) { gu::ssl_register_params(cnf); if (gcs_register_params(reinterpret_cast(&cnf))) { gu_throw_fatal << "Error initializing GCS parameters"; } } } params_; struct ParseOptions { ParseOptions(gu::Config& cnf, const std::string& opt) { cnf.parse(opt); } } parse_; Gcs gcs_; }; /* RecvLoop */ } /* namespace garb */ #endif /* _GARB_RECV_LOOP_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/garb/garb_logger.hpp0000644000175000017500000000044413136555240023456 0ustar jenkinsjenkins/* Copyright (C) 2011 Codership Oy */ #ifndef _GARB_LOGGER_HPP_ #define _GARB_LOGGER_HPP_ #include namespace garb { extern void set_logfile (const std::string& fname); extern void set_syslog (); } /* namespace garb */ #endif /* _GARB_LOGGER_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/garb/garb_gcs.hpp0000644000175000017500000000142113136555240022747 0ustar jenkinsjenkins/* Copyright (C) 2011-2013 Codership Oy */ #ifndef _GARB_GCS_HPP_ #define _GARB_GCS_HPP_ #include #include namespace garb { class Gcs { public: Gcs (gu::Config& conf, const std::string& name, const std::string& address, const std::string& group); ~Gcs (); void recv (gcs_action& act); void request_state_transfer (const std::string& request, const std::string& donor); void join (gcs_seqno_t); void set_last_applied(gcs_seqno_t); void close (); private: bool closed_; gcs_conn_t* gcs_; Gcs (const Gcs&); Gcs& operator= (const Gcs&); }; /* class Gcs */ } /* namespace garb */ #endif /* _GARB_GCS_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/garb/garb_config.cpp0000644000175000017500000001135313136555240023440 0ustar jenkinsjenkins/* Copyright (C) 2011-2013 Codership Oy */ #include "garb_config.hpp" #include "garb_logger.hpp" #include #include #include #include #include #include namespace po = boost::program_options; #include #include #include namespace garb { static void strip_quotes(std::string& s) { /* stripping no more than one pair of quotes */ if ('"' == *s.begin() && '"' == *s.rbegin()) { std::string stripped(s.substr(1, s.length() - 2)); s = stripped; } } std::string const Config::DEFAULT_SST(WSREP_STATE_TRANSFER_TRIVIAL); Config::Config (int argc, char* argv[]) : daemon_ (false), name_ (GCS_ARBITRATOR_NAME), address_ (), group_ ("my_test_cluster"), sst_ (DEFAULT_SST), donor_ (), options_ (), log_ (), cfg_ (), exit_ (false) { po::options_description other ("Other options"); other.add_options() ("version,v", "Print version & exit") ("help,h", "Show help message & exit") ; // only these are read from cfg file po::options_description config ("Configuration"); config.add_options() ("daemon,d", "Become daemon") ("name,n", po::value(&name_), "Node name") ("address,a",po::value(&address_), "Group address") ("group,g", po::value(&group_), "Group name") ("sst", po::value(&sst_), "SST request string") ("donor", po::value(&donor_), "SST donor name") ("options,o",po::value(&options_), "GCS/GCOMM option list") ("log,l", po::value(&log_), "Log file") ; po::options_description cfg_opt; cfg_opt.add_options() ("cfg,c", po::value(&cfg_), "Configuration file") ; // these are accepted on the command line po::options_description cmdline_opts; cmdline_opts.add(config).add(cfg_opt).add(other); // we can submit address without option po::positional_options_description p; p.add("address", -1); po::variables_map vm; store(po::command_line_parser(argc, argv). options(cmdline_opts).positional(p).run(), vm); notify(vm); if (vm.count("help")) { std::cerr << "\nUsage: " << argv[0] << " [options] [group address]\n" << cmdline_opts << std::endl; exit_= true; return; } if (vm.count("version")) { log_info << GALERA_VER << ".r" << GALERA_REV; exit_= true; return; } if (vm.count("cfg")) { std::ifstream ifs(cfg_.c_str()); if (!ifs.good()) { gu_throw_error(errno) << "Failed to open configuration file '" << cfg_ << "' for reading."; } store(parse_config_file(ifs, config), vm); notify(vm); } if (!vm.count("address")) { gu_throw_error(EDESTADDRREQ) << "Group address not specified"; } if (!vm.count("group")) { gu_throw_error(EDESTADDRREQ) << "Group name not specified"; } if (vm.count("daemon")) { daemon_ = true; } /* Seeing how https://svn.boost.org/trac/boost/ticket/850 is fixed long and * hard, it becomes clear what an undercooked piece of... cake(?) boost is. * - need to strip quotes manually if used in config file. * (which is done in a very simplistic manner, but should work for most) */ strip_quotes(name_); strip_quotes(address_); strip_quotes(group_); strip_quotes(sst_); strip_quotes(donor_); strip_quotes(options_); strip_quotes(log_); strip_quotes(cfg_); if (options_.length() > 0) options_ += "; "; options_ += "gcs.fc_limit=9999999; gcs.fc_factor=1.0; gcs.fc_master_slave=yes"; // this block must be the very last. gu_conf_self_tstamp_on(); if (vm.count("log")) { set_logfile (log_); } else if (daemon_) /* if no log file given AND daemon operation requested - * log to syslog */ { gu_conf_self_tstamp_off(); set_syslog(); } gu_crc32c_configure(); } std::ostream& operator << (std::ostream& os, const Config& c) { os << "\n\tdaemon: " << c.daemon() << "\n\tname: " << c.name() << "\n\taddress: " << c.address() << "\n\tgroup: " << c.group() << "\n\tsst: " << c.sst() << "\n\tdonor: " << c.donor() << "\n\toptions: " << c.options() << "\n\tcfg: " << c.cfg() << "\n\tlog: " << c.log(); return os; } } percona-xtradb-cluster-galera-3.x-3.21/garb/garb_gcs.cpp0000644000175000017500000000734113136555240022751 0ustar jenkinsjenkins/* * Copyright (C) 2011-2014 Codership Oy */ #include "garb_gcs.hpp" namespace garb { static int const REPL_PROTO_VER(127); static int const APPL_PROTO_VER(127); Gcs::Gcs (gu::Config& gconf, const std::string& name, const std::string& address, const std::string& group) : closed_ (true), gcs_ (gcs_create (reinterpret_cast(&gconf), NULL, name.c_str(), "", REPL_PROTO_VER, APPL_PROTO_VER)) { if (!gcs_) { gu_throw_fatal << "Failed to create GCS object"; } ssize_t ret = gcs_open (gcs_, group.c_str(), address.c_str(), false); if (ret < 0) { gcs_destroy (gcs_); gu_throw_error(-ret) << "Failed to open connection to group"; } closed_ = false; } Gcs::~Gcs () { if (!closed_) { log_warn << "Destroying non-closed object, bad idea"; close (); } gcs_destroy (gcs_); } void Gcs::recv (gcs_action& act) { again: ssize_t ret = gcs_recv(gcs_, &act); if (gu_unlikely(ret < 0)) { if (-ECANCELED == ret) { ret = gcs_resume_recv (gcs_); if (0 == ret) goto again; } log_fatal << "Receiving from group failed: " << ret << " (" << strerror(-ret) << ")"; gu_throw_error(-ret) << "Receiving from group failed"; } } void Gcs::request_state_transfer (const std::string& request, const std::string& donor) { gcs_seqno_t order; log_info << "Sending state transfer request: '" << request << "', size: " << request.length(); /* Need to substitute the first ':' for \0 */ ssize_t req_len = request.length() + 1 /* \0 */; char* const req_str(reinterpret_cast(::malloc( req_len + 1 /* potentially need one more \0 */))); // cppcheck-suppress nullPointer if (!req_str) { gu_throw_error (ENOMEM) << "Cannot allocate " << req_len << " bytes for state transfer request"; } ::strcpy(req_str, request.c_str()); char* column_ptr = ::strchr(req_str, ':'); if (column_ptr) { *column_ptr = '\0'; } else /* append an empty string */ { req_str[req_len] = '\0'; req_len++; } ssize_t ret; do { gu_uuid_t ist_uuid = {{0, }}; gcs_seqno_t ist_seqno = GCS_SEQNO_ILL; // for garb we use the lowest str_version. ret = gcs_request_state_transfer (gcs_, 0, req_str, req_len, donor.c_str(), &ist_uuid, ist_seqno, &order); } while (-EAGAIN == ret && (usleep(1000000), true)); free (req_str); if (ret < 0) { log_fatal << "State transfer request failed: " << ret << " (" << strerror(-ret) << ")"; gu_throw_error(-ret) << "State transfer request failed"; } } void Gcs::join (gcs_seqno_t seqno) { ssize_t ret = gcs_join (gcs_, seqno); if (ret < 0) { log_fatal << "Joining group failed: " << ret << " (" << strerror(-ret) << ")"; gu_throw_error(-ret) << "Joining group failed"; } } void Gcs::set_last_applied (gcs_seqno_t seqno) { (void) gcs_set_last_applied(gcs_, seqno); } void Gcs::close () { if (!closed_) { ssize_t ret = gcs_close (gcs_); if (ret < 0) { log_error << "Failed to close connection to group"; } else { closed_ = true; } } else { log_warn << "Attempt to close a closed connection"; } } } /* namespace garb */ percona-xtradb-cluster-galera-3.x-3.21/garb/garb_logger.cpp0000644000175000017500000000215513136555240023452 0ustar jenkinsjenkins/* Copyright (C) 2011 Codership Oy */ #include "garb_logger.hpp" #include #include #include #include #include namespace garb { void set_logfile (const std::string& fname) { FILE* log_file = fopen (fname.c_str(), "a"); if (!log_file) { gu_throw_error (errno) << "Failed to open '" << fname << "' for appending"; } gu_conf_set_log_file (log_file); } static void log_to_syslog (int level, const char* msg) { int p = LOG_NOTICE; switch (level) { case GU_LOG_FATAL: p = LOG_CRIT; break; case GU_LOG_ERROR: p = LOG_ERR; break; case GU_LOG_WARN: p = LOG_WARNING; break; case GU_LOG_INFO: p = LOG_INFO; break; case GU_LOG_DEBUG: p = LOG_DEBUG; break; } syslog (p | LOG_DAEMON, "%s", msg); } void set_syslog () { openlog ("garbd", LOG_PID, LOG_DAEMON); gu_conf_set_log_callback (log_to_syslog); } } /* namespace garb */ percona-xtradb-cluster-galera-3.x-3.21/garb/SConscript0000644000175000017500000000337613136555240022514 0ustar jenkinsjenkins# Copyright (C) 2011 Codership Oy Import('env', 'libboost_program_options', 'static_ssl', 'with_ssl') garb_env = env.Clone() # Include paths garb_env.Append(CPPPATH = Split(''' # #/common #/galerautils/src #/gcs/src ''')) garb_env.Append(CPPFLAGS = ' -DGCS_FOR_GARB') garb_env.Prepend(LIBS=File('#/galerautils/src/libgalerautils.a')) garb_env.Prepend(LIBS=File('#/galerautils/src/libgalerautils++.a')) garb_env.Prepend(LIBS=File('#/gcomm/src/libgcomm.a')) garb_env.Prepend(LIBS=File('#/gcs/src/libgcs4garb.a')) if libboost_program_options: garb_env.Append(LIBS=libboost_program_options) # special environment for garb_config.cpp conf_env = garb_env.Clone() Import('GALERA_VER', 'GALERA_REV') conf_env.Append(CPPFLAGS = ' -DGALERA_VER=\\"' + GALERA_VER + '\\"') conf_env.Append(CPPFLAGS = ' -DGALERA_REV=\\"' + GALERA_REV + '\\"') if static_ssl == 1: garb_env.Append(LIBPATH = [with_ssl]) garb_env.Append(LIBS=File('%s/libssl.a' %(with_ssl))) garb_env.Append(LIBS=File('%s/libcrypto.a' %(with_ssl))) garb_env.Append(LIBS=File('%s/libz.a' %(with_ssl))) garb_env.Append(LIBS=['dl']) garb = garb_env.Program(target = 'garbd', source = Split(''' garb_logger.cpp garb_gcs.cpp garb_recv_loop.cpp garb_main.cpp ''') + conf_env.SharedObject(['garb_config.cpp']) ) percona-xtradb-cluster-galera-3.x-3.21/garb/garb_config.hpp0000644000175000017500000000247613136555240023453 0ustar jenkinsjenkins/* Copyright (C) 2011-2013 Codership Oy */ #ifndef _GARB_CONFIG_HPP_ #define _GARB_CONFIG_HPP_ #include #include namespace garb { class Config { public: static std::string const DEFAULT_SST; // default (empty) SST request Config (int argc, char* argv[]); ~Config () {} bool daemon() const { return daemon_ ; } const std::string& name() const { return name_ ; } const std::string& address() const { return address_; } const std::string& group() const { return group_ ; } const std::string& sst() const { return sst_ ; } const std::string& donor() const { return donor_ ; } const std::string& options() const { return options_; } const std::string& cfg() const { return cfg_ ; } const std::string& log() const { return log_ ; } bool exit() const { return exit_ ; } private: bool daemon_; std::string name_; std::string address_; std::string group_; std::string sst_; std::string donor_; std::string options_; std::string log_; std::string cfg_; bool exit_; /* Exit on --help or --version */ }; /* class Config */ std::ostream& operator << (std::ostream&, const Config&); } /* namespace garb */ #endif /* _GARB_CONFIG_HPP_ */ percona-xtradb-cluster-galera-3.x-3.21/garb/garb_recv_loop.cpp0000644000175000017500000000516513136555240024167 0ustar jenkinsjenkins/* Copyright (C) 2011-2014 Codership Oy */ #include "garb_recv_loop.hpp" #include namespace garb { static Gcs* global_gcs(0); void signal_handler (int signum) { log_info << "Received signal " << signum; global_gcs->close(); } RecvLoop::RecvLoop (const Config& config) : config_(config), gconf_ (), params_(gconf_), parse_ (gconf_, config_.options()), gcs_ (gconf_, config_.name(), config_.address(), config_.group()) { /* set up signal handlers */ global_gcs = &gcs_; struct sigaction sa; memset (&sa, 0, sizeof(sa)); sa.sa_handler = signal_handler; if (sigaction (SIGTERM, &sa, NULL)) { gu_throw_error(errno) << "Falied to install signal hadler for signal " << "SIGTERM"; } if (sigaction (SIGINT, &sa, NULL)) { gu_throw_error(errno) << "Falied to install signal hadler for signal " << "SIGINT"; } loop(); } void RecvLoop::loop() { while (1) { gcs_action act; gcs_.recv (act); switch (act.type) { case GCS_ACT_TORDERED: if (gu_unlikely(!(act.seqno_g & 127))) /* == report_interval_ of 128 */ { gcs_.set_last_applied (act.seqno_g); } break; case GCS_ACT_COMMIT_CUT: break; case GCS_ACT_STATE_REQ: gcs_.join (-ENOSYS); /* we can't donate state */ break; case GCS_ACT_CONF: { const gcs_act_conf_t* const cc (reinterpret_cast(act.buf)); if (cc->conf_id > 0) /* PC */ { if (GCS_NODE_STATE_PRIM == cc->my_state) { gcs_.request_state_transfer (config_.sst(),config_.donor()); gcs_.join(cc->seqno); } } else if (cc->memb_num == 0) // SELF-LEAVE after closing connection { log_info << "Exiting main loop"; return; } if (config_.sst() != Config::DEFAULT_SST) { // we requested custom SST, so we're done here gcs_.close(); } break; } case GCS_ACT_JOIN: case GCS_ACT_SYNC: case GCS_ACT_FLOW: case GCS_ACT_SERVICE: case GCS_ACT_ERROR: case GCS_ACT_UNKNOWN: break; } if (act.buf) { free (const_cast(act.buf)); } } } } /* namespace garb */ percona-xtradb-cluster-galera-3.x-3.21/man/0000755000175000017500000000000013136555240020331 5ustar jenkinsjenkinspercona-xtradb-cluster-galera-3.x-3.21/man/garbd.80000644000175000017500000000435213136555240021505 0ustar jenkinsjenkins.TH GARBD "8" "December 2014" "garbd INFO: 2.8.r165" "System Administration Utilities" .SH NAME garbd \- arbitrator daemon for Galera cluster .SH SYNOPSIS .B garbd [\fI\,options\/\fR] [\fI\,group address\/\fR] .SH DESCRIPTION .B garbd joins Galera cluster as an additional node for the purpose of establishing quorum in case of network partitioning. It can do so by serving: .RS a) as an odd node to prevent split-brains; .RE .RS b) as a reference connection point outside a datacenter. .RE Arbitrator node must see all messages that the other nodes of the cluster see, however it does not process them any further and just discards them. As such it does not store any cluster state and can't be used to bootstrap the cluster, so it only can join existing cluster. .SH OPTIONS .SS "Configuration:" .TP \fB\-d\fR [ \fB\-\-daemon\fR ] Become daemon .TP \fB\-a\fR [ \fB\-\-address\fR ] arg Group address in Galera format .TP \fB\-g\fR [ \fB\-\-group\fR ] arg Group name .TP \fB\-\-sst\fR arg SST request string that contains SST request to trigger state snapshot dump (state backup) on one of the other nodes. For details refer to Galera documentation at http://www.galeracluster.com .TP \fB\-\-donor\fR arg SST donor name (for state dump) .TP \fB\-o\fR [ \fB\-\-options\fR ] arg GCS/GCOMM option list. It is likely to be the same as on other nodes of the cluster. .TP \fB\-l\fR [ \fB\-\-log\fR ] arg Path to log file .TP \fB\-c\fR [ \fB\-\-cfg\fR ] arg Path to configuration file. Configuration file contains garbd options in the form \fB